diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13ae189 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tools/polyexen/target diff --git a/tools/polyexen/.gitignore b/tools/polyexen/.gitignore new file mode 100644 index 0000000..0a25f36 --- /dev/null +++ b/tools/polyexen/.gitignore @@ -0,0 +1,2 @@ +/target +/out diff --git a/tools/polyexen/Cargo.lock b/tools/polyexen/Cargo.lock new file mode 100644 index 0000000..dd02d5e --- /dev/null +++ b/tools/polyexen/Cargo.lock @@ -0,0 +1,4943 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "alloy-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal 0.4.1", + "itoa", + "ruint", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +dependencies = [ + "alloy-rlp-derive", + "arrayvec 0.7.4", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "anstream" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.4", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "colored", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.51", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + +[[package]] +name = "auto_impl" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" +dependencies = [ + "serde", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bellperson" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93eaee4b4753554139ae52ecf0e8b8c128cbc561b32e1bfaa32f70cba8518c1f" +dependencies = [ + "bincode", + "blake2s_simd 1.0.2", + "blstrs", + "byteorder", + "crossbeam-channel", + "digest 0.10.7", + "ec-gpu", + "ec-gpu-gen", + "ff", + "group", + "log", + "memmap2", + "pairing", + "rand 0.8.5", + "rand_core 0.6.4", + "rayon", + "rustversion", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.51", + "which", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac926d808fb72fe09ebf471a091d6d72918876ccf0b4989766093d2d0d24a0ef" +dependencies = [ + "bindgen", + "blst", + "cc", + "glob", + "hex", + "libc", + "serde", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.22", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3 0.10.8", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "const-hex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbd12d49ab0eaf8193ba9175e45f56bbc2e4b27d57b8cfe62aa47942a46b9a9" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ec-gpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45" + +[[package]] +name = "ec-gpu-gen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "892df2aa20abec5b816e15d5d6383892ca142077708efa3067dd3ac44b75c664" +dependencies = [ + "bitvec", + "crossbeam-channel", + "ec-gpu", + "execute", + "ff", + "group", + "hex", + "log", + "num_cpus", + "once_cell", + "rayon", + "sha2", + "thiserror", + "yastl", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3 0.10.8", + "zeroize", +] + +[[package]] +name = "enumn" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c012a26a7f605efc424dd53697843a72be7dc86ad2d01f7814337794a12231d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3 0.10.8", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c7cd562832e2ff584fa844cd2f6e5d4f35bbe11b28c7c9b8df957b2e1d0c701" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35dc9a249c066d17e8947ff52a4116406163cf92c7f0763cb8c001760b26403f" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43304317c7f776876e47f2f637859f6d0701c1ec7930a150f169d5fbe7d76f5a" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f96502317bf34f6d71a3e3d270defaa9485d754d789e15a8e04a84161c95eb" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.51", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "452ff6b0a64507ce8d67ffd48b1da3b42f03680dcf5382244e9c93822cbbf5de" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.51", +] + +[[package]] +name = "ethers-core" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab3cef6cc1c9fd7f787043c81ad3052eff2b96a3878ef1526aa446311bdbfc9" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.51", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d45b981f5fa769e1d0343ebc2a44cfa88c9bc312eb681b676318b40cef6fb1" +dependencies = [ + "chrono", + "ethers-core", + "ethers-solc", + "reqwest", + "semver 1.0.22", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145211f34342487ef83a597c1e69f0d3e01512217a7c72cc8a25931854c7dca0" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb6b15393996e3b8a78ef1332d6483c11d839042c17be58decc92fa8b1c3508a" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b125a103b56aef008af5d5fb48191984aa326b50bfd2557d231dc499833de3" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d21df08582e0a43005018a858cc9b465c5fff9cf4056651be64f844e57d1f55f" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver 1.0.22", + "serde", + "serde_json", + "solang-parser", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "execute" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a82608ee96ce76aeab659e9b8d3c2b787bffd223199af88c674923d861ada10" +dependencies = [ + "execute-command-macro", + "execute-command-tokens", + "generic-array 1.0.0", +] + +[[package]] +name = "execute-command-macro" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dec53d547564e911dc4ff3ecb726a64cf41a6fa01a2370ebc0d95175dd08bd" +dependencies = [ + "execute-command-macro-impl", +] + +[[package]] +name = "execute-command-macro-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b" +dependencies = [ + "execute-command-tokens", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "execute-command-tokens" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69dc321eb6be977f44674620ca3aa21703cb20ffbe560e1ae97da08401ffbcad" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff_ce" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a682c12d0cc98a32ab7540401a5ea1ed21d11571eea11d5829cd721f85ff0" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ff_derive_ce" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b" +dependencies = [ + "num-bigint 0.2.6", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halo2_gadgets" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "ff", + "group", + "halo2_proofs", + "halo2curves", + "lazy_static", + "rand 0.8.5", + "subtle", + "uint", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves", + "maybe-rayon", + "rand_chacha", + "rand_core 0.6.4", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2_solidity_verifier" +version = "0.1.0" +source = "git+https://github.com/summa-dev/halo2-solidity-verifier#d33972567f83f3218257b286b541ad97ba32928c" +dependencies = [ + "askama", + "blake2b_simd", + "halo2_proofs", + "hex", + "itertools 0.11.0", + "revm", + "ruint", + "sha3 0.10.8", +] + +[[package]] +name = "halo2curves" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint 0.4.4", + "num-traits", + "pasta_curves", + "paste", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "serde_arrays", + "static_assertions", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.7.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "neptune" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9a64337e6d214e2a48db5714ef18cf1e5a7bbff9043838fdf6e57ce5659335" +dependencies = [ + "bellperson", + "blake2s_simd 0.5.11", + "blstrs", + "byteorder", + "ff", + "generic-array 0.14.7", + "itertools 0.8.2", + "log", + "pasta_curves", + "serde", + "trait-set", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nova-scotia" +version = "0.5.0" +source = "git+https://github.com/nalinbhardwaj/Nova-Scotia#54f2bdbb78aad841d8714f7e2d0344bcc593a922" +dependencies = [ + "anyhow", + "bellperson", + "byteorder", + "ff", + "hex-literal 0.3.4", + "itertools 0.9.0", + "js-sys", + "nova-snark", + "num-bigint 0.4.4", + "num-traits", + "pasta_curves", + "rayon", + "serde", + "serde_json", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-rayon", +] + +[[package]] +name = "nova-snark" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e12911ac9672ad436acfc992f09e26a5960513bbe81d1572005cadd8c1be8f4" +dependencies = [ + "bellperson", + "bincode", + "bitvec", + "byteorder", + "digest 0.10.7", + "ff", + "flate2", + "generic-array 0.14.7", + "getrandom", + "halo2curves", + "itertools 0.11.0", + "neptune", + "num-bigint 0.4.4", + "num-integer", + "num-traits", + "pasta-msm", + "pasta_curves", + "rand_chacha", + "rand_core 0.6.4", + "rayon", + "serde", + "sha3 0.10.8", + "subtle", + "thiserror", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pasta-msm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85d75eba3e7e9ee3bd11342b669185e194dadda3557934bc1000d9b87159d3" +dependencies = [ + "cc", + "pasta_curves", + "semolina", + "sppark", + "which", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polyexen" +version = "0.1.0" +dependencies = [ + "halo2_proofs", + "lazy_static", + "log", + "nom", + "num-bigint 0.4.4", + "num-integer", + "num-traits", + "pest", + "pest_derive", + "rand 0.8.5", + "rand_chacha", + "static_assertions", +] + +[[package]] +name = "poseidon-rs" +version = "0.0.10" +source = "git+https://github.com/arnaucube/poseidon-rs#f4ba1f7c32905cd2ae5a71e7568564bb150a9862" +dependencies = [ + "ff_ce", + "rand 0.4.6", + "serde_json", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.51", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", + "wasm_sync", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", + "wasm_sync", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[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_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "revm" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f4ca8ae0345104523b4af1a8a7ea97cfa1865cdb7a7c25d23c1a18d9b48598" +dependencies = [ + "auto_impl", + "revm-interpreter", + "revm-precompile", +] + +[[package]] +name = "revm-interpreter" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f959cafdf64a7f89b014fa73dc2325001cf654b3d9400260b212d19a2ebe3da0" +dependencies = [ + "revm-primitives", +] + +[[package]] +name = "revm-precompile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d360a88223d85709d2e95d4609eb1e19c649c47e28954bfabae5e92bb37e83e" +dependencies = [ + "c-kzg", + "k256", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51187b852d9e458816a2e19c81f1dd6c924077e1a8fccd16e4f044f865f299d7" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "auto_impl", + "bitflags 2.4.2", + "bitvec", + "c-kzg", + "enumn", + "hashbrown", + "hex", + "once_cell", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ruint" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint 0.4.4", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.22", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "semolina" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0111fd4fa831becb0606b9a2285ef3bee3c6a70d690209b8ae9514e9befe23" +dependencies = [ + "cc", + "glob", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sppark" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb266b15daead53670d477d7e136b8fc92d46e31bb9007ac46d304df23689a4b" +dependencies = [ + "cc", + "which", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.51", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "summa-polyexen" +version = "0.1.0" +dependencies = [ + "env_logger", + "halo2_proofs", + "log", + "num-bigint 0.4.4", + "polyexen", + "summa-solvency", +] + +[[package]] +name = "summa-solvency" +version = "0.1.0" +dependencies = [ + "ark-std 0.3.0", + "csv", + "ethers", + "ff_ce", + "halo2_gadgets", + "halo2_proofs", + "halo2_solidity_verifier", + "hex", + "itertools 0.11.0", + "nova-scotia", + "nova-snark", + "num-bigint 0.4.4", + "num-traits", + "num_cpus", + "poseidon-rs", + "rand 0.8.5", + "rayon", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.6", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.2", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.51", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-rayon" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e02b7785fe15de188657b7d3a234ef042bfd8da10822016915e06d4e29cba7" +dependencies = [ + "crossbeam-channel", + "js-sys", + "rayon", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" + +[[package]] +name = "wasm_sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff360cade7fec41ff0e9d2cda57fe58258c5f16def0e21302394659e6bbb0ea" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.3", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +dependencies = [ + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.51", +] diff --git a/tools/polyexen/Cargo.toml b/tools/polyexen/Cargo.toml new file mode 100644 index 0000000..2198dd1 --- /dev/null +++ b/tools/polyexen/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "summa-polyexen" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-bigint = { version = "0.4", features = [ "rand" ] } +halo2_proofs = { git = "https://github.com/summa-dev/halo2", commit= "8386d6e" } +polyexen = { path = "./deps/polyexen" } +summa-solvency = { path = "./circuit/solvency/zk_prover" } +log = "0.4.20" +env_logger = "0.11.2" diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/.github/workflows/ci.yml b/tools/polyexen/circuit/halo2-solidity-verifier/.github/workflows/ci.yml new file mode 100644 index 0000000..03e508c --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: Install solc + run: (hash svm 2>/dev/null || cargo install --locked --git https://github.com/alloy-rs/svm-rs) && svm install 0.8.21 && solc --version + + - name: Run test + run: cargo test --workspace --all-features --all-targets -- --nocapture + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + components: rustfmt, clippy + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: Run fmt + run: cargo fmt --all -- --check + + - name: Run clippy + run: cargo clippy --workspace --all-features --all-targets -- -D warnings diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/.gitignore b/tools/polyexen/circuit/halo2-solidity-verifier/.gitignore new file mode 100644 index 0000000..7e85a55 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/.gitignore @@ -0,0 +1,17 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +.vscode +generated/ \ No newline at end of file diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/Cargo.toml b/tools/polyexen/circuit/halo2-solidity-verifier/Cargo.toml new file mode 100644 index 0000000..9742da3 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "halo2_solidity_verifier" +version = "0.1.0" +edition = "2021" + +[dependencies] +halo2_proofs = { git = "https://github.com/summa-dev/halo2"} +askama = { version = "0.12.0", features = ["config"], default-features = false } +hex = "0.4.3" +ruint = "1" +sha3 = "0.10" +itertools = "0.11.0" + +# Remove when `vk.transcript_repr()` is ready for usage. +blake2b_simd = "1" + +# For feature = "evm" +revm = { version = "3.3.0", optional = true } + +[dev-dependencies] +rand = "0.8.5" +revm = "3.3.0" +halo2_maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20", package = "maingate" } + +[features] +default = [] +evm = ["dep:revm"] + +[[example]] +name = "separately" +required-features = ["evm"] diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/LICENSE b/tools/polyexen/circuit/halo2-solidity-verifier/LICENSE new file mode 100644 index 0000000..245499e --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Privacy & Scaling Explorations (formerly known as appliedzkp) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/README.md b/tools/polyexen/circuit/halo2-solidity-verifier/README.md new file mode 100644 index 0000000..5152dfd --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/README.md @@ -0,0 +1,45 @@ +# Halo2 Solidity Verifier + +> ⚠️ This repo has NOT been audited and is NOT intended for a production environment yet. + +Solidity verifier generator for [`halo2`](http://github.com/privacy-scaling-explorations/halo2) proof with KZG polynomial commitment scheme on BN254 + +## Usage + +### Generate verifier and verifying key separately as 2 solidity contracts + +```rust +let generator = SolidityGenerator::new(¶ms, &vk, Bdfg21, num_instances); +let (verifier_solidity, vk_solidity) = generator.render_separately().unwrap(); +``` + +Check [`examples/separately.rs`](./examples/separately.rs) for more details. + +### Generate verifier and verifying key in a single solidity contract + +```rust +let generator = SolidityGenerator::new(¶ms, &vk, Bdfg21, num_instances); +let verifier_solidity = generator.render().unwrap(); +``` + +### Encode proof into calldata to invoke `verifyProof` + +```rust +let calldata = encode_calldata(vk_address, &proof, &instances); +``` + +Note that function selector is already included. + +## Limitations + +- It only allows circuit with **exact 1 instance column** and **no rotated query to this instance column**. +- Currently even the `configure` is same, the [selector compression](https://github.com/privacy-scaling-explorations/halo2/blob/7a2165617195d8baa422ca7b2b364cef02380390/halo2_proofs/src/plonk/circuit/compress_selectors.rs#L51) might lead to different configuration when selector assignments are different. After PR https://github.com/privacy-scaling-explorations/halo2/pull/212 is merged we will have an alternative API to do key generation without selector compression. +- Now it only supports BDFG21 batch open scheme (aka SHPLONK), GWC19 is not yet implemented. + +## Compatibility + +The [`Keccak256Transcript`](./src/transcript.rs#L19) behaves exactly same as the `EvmTranscript` in `snark-verifier`. + +## Acknowledgement + +The template is heavily inspired by Aztec's [`BaseUltraVerifier.sol`](https://github.com/AztecProtocol/barretenberg/blob/4c456a2b196282160fd69bead6a1cea85289af37/sol/src/ultra/BaseUltraVerifier.sol). diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/askama.toml b/tools/polyexen/circuit/halo2-solidity-verifier/askama.toml new file mode 100644 index 0000000..44f2f2f --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/askama.toml @@ -0,0 +1,3 @@ +[[escaper]] +path = "askama::Text" +extensions = ["sol"] diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/examples/separately.rs b/tools/polyexen/circuit/halo2-solidity-verifier/examples/separately.rs new file mode 100644 index 0000000..d748332 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/examples/separately.rs @@ -0,0 +1,242 @@ +use application::StandardPlonk; +use prelude::*; + +use halo2_solidity_verifier::{ + compile_solidity, encode_calldata, BatchOpenScheme::Bdfg21, Evm, Keccak256Transcript, + SolidityGenerator, +}; + +const K_RANGE: Range = 10..17; + +fn main() { + let mut rng = seeded_std_rng(); + + let params = setup(K_RANGE, &mut rng); + + let vk = keygen_vk(¶ms[&K_RANGE.start], &StandardPlonk::default()).unwrap(); + let generator = SolidityGenerator::new(¶ms[&K_RANGE.start], &vk, Bdfg21, 0); + let (verifier_solidity, _) = generator.render_separately().unwrap(); + save_solidity("Halo2Verifier.sol", &verifier_solidity); + + let verifier_creation_code = compile_solidity(&verifier_solidity); + let verifier_creation_code_size = verifier_creation_code.len(); + println!("Verifier creation code size: {verifier_creation_code_size}"); + + let mut evm = Evm::default(); + let verifier_address = evm.create(verifier_creation_code); + + let deployed_verifier_solidity = verifier_solidity; + + for k in K_RANGE { + let num_instances = k as usize; + let circuit = StandardPlonk::rand(num_instances, &mut rng); + + let vk = keygen_vk(¶ms[&k], &circuit).unwrap(); + let pk = keygen_pk(¶ms[&k], vk, &circuit).unwrap(); + let generator = SolidityGenerator::new(¶ms[&k], pk.get_vk(), Bdfg21, num_instances); + let (verifier_solidity, vk_solidity) = generator.render_separately().unwrap(); + save_solidity(format!("Halo2VerifyingKey-{k}.sol"), &vk_solidity); + + assert_eq!(deployed_verifier_solidity, verifier_solidity); + + let vk_creation_code = compile_solidity(&vk_solidity); + let vk_address = evm.create(vk_creation_code); + + let calldata = { + let instances = circuit.instances(); + let proof = create_proof_checked(¶ms[&k], &pk, circuit, &instances, &mut rng); + encode_calldata(Some(vk_address.into()), &proof, &instances) + }; + let (gas_cost, output) = evm.call(verifier_address, calldata); + assert_eq!(output, [vec![0; 31], vec![1]].concat()); + println!("Gas cost of verifying standard Plonk with 2^{k} rows: {gas_cost}"); + } +} + +fn save_solidity(name: impl AsRef, solidity: &str) { + const DIR_GENERATED: &str = "./generated"; + + create_dir_all(DIR_GENERATED).unwrap(); + File::create(format!("{DIR_GENERATED}/{}", name.as_ref())) + .unwrap() + .write_all(solidity.as_bytes()) + .unwrap(); +} + +fn setup(k_range: Range, mut rng: impl RngCore) -> HashMap> { + k_range + .clone() + .zip(k_range.map(|k| ParamsKZG::::setup(k, &mut rng))) + .collect() +} + +fn create_proof_checked( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: impl Circuit, + instances: &[Fr], + mut rng: impl RngCore, +) -> Vec { + use halo2_proofs::{ + poly::kzg::{ + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + transcript::TranscriptWriterBuffer, + }; + + let proof = { + let mut transcript = Keccak256Transcript::new(Vec::new()); + create_proof::<_, ProverSHPLONK<_>, _, _, _, _>( + params, + pk, + &[circuit], + &[&[instances]], + &mut rng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + let result = { + let mut transcript = Keccak256Transcript::new(proof.as_slice()); + verify_proof::<_, VerifierSHPLONK<_>, _, _, SingleStrategy<_>>( + params, + pk.get_vk(), + SingleStrategy::new(params), + &[&[instances]], + &mut transcript, + ) + }; + assert!(result.is_ok()); + + proof +} + +mod application { + use crate::prelude::*; + + #[derive(Clone)] + pub struct StandardPlonkConfig { + selectors: [Column; 5], + wires: [Column; 3], + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [w_l, w_r, w_o] = [(); 3].map(|_| meta.advice_column()); + let [q_l, q_r, q_o, q_m, q_c] = [(); 5].map(|_| meta.fixed_column()); + let pi = meta.instance_column(); + [w_l, w_r, w_o].map(|column| meta.enable_equality(column)); + meta.create_gate( + "q_l·w_l + q_r·w_r + q_o·w_o + q_m·w_l·w_r + q_c + pi = 0", + |meta| { + let [w_l, w_r, w_o] = + [w_l, w_r, w_o].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_l, q_r, q_o, q_m, q_c] = [q_l, q_r, q_o, q_m, q_c] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let pi = meta.query_instance(pi, Rotation::cur()); + Some( + q_l * w_l.clone() + + q_r * w_r.clone() + + q_o * w_o + + q_m * w_l * w_r + + q_c + + pi, + ) + }, + ); + StandardPlonkConfig { + selectors: [q_l, q_r, q_o, q_m, q_c], + wires: [w_l, w_r, w_o], + } + } + } + + #[derive(Clone, Debug, Default)] + pub struct StandardPlonk(Vec); + + impl StandardPlonk { + pub fn rand(num_instances: usize, mut rng: R) -> Self { + Self((0..num_instances).map(|_| F::random(&mut rng)).collect()) + } + + pub fn instances(&self) -> Vec { + self.0.clone() + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + unimplemented!() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let [q_l, q_r, q_o, q_m, q_c] = config.selectors; + let [w_l, w_r, w_o] = config.wires; + layouter.assign_region( + || "", + |mut region| { + for (offset, instance) in self.0.iter().enumerate() { + region.assign_advice(|| "", w_l, offset, || Value::known(*instance))?; + region.assign_fixed(|| "", q_l, offset, || Value::known(-F::ONE))?; + } + let offset = self.0.len(); + let a = region.assign_advice(|| "", w_l, offset, || Value::known(F::ONE))?; + a.copy_advice(|| "", &mut region, w_r, offset)?; + a.copy_advice(|| "", &mut region, w_o, offset)?; + let offset = offset + 1; + region.assign_advice(|| "", w_l, offset, || Value::known(-F::from(5)))?; + for (column, idx) in [q_l, q_r, q_o, q_m, q_c].iter().zip(1..) { + region.assign_fixed( + || "", + *column, + offset, + || Value::known(F::from(idx)), + )?; + } + Ok(()) + }, + ) + } + } +} + +mod prelude { + pub use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::{ + bn256::{Bn256, Fr, G1Affine}, + ff::PrimeField, + }, + plonk::*, + poly::{commitment::Params, kzg::commitment::ParamsKZG, Rotation}, + }; + pub use rand::{ + rngs::{OsRng, StdRng}, + RngCore, SeedableRng, + }; + pub use std::{ + collections::HashMap, + fs::{create_dir_all, File}, + io::Write, + ops::Range, + }; + + pub fn seeded_std_rng() -> impl RngCore { + StdRng::seed_from_u64(OsRng.next_u64()) + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen.rs new file mode 100644 index 0000000..7d420ca --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen.rs @@ -0,0 +1,337 @@ +use crate::codegen::{ + evaluator::Evaluator, + pcs::{ + bdfg21_computations, queries, rotation_sets, + BatchOpenScheme::{Bdfg21, Gwc19}, + }, + template::{Halo2Verifier, Halo2VerifyingKey}, + util::{fr_to_u256, g1_to_u256s, g2_to_u256s, ConstraintSystemMeta, Data, Ptr}, +}; +use halo2_proofs::{ + halo2curves::{bn256, ff::Field}, + plonk::VerifyingKey, + poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG, Rotation}, +}; +use itertools::{chain, Itertools}; +use ruint::aliases::U256; +use std::fmt::{self, Debug}; + +mod evaluator; +mod pcs; +mod template; +pub(crate) mod util; + +pub use pcs::BatchOpenScheme; + +/// Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254. +#[derive(Debug)] +pub struct SolidityGenerator<'a> { + params: &'a ParamsKZG, + vk: &'a VerifyingKey, + scheme: BatchOpenScheme, + num_instances: usize, + acc_encoding: Option, + meta: ConstraintSystemMeta, +} + +/// KZG accumulator encoding information. +/// Limbs of each field element are assumed to be least significant limb first. +/// +/// Given instances and `AccumulatorEncoding`, the accumulator will be interpreted as below: +/// ```rust +/// use halo2_proofs::halo2curves::{bn256, ff::{Field, PrimeField}, CurveAffine}; +/// +/// fn accumulator_from_limbs( +/// instances: &[bn256::Fr], +/// offset: usize, +/// num_limbs: usize, +/// num_limb_bits: usize, +/// ) -> (bn256::G1Affine, bn256::G1Affine) { +/// let limbs = |offset| &instances[offset..offset + num_limbs]; +/// let acc_lhs_x = fe_from_limbs(limbs(offset), num_limb_bits); +/// let acc_lhs_y = fe_from_limbs(limbs(offset + num_limbs), num_limb_bits); +/// let acc_rhs_x = fe_from_limbs(limbs(offset + 2 * num_limbs), num_limb_bits); +/// let acc_rhs_y = fe_from_limbs(limbs(offset + 3 * num_limbs), num_limb_bits); +/// let acc_lhs = bn256::G1Affine::from_xy(acc_lhs_x, acc_lhs_y).unwrap(); +/// let acc_rhs = bn256::G1Affine::from_xy(acc_rhs_x, acc_rhs_y).unwrap(); +/// (acc_lhs, acc_rhs) +/// } +/// +/// fn fe_from_limbs(limbs: &[bn256::Fr], num_limb_bits: usize) -> bn256::Fq { +/// limbs.iter().rev().fold(bn256::Fq::ZERO, |acc, limb| { +/// acc * bn256::Fq::from(2).pow_vartime([num_limb_bits as u64]) +/// + bn256::Fq::from_repr_vartime(limb.to_repr()).unwrap() +/// }) +/// } +/// ``` +/// +/// In the end of `verifyProof`, the accumulator will be used to do batched pairing with the +/// pairing input of incoming proof. +#[derive(Clone, Copy, Debug)] +pub struct AccumulatorEncoding { + /// Offset of accumulator limbs in instances. + pub offset: usize, + /// Number of limbs per base field element. + pub num_limbs: usize, + /// Number of bits per limb. + pub num_limb_bits: usize, +} + +impl AccumulatorEncoding { + /// Return a new `AccumulatorEncoding`. + pub fn new(offset: usize, num_limbs: usize, num_limb_bits: usize) -> Self { + Self { + offset, + num_limbs, + num_limb_bits, + } + } +} + +impl<'a> SolidityGenerator<'a> { + /// Return a new `SolidityGenerator`. + pub fn new( + params: &'a ParamsKZG, + vk: &'a VerifyingKey, + scheme: BatchOpenScheme, + num_instances: usize, + ) -> Self { + assert_ne!(vk.cs().num_advice_columns(), 0); + assert!( + vk.cs().num_instance_columns() <= 1, + "Multiple instance columns is not yet implemented" + ); + assert!( + !vk.cs() + .instance_queries() + .iter() + .any(|(_, rotation)| *rotation != Rotation::cur()), + "Rotated query to instance column is not yet implemented" + ); + assert_eq!( + scheme, + BatchOpenScheme::Bdfg21, + "BatchOpenScheme::Gwc19 is not yet implemented" + ); + + Self { + params, + vk, + scheme, + num_instances, + acc_encoding: None, + meta: ConstraintSystemMeta::new(vk.cs()), + } + } + + /// Set `AccumulatorEncoding`. + pub fn set_acc_encoding(mut self, acc_encoding: Option) -> Self { + self.acc_encoding = acc_encoding; + self + } +} + +impl<'a> SolidityGenerator<'a> { + /// Render `Halo2Verifier.sol` with verifying key embedded into writer. + pub fn render_into(&self, verifier_writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.generate_verifier(false).render(verifier_writer) + } + + /// Render `Halo2Verifier.sol` with verifying key embedded and return it as `String`. + pub fn render(&self) -> Result { + let mut verifier_output = String::new(); + self.render_into(&mut verifier_output)?; + Ok(verifier_output) + } + + /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` into writers. + pub fn render_separately_into( + &self, + verifier_writer: &mut impl fmt::Write, + vk_writer: &mut impl fmt::Write, + ) -> Result<(), fmt::Error> { + self.generate_verifier(true).render(verifier_writer)?; + self.generate_vk().render(vk_writer)?; + Ok(()) + } + + /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` and return them as `String`. + pub fn render_separately(&self) -> Result<(String, String), fmt::Error> { + let mut verifier_output = String::new(); + let mut vk_output = String::new(); + self.render_separately_into(&mut verifier_output, &mut vk_output)?; + Ok((verifier_output, vk_output)) + } + + fn generate_vk(&self) -> Halo2VerifyingKey { + let constants = { + let domain = self.vk.get_domain(); + let vk_digest = fr_to_u256(vk_transcript_repr(self.vk)); + let k = U256::from(domain.k()); + let n_inv = fr_to_u256(bn256::Fr::from(1 << domain.k()).invert().unwrap()); + let omega = fr_to_u256(domain.get_omega()); + let omega_inv = fr_to_u256(domain.get_omega_inv()); + let omega_inv_to_l = { + let l = self.meta.rotation_last.unsigned_abs() as u64; + fr_to_u256(domain.get_omega_inv().pow_vartime([l])) + }; + let num_instances = U256::from(self.num_instances); + let has_accumulator = if self.acc_encoding.is_some() { + U256::from(1) + } else { + U256::from(0) + }; + let acc_offset = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.offset)) + .unwrap_or_default(); + let num_acc_limbs = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.num_limbs)) + .unwrap_or_default(); + let num_acc_limb_bits = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.num_limb_bits)) + .unwrap_or_default(); + let g1 = self.params.get_g()[0]; + let g1 = g1_to_u256s(g1); + let g2 = g2_to_u256s(self.params.g2()); + let neg_s_g2 = g2_to_u256s(-self.params.s_g2()); + vec![ + ("vk_digest", vk_digest), + ("k", k), + ("n_inv", n_inv), + ("omega", omega), + ("omega_inv", omega_inv), + ("omega_inv_to_l", omega_inv_to_l), + ("num_instances", num_instances), + ("has_accumulator", has_accumulator), + ("acc_offset", acc_offset), + ("num_acc_limbs", num_acc_limbs), + ("num_acc_limb_bits", num_acc_limb_bits), + ("g1_x", g1[0]), + ("g1_y", g1[1]), + ("g2_x_1", g2[0]), + ("g2_x_2", g2[1]), + ("g2_y_1", g2[2]), + ("g2_y_2", g2[3]), + ("neg_s_g2_x_1", neg_s_g2[0]), + ("neg_s_g2_x_2", neg_s_g2[1]), + ("neg_s_g2_y_1", neg_s_g2[2]), + ("neg_s_g2_y_2", neg_s_g2[3]), + ] + }; + let fixed_comms = chain![self.vk.fixed_commitments()] + .flat_map(g1_to_u256s) + .tuples() + .collect(); + let permutation_comms = chain![self.vk.permutation().commitments()] + .flat_map(g1_to_u256s) + .tuples() + .collect(); + Halo2VerifyingKey { + constants, + fixed_comms, + permutation_comms, + } + } + + fn generate_verifier(&self, separate: bool) -> Halo2Verifier { + let proof_cptr = Ptr::calldata(if separate { 0x84 } else { 0x64 }); + + let vk = self.generate_vk(); + let vk_len = vk.len(); + let vk_mptr = Ptr::memory(self.estimate_static_working_memory_size(&vk, proof_cptr)); + let data = Data::new(&self.meta, &vk, vk_mptr, proof_cptr); + + let evaluator = Evaluator::new(self.vk.cs(), &self.meta, &data); + let quotient_eval_numer_computations = chain![ + evaluator.gate_computations(), + evaluator.permutation_computations(), + evaluator.lookup_computations() + ] + .enumerate() + .map(|(idx, (mut lines, var))| { + let line = if idx == 0 { + format!("quotient_eval_numer := {var}") + } else { + format!( + "quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), {var}, r)" + ) + }; + lines.push(line); + lines + }) + .collect(); + + let pcs_computations = match self.scheme { + Bdfg21 => bdfg21_computations(&self.meta, &data), + Gwc19 => unimplemented!(), + }; + + Halo2Verifier { + scheme: self.scheme, + vk: (!separate).then_some(vk), + vk_len, + vk_mptr, + num_neg_lagranges: self.meta.rotation_last.unsigned_abs() as usize, + num_advices: self.meta.num_advices(), + num_challenges: self.meta.num_challenges(), + num_evals: self.meta.num_evals, + num_quotients: self.meta.num_quotients, + proof_cptr, + quotient_comm_cptr: data.quotient_comm_cptr, + proof_len: self.meta.proof_len(self.scheme), + challenge_mptr: data.challenge_mptr, + theta_mptr: data.theta_mptr, + quotient_eval_numer_computations, + pcs_computations, + } + } + + fn estimate_static_working_memory_size( + &self, + vk: &Halo2VerifyingKey, + proof_cptr: Ptr, + ) -> usize { + let pcs_computation = match self.scheme { + Bdfg21 => { + let mock_vk_mptr = Ptr::memory(0x100000); + let mock = Data::new(&self.meta, vk, mock_vk_mptr, proof_cptr); + let (superset, sets) = rotation_sets(&queries(&self.meta, &mock)); + let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::(); + 2 * (1 + num_coeffs) + 6 + 2 * superset.len() + 1 + 3 * sets.len() + } + Gwc19 => unimplemented!(), + }; + + itertools::max(chain![ + // Hashing advice commitments + chain![self.meta.num_advices().into_iter()].map(|n| n * 2 + 1), + // Hashing evaluations + [self.meta.num_evals + 1], + // PCS computation + [pcs_computation], + // Pairing + [12], + ]) + .unwrap() + * 0x20 + } +} + +// Remove when `vk.transcript_repr()` is ready for usage. +fn vk_transcript_repr(vk: &VerifyingKey) -> bn256::Fr { + use blake2b_simd::Params; + use halo2_proofs::halo2curves::ff::FromUniformBytes; + + let fmtted_pinned_vk = format!("{:?}", vk.pinned()); + let mut hasher = Params::new() + .hash_length(64) + .personal(b"Halo2-Verify-Key") + .to_state(); + hasher + .update(&(fmtted_pinned_vk.len() as u64).to_le_bytes()) + .update(fmtted_pinned_vk.as_bytes()); + FromUniformBytes::from_uniform_bytes(hasher.finalize().as_array()) +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/evaluator.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/evaluator.rs new file mode 100644 index 0000000..c65a654 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/evaluator.rs @@ -0,0 +1,370 @@ +#![allow(clippy::useless_format)] + +use crate::codegen::util::{code_block, fe_to_u256, ConstraintSystemMeta, Data}; +use halo2_proofs::{ + halo2curves::ff::PrimeField, + plonk::{ + Advice, AdviceQuery, Any, Challenge, ConstraintSystem, Expression, Fixed, FixedQuery, Gate, + InstanceQuery, + }, +}; +use itertools::{chain, izip, Itertools}; +use ruint::aliases::U256; +use std::{cell::RefCell, cmp::Ordering, collections::HashMap, iter}; + +#[derive(Debug)] +pub(crate) struct Evaluator<'a, F: PrimeField> { + cs: &'a ConstraintSystem, + meta: &'a ConstraintSystemMeta, + data: &'a Data, + var_counter: RefCell, + var_cache: RefCell>, +} + +impl<'a, F> Evaluator<'a, F> +where + F: PrimeField, +{ + pub(crate) fn new( + cs: &'a ConstraintSystem, + meta: &'a ConstraintSystemMeta, + data: &'a Data, + ) -> Self { + Self { + cs, + meta, + data, + var_counter: Default::default(), + var_cache: Default::default(), + } + } + + pub fn gate_computations(&self) -> Vec<(Vec, String)> { + self.cs + .gates() + .iter() + .flat_map(Gate::polynomials) + .map(|expression| self.evaluate_and_reset(expression)) + .collect() + } + + pub fn permutation_computations(&self) -> Vec<(Vec, String)> { + let Self { meta, data, .. } = self; + let last_chunk_idx = meta.num_permutation_zs - 1; + chain![ + data.permutation_z_evals.first().map(|(z, _, _)| { + vec![ + format!("let l_0 := mload(L_0_MPTR)"), + format!("let eval := addmod(l_0, sub(r, mulmod(l_0, {z}, r)), r)"), + ] + }), + data.permutation_z_evals.last().map(|(z, _, _)| { + let item = "addmod(mulmod(perm_z_last, perm_z_last, r), sub(r, perm_z_last), r)"; + vec![ + format!("let perm_z_last := {z}"), + format!("let eval := mulmod(mload(L_LAST_MPTR), {item}, r)"), + ] + }), + data.permutation_z_evals.iter().tuple_windows().map( + |((_, _, z_i_last), (z_j, _, _))| { + let item = format!("addmod({z_j}, sub(r, {z_i_last}), r)"); + vec![format!("let eval := mulmod(mload(L_0_MPTR), {item}, r)")] + } + ), + izip!( + meta.permutation_columns.chunks(meta.permutation_chunk_len), + &data.permutation_z_evals, + ) + .enumerate() + .map(|(chunk_idx, (columns, evals))| { + let last_column_idx = columns.len() - 1; + chain![ + [ + format!("let gamma := mload(GAMMA_MPTR)"), + format!("let beta := mload(BETA_MPTR)"), + format!("let lhs := {}", evals.1), + format!("let rhs := {}", evals.0), + ], + columns.iter().flat_map(|column| { + let perm_eval = &data.permutation_evals[column]; + let eval = self.eval(*column.column_type(), column.index(), 0); + let item = format!("mulmod(beta, {perm_eval}, r)"); + [format!( + "lhs := mulmod(lhs, addmod(addmod({eval}, {item}, r), gamma, r), r)" + )] + }), + (chunk_idx == 0) + .then(|| "mstore(0x00, mulmod(beta, mload(X_MPTR), r))".to_string()), + columns.iter().enumerate().flat_map(|(idx, column)| { + let eval = self.eval(*column.column_type(), column.index(), 0); + let item = format!("addmod(addmod({eval}, mload(0x00), r), gamma, r)"); + chain![ + [format!("rhs := mulmod(rhs, {item}, r)")], + (!(chunk_idx == last_chunk_idx && idx == last_column_idx)) + .then(|| "mstore(0x00, mulmod(mload(0x00), delta, r))".to_string()), + ] + }), + { + let item = format!("addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)"); + let item = format!("sub(r, mulmod(left_sub_right, {item}, r))"); + [ + format!("let left_sub_right := addmod(lhs, sub(r, rhs), r)"), + format!("let eval := addmod(left_sub_right, {item}, r)"), + ] + } + ] + .collect_vec() + }) + ] + .zip(iter::repeat("eval".to_string())) + .collect() + } + + pub fn lookup_computations(&self) -> Vec<(Vec, String)> { + let input_tables = self + .cs + .lookups() + .iter() + .map(|lookup| { + let [(input_lines, inputs), (table_lines, tables)] = + [lookup.input_expressions(), lookup.table_expressions()].map(|expressions| { + let (lines, inputs) = expressions + .iter() + .map(|expression| self.evaluate(expression)) + .fold((Vec::new(), Vec::new()), |mut acc, result| { + acc.0.extend(result.0); + acc.1.push(result.1); + acc + }); + self.reset(); + (lines, inputs) + }); + (input_lines, inputs, table_lines, tables) + }) + .collect_vec(); + izip!(input_tables, &self.data.lookup_evals) + .flat_map(|(input_table, evals)| { + let (input_lines, inputs, table_lines, tables) = input_table; + let (input_0, rest_inputs) = inputs.split_first().unwrap(); + let (table_0, rest_tables) = tables.split_first().unwrap(); + let (z, z_next, p_input, p_input_prev, p_table) = evals; + [ + vec![ + format!("let l_0 := mload(L_0_MPTR)"), + format!("let eval := addmod(l_0, mulmod(l_0, sub(r, {z}), r), r)"), + ], + { + let item = format!("addmod(mulmod({z}, {z}, r), sub(r, {z}), r)"); + vec![ + format!("let l_last := mload(L_LAST_MPTR)"), + format!("let eval := mulmod(l_last, {item}, r)"), + ] + }, + chain![ + ["let theta := mload(THETA_MPTR)", "let input"].map(str::to_string), + code_block::<1, false>(chain![ + input_lines, + [format!("input := {input_0}")], + rest_inputs.iter().map(|input| format!( + "input := addmod(mulmod(input, theta, r), {input}, r)" + )) + ]), + ["let table"].map(str::to_string), + code_block::<1, false>(chain![ + table_lines, + [format!("table := {table_0}")], + rest_tables.iter().map(|table| format!( + "table := addmod(mulmod(table, theta, r), {table}, r)" + )) + ]), + { + let lhs = format!("addmod({p_input}, beta, r)"); + let rhs = format!("addmod({p_table}, gamma, r)"); + let permuted = format!("mulmod({lhs}, {rhs}, r)"); + let input = + "mulmod(addmod(input, beta, r), addmod(table, gamma, r), r)"; + [ + format!("let beta := mload(BETA_MPTR)"), + format!("let gamma := mload(GAMMA_MPTR)"), + format!("let lhs := mulmod({z_next}, {permuted}, r)"), + format!("let rhs := mulmod({z}, {input}, r)"), + ] + }, + { + let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)"; + let l_active = format!("addmod(1, sub(r, {l_inactive}), r)"); + [format!( + "let eval := mulmod({l_active}, addmod(lhs, sub(r, rhs), r), r)" + )] + }, + ] + .collect_vec(), + { + let l_0 = "mload(L_0_MPTR)"; + let item = format!("addmod({p_input}, sub(r, {p_table}), r)"); + vec![format!("let eval := mulmod({l_0}, {item}, r)")] + }, + { + let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)"; + let l_active = format!("addmod(1, sub(r, {l_inactive}), r)"); + let lhs = format!("addmod({p_input}, sub(r, {p_table}), r)"); + let rhs = format!("addmod({p_input}, sub(r, {p_input_prev}), r)"); + vec![format!( + "let eval := mulmod({l_active}, mulmod({lhs}, {rhs}, r), r)" + )] + }, + ] + }) + .zip(iter::repeat("eval".to_string())) + .collect_vec() + } + + fn eval(&self, column_type: impl Into, column_index: usize, rotation: i32) -> String { + match column_type.into() { + Any::Advice(_) => self.data.advice_evals[&(column_index, rotation)].to_string(), + Any::Fixed => self.data.fixed_evals[&(column_index, rotation)].to_string(), + Any::Instance => self.data.instance_eval.to_string(), + } + } + + fn reset(&self) { + *self.var_counter.borrow_mut() = Default::default(); + *self.var_cache.borrow_mut() = Default::default(); + } + + fn evaluate_and_reset(&self, expression: &Expression) -> (Vec, String) { + let result = self.evaluate(expression); + self.reset(); + result + } + + fn evaluate(&self, expression: &Expression) -> (Vec, String) { + evaluate( + expression, + &|constant| { + let constant = u256_string(constant); + self.init_var(constant, None) + }, + &|query| { + self.init_var( + self.eval(Fixed, query.column_index(), query.rotation().0), + Some(fixed_eval_var(query)), + ) + }, + &|query| { + self.init_var( + self.eval(Advice::default(), query.column_index(), query.rotation().0), + Some(advice_eval_var(query)), + ) + }, + &|_| self.init_var(self.data.instance_eval, Some("i_eval".to_string())), + &|challenge| { + self.init_var( + self.data.challenges[challenge.index()], + Some(format!("c_{}", challenge.index())), + ) + }, + &|(mut acc, var)| { + let (lines, var) = self.init_var(format!("sub(r, {var})"), None); + acc.extend(lines); + (acc, var) + }, + &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| { + let (lines, var) = self.init_var(format!("addmod({lhs_var}, {rhs_var}, r)"), None); + lhs_acc.extend(rhs_acc); + lhs_acc.extend(lines); + (lhs_acc, var) + }, + &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| { + let (lines, var) = self.init_var(format!("mulmod({lhs_var}, {rhs_var}, r)"), None); + lhs_acc.extend(rhs_acc); + lhs_acc.extend(lines); + (lhs_acc, var) + }, + &|(mut acc, var), scalar| { + let scalar = u256_string(scalar); + let (lines, var) = self.init_var(format!("mulmod({var}, {scalar}, r)"), None); + acc.extend(lines); + (acc, var) + }, + ) + } + + fn init_var(&self, value: impl ToString, var: Option) -> (Vec, String) { + let value = value.to_string(); + if self.var_cache.borrow().contains_key(&value) { + (vec![], self.var_cache.borrow()[&value].clone()) + } else { + let var = var.unwrap_or_else(|| self.next_var()); + self.var_cache + .borrow_mut() + .insert(value.clone(), var.clone()); + (vec![format!("let {var} := {value}")], var) + } + } + + fn next_var(&self) -> String { + let count = *self.var_counter.borrow(); + *self.var_counter.borrow_mut() += 1; + format!("var{count}") + } +} + +fn u256_string(value: U256) -> String { + if value.bit_len() < 64 { + format!("0x{:x}", value.as_limbs()[0]) + } else { + format!("0x{value:x}") + } +} + +fn fixed_eval_var(fixed_query: FixedQuery) -> String { + column_eval_var("f", fixed_query.column_index(), fixed_query.rotation().0) +} + +fn advice_eval_var(advice_query: AdviceQuery) -> String { + column_eval_var("a", advice_query.column_index(), advice_query.rotation().0) +} + +fn column_eval_var(prefix: &'static str, column_index: usize, rotation: i32) -> String { + match rotation.cmp(&0) { + Ordering::Less => format!("{prefix}_{column_index}_prev_{}", rotation.abs()), + Ordering::Equal => format!("{prefix}_{column_index}"), + Ordering::Greater => format!("{prefix}_{column_index}_next_{rotation}"), + } +} + +#[allow(clippy::too_many_arguments)] +fn evaluate( + expression: &Expression, + constant: &impl Fn(U256) -> T, + fixed: &impl Fn(FixedQuery) -> T, + advice: &impl Fn(AdviceQuery) -> T, + instance: &impl Fn(InstanceQuery) -> T, + challenge: &impl Fn(Challenge) -> T, + negated: &impl Fn(T) -> T, + sum: &impl Fn(T, T) -> T, + product: &impl Fn(T, T) -> T, + scaled: &impl Fn(T, U256) -> T, +) -> T +where + F: PrimeField, +{ + let evaluate = |expr| { + evaluate( + expr, constant, fixed, advice, instance, challenge, negated, sum, product, scaled, + ) + }; + match expression { + Expression::Constant(scalar) => constant(fe_to_u256(*scalar)), + Expression::Selector(_) => unreachable!(), + Expression::Fixed(query) => fixed(*query), + Expression::Advice(query) => advice(*query), + Expression::Instance(query) => instance(*query), + Expression::Challenge(value) => challenge(*value), + Expression::Negated(value) => negated(evaluate(value)), + Expression::Sum(lhs, rhs) => sum(evaluate(lhs), evaluate(rhs)), + Expression::Product(lhs, rhs) => product(evaluate(lhs), evaluate(rhs)), + Expression::Scaled(value, scalar) => scaled(evaluate(value), fe_to_u256(*scalar)), + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/pcs.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/pcs.rs new file mode 100644 index 0000000..2b7536a --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/pcs.rs @@ -0,0 +1,592 @@ +#![allow(clippy::useless_format)] + +use crate::codegen::util::{for_loop, ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word}; +use itertools::{chain, izip, Itertools}; +use std::collections::{BTreeMap, BTreeSet}; + +/// KZG batch open schemes in `halo2`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BatchOpenScheme { + /// Batch open scheme in [Plonk] paper. + /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverGWC` + /// + /// [Plonk]: https://eprint.iacr.org/2019/953.pdf + Gwc19, + /// Batch open scheme in [BDFG21] paper. + /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverSHPLONK` + /// + /// [BDFG21]: https://eprint.iacr.org/2020/081.pdf + Bdfg21, +} + +#[derive(Debug)] +pub(crate) struct Query { + comm: EcPoint, + rot: i32, + eval: Word, +} + +impl Query { + fn new(comm: EcPoint, rot: i32, eval: Word) -> Self { + Self { comm, rot, eval } + } +} + +pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec { + chain![ + meta.advice_queries.iter().map(|query| { + let comm = data.advice_comms[query.0]; + let eval = data.advice_evals[query]; + Query::new(comm, query.1, eval) + }), + izip!(&data.permutation_z_comms, &data.permutation_z_evals).flat_map(|(&comm, evals)| { + [Query::new(comm, 0, evals.0), Query::new(comm, 1, evals.1)] + }), + izip!(&data.permutation_z_comms, &data.permutation_z_evals) + .rev() + .skip(1) + .map(|(&comm, evals)| Query::new(comm, meta.rotation_last, evals.2)), + izip!( + &data.lookup_permuted_comms, + &data.lookup_z_comms, + &data.lookup_evals + ) + .flat_map(|(permuted_comms, &z_comm, evals)| { + [ + Query::new(z_comm, 0, evals.0), + Query::new(permuted_comms.0, 0, evals.2), + Query::new(permuted_comms.1, 0, evals.4), + Query::new(permuted_comms.0, -1, evals.3), + Query::new(z_comm, 1, evals.1), + ] + }), + meta.fixed_queries.iter().map(|query| { + let comm = data.fixed_comms[query.0]; + let eval = data.fixed_evals[query]; + Query::new(comm, query.1, eval) + }), + meta.permutation_columns.iter().map(|column| { + let comm = data.permutation_comms[column]; + let eval = data.permutation_evals[column]; + Query::new(comm, 0, eval) + }), + [ + Query::new(data.computed_quotient_comm, 0, data.computed_quotient_eval), + Query::new(data.random_comm, 0, data.random_eval), + ] + ] + .collect() +} + +#[derive(Debug)] +pub(crate) struct RotationSet { + rots: BTreeSet, + diffs: BTreeSet, + comms: Vec, + evals: Vec>, +} + +impl RotationSet { + pub(crate) fn rots(&self) -> &BTreeSet { + &self.rots + } + + pub(crate) fn diffs(&self) -> &BTreeSet { + &self.diffs + } + + pub(crate) fn comms(&self) -> &[EcPoint] { + &self.comms + } + + pub(crate) fn evals(&self) -> &[Vec] { + &self.evals + } +} + +pub(crate) fn rotation_sets(queries: &[Query]) -> (BTreeSet, Vec) { + let mut superset = BTreeSet::new(); + let comm_queries = queries.iter().fold( + Vec::<(EcPoint, BTreeMap)>::new(), + |mut comm_queries, query| { + superset.insert(query.rot); + if let Some(pos) = comm_queries + .iter() + .position(|(comm, _)| comm == &query.comm) + { + let (_, queries) = &mut comm_queries[pos]; + assert!(!queries.contains_key(&query.rot)); + queries.insert(query.rot, query.eval); + } else { + comm_queries.push((query.comm, BTreeMap::from_iter([(query.rot, query.eval)]))); + } + comm_queries + }, + ); + let superset = superset; + let sets = + comm_queries + .into_iter() + .fold(Vec::::new(), |mut sets, (comm, queries)| { + if let Some(pos) = sets + .iter() + .position(|set| itertools::equal(&set.rots, queries.keys())) + { + let set = &mut sets[pos]; + if !set.comms.contains(&comm) { + set.comms.push(comm); + set.evals.push(queries.into_values().collect_vec()); + } + } else { + let diffs = BTreeSet::from_iter( + superset + .iter() + .filter(|rot| !queries.contains_key(rot)) + .copied(), + ); + let set = RotationSet { + rots: BTreeSet::from_iter(queries.keys().copied()), + diffs, + comms: vec![comm], + evals: vec![queries.into_values().collect()], + }; + sets.push(set); + } + sets + }); + (superset, sets) +} + +pub(crate) fn bdfg21_computations(meta: &ConstraintSystemMeta, data: &Data) -> Vec> { + let queries = queries(meta, data); + let (superset, sets) = rotation_sets(&queries); + let min_rot = *superset.first().unwrap(); + let max_rot = *superset.last().unwrap(); + let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::(); + + let w = EcPoint::from(data.w_cptr); + let w_prime = EcPoint::from(data.w_cptr + 2); + + let diff_0 = Word::from(Ptr::memory(0x00)); + let coeffs = sets + .iter() + .scan(diff_0.ptr() + 1, |state, set| { + let ptrs = Word::range(*state).take(set.rots().len()).collect_vec(); + *state = *state + set.rots().len(); + Some(ptrs) + }) + .collect_vec(); + + let first_batch_invert_end = diff_0.ptr() + 1 + num_coeffs; + let second_batch_invert_end = diff_0.ptr() + sets.len(); + let free_mptr = diff_0.ptr() + 2 * (1 + num_coeffs) + 6; + + let point_mptr = free_mptr; + let mu_minus_point_mptr = point_mptr + superset.len(); + let vanishing_0_mptr = mu_minus_point_mptr + superset.len(); + let diff_mptr = vanishing_0_mptr + 1; + let r_eval_mptr = diff_mptr + sets.len(); + let sum_mptr = r_eval_mptr + sets.len(); + + let point_vars = + izip!(&superset, (0..).map(|idx| format!("point_{idx}"))).collect::>(); + let points = izip!(&superset, Word::range(point_mptr)).collect::>(); + let mu_minus_points = + izip!(&superset, Word::range(mu_minus_point_mptr)).collect::>(); + let vanishing_0 = Word::from(vanishing_0_mptr); + let diffs = Word::range(diff_mptr).take(sets.len()).collect_vec(); + let r_evals = Word::range(r_eval_mptr).take(sets.len()).collect_vec(); + let sums = Word::range(sum_mptr).take(sets.len()).collect_vec(); + + let point_computations = chain![ + [ + "let x := mload(X_MPTR)", + "let omega := mload(OMEGA_MPTR)", + "let omega_inv := mload(OMEGA_INV_MPTR)", + "let x_pow_of_omega := mulmod(x, omega, r)" + ] + .map(str::to_string), + (1..=max_rot).flat_map(|rot| { + chain![ + points + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())), + (rot != max_rot) + .then(|| { "x_pow_of_omega := mulmod(x_pow_of_omega, omega, r)".to_string() }) + ] + }), + [ + format!("mstore({}, x)", points[&0].ptr()), + format!("x_pow_of_omega := mulmod(x, omega_inv, r)") + ], + (min_rot..0).rev().flat_map(|rot| { + chain![ + points + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())), + (rot != min_rot).then(|| { + "x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r)".to_string() + }) + ] + }) + ] + .collect_vec(); + + let vanishing_computations = chain![ + ["let mu := mload(MU_MPTR)".to_string()], + { + let mptr = mu_minus_points.first_key_value().unwrap().1.ptr(); + let mptr_end = mptr + mu_minus_points.len(); + for_loop( + [ + format!("let mptr := {mptr}"), + format!("let mptr_end := {mptr_end}"), + format!("let point_mptr := {free_mptr}"), + ], + "lt(mptr, mptr_end)", + [ + "mptr := add(mptr, 0x20)", + "point_mptr := add(point_mptr, 0x20)", + ] + .map(str::to_string), + ["mstore(mptr, addmod(mu, sub(r, mload(point_mptr)), r))".to_string()], + ) + }, + ["let s".to_string()], + chain![ + [format!( + "s := {}", + mu_minus_points[sets[0].rots().first().unwrap()] + )], + chain![sets[0].rots().iter().skip(1)] + .map(|rot| { format!("s := mulmod(s, {}, r)", mu_minus_points[rot]) }), + [format!("mstore({}, s)", vanishing_0.ptr())], + ], + ["let diff".to_string()], + izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, diff)| { + chain![ + [set.diffs() + .first() + .map(|rot| format!("diff := {}", mu_minus_points[rot])) + .unwrap_or_else(|| "diff := 1".to_string())], + chain![set.diffs().iter().skip(1)] + .map(|rot| { format!("diff := mulmod(diff, {}, r)", mu_minus_points[rot]) }), + [format!("mstore({}, diff)", diff.ptr())], + (set_idx == 0).then(|| format!("mstore({}, diff)", diff_0.ptr())), + ] + }) + ] + .collect_vec(); + + let coeff_computations = izip!(&sets, &coeffs) + .map(|(set, coeffs)| { + let coeff_points = set + .rots() + .iter() + .map(|rot| &point_vars[rot]) + .enumerate() + .map(|(i, rot_i)| { + set.rots() + .iter() + .map(|rot| &point_vars[rot]) + .enumerate() + .filter_map(|(j, rot_j)| (i != j).then_some((rot_i, rot_j))) + .collect_vec() + }) + .collect_vec(); + chain![ + set.rots() + .iter() + .map(|rot| { format!("let {} := {}", &point_vars[rot], points[rot]) }), + ["let coeff".to_string()], + izip!(set.rots(), &coeff_points, coeffs).flat_map( + |(rot_i, coeff_points, coeff)| chain![ + [coeff_points + .first() + .map(|(point_i, point_j)| { + format!("coeff := addmod({point_i}, sub(r, {point_j}), r)") + }) + .unwrap_or_else(|| { "coeff := 1".to_string() })], + coeff_points.iter().skip(1).map(|(point_i, point_j)| { + let item = format!("addmod({point_i}, sub(r, {point_j}), r)"); + format!("coeff := mulmod(coeff, {item}, r)") + }), + [ + format!("coeff := mulmod(coeff, {}, r)", mu_minus_points[rot_i]), + format!("mstore({}, coeff)", coeff.ptr()) + ], + ] + ) + ] + .collect_vec() + }) + .collect_vec(); + + let normalized_coeff_computations = chain![ + [ + format!("success := batch_invert(success, 0, {first_batch_invert_end}, r)"), + format!("let diff_0_inv := {diff_0}"), + format!("mstore({}, diff_0_inv)", diffs[0].ptr()), + ], + for_loop( + [ + format!("let mptr := {}", diffs[0].ptr() + 1), + format!("let mptr_end := {}", diffs[0].ptr() + sets.len()), + ], + "lt(mptr, mptr_end)", + ["mptr := add(mptr, 0x20)".to_string()], + ["mstore(mptr, mulmod(mload(mptr), diff_0_inv, r))".to_string()], + ), + ] + .collect_vec(); + + let r_evals_computations = izip!(0.., &sets, &coeffs, &diffs, &r_evals).map( + |(set_idx, set, coeffs, set_coeff, r_eval)| { + let is_single_rot_set = set.rots().len() == 1; + chain![ + is_single_rot_set.then(|| format!("let coeff := {}", coeffs[0])), + ["let zeta := mload(ZETA_MPTR)", "let r_eval := 0"].map(str::to_string), + if is_single_rot_set { + let eval_groups = set.evals().iter().rev().fold( + Vec::>::new(), + |mut eval_groups, evals| { + let eval = &evals[0]; + if let Some(last_group) = eval_groups.last_mut() { + let last_eval = **last_group.last().unwrap(); + if last_eval.ptr().value().is_integer() + && last_eval.ptr() - 1 == eval.ptr() + { + last_group.push(eval) + } else { + eval_groups.push(vec![eval]) + } + eval_groups + } else { + vec![vec![eval]] + } + }, + ); + chain![eval_groups.iter().enumerate()] + .flat_map(|(group_idx, evals)| { + if evals.len() < 3 { + chain![evals.iter().enumerate()] + .flat_map(|(eval_idx, eval)| { + let is_first_eval = group_idx == 0 && eval_idx == 0; + let item = format!("mulmod(coeff, {eval}, r)"); + chain![ + (!is_first_eval).then(|| format!( + "r_eval := mulmod(r_eval, zeta, r)" + )), + [format!("r_eval := addmod(r_eval, {item}, r)")], + ] + }) + .collect_vec() + } else { + let item = "mulmod(coeff, calldataload(mptr), r)"; + for_loop( + [ + format!("let mptr := {}", evals[0].ptr()), + format!("let mptr_end := {}", evals[0].ptr() - evals.len()), + ], + "lt(mptr_end, mptr)".to_string(), + ["mptr := sub(mptr, 0x20)".to_string()], + [format!( + "r_eval := addmod(mulmod(r_eval, zeta, r), {item}, r)" + )], + ) + } + }) + .collect_vec() + } else { + chain![set.evals().iter().enumerate().rev()] + .flat_map(|(idx, evals)| { + chain![ + izip!(evals, coeffs).map(|(eval, coeff)| { + let item = format!("mulmod({coeff}, {eval}, r)"); + format!("r_eval := addmod(r_eval, {item}, r)") + }), + (idx != 0).then(|| format!("r_eval := mulmod(r_eval, zeta, r)")), + ] + }) + .collect_vec() + }, + (set_idx != 0).then(|| format!("r_eval := mulmod(r_eval, {set_coeff}, r)")), + [format!("mstore({}, r_eval)", r_eval.ptr())], + ] + .collect_vec() + }, + ); + + let coeff_sums_computation = izip!(&coeffs, &sums).map(|(coeffs, sum)| { + let (coeff_0, rest_coeffs) = coeffs.split_first().unwrap(); + chain![ + [format!("let sum := {coeff_0}")], + rest_coeffs + .iter() + .map(|coeff_mptr| format!("sum := addmod(sum, {coeff_mptr}, r)")), + [format!("mstore({}, sum)", sum.ptr())], + ] + .collect_vec() + }); + + let r_eval_computations = chain![ + for_loop( + [ + format!("let mptr := 0x00"), + format!("let mptr_end := {second_batch_invert_end}"), + format!("let sum_mptr := {}", sums[0].ptr()), + ], + "lt(mptr, mptr_end)", + ["mptr := add(mptr, 0x20)", "sum_mptr := add(sum_mptr, 0x20)"].map(str::to_string), + ["mstore(mptr, mload(sum_mptr))".to_string()], + ), + [ + format!("success := batch_invert(success, 0, {second_batch_invert_end}, r)"), + format!( + "let r_eval := mulmod(mload({}), {}, r)", + second_batch_invert_end - 1, + r_evals.last().unwrap() + ) + ], + for_loop( + [ + format!("let sum_inv_mptr := {}", second_batch_invert_end - 2), + format!("let sum_inv_mptr_end := {second_batch_invert_end}"), + format!("let r_eval_mptr := {}", r_evals[r_evals.len() - 2].ptr()), + ], + "lt(sum_inv_mptr, sum_inv_mptr_end)", + [ + "sum_inv_mptr := sub(sum_inv_mptr, 0x20)", + "r_eval_mptr := sub(r_eval_mptr, 0x20)" + ] + .map(str::to_string), + [ + "r_eval := mulmod(r_eval, mload(NU_MPTR), r)", + "r_eval := addmod(r_eval, mulmod(mload(sum_inv_mptr), mload(r_eval_mptr), r), r)" + ] + .map(str::to_string), + ), + ["mstore(R_EVAL_MPTR, r_eval)".to_string()], + ] + .collect_vec(); + + let pairing_input_computations = chain![ + ["let nu := mload(NU_MPTR)".to_string()], + izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, set_coeff)| { + let is_first_set = set_idx == 0; + let is_last_set = set_idx == sets.len() - 1; + + let ec_add = &format!("ec_add_{}", if is_first_set { "acc" } else { "tmp" }); + let ec_mul = &format!("ec_mul_{}", if is_first_set { "acc" } else { "tmp" }); + let acc_x = Ptr::memory(0x00) + if is_first_set { 0 } else { 4 }; + let acc_y = acc_x + 1; + + let comm_groups = set.comms().iter().rev().skip(1).fold( + Vec::<(Location, Vec<&EcPoint>)>::new(), + |mut comm_groups, comm| { + if let Some(last_group) = comm_groups.last_mut() { + let last_comm = **last_group.1.last().unwrap(); + if last_group.0 == comm.loc() + && last_comm.x().ptr().value().is_integer() + && last_comm.x().ptr() - 2 == comm.x().ptr() + { + last_group.1.push(comm) + } else { + comm_groups.push((comm.loc(), vec![comm])) + } + comm_groups + } else { + vec![(comm.loc(), vec![comm])] + } + }, + ); + + chain![ + set.comms() + .last() + .map(|comm| { + [ + format!("mstore({acc_x}, {})", comm.x()), + format!("mstore({acc_y}, {})", comm.y()), + ] + }) + .into_iter() + .flatten(), + comm_groups.into_iter().flat_map(move |(loc, comms)| { + if comms.len() < 3 { + comms + .iter() + .flat_map(|comm| { + let (x, y) = (comm.x(), comm.y()); + [ + format!("success := {ec_mul}(success, mload(ZETA_MPTR))"), + format!("success := {ec_add}(success, {x}, {y})"), + ] + }) + .collect_vec() + } else { + let mptr = comms.first().unwrap().x().ptr(); + let mptr_end = mptr - 2 * comms.len(); + let x = Word::from(Ptr::new(loc, "mptr")); + let y = Word::from(Ptr::new(loc, "add(mptr, 0x20)")); + for_loop( + [ + format!("let mptr := {mptr}"), + format!("let mptr_end := {mptr_end}"), + ], + "lt(mptr_end, mptr)", + ["mptr := sub(mptr, 0x40)".to_string()], + [ + format!("success := {ec_mul}(success, mload(ZETA_MPTR))"), + format!("success := {ec_add}(success, {x}, {y})"), + ], + ) + } + }), + (!is_first_set) + .then(|| { + let scalar = format!("mulmod(nu, {set_coeff}, r)"); + chain![ + [ + format!("success := ec_mul_tmp(success, {scalar})"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + ], + (!is_last_set).then(|| format!("nu := mulmod(nu, mload(NU_MPTR), r)")) + ] + }) + .into_iter() + .flatten(), + ] + .collect_vec() + }), + [ + format!("mstore(0x80, mload(G1_X_MPTR))"), + format!("mstore(0xa0, mload(G1_Y_MPTR))"), + format!("success := ec_mul_tmp(success, sub(r, mload(R_EVAL_MPTR)))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(0x80, {})", w.x()), + format!("mstore(0xa0, {})", w.y()), + format!("success := ec_mul_tmp(success, sub(r, {vanishing_0}))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(0x80, {})", w_prime.x()), + format!("mstore(0xa0, {})", w_prime.y()), + format!("success := ec_mul_tmp(success, mload(MU_MPTR))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(PAIRING_LHS_X_MPTR, mload(0x00))"), + format!("mstore(PAIRING_LHS_Y_MPTR, mload(0x20))"), + format!("mstore(PAIRING_RHS_X_MPTR, {})", w_prime.x()), + format!("mstore(PAIRING_RHS_Y_MPTR, {})", w_prime.y()), + ], + ] + .collect_vec(); + + chain![ + [point_computations, vanishing_computations], + coeff_computations, + [normalized_coeff_computations], + r_evals_computations, + coeff_sums_computation, + [r_eval_computations, pairing_input_computations], + ] + .collect_vec() +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/template.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/template.rs new file mode 100644 index 0000000..e25f723 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/template.rs @@ -0,0 +1,83 @@ +use crate::codegen::{ + pcs::BatchOpenScheme::{self, Bdfg21, Gwc19}, + util::Ptr, +}; +use askama::{Error, Template}; +use ruint::aliases::U256; +use std::fmt; + +#[derive(Template)] +#[template(path = "Halo2VerifyingKey.sol")] +pub(crate) struct Halo2VerifyingKey { + pub(crate) constants: Vec<(&'static str, U256)>, + pub(crate) fixed_comms: Vec<(U256, U256)>, + pub(crate) permutation_comms: Vec<(U256, U256)>, +} + +impl Halo2VerifyingKey { + pub(crate) fn len(&self) -> usize { + (self.constants.len() * 0x20) + + (self.fixed_comms.len() + self.permutation_comms.len()) * 0x40 + } +} + +#[derive(Template)] +#[template(path = "Halo2Verifier.sol")] +pub(crate) struct Halo2Verifier { + pub(crate) scheme: BatchOpenScheme, + pub(crate) vk: Option, + pub(crate) vk_len: usize, + pub(crate) proof_len: usize, + pub(crate) vk_mptr: Ptr, + pub(crate) challenge_mptr: Ptr, + pub(crate) theta_mptr: Ptr, + pub(crate) proof_cptr: Ptr, + pub(crate) quotient_comm_cptr: Ptr, + pub(crate) num_neg_lagranges: usize, + pub(crate) num_advices: Vec, + pub(crate) num_challenges: Vec, + pub(crate) num_evals: usize, + pub(crate) num_quotients: usize, + pub(crate) quotient_eval_numer_computations: Vec>, + pub(crate) pcs_computations: Vec>, +} + +impl Halo2VerifyingKey { + pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.render_into(writer).map_err(|err| match err { + Error::Fmt(err) => err, + _ => unreachable!(), + }) + } +} + +impl Halo2Verifier { + pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.render_into(writer).map_err(|err| match err { + Error::Fmt(err) => err, + _ => unreachable!(), + }) + } +} + +mod filters { + use std::fmt::LowerHex; + + pub fn hex(value: impl LowerHex) -> ::askama::Result { + let value = format!("{value:x}"); + Ok(if value.len() % 2 == 1 { + format!("0x0{value}") + } else { + format!("0x{value}") + }) + } + + pub fn hex_padded(value: impl LowerHex, pad: usize) -> ::askama::Result { + let string = format!("0x{value:0pad$x}"); + if string == "0x0" { + Ok(format!("0x{}", "0".repeat(pad))) + } else { + Ok(string) + } + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/util.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/util.rs new file mode 100644 index 0000000..9d3aea9 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/codegen/util.rs @@ -0,0 +1,614 @@ +use crate::codegen::{ + template::Halo2VerifyingKey, + BatchOpenScheme::{self, Bdfg21, Gwc19}, +}; +use halo2_proofs::{ + halo2curves::{bn256, ff::PrimeField, CurveAffine}, + plonk::{Any, Column, ConstraintSystem}, +}; +use itertools::{chain, izip, Itertools}; +use ruint::{aliases::U256, UintTryFrom}; +use std::{ + borrow::Borrow, + collections::HashMap, + fmt::{self, Display, Formatter}, + ops::{Add, Sub}, +}; + +#[derive(Debug)] +pub(crate) struct ConstraintSystemMeta { + pub(crate) num_fixeds: usize, + pub(crate) permutation_columns: Vec>, + pub(crate) permutation_chunk_len: usize, + pub(crate) num_lookup_permuteds: usize, + pub(crate) num_permutation_zs: usize, + pub(crate) num_lookup_zs: usize, + pub(crate) num_quotients: usize, + pub(crate) advice_queries: Vec<(usize, i32)>, + pub(crate) fixed_queries: Vec<(usize, i32)>, + pub(crate) num_evals: usize, + pub(crate) num_user_advices: Vec, + pub(crate) num_user_challenges: Vec, + pub(crate) advice_indices: Vec, + pub(crate) challenge_indices: Vec, + pub(crate) rotation_last: i32, +} + +impl ConstraintSystemMeta { + pub(crate) fn new(cs: &ConstraintSystem) -> Self { + let num_fixeds = cs.num_fixed_columns(); + let permutation_columns = cs.permutation().get_columns(); + let permutation_chunk_len = cs.degree() - 2; + let num_lookup_permuteds = 2 * cs.lookups().len(); + let num_permutation_zs = cs + .permutation() + .get_columns() + .chunks(cs.degree() - 2) + .count(); + let num_lookup_zs = cs.lookups().len(); + let num_quotients = cs.degree() - 1; + let advice_queries = cs + .advice_queries() + .iter() + .map(|(column, rotation)| (column.index(), rotation.0)) + .collect_vec(); + let fixed_queries = cs + .fixed_queries() + .iter() + .map(|(column, rotation)| (column.index(), rotation.0)) + .collect_vec(); + let num_evals = advice_queries.len() + + fixed_queries.len() + + 1 + + cs.permutation().get_columns().len() + + (3 * num_permutation_zs - 1) + + 5 * cs.lookups().len(); + let num_phase = *cs.advice_column_phase().iter().max().unwrap_or(&0) as usize + 1; + // Indices of advice and challenge are not same as their position in calldata/memory, + // because we support multiple phases, we need to remap them and find their actual indices. + let remapping = |phase: Vec| { + let nums = phase.iter().fold(vec![0; num_phase], |mut nums, phase| { + nums[*phase as usize] += 1; + nums + }); + let offsets = nums + .iter() + .take(num_phase - 1) + .fold(vec![0], |mut offsets, n| { + offsets.push(offsets.last().unwrap() + n); + offsets + }); + let index = phase + .iter() + .scan(offsets, |state, phase| { + let index = state[*phase as usize]; + state[*phase as usize] += 1; + Some(index) + }) + .collect::>(); + (nums, index) + }; + let (num_user_advices, advice_indices) = remapping(cs.advice_column_phase()); + let (num_user_challenges, challenge_indices) = remapping(cs.challenge_phase()); + let rotation_last = -(cs.blinding_factors() as i32 + 1); + Self { + num_fixeds, + permutation_columns, + permutation_chunk_len, + num_lookup_permuteds, + num_permutation_zs, + num_lookup_zs, + num_quotients, + advice_queries, + fixed_queries, + num_evals, + num_user_advices, + num_user_challenges, + advice_indices, + challenge_indices, + rotation_last, + } + } + + pub(crate) fn num_advices(&self) -> Vec { + chain![ + self.num_user_advices.iter().cloned(), + (self.num_lookup_permuteds != 0).then_some(self.num_lookup_permuteds), // lookup permuted + [ + self.num_permutation_zs + self.num_lookup_zs + 1, // permutation and lookup grand products, random + self.num_quotients, // quotients + ], + ] + .collect() + } + + pub(crate) fn num_challenges(&self) -> Vec { + let mut num_challenges = self.num_user_challenges.clone(); + // If there is no lookup used, merge also beta and gamma into the last user phase, to avoid + // squeezing challenge from nothing. + // Otherwise, merge theta into last user phase since they are originally adjacent. + if self.num_lookup_permuteds == 0 { + *num_challenges.last_mut().unwrap() += 3; // theta, beta, gamma + num_challenges.extend([ + 1, // y + 1, // x + ]); + } else { + *num_challenges.last_mut().unwrap() += 1; // theta + num_challenges.extend([ + 2, // beta, gamma + 1, // y + 1, // x + ]); + } + num_challenges + } + + pub(crate) fn num_permutations(&self) -> usize { + self.permutation_columns.len() + } + + pub(crate) fn num_lookups(&self) -> usize { + self.num_lookup_zs + } + + pub(crate) fn proof_len(&self, scheme: BatchOpenScheme) -> usize { + self.num_advices().iter().sum::() * 0x40 + + self.num_evals * 0x20 + + self.batch_open_proof_len(scheme) + } + + pub(crate) fn batch_open_proof_len(&self, scheme: BatchOpenScheme) -> usize { + match scheme { + Bdfg21 => 2 * 0x40, + Gwc19 => { + unimplemented!() + } + } + } +} + +#[derive(Debug)] +pub(crate) struct Data { + pub(crate) challenge_mptr: Ptr, + pub(crate) theta_mptr: Ptr, + + pub(crate) quotient_comm_cptr: Ptr, + pub(crate) w_cptr: Ptr, + + pub(crate) fixed_comms: Vec, + pub(crate) permutation_comms: HashMap, EcPoint>, + pub(crate) advice_comms: Vec, + pub(crate) lookup_permuted_comms: Vec<(EcPoint, EcPoint)>, + pub(crate) permutation_z_comms: Vec, + pub(crate) lookup_z_comms: Vec, + pub(crate) random_comm: EcPoint, + + pub(crate) challenges: Vec, + + pub(crate) instance_eval: Word, + pub(crate) advice_evals: HashMap<(usize, i32), Word>, + pub(crate) fixed_evals: HashMap<(usize, i32), Word>, + pub(crate) random_eval: Word, + pub(crate) permutation_evals: HashMap, Word>, + pub(crate) permutation_z_evals: Vec<(Word, Word, Word)>, + pub(crate) lookup_evals: Vec<(Word, Word, Word, Word, Word)>, + + pub(crate) computed_quotient_comm: EcPoint, + pub(crate) computed_quotient_eval: Word, +} + +impl Data { + pub(crate) fn new( + meta: &ConstraintSystemMeta, + vk: &Halo2VerifyingKey, + vk_mptr: Ptr, + proof_cptr: Ptr, + ) -> Self { + let fixed_comm_mptr = vk_mptr + vk.constants.len(); + let permutation_comm_mptr = fixed_comm_mptr + 2 * vk.fixed_comms.len(); + let challenge_mptr = permutation_comm_mptr + 2 * vk.permutation_comms.len(); + let theta_mptr = challenge_mptr + meta.challenge_indices.len(); + + let advice_comm_start = proof_cptr; + let lookup_permuted_comm_start = advice_comm_start + 2 * meta.advice_indices.len(); + let permutation_z_comm_start = lookup_permuted_comm_start + 2 * meta.num_lookup_permuteds; + let lookup_z_comm_start = permutation_z_comm_start + 2 * meta.num_permutation_zs; + let random_comm_start = lookup_z_comm_start + 2 * meta.num_lookup_zs; + let quotient_comm_start = random_comm_start + 2; + + let eval_cptr = quotient_comm_start + 2 * meta.num_quotients; + let advice_eval_cptr = eval_cptr; + let fixed_eval_cptr = advice_eval_cptr + meta.advice_queries.len(); + let random_eval_cptr = fixed_eval_cptr + meta.fixed_queries.len(); + let permutation_eval_cptr = random_eval_cptr + 1; + let permutation_z_eval_cptr = permutation_eval_cptr + meta.num_permutations(); + let lookup_eval_cptr = permutation_z_eval_cptr + 3 * meta.num_permutation_zs - 1; + let w_cptr = lookup_eval_cptr + 5 * meta.num_lookups(); + + let fixed_comms = EcPoint::range(fixed_comm_mptr) + .take(meta.num_fixeds) + .collect(); + let permutation_comms = izip!( + meta.permutation_columns.iter().cloned(), + EcPoint::range(permutation_comm_mptr) + ) + .collect(); + let advice_comms = meta + .advice_indices + .iter() + .map(|idx| advice_comm_start + 2 * idx) + .map_into() + .collect(); + let lookup_permuted_comms = EcPoint::range(lookup_permuted_comm_start) + .take(meta.num_lookup_permuteds) + .tuples() + .collect(); + let permutation_z_comms = EcPoint::range(permutation_z_comm_start) + .take(meta.num_permutation_zs) + .collect(); + let lookup_z_comms = EcPoint::range(lookup_z_comm_start) + .take(meta.num_lookup_zs) + .collect(); + let random_comm = random_comm_start.into(); + let computed_quotient_comm = EcPoint::new( + Ptr::memory("QUOTIENT_X_MPTR"), + Ptr::memory("QUOTIENT_Y_MPTR"), + ); + + let challenges = meta + .challenge_indices + .iter() + .map(|idx| challenge_mptr + *idx) + .map_into() + .collect_vec(); + let instance_eval = Ptr::memory("INSTANCE_EVAL_MPTR").into(); + let advice_evals = izip!( + meta.advice_queries.iter().cloned(), + Word::range(advice_eval_cptr) + ) + .collect(); + let fixed_evals = izip!( + meta.fixed_queries.iter().cloned(), + Word::range(fixed_eval_cptr) + ) + .collect(); + let random_eval = random_eval_cptr.into(); + let permutation_evals = izip!( + meta.permutation_columns.iter().cloned(), + Word::range(permutation_eval_cptr) + ) + .collect(); + let permutation_z_evals = Word::range(permutation_z_eval_cptr) + .take(3 * meta.num_permutation_zs) + .tuples() + .collect_vec(); + let lookup_evals = Word::range(lookup_eval_cptr) + .take(5 * meta.num_lookup_zs) + .tuples() + .collect_vec(); + let computed_quotient_eval = Ptr::memory("QUOTIENT_EVAL_MPTR").into(); + + Self { + challenge_mptr, + theta_mptr, + quotient_comm_cptr: quotient_comm_start, + w_cptr, + + fixed_comms, + permutation_comms, + advice_comms, + lookup_permuted_comms, + permutation_z_comms, + lookup_z_comms, + random_comm, + computed_quotient_comm, + + challenges, + + instance_eval, + advice_evals, + fixed_evals, + permutation_evals, + permutation_z_evals, + lookup_evals, + random_eval, + computed_quotient_eval, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Location { + Calldata, + Memory, +} + +impl Location { + fn opcode(&self) -> &'static str { + match self { + Location::Calldata => "calldataload", + Location::Memory => "mload", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Value { + Integer(usize), + Identifier(&'static str), +} + +impl Value { + pub(crate) fn is_integer(&self) -> bool { + match self { + Value::Integer(_) => true, + Value::Identifier(_) => false, + } + } + + pub(crate) fn as_usize(&self) -> usize { + match self { + Value::Integer(int) => *int, + Value::Identifier(_) => unreachable!(), + } + } +} + +impl Default for Value { + fn default() -> Self { + Self::Integer(0) + } +} + +impl From<&'static str> for Value { + fn from(ident: &'static str) -> Self { + Value::Identifier(ident) + } +} + +impl From for Value { + fn from(int: usize) -> Self { + Value::Integer(int) + } +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Value::Integer(int) => { + let hex = format!("{int:x}"); + if hex.len() % 2 == 1 { + write!(f, "0x0{hex}") + } else { + write!(f, "0x{hex}") + } + } + Value::Identifier(ident) => { + write!(f, "{ident}") + } + } + } +} + +impl Add for Value { + type Output = Value; + + fn add(self, rhs: usize) -> Self::Output { + (self.as_usize() + rhs * 0x20).into() + } +} + +impl Sub for Value { + type Output = Value; + + fn sub(self, rhs: usize) -> Self::Output { + (self.as_usize() - rhs * 0x20).into() + } +} + +/// `Ptr` points to a EVM word at either calldata or memory. +/// +/// When adding or subtracting it by 1, its value moves by 32 and points to next/previous EVM word. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Ptr { + loc: Location, + value: Value, +} + +impl Ptr { + pub(crate) fn new(loc: Location, value: impl Into) -> Self { + Self { + loc, + value: value.into(), + } + } + + pub(crate) fn memory(value: impl Into) -> Self { + Self::new(Location::Memory, value.into()) + } + + pub(crate) fn calldata(value: impl Into) -> Self { + Self::new(Location::Calldata, value.into()) + } + + pub(crate) fn loc(&self) -> Location { + self.loc + } + + pub(crate) fn value(&self) -> Value { + self.value + } +} + +impl Display for Ptr { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Add for Ptr { + type Output = Ptr; + + fn add(mut self, rhs: usize) -> Self::Output { + self.value = self.value + rhs; + self + } +} + +impl Sub for Ptr { + type Output = Ptr; + + fn sub(mut self, rhs: usize) -> Self::Output { + self.value = self.value - rhs; + self + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Word(Ptr); + +impl Word { + pub(crate) fn range(word: impl Into) -> impl Iterator { + let ptr = word.into().ptr(); + (0..).map(move |idx| ptr + idx).map_into() + } + + pub(crate) fn ptr(&self) -> Ptr { + self.0 + } +} + +impl Display for Word { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}({})", self.0.loc.opcode(), self.0.value) + } +} + +impl From for Word { + fn from(ptr: Ptr) -> Self { + Self(ptr) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct EcPoint { + x: Word, + y: Word, +} + +impl EcPoint { + pub(crate) fn new(x: impl Into, y: impl Into) -> Self { + Self { + x: x.into(), + y: y.into(), + } + } + + pub(crate) fn range(ec_point: impl Into) -> impl Iterator { + let ptr = ec_point.into().x.ptr(); + (0..).map(move |idx| ptr + 2 * idx).map_into() + } + + pub(crate) fn loc(&self) -> Location { + self.x.ptr().loc() + } + + pub(crate) fn x(&self) -> Word { + self.x + } + + pub(crate) fn y(&self) -> Word { + self.y + } +} + +impl From for EcPoint { + fn from(ptr: Ptr) -> Self { + Self::new(ptr, ptr + 1) + } +} + +/// Add indention to given lines by `4 * N` spaces. +pub(crate) fn indent(lines: impl IntoIterator) -> Vec { + lines + .into_iter() + .map(|line| format!("{}{line}", " ".repeat(N * 4))) + .collect() +} + +/// Create a code block for given lines with indention. +/// +/// If `PACKED` is true, single line code block will be packed into single line. +pub(crate) fn code_block( + lines: impl IntoIterator, +) -> Vec { + let lines = lines.into_iter().collect_vec(); + let bracket_indent = " ".repeat((N - 1) * 4); + match lines.len() { + 0 => vec![format!("{bracket_indent}{{}}")], + 1 if PACKED => vec![format!("{bracket_indent}{{ {} }}", lines[0])], + _ => chain![ + [format!("{bracket_indent}{{")], + indent::(lines), + [format!("{bracket_indent}}}")], + ] + .collect(), + } +} + +/// Create a for loop with proper indention. +pub(crate) fn for_loop( + initialization: impl IntoIterator, + condition: impl Into, + advancement: impl IntoIterator, + body: impl IntoIterator, +) -> Vec { + chain![ + ["for".to_string()], + code_block::<2, true>(initialization), + indent::<1>([condition.into()]), + code_block::<2, true>(advancement), + code_block::<1, false>(body), + ] + .collect() +} + +pub(crate) fn g1_to_u256s(ec_point: impl Borrow) -> [U256; 2] { + let coords = ec_point.borrow().coordinates().unwrap(); + [coords.x(), coords.y()].map(fq_to_u256) +} + +pub(crate) fn g2_to_u256s(ec_point: impl Borrow) -> [U256; 4] { + let coords = ec_point.borrow().coordinates().unwrap(); + let x = coords.x().to_repr(); + let y = coords.y().to_repr(); + [ + U256::try_from_le_slice(&x.as_ref()[0x20..]).unwrap(), + U256::try_from_le_slice(&x.as_ref()[..0x20]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[0x20..]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[..0x20]).unwrap(), + ] +} + +pub(crate) fn fq_to_u256(fe: impl Borrow) -> U256 { + fe_to_u256(fe) +} + +pub(crate) fn fr_to_u256(fe: impl Borrow) -> U256 { + fe_to_u256(fe) +} + +pub(crate) fn fe_to_u256(fe: impl Borrow) -> U256 +where + F: PrimeField, +{ + U256::from_le_bytes(fe.borrow().to_repr()) +} + +pub(crate) fn to_u256_be_bytes(value: T) -> [u8; 32] +where + U256: UintTryFrom, +{ + U256::from(value).to_be_bytes() +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/evm.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/evm.rs new file mode 100644 index 0000000..1156ee3 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/evm.rs @@ -0,0 +1,216 @@ +use crate::codegen::util::{fr_to_u256, to_u256_be_bytes}; +use halo2_proofs::halo2curves::bn256; +use itertools::chain; +use ruint::aliases::U256; + +/// Function signature of `verifyProof(bytes,uint256[])`. +pub const FN_SIG_VERIFY_PROOF: [u8; 4] = [0x1e, 0x8e, 0x1e, 0x13]; + +/// Function signature of `verifyProof(address,bytes,uint256[])`. +pub const FN_SIG_VERIFY_PROOF_WITH_VK_ADDRESS: [u8; 4] = [0xaf, 0x83, 0xa1, 0x8d]; + +/// Encode proof into calldata to invoke `Halo2Verifier.verifyProof`. +/// +/// For `vk_address`: +/// - Pass `None` if verifying key is embedded in `Halo2Verifier` +/// - Pass `Some(vk_address)` if verifying key is separated and deployed at `vk_address` +pub fn encode_calldata( + vk_address: Option<[u8; 20]>, + proof: &[u8], + instances: &[bn256::Fr], +) -> Vec { + let (fn_sig, offset) = if vk_address.is_some() { + (FN_SIG_VERIFY_PROOF_WITH_VK_ADDRESS, 0x60) + } else { + (FN_SIG_VERIFY_PROOF, 0x40) + }; + let vk_address = if let Some(vk_address) = vk_address { + U256::try_from_be_slice(&vk_address) + .unwrap() + .to_be_bytes::<0x20>() + .to_vec() + } else { + Vec::new() + }; + let num_instances = instances.len(); + chain![ + fn_sig, // function signature + vk_address, // verifying key address + to_u256_be_bytes(offset), // offset of proof + to_u256_be_bytes(offset + 0x20 + proof.len()), // offset of instances + to_u256_be_bytes(proof.len()), // length of proof + proof.iter().cloned(), // proof + to_u256_be_bytes(num_instances), // length of instances + instances.iter().map(fr_to_u256).flat_map(to_u256_be_bytes), // instances + ] + .collect() +} + +#[cfg(any(test, feature = "evm"))] +pub(crate) mod test { + pub use revm; + use revm::{ + primitives::{Address, CreateScheme, ExecutionResult, Output, TransactTo, TxEnv}, + InMemoryDB, EVM, + }; + use std::{ + fmt::{self, Debug, Formatter}, + io::{self, Write}, + process::{Command, Stdio}, + str, + }; + + /// Compile solidity with `--via-ir` flag, then return creation bytecode. + /// + /// # Panics + /// Panics if executable `solc` can not be found, or compilation fails. + pub fn compile_solidity(solidity: impl AsRef<[u8]>) -> Vec { + let mut process = match Command::new("solc") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("--bin") + .arg("--optimize") + .arg("-") + .spawn() + { + Ok(process) => process, + Err(err) if err.kind() == io::ErrorKind::NotFound => { + panic!("Command 'solc' not found"); + } + Err(err) => { + panic!("Failed to spwan process with command 'solc':\n{err}"); + } + }; + process + .stdin + .take() + .unwrap() + .write_all(solidity.as_ref()) + .unwrap(); + let output = process.wait_with_output().unwrap(); + let stdout = str::from_utf8(&output.stdout).unwrap(); + if let Some(binary) = find_binary(stdout) { + binary + } else { + panic!( + "Compilation fails:\n{}", + str::from_utf8(&output.stderr).unwrap() + ) + } + } + + fn find_binary(stdout: &str) -> Option> { + let start = stdout.find("Binary:")? + 8; + Some(hex::decode(&stdout[start..stdout.len() - 1]).unwrap()) + } + + /// Evm runner. + pub struct Evm { + evm: EVM, + } + + impl Debug for Evm { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("Evm"); + debug_struct + .field("env", &self.evm.env) + .field("db", &self.evm.db.as_ref().unwrap()) + .finish() + } + } + + impl Default for Evm { + fn default() -> Self { + Self { + evm: EVM { + env: Default::default(), + db: Some(Default::default()), + }, + } + } + } + + impl Evm { + /// Return code_size of given address. + /// + /// # Panics + /// Panics if given address doesn't have bytecode. + pub fn code_size(&mut self, address: Address) -> usize { + self.evm.db.as_ref().unwrap().accounts[&address] + .info + .code + .as_ref() + .unwrap() + .len() + } + + /// Apply create transaction with given `bytecode` as creation bytecode. + /// Return created `address`. + /// + /// # Panics + /// Panics if execution reverts or halts unexpectedly. + pub fn create(&mut self, bytecode: Vec) -> Address { + let (_, output) = self.transact_success_or_panic(TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Create(CreateScheme::Create), + data: bytecode.into(), + ..Default::default() + }); + match output { + Output::Create(_, Some(address)) => address, + _ => unreachable!(), + } + } + + /// Apply call transaction to given `address` with `calldata`. + /// Returns `gas_used` and `return_data`. + /// + /// # Panics + /// Panics if execution reverts or halts unexpectedly. + pub fn call(&mut self, address: Address, calldata: Vec) -> (u64, Vec) { + let (gas_used, output) = self.transact_success_or_panic(TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Call(address), + data: calldata.into(), + ..Default::default() + }); + match output { + Output::Call(output) => (gas_used, output.into()), + _ => unreachable!(), + } + } + + fn transact_success_or_panic(&mut self, tx: TxEnv) -> (u64, Output) { + self.evm.env.tx = tx; + let result = self.evm.transact_commit().unwrap(); + self.evm.env.tx = Default::default(); + match result { + ExecutionResult::Success { + gas_used, + output, + logs, + .. + } => { + if !logs.is_empty() { + println!("--- logs from {} ---", logs[0].address); + for (log_idx, log) in logs.iter().enumerate() { + println!("log#{log_idx}"); + for (topic_idx, topic) in log.topics.iter().enumerate() { + println!(" topic{topic_idx}: {topic:?}"); + } + } + println!("--- end ---"); + } + (gas_used, output) + } + ExecutionResult::Revert { gas_used, output } => { + panic!("Transaction reverts with gas_used {gas_used} and output {output:#x}") + } + ExecutionResult::Halt { reason, gas_used } => panic!( + "Transaction halts unexpectedly with gas_used {gas_used} and reason {reason:?}" + ), + } + } + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/lib.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/lib.rs new file mode 100644 index 0000000..9c6f65d --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/lib.rs @@ -0,0 +1,21 @@ +//! Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254. +//! +//! [`halo2`]: http://github.com/privacy-scaling-explorations/halo2 + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![deny(rustdoc::broken_intra_doc_links)] + +mod codegen; +mod evm; +mod transcript; + +#[cfg(test)] +mod test; + +pub use codegen::{AccumulatorEncoding, BatchOpenScheme, SolidityGenerator}; +pub use evm::{encode_calldata, FN_SIG_VERIFY_PROOF, FN_SIG_VERIFY_PROOF_WITH_VK_ADDRESS}; +pub use transcript::Keccak256Transcript; + +#[cfg(feature = "evm")] +pub use evm::test::{compile_solidity, revm, Evm}; diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/test.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/test.rs new file mode 100644 index 0000000..fb31148 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/test.rs @@ -0,0 +1,612 @@ +use crate::{ + codegen::{AccumulatorEncoding, BatchOpenScheme::Bdfg21, SolidityGenerator}, + encode_calldata, + evm::test::{compile_solidity, Evm}, + FN_SIG_VERIFY_PROOF, FN_SIG_VERIFY_PROOF_WITH_VK_ADDRESS, +}; +use halo2_proofs::halo2curves::bn256::{Bn256, Fr}; +use rand::{rngs::StdRng, RngCore, SeedableRng}; +use sha3::Digest; +use std::{fs::File, io::Write}; + +#[test] +fn function_signature() { + for (fn_name, fn_sig) in [ + ("verifyProof(bytes,uint256[])", FN_SIG_VERIFY_PROOF), + ( + "verifyProof(address,bytes,uint256[])", + FN_SIG_VERIFY_PROOF_WITH_VK_ADDRESS, + ), + ] { + assert_eq!( + <[u8; 32]>::from(sha3::Keccak256::digest(fn_name))[..4], + fn_sig, + ); + } +} + +#[test] +fn render_huge() { + run_render::>() +} + +#[test] +fn render_maingate() { + run_render::>() +} + +#[test] +fn render_separately_huge() { + run_render_separately::>() +} + +#[test] +fn render_separately_maingate() { + run_render_separately::>() +} + +fn run_render>() { + let acc_encoding = AccumulatorEncoding::new(0, 4, 68).into(); + let (params, vk, instances, proof) = + halo2::create_testdata_bdfg21::(C::min_k(), acc_encoding, std_rng()); + + let generator = SolidityGenerator::new(¶ms, &vk, Bdfg21, instances.len()) + .set_acc_encoding(acc_encoding); + let verifier_solidity = generator.render().unwrap(); + let verifier_creation_code = compile_solidity(verifier_solidity); + let verifier_creation_code_size = verifier_creation_code.len(); + + let mut evm = Evm::default(); + let verifier_address = evm.create(verifier_creation_code); + let verifier_runtime_code_size = evm.code_size(verifier_address); + + println!("Verifier creation code size: {verifier_creation_code_size}"); + println!("Verifier runtime code size: {verifier_runtime_code_size}"); + + let (gas_cost, output) = evm.call(verifier_address, encode_calldata(None, &proof, &instances)); + assert_eq!(output, [vec![0; 31], vec![1]].concat()); + println!("Gas cost: {gas_cost}"); +} + +fn run_render_separately>() { + let acc_encoding = AccumulatorEncoding::new(0, 4, 68).into(); + let (params, vk, instances, _) = + halo2::create_testdata_bdfg21::(C::min_k(), acc_encoding, std_rng()); + + let generator = SolidityGenerator::new(¶ms, &vk, Bdfg21, instances.len()) + .set_acc_encoding(acc_encoding); + let (verifier_solidity, _vk_solidity) = generator.render_separately().unwrap(); + let verifier_creation_code = compile_solidity(&verifier_solidity); + let verifier_creation_code_size = verifier_creation_code.len(); + + let mut evm = Evm::default(); + let verifier_address = evm.create(verifier_creation_code); + let verifier_runtime_code_size = evm.code_size(verifier_address); + + println!("Verifier creation code size: {verifier_creation_code_size}"); + println!("Verifier runtime code size: {verifier_runtime_code_size}"); + + let deployed_verifier_solidity = verifier_solidity; + + for k in C::min_k()..C::min_k() + 4 { + let (params, vk, instances, proof) = + halo2::create_testdata_bdfg21::(k, acc_encoding, std_rng()); + let generator = SolidityGenerator::new(¶ms, &vk, Bdfg21, instances.len()) + .set_acc_encoding(acc_encoding); + + let (verifier_solidity, vk_solidity) = generator.render_separately().unwrap(); + assert_eq!(deployed_verifier_solidity, verifier_solidity); + + let vk_creation_code = compile_solidity(&vk_solidity); + let vk_address = evm.create(vk_creation_code); + + let (gas_cost, output) = evm.call( + verifier_address, + encode_calldata(Some(vk_address.into()), &proof, &instances), + ); + assert_eq!(output, [vec![0; 31], vec![1]].concat()); + println!("Gas cost: {gas_cost}"); + } +} + +fn std_rng() -> impl RngCore + Clone { + StdRng::seed_from_u64(0) +} + +#[allow(dead_code)] +fn save_generated(verifier: &str, vk: Option<&str>) { + const DIR_GENERATED: &str = "./target/generated"; + + std::fs::create_dir_all(DIR_GENERATED).unwrap(); + File::create(format!("{DIR_GENERATED}/Halo2Verifier.sol")) + .unwrap() + .write_all(verifier.as_bytes()) + .unwrap(); + if let Some(vk) = vk { + File::create(format!("{DIR_GENERATED}/Halo2VerifyingKey.sol")) + .unwrap() + .write_all(vk.as_bytes()) + .unwrap(); + } +} + +mod halo2 { + use crate::{codegen::AccumulatorEncoding, transcript::Keccak256Transcript}; + use halo2_proofs::{ + arithmetic::CurveAffine, + halo2curves::{ + bn256, + ff::{Field, PrimeField}, + group::{prime::PrimeCurveAffine, Curve, Group}, + pairing::{MillerLoopResult, MultiMillerLoop}, + }, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, VerifyingKey}, + poly::kzg::{ + commitment::ParamsKZG, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + transcript::TranscriptWriterBuffer, + }; + use itertools::Itertools; + use rand::RngCore; + use ruint::aliases::U256; + use std::borrow::Borrow; + + pub trait TestCircuit: Circuit { + fn min_k() -> u32; + + fn new(acc_encoding: Option, rng: impl RngCore) -> Self; + + fn instances(&self) -> Vec; + } + + #[allow(clippy::type_complexity)] + pub fn create_testdata_bdfg21>( + k: u32, + acc_encoding: Option, + mut rng: impl RngCore + Clone, + ) -> ( + ParamsKZG, + VerifyingKey, + Vec, + Vec, + ) { + let circuit = C::new(acc_encoding, rng.clone()); + let instances = circuit.instances(); + + let params = ParamsKZG::::setup(k, &mut rng); + let vk = keygen_vk(¶ms, &circuit).unwrap(); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).unwrap(); + + let proof = { + let mut transcript = Keccak256Transcript::new(Vec::new()); + create_proof::<_, ProverSHPLONK<_>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + &[&[&instances]], + &mut rng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + let result = { + let mut transcript = Keccak256Transcript::new(proof.as_slice()); + verify_proof::<_, VerifierSHPLONK<_>, _, _, SingleStrategy<_>>( + ¶ms, + pk.get_vk(), + SingleStrategy::new(¶ms), + &[&[&instances]], + &mut transcript, + ) + }; + assert!(result.is_ok()); + + (params, vk, instances, proof) + } + + fn random_accumulator_limbs( + acc_encoding: AccumulatorEncoding, + mut rng: impl RngCore, + ) -> Vec + where + M: MultiMillerLoop, + ::Base: PrimeField, + M::Scalar: PrimeField, + { + let s = M::Scalar::random(&mut rng); + let g1 = M::G1Affine::generator(); + let g2 = M::G2Affine::generator(); + let neg_s_g2 = (g2 * -s).to_affine(); + let lhs_scalar = M::Scalar::random(&mut rng); + let rhs_scalar = lhs_scalar * s.invert().unwrap(); + let [lhs, rhs] = [lhs_scalar, rhs_scalar].map(|scalar| (g1 * scalar).to_affine()); + + assert!(bool::from( + M::multi_miller_loop(&[(&lhs, &g2.into()), (&rhs, &neg_s_g2.into())]) + .final_exponentiation() + .is_identity() + )); + + [lhs, rhs] + .into_iter() + .flat_map(|ec_point| ec_point_to_limbs(ec_point, acc_encoding.num_limb_bits)) + .collect() + } + + fn ec_point_to_limbs(ec_point: impl Borrow, num_limb_bits: usize) -> Vec + where + C: CurveAffine, + C::Base: PrimeField, + C::Scalar: PrimeField, + { + let coords = ec_point.borrow().coordinates().unwrap(); + [*coords.x(), *coords.y()] + .into_iter() + .flat_map(|coord| fe_to_limbs(coord, num_limb_bits)) + .collect() + } + + fn fe_to_limbs(fe: impl Borrow, num_limb_bits: usize) -> Vec + where + F1: PrimeField, + F2: PrimeField, + { + let big = U256::from_le_bytes(fe.borrow().to_repr()); + let mask = &((U256::from(1) << num_limb_bits) - U256::from(1)); + (0usize..) + .step_by(num_limb_bits) + .map(|shift| fe_from_u256((big >> shift) & mask)) + .take((F1::NUM_BITS as usize + num_limb_bits - 1) / num_limb_bits) + .collect_vec() + } + + fn fe_from_u256(u256: impl Borrow) -> F + where + F: PrimeField, + { + let bytes = u256.borrow().to_le_bytes::<32>(); + F::from_repr_vartime(bytes).unwrap() + } + + pub mod huge { + use crate::{ + codegen::AccumulatorEncoding, + test::halo2::{random_accumulator_limbs, TestCircuit}, + }; + use halo2_proofs::{ + arithmetic::CurveAffine, + circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::{ + ff::{Field, PrimeField}, + pairing::MultiMillerLoop, + }, + plonk::{ + self, Advice, Circuit, Column, ConstraintSystem, Expression, FirstPhase, Fixed, + Instance, SecondPhase, Selector, ThirdPhase, + }, + poly::Rotation, + }; + use itertools::{izip, Itertools}; + use rand::RngCore; + use std::{array, fmt::Debug, iter, mem}; + + #[derive(Clone, Debug, Default)] + pub struct HugeCircuit(Vec); + + impl TestCircuit for HugeCircuit + where + M: MultiMillerLoop, + ::Base: PrimeField, + M::Scalar: PrimeField, + { + fn min_k() -> u32 { + 6 + } + + fn new(acc_encoding: Option, mut rng: impl RngCore) -> Self { + let instances = if let Some(acc_encoding) = acc_encoding { + random_accumulator_limbs::(acc_encoding, rng) + } else { + iter::repeat_with(|| M::Scalar::random(&mut rng)) + .take(10) + .collect() + }; + Self(instances) + } + + fn instances(&self) -> Vec { + self.0.clone() + } + } + + impl Circuit for HugeCircuit + where + M::Scalar: PrimeField, + { + type Config = ( + [Selector; 10], + [Selector; 10], + [Column; 10], + [Column; 10], + Column, + ); + type FloorPlanner = SimpleFloorPlanner; + #[cfg(feature = "halo2_circuit_params")] + type Params = (); + + fn without_witnesses(&self) -> Self { + unimplemented!() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let selectors = [(); 10].map(|_| meta.selector()); + let complex_selectors = [(); 10].map(|_| meta.complex_selector()); + let fixeds = [(); 10].map(|_| meta.fixed_column()); + let (advices, challenges) = (0..10) + .map(|idx| match idx % 3 { + 0 => ( + meta.advice_column_in(FirstPhase), + meta.challenge_usable_after(FirstPhase), + ), + 1 => ( + meta.advice_column_in(SecondPhase), + meta.challenge_usable_after(SecondPhase), + ), + 2 => ( + meta.advice_column_in(ThirdPhase), + meta.challenge_usable_after(ThirdPhase), + ), + _ => unreachable!(), + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + let advices: [_; 10] = advices.try_into().unwrap(); + let challenges: [_; 10] = challenges.try_into().unwrap(); + let instance = meta.instance_column(); + + meta.create_gate("", |meta| { + let selectors = selectors.map(|selector| meta.query_selector(selector)); + let advices: [Expression; 10] = array::from_fn(|idx| { + let rotation = Rotation((idx as i32 - advices.len() as i32) / 2); + meta.query_advice(advices[idx], rotation) + }); + let challenges = challenges.map(|challenge| meta.query_challenge(challenge)); + + izip!( + selectors, + advices.iter().cloned(), + advices[1..].iter().cloned(), + advices[2..].iter().cloned(), + challenges.iter().cloned(), + challenges[1..].iter().cloned(), + challenges[2..].iter().cloned(), + ) + .map(|(q, a1, a2, a3, c1, c2, c3)| q * a1 * a2 * a3 * c1 * c2 * c3) + .collect_vec() + }); + + for ((q1, q2, q3), (f1, f2, f3), (a1, a2, a3)) in izip!( + complex_selectors.iter().tuple_windows(), + fixeds.iter().tuple_windows(), + advices.iter().tuple_windows() + ) { + meta.lookup_any("", |meta| { + izip!([q1, q2, q3], [f1, f2, f3], [a1, a2, a3]) + .map(|(q, f, a)| { + let q = meta.query_selector(*q); + let f = meta.query_fixed(*f, Rotation::cur()); + let a = meta.query_advice(*a, Rotation::cur()); + (q * a, f) + }) + .collect_vec() + }); + } + + fixeds.map(|column| meta.enable_equality(column)); + advices.map(|column| meta.enable_equality(column)); + meta.enable_equality(instance); + + (selectors, complex_selectors, fixeds, advices, instance) + } + + fn synthesize( + &self, + (selectors, complex_selectors, fixeds, advices, instance): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), plonk::Error> { + let assigneds = layouter.assign_region( + || "", + |mut region| { + let offset = &mut 10; + let mut next_offset = || mem::replace(offset, *offset + 1); + + for q in selectors { + q.enable(&mut region, next_offset())?; + } + for q in complex_selectors { + q.enable(&mut region, next_offset())?; + } + for (idx, column) in izip!(1.., fixeds) { + let value = Value::known(M::Scalar::from(idx)); + region.assign_fixed(|| "", column, next_offset(), || value)?; + } + izip!(advices, &self.0) + .map(|(column, value)| { + let value = Value::known(*value); + region.assign_advice(|| "", column, next_offset(), || value) + }) + .try_collect::<_, Vec<_>, _>() + }, + )?; + for (idx, assigned) in izip!(0.., assigneds) { + layouter.constrain_instance(assigned.cell(), instance, idx)?; + } + Ok(()) + } + } + } + + pub mod maingate { + use crate::{ + codegen::AccumulatorEncoding, + test::halo2::{random_accumulator_limbs, TestCircuit}, + }; + use halo2_maingate::{ + MainGate, MainGateConfig, MainGateInstructions, RangeChip, RangeConfig, + RangeInstructions, RegionCtx, + }; + use halo2_proofs::{ + arithmetic::CurveAffine, + circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::{ + ff::{Field, PrimeField}, + pairing::MultiMillerLoop, + }, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use itertools::Itertools; + use rand::RngCore; + use std::iter; + + #[derive(Clone)] + pub struct MainGateWithRangeConfig { + main_gate_config: MainGateConfig, + range_config: RangeConfig, + } + + impl MainGateWithRangeConfig { + fn configure( + meta: &mut ConstraintSystem, + composition_bits: Vec, + overflow_bits: Vec, + ) -> Self { + let main_gate_config = MainGate::::configure(meta); + let range_config = RangeChip::::configure( + meta, + &main_gate_config, + composition_bits, + overflow_bits, + ); + MainGateWithRangeConfig { + main_gate_config, + range_config, + } + } + + fn main_gate(&self) -> MainGate { + MainGate::new(self.main_gate_config.clone()) + } + + fn range_chip(&self) -> RangeChip { + RangeChip::new(self.range_config.clone()) + } + } + + #[derive(Clone, Default)] + pub struct MainGateWithRange { + instances: Vec, + } + + impl TestCircuit for MainGateWithRange + where + M: MultiMillerLoop, + ::Base: PrimeField, + M::Scalar: PrimeField, + { + fn min_k() -> u32 { + 9 + } + + fn new(acc_encoding: Option, mut rng: impl RngCore) -> Self { + let instances = if let Some(acc_encoding) = acc_encoding { + random_accumulator_limbs::(acc_encoding, rng) + } else { + iter::repeat_with(|| M::Scalar::random(&mut rng)) + .take(10) + .collect() + }; + Self { instances } + } + + fn instances(&self) -> Vec { + self.instances.clone() + } + } + + impl Circuit for MainGateWithRange + where + M::Scalar: PrimeField, + { + type Config = MainGateWithRangeConfig; + type FloorPlanner = SimpleFloorPlanner; + #[cfg(feature = "halo2_circuit_params")] + type Params = (); + + fn without_witnesses(&self) -> Self { + unimplemented!() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + MainGateWithRangeConfig::configure(meta, vec![8], vec![4, 7]) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let main_gate = config.main_gate(); + let range_chip = config.range_chip(); + range_chip.load_table(&mut layouter)?; + + let advices = layouter.assign_region( + || "", + |region| { + let mut ctx = RegionCtx::new(region, 0); + + let advices = self + .instances + .iter() + .map(|value| main_gate.assign_value(&mut ctx, Value::known(*value))) + .try_collect::<_, Vec<_>, _>()?; + + // Dummy gates to make all fixed column with values + range_chip.decompose( + &mut ctx, + Value::known(M::Scalar::from(u64::MAX)), + 8, + 64, + )?; + range_chip.decompose( + &mut ctx, + Value::known(M::Scalar::from(u32::MAX as u64)), + 8, + 39, + )?; + let a = &advices[0]; + let b = main_gate.sub_sub_with_constant( + &mut ctx, + a, + a, + a, + M::Scalar::from(2), + )?; + let cond = main_gate.assign_bit(&mut ctx, Value::known(M::Scalar::ONE))?; + main_gate.select(&mut ctx, a, &b, &cond)?; + + Ok(advices) + }, + )?; + + for (offset, advice) in advices.into_iter().enumerate() { + main_gate.expose_public(layouter.namespace(|| ""), advice, offset)? + } + + Ok(()) + } + } + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/src/transcript.rs b/tools/polyexen/circuit/halo2-solidity-verifier/src/transcript.rs new file mode 100644 index 0000000..f125329 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/src/transcript.rs @@ -0,0 +1,192 @@ +use halo2_proofs::{ + halo2curves::{ff::PrimeField, Coordinates, CurveAffine}, + transcript::{ + EncodedChallenge, Transcript, TranscriptRead, TranscriptReadBuffer, TranscriptWrite, + TranscriptWriterBuffer, + }, +}; +use itertools::{chain, Itertools}; +use ruint::aliases::U256; +use sha3::{Digest, Keccak256}; +use std::{ + io::{self, Read, Write}, + marker::PhantomData, + mem, +}; + +/// Transcript using Keccak256 as hash function in Fiat-Shamir transformation. +#[derive(Debug, Default)] +pub struct Keccak256Transcript { + stream: S, + buf: Vec, + _marker: PhantomData, +} + +impl Keccak256Transcript { + /// Return a `Keccak256Transcript` with empty buffer. + pub fn new(stream: S) -> Self { + Self { + stream, + buf: Vec::new(), + _marker: PhantomData, + } + } +} + +#[derive(Debug)] +pub struct ChallengeEvm(C::Scalar) +where + C: CurveAffine, + C::Scalar: PrimeField; + +impl EncodedChallenge for ChallengeEvm +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + type Input = [u8; 0x20]; + + fn new(challenge_input: &[u8; 0x20]) -> Self { + ChallengeEvm(u256_to_fe(U256::from_be_bytes(*challenge_input))) + } + + fn get_scalar(&self) -> C::Scalar { + self.0 + } +} + +impl Transcript> for Keccak256Transcript +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn squeeze_challenge(&mut self) -> ChallengeEvm { + let buf_len = self.buf.len(); + let data = chain![ + mem::take(&mut self.buf), + if buf_len == 0x20 { Some(1) } else { None } + ] + .collect_vec(); + let hash: [u8; 0x20] = Keccak256::digest(data).into(); + self.buf = hash.to_vec(); + ChallengeEvm::new(&hash) + } + + fn common_point(&mut self, ec_point: C) -> io::Result<()> { + let coords: Coordinates = Option::from(ec_point.coordinates()).ok_or_else(|| { + io::Error::new( + io::ErrorKind::Other, + "Invalid elliptic curve point".to_string(), + ) + })?; + [coords.x(), coords.y()].map(|coordinate| { + self.buf + .extend(coordinate.to_repr().as_ref().iter().rev().cloned()); + }); + Ok(()) + } + + fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + self.buf.extend(scalar.to_repr().as_ref().iter().rev()); + Ok(()) + } +} + +impl TranscriptRead> for Keccak256Transcript +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn read_point(&mut self) -> io::Result { + let mut reprs = [::Repr::default(); 2]; + for repr in &mut reprs { + self.stream.read_exact(repr.as_mut())?; + repr.as_mut().reverse(); + } + let [x, y] = reprs.map(|repr| Option::from(C::Base::from_repr(repr))); + let ec_point = x + .zip(y) + .and_then(|(x, y)| Option::from(C::from_xy(x, y))) + .ok_or_else(|| { + io::Error::new( + io::ErrorKind::Other, + "Invalid elliptic curve point".to_string(), + ) + })?; + self.common_point(ec_point)?; + Ok(ec_point) + } + + fn read_scalar(&mut self) -> io::Result { + let mut data = [0; 0x20]; + self.stream.read_exact(data.as_mut())?; + data.reverse(); + let scalar = C::Scalar::from_repr_vartime(data) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid scalar".to_string()))?; + Transcript::>::common_scalar(self, scalar)?; + Ok(scalar) + } +} + +impl TranscriptReadBuffer> for Keccak256Transcript +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn init(reader: R) -> Self { + Keccak256Transcript::new(reader) + } +} + +impl TranscriptWrite> for Keccak256Transcript +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn write_point(&mut self, ec_point: C) -> io::Result<()> { + self.common_point(ec_point)?; + let coords = ec_point.coordinates().unwrap(); + for coord in [coords.x(), coords.y()] { + let mut repr = coord.to_repr(); + repr.as_mut().reverse(); + self.stream.write_all(repr.as_ref())?; + } + Ok(()) + } + + fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + Transcript::>::common_scalar(self, scalar)?; + let mut data = scalar.to_repr(); + data.as_mut().reverse(); + self.stream.write_all(data.as_ref()) + } +} + +impl TranscriptWriterBuffer> for Keccak256Transcript +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn init(writer: W) -> Self { + Keccak256Transcript::new(writer) + } + + fn finalize(self) -> W { + self.stream + } +} + +fn u256_to_fe(value: U256) -> F +where + F: PrimeField, +{ + let value = value % modulus::(); + F::from_repr(value.to_le_bytes::<0x20>()).unwrap() +} + +fn modulus() -> U256 +where + F: PrimeField, +{ + U256::from_le_bytes((-F::ONE).to_repr()) + U256::from(1) +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2Verifier.sol b/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2Verifier.sol new file mode 100644 index 0000000..81b2db6 --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2Verifier.sol @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract Halo2Verifier { + uint256 internal constant PROOF_LEN_CPTR = {{ proof_cptr - 1 }}; + uint256 internal constant PROOF_CPTR = {{ proof_cptr }}; + uint256 internal constant NUM_INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) }}; + uint256 internal constant INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) + 1 }}; + + uint256 internal constant FIRST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr }}; + uint256 internal constant LAST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr + 2 * (num_quotients - 1) }}; + + uint256 internal constant VK_MPTR = {{ vk_mptr }}; + uint256 internal constant VK_DIGEST_MPTR = {{ vk_mptr }}; + uint256 internal constant K_MPTR = {{ vk_mptr + 1 }}; + uint256 internal constant N_INV_MPTR = {{ vk_mptr + 2 }}; + uint256 internal constant OMEGA_MPTR = {{ vk_mptr + 3 }}; + uint256 internal constant OMEGA_INV_MPTR = {{ vk_mptr + 4 }}; + uint256 internal constant OMEGA_INV_TO_L_MPTR = {{ vk_mptr + 5 }}; + uint256 internal constant NUM_INSTANCES_MPTR = {{ vk_mptr + 6 }}; + uint256 internal constant HAS_ACCUMULATOR_MPTR = {{ vk_mptr + 7 }}; + uint256 internal constant ACC_OFFSET_MPTR = {{ vk_mptr + 8 }}; + uint256 internal constant NUM_ACC_LIMBS_MPTR = {{ vk_mptr + 9 }}; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = {{ vk_mptr + 10 }}; + uint256 internal constant G1_X_MPTR = {{ vk_mptr + 11 }}; + uint256 internal constant G1_Y_MPTR = {{ vk_mptr + 12 }}; + uint256 internal constant G2_X_1_MPTR = {{ vk_mptr + 13 }}; + uint256 internal constant G2_X_2_MPTR = {{ vk_mptr + 14 }}; + uint256 internal constant G2_Y_1_MPTR = {{ vk_mptr + 15 }}; + uint256 internal constant G2_Y_2_MPTR = {{ vk_mptr + 16 }}; + uint256 internal constant NEG_S_G2_X_1_MPTR = {{ vk_mptr + 17 }}; + uint256 internal constant NEG_S_G2_X_2_MPTR = {{ vk_mptr + 18 }}; + uint256 internal constant NEG_S_G2_Y_1_MPTR = {{ vk_mptr + 19 }}; + uint256 internal constant NEG_S_G2_Y_2_MPTR = {{ vk_mptr + 20 }}; + + uint256 internal constant CHALLENGE_MPTR = {{ challenge_mptr }}; + + uint256 internal constant THETA_MPTR = {{ theta_mptr }}; + uint256 internal constant BETA_MPTR = {{ theta_mptr + 1 }}; + uint256 internal constant GAMMA_MPTR = {{ theta_mptr + 2 }}; + uint256 internal constant Y_MPTR = {{ theta_mptr + 3 }}; + uint256 internal constant X_MPTR = {{ theta_mptr + 4 }}; + {%- match scheme %} + {%- when Bdfg21 %} + uint256 internal constant ZETA_MPTR = {{ theta_mptr + 5 }}; + uint256 internal constant NU_MPTR = {{ theta_mptr + 6 }}; + uint256 internal constant MU_MPTR = {{ theta_mptr + 7 }}; + {%- when Gwc19 %} + // TODO + {%- endmatch %} + + uint256 internal constant ACC_LHS_X_MPTR = {{ theta_mptr + 8 }}; + uint256 internal constant ACC_LHS_Y_MPTR = {{ theta_mptr + 9 }}; + uint256 internal constant ACC_RHS_X_MPTR = {{ theta_mptr + 10 }}; + uint256 internal constant ACC_RHS_Y_MPTR = {{ theta_mptr + 11 }}; + uint256 internal constant X_N_MPTR = {{ theta_mptr + 12 }}; + uint256 internal constant X_N_MINUS_1_INV_MPTR = {{ theta_mptr + 13 }}; + uint256 internal constant L_LAST_MPTR = {{ theta_mptr + 14 }}; + uint256 internal constant L_BLIND_MPTR = {{ theta_mptr + 15 }}; + uint256 internal constant L_0_MPTR = {{ theta_mptr + 16 }}; + uint256 internal constant INSTANCE_EVAL_MPTR = {{ theta_mptr + 17 }}; + uint256 internal constant QUOTIENT_EVAL_MPTR = {{ theta_mptr + 18 }}; + uint256 internal constant QUOTIENT_X_MPTR = {{ theta_mptr + 19 }}; + uint256 internal constant QUOTIENT_Y_MPTR = {{ theta_mptr + 20 }}; + uint256 internal constant R_EVAL_MPTR = {{ theta_mptr + 21 }}; + uint256 internal constant PAIRING_LHS_X_MPTR = {{ theta_mptr + 22 }}; + uint256 internal constant PAIRING_LHS_Y_MPTR = {{ theta_mptr + 23 }}; + uint256 internal constant PAIRING_RHS_X_MPTR = {{ theta_mptr + 24 }}; + uint256 internal constant PAIRING_RHS_Y_MPTR = {{ theta_mptr + 25 }}; + + function verifyProof( + {%- match vk %} + {%- when Some with (vk) %} + {%- when None %} + address vk, + {%- endmatch %} + bytes calldata proof, + uint256[] calldata instances + ) public returns (bool) { + assembly { + // Read EC point (x, y) at (proof_cptr, proof_cptr + 0x20), + // and check if the point is on affine plane, + // and store them in (hash_mptr, hash_mptr + 0x20). + // Return updated (success, proof_cptr, hash_mptr). + function read_ec_point(success, proof_cptr, hash_mptr, q) -> ret0, ret1, ret2 { + let x := calldataload(proof_cptr) + let y := calldataload(add(proof_cptr, 0x20)) + ret0 := and(success, lt(x, q)) + ret0 := and(ret0, lt(y, q)) + ret0 := and(ret0, eq(mulmod(y, y, q), addmod(mulmod(x, mulmod(x, x, q), q), 3, q))) + mstore(hash_mptr, x) + mstore(add(hash_mptr, 0x20), y) + ret1 := add(proof_cptr, 0x40) + ret2 := add(hash_mptr, 0x40) + } + + // Squeeze challenge by keccak256(memory[0..hash_mptr]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr, hash_mptr). + function squeeze_challenge(challenge_mptr, hash_mptr, r) -> ret0, ret1 { + let hash := keccak256(0x00, hash_mptr) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret0 := add(challenge_mptr, 0x20) + ret1 := 0x20 + } + + // Squeeze challenge without absorbing new input from calldata, + // by putting an extra 0x01 in memory[0x20] and squeeze by keccak256(memory[0..21]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr). + function squeeze_challenge_cont(challenge_mptr, r) -> ret { + mstore8(0x20, 0x01) + let hash := keccak256(0x00, 0x21) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret := add(challenge_mptr, 0x20) + } + + // Batch invert values in memory[mptr_start..mptr_end] in place. + // Return updated (success). + function batch_invert(success, mptr_start, mptr_end, r) -> ret { + let gp_mptr := mptr_end + let gp := mload(mptr_start) + let mptr := add(mptr_start, 0x20) + for + {} + lt(mptr, sub(mptr_end, 0x20)) + {} + { + gp := mulmod(gp, mload(mptr), r) + mstore(gp_mptr, gp) + mptr := add(mptr, 0x20) + gp_mptr := add(gp_mptr, 0x20) + } + gp := mulmod(gp, mload(mptr), r) + + mstore(gp_mptr, 0x20) + mstore(add(gp_mptr, 0x20), 0x20) + mstore(add(gp_mptr, 0x40), 0x20) + mstore(add(gp_mptr, 0x60), gp) + mstore(add(gp_mptr, 0x80), sub(r, 2)) + mstore(add(gp_mptr, 0xa0), r) + ret := and(success, staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20)) + let all_inv := mload(gp_mptr) + + let first_mptr := mptr_start + let second_mptr := add(first_mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + for + {} + lt(second_mptr, mptr) + {} + { + let inv := mulmod(all_inv, mload(gp_mptr), r) + all_inv := mulmod(all_inv, mload(mptr), r) + mstore(mptr, inv) + mptr := sub(mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + } + let inv_first := mulmod(all_inv, mload(second_mptr), r) + let inv_second := mulmod(all_inv, mload(first_mptr), r) + mstore(first_mptr, inv_first) + mstore(second_mptr, inv_second) + } + + // Add (x, y) into point at (0x00, 0x20). + // Return updated (success). + function ec_add_acc(success, x, y) -> ret { + mstore(0x40, x) + mstore(0x60, y) + ret := and(success, staticcall(gas(), 0x06, 0x00, 0x80, 0x00, 0x40)) + } + + // Scale point at (0x00, 0x20) by scalar. + function ec_mul_acc(success, scalar) -> ret { + mstore(0x40, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40)) + } + + // Add (x, y) into point at (0x80, 0xa0). + // Return updated (success). + function ec_add_tmp(success, x, y) -> ret { + mstore(0xc0, x) + mstore(0xe0, y) + ret := and(success, staticcall(gas(), 0x06, 0x80, 0x80, 0x80, 0x40)) + } + + // Scale point at (0x80, 0xa0) by scalar. + // Return updated (success). + function ec_mul_tmp(success, scalar) -> ret { + mstore(0xc0, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x80, 0x60, 0x80, 0x40)) + } + + // Perform pairing check. + // Return updated (success). + function ec_pairing(success, lhs_x, lhs_y, rhs_x, rhs_y) -> ret { + mstore(0x00, lhs_x) + mstore(0x20, lhs_y) + mstore(0x40, mload(G2_X_1_MPTR)) + mstore(0x60, mload(G2_X_2_MPTR)) + mstore(0x80, mload(G2_Y_1_MPTR)) + mstore(0xa0, mload(G2_Y_2_MPTR)) + mstore(0xc0, rhs_x) + mstore(0xe0, rhs_y) + mstore(0x100, mload(NEG_S_G2_X_1_MPTR)) + mstore(0x120, mload(NEG_S_G2_X_2_MPTR)) + mstore(0x140, mload(NEG_S_G2_Y_1_MPTR)) + mstore(0x160, mload(NEG_S_G2_Y_2_MPTR)) + ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20)) + ret := and(ret, mload(0x00)) + } + + // Modulus + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // BN254 base field + let r := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // BN254 scalar field + + // Initialize success as true + let success := true + + { + {%- match vk %} + {%- when Some with (vk) %} + // Load vk into memory + {%- for (name, chunk) in vk.constants %} + mstore({{ vk_mptr + loop.index0 }}, {{ chunk|hex_padded(64) }}) // {{ name }} + {%- endfor %} + {%- for (x, y) in vk.fixed_comms %} + {%- let offset = vk.constants.len() %} + mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x + mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- for (x, y) in vk.permutation_comms %} + {%- let offset = vk.constants.len() + 2 * vk.fixed_comms.len() %} + mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x + mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- when None %} + // Copy vk into memory + extcodecopy(vk, VK_MPTR, 0x00, {{ vk_len|hex() }}) + {%- endmatch %} + + // Check valid length of proof + success := and(success, eq({{ proof_len|hex() }}, calldataload(PROOF_LEN_CPTR))) + + // Check valid length of instances + let num_instances := mload(NUM_INSTANCES_MPTR) + success := and(success, eq(num_instances, calldataload(NUM_INSTANCE_CPTR))) + + // Absorb vk diegst + mstore(0x00, mload(VK_DIGEST_MPTR)) + + // Read instances and witness commitments and generate challenges + let hash_mptr := 0x20 + let instance_cptr := INSTANCE_CPTR + for + { let instance_cptr_end := add(instance_cptr, mul(0x20, num_instances)) } + lt(instance_cptr, instance_cptr_end) + {} + { + let instance := calldataload(instance_cptr) + success := and(success, lt(instance, r)) + mstore(hash_mptr, instance) + instance_cptr := add(instance_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + let proof_cptr := PROOF_CPTR + let challenge_mptr := CHALLENGE_MPTR + {%- for num_advices in num_advices %} + {%- let num_challenges = num_challenges[loop.index0] %} + + // Phase {{ loop.index }} + for + { let proof_cptr_end := add(proof_cptr, {{ (2 * 32 * num_advices)|hex() }}) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + {%- for _ in 0..num_challenges - 1 %} + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) + {%- endfor %} + {%- endfor %} + + // Read evaluations + for + { let proof_cptr_end := add(proof_cptr, {{ (32 * num_evals)|hex() }}) } + lt(proof_cptr, proof_cptr_end) + {} + { + let eval := calldataload(proof_cptr) + success := and(success, lt(eval, r)) + mstore(hash_mptr, eval) + proof_cptr := add(proof_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + // Read batch opening proof and generate challenges + {%- match scheme %} + {%- when Bdfg21 %} + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // zeta + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) // nu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W' + {%- when Gwc19 %} + // TODO + {%- endmatch %} + + // Read accumulator from instances + if mload(HAS_ACCUMULATOR_MPTR) { + let num_limbs := mload(NUM_ACC_LIMBS_MPTR) + let num_limb_bits := mload(NUM_ACC_LIMB_BITS_MPTR) + + let cptr := add(INSTANCE_CPTR, mul(mload(ACC_OFFSET_MPTR), 0x20)) + let lhs_y_off := mul(num_limbs, 0x20) + let rhs_x_off := mul(lhs_y_off, 2) + let rhs_y_off := mul(lhs_y_off, 3) + let lhs_x := calldataload(cptr) + let lhs_y := calldataload(add(cptr, lhs_y_off)) + let rhs_x := calldataload(add(cptr, rhs_x_off)) + let rhs_y := calldataload(add(cptr, rhs_y_off)) + for + { + let cptr_end := add(cptr, mul(0x20, num_limbs)) + let shift := num_limb_bits + } + lt(cptr, cptr_end) + {} + { + cptr := add(cptr, 0x20) + lhs_x := add(lhs_x, shl(shift, calldataload(cptr))) + lhs_y := add(lhs_y, shl(shift, calldataload(add(cptr, lhs_y_off)))) + rhs_x := add(rhs_x, shl(shift, calldataload(add(cptr, rhs_x_off)))) + rhs_y := add(rhs_y, shl(shift, calldataload(add(cptr, rhs_y_off)))) + shift := add(shift, num_limb_bits) + } + + success := and(success, eq(mulmod(lhs_y, lhs_y, q), addmod(mulmod(lhs_x, mulmod(lhs_x, lhs_x, q), q), 3, q))) + success := and(success, eq(mulmod(rhs_y, rhs_y, q), addmod(mulmod(rhs_x, mulmod(rhs_x, rhs_x, q), q), 3, q))) + + mstore(ACC_LHS_X_MPTR, lhs_x) + mstore(ACC_LHS_Y_MPTR, lhs_y) + mstore(ACC_RHS_X_MPTR, rhs_x) + mstore(ACC_RHS_Y_MPTR, rhs_y) + } + + pop(q) + } + + // Revert earlier if anything from calldata is invalid + if iszero(success) { + revert(0, 0) + } + + // Compute lagrange evaluations and instance evaluation + { + let k := mload(K_MPTR) + let x := mload(X_MPTR) + let x_n := x + for + { let idx := 0 } + lt(idx, k) + { idx := add(idx, 1) } + { + x_n := mulmod(x_n, x_n, r) + } + + let omega := mload(OMEGA_MPTR) + + let mptr := X_N_MPTR + let mptr_end := add(mptr, mul(0x20, add(mload(NUM_INSTANCES_MPTR), {{ num_neg_lagranges }}))) + if iszero(mload(NUM_INSTANCES_MPTR)) { + mptr_end := add(mptr_end, 0x20) + } + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, addmod(x, sub(r, pow_of_omega), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) + success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), r) + + mptr := X_N_MPTR + let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + + let l_blind := mload(add(X_N_MPTR, 0x20)) + let l_i_cptr := add(X_N_MPTR, 0x40) + for + { let l_i_cptr_end := add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }}) } + lt(l_i_cptr, l_i_cptr_end) + { l_i_cptr := add(l_i_cptr, 0x20) } + { + l_blind := addmod(l_blind, mload(l_i_cptr), r) + } + + let instance_eval := 0 + for + { + let instance_cptr := INSTANCE_CPTR + let instance_cptr_end := add(instance_cptr, mul(0x20, mload(NUM_INSTANCES_MPTR))) + } + lt(instance_cptr, instance_cptr_end) + { + instance_cptr := add(instance_cptr, 0x20) + l_i_cptr := add(l_i_cptr, 0x20) + } + { + instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r) + } + + let x_n_minus_1_inv := mload(mptr_end) + let l_last := mload(X_N_MPTR) + let l_0 := mload(add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }})) + + mstore(X_N_MPTR, x_n) + mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) + mstore(L_LAST_MPTR, l_last) + mstore(L_BLIND_MPTR, l_blind) + mstore(L_0_MPTR, l_0) + mstore(INSTANCE_EVAL_MPTR, instance_eval) + } + + // Compute quotient evavluation + { + let quotient_eval_numer + let delta := 4131629893567559867359510883348571134090853742863529169391034518566172092834 + let y := mload(Y_MPTR) + + {%- for code_block in quotient_eval_numer_computations %} + { + {%- for line in code_block %} + {{ line }} + {%- endfor %} + } + {%- endfor %} + + pop(y) + pop(delta) + + let quotient_eval := mulmod(quotient_eval_numer, mload(X_N_MINUS_1_INV_MPTR), r) + mstore(QUOTIENT_EVAL_MPTR, quotient_eval) + } + + // Compute quotient commitment + { + mstore(0x00, calldataload(LAST_QUOTIENT_X_CPTR)) + mstore(0x20, calldataload(add(LAST_QUOTIENT_X_CPTR, 0x20))) + let x_n := mload(X_N_MPTR) + for + { + let cptr := sub(LAST_QUOTIENT_X_CPTR, 0x40) + let cptr_end := sub(FIRST_QUOTIENT_X_CPTR, 0x40) + } + lt(cptr_end, cptr) + {} + { + success := ec_mul_acc(success, x_n) + success := ec_add_acc(success, calldataload(cptr), calldataload(add(cptr, 0x20))) + cptr := sub(cptr, 0x40) + } + mstore(QUOTIENT_X_MPTR, mload(0x00)) + mstore(QUOTIENT_Y_MPTR, mload(0x20)) + } + + // Compute pairing lhs and rhs + { + {%- for code_block in pcs_computations %} + { + {%- for line in code_block %} + {{ line }} + {%- endfor %} + } + {%- endfor %} + } + + // Random linear combine with accumulator + if mload(HAS_ACCUMULATOR_MPTR) { + mstore(0x00, mload(ACC_LHS_X_MPTR)) + mstore(0x20, mload(ACC_LHS_Y_MPTR)) + mstore(0x40, mload(ACC_RHS_X_MPTR)) + mstore(0x60, mload(ACC_RHS_Y_MPTR)) + mstore(0x80, mload(PAIRING_LHS_X_MPTR)) + mstore(0xa0, mload(PAIRING_LHS_Y_MPTR)) + mstore(0xc0, mload(PAIRING_RHS_X_MPTR)) + mstore(0xe0, mload(PAIRING_RHS_Y_MPTR)) + let challenge := mod(keccak256(0x00, 0x100), r) + + // [pairing_lhs] += challenge * [acc_lhs] + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_LHS_X_MPTR), mload(PAIRING_LHS_Y_MPTR)) + mstore(PAIRING_LHS_X_MPTR, mload(0x00)) + mstore(PAIRING_LHS_Y_MPTR, mload(0x20)) + + // [pairing_rhs] += challenge * [acc_rhs] + mstore(0x00, mload(ACC_RHS_X_MPTR)) + mstore(0x20, mload(ACC_RHS_Y_MPTR)) + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_RHS_X_MPTR), mload(PAIRING_RHS_Y_MPTR)) + mstore(PAIRING_RHS_X_MPTR, mload(0x00)) + mstore(PAIRING_RHS_Y_MPTR, mload(0x20)) + } + + // Perform pairing + success := ec_pairing( + success, + mload(PAIRING_LHS_X_MPTR), + mload(PAIRING_LHS_Y_MPTR), + mload(PAIRING_RHS_X_MPTR), + mload(PAIRING_RHS_Y_MPTR) + ) + + // Revert if anything fails + if iszero(success) { + revert(0x00, 0x00) + } + + // Return 1 as result if everything succeeds + mstore(0x00, 1) + return(0x00, 0x20) + } + } +} diff --git a/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2VerifyingKey.sol b/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2VerifyingKey.sol new file mode 100644 index 0000000..c9edfce --- /dev/null +++ b/tools/polyexen/circuit/halo2-solidity-verifier/templates/Halo2VerifyingKey.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract Halo2VerifyingKey { + constructor() { + assembly { + {%- for (name, chunk) in constants %} + mstore({{ (32 * loop.index0)|hex_padded(4) }}, {{ chunk|hex_padded(64) }}) // {{ name }} + {%- endfor %} + {%- for (x, y) in fixed_comms %} + {%- let offset = constants.len() %} + mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x + mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- for (x, y) in permutation_comms %} + {%- let offset = constants.len() + 2 * fixed_comms.len() %} + mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x + mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y + {%- endfor %} + + return(0, {{ (32 * (constants.len() + 2 * fixed_comms.len() + 2 * permutation_comms.len()))|hex() }}) + } + } +} diff --git a/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/bug.md b/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 0000000..c4fc05c --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,21 @@ +--- +name: BUG +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + + +**To Reproduce** +Steps to reproduce the behavior: + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/feature_request.md b/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/tools/polyexen/circuit/solvency/.github/scripts/wakeup.sh b/tools/polyexen/circuit/solvency/.github/scripts/wakeup.sh new file mode 100755 index 0000000..e830227 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/scripts/wakeup.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +runner="i-0e04845bff4576909" + +while true; do + runner_status=$(aws ec2 describe-instances --instance-ids $runner --query "Reservations[*].Instances[*].State.[Name]" --output text) + if [ $runner_status = "stopped" ]; then + aws ec2 start-instances --instance-ids $runner + break + elif [ $runner_status = "running" ]; then + break + else + sleep 5 + fi +done + +exit 0 diff --git a/tools/polyexen/circuit/solvency/.github/workflows/benchmark.yml b/tools/polyexen/circuit/solvency/.github/workflows/benchmark.yml new file mode 100644 index 0000000..8599060 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/workflows/benchmark.yml @@ -0,0 +1,51 @@ +name: Benchmark + +on: + workflow_dispatch: + inputs: + run_benchmark: + description: 'Run benchmark tests (yes/no)' + required: true + default: 'no' + +env: + CARGO_TERM_COLOR: always + +jobs: + wakeup: + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.run_benchmark == 'yes' }} + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v3 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::490752553772:role/summa-solvency-ec2-slc + role-duration-seconds: 900 + aws-region: us-west-2 + + - name: Wakeup runner + run: .github/scripts/wakeup.sh + + benchmark: + runs-on: [summa-solvency-runner] + needs: [wakeup] + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.run_benchmark == 'yes' }} + steps: + - uses: actions/checkout@v3 + + - name: Run Benchmark + run: | + cd zk_prover + cargo bench + + - name: Upload Benchmark Results + uses: actions/upload-artifact@v2 + with: + name: benchmark-results + path: zk_prover/target/criterion diff --git a/tools/polyexen/circuit/solvency/.github/workflows/contracts.yml b/tools/polyexen/circuit/solvency/.github/workflows/contracts.yml new file mode 100644 index 0000000..73cfe19 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/workflows/contracts.yml @@ -0,0 +1,23 @@ +name: Contracts + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Install packages + uses: actions/setup-node@v3 + - run: | + cd contracts + npm ci + - name: Run Tests + run: | + cd contracts + npx hardhat node & npx hardhat test diff --git a/tools/polyexen/circuit/solvency/.github/workflows/rust.yml b/tools/polyexen/circuit/solvency/.github/workflows/rust.yml new file mode 100644 index 0000000..16e92c7 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.github/workflows/rust.yml @@ -0,0 +1,74 @@ +name: Rust + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + wakeup: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v3 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::490752553772:role/summa-solvency-ec2-slc + role-duration-seconds: 900 + aws-region: us-west-2 + + - name: Wakeup runner + run: .github/scripts/wakeup.sh + + build: + runs-on: [summa-solvency-runner] + needs: [wakeup] + + steps: + - uses: actions/checkout@v3 + + - name: Set Environment + run: echo "PATH=/home/ubuntu/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$GITHUB_ENV" + + - name: Install solc + run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.20 && solc --version + + - name: Test Zk Prover + run: | + cd zk_prover + cargo test --release --features dev-graph -- --nocapture + + - name: Test Zk Prover examples + run: | + cd zk_prover + cargo run --release --example gen_inclusion_verifier + cargo run --release --example gen_commitment + cargo run --release --example gen_inclusion_proof + cargo run --release --example nova_incremental_verifier + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Test backend + run: | + cd backend + cargo test --release -- --nocapture + + - name: Test backend example + run: | + cd backend + cargo run --release --example summa_solvency_flow + diff --git a/tools/polyexen/circuit/solvency/.vscode/settings.json b/tools/polyexen/circuit/solvency/.vscode/settings.json new file mode 100644 index 0000000..dffd4e7 --- /dev/null +++ b/tools/polyexen/circuit/solvency/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file" + }, +} diff --git a/tools/polyexen/circuit/solvency/LICENSE-APACHE b/tools/polyexen/circuit/solvency/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/tools/polyexen/circuit/solvency/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/tools/polyexen/circuit/solvency/LICENSE-MIT b/tools/polyexen/circuit/solvency/LICENSE-MIT new file mode 100644 index 0000000..20fb473 --- /dev/null +++ b/tools/polyexen/circuit/solvency/LICENSE-MIT @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2020-2022 The Electric Coin Company +Copyright (c) 2022 The Halo 2 developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/README.md b/tools/polyexen/circuit/solvency/README.md new file mode 100644 index 0000000..a538529 --- /dev/null +++ b/tools/polyexen/circuit/solvency/README.md @@ -0,0 +1,17 @@ +# Summa Solvency + +A monorepo for Summa, zk proof of solvency protocol + +### Subdirectories + +- `zk_prover`: Halo2 based zk prover for Summa +- `contracts`: Solidity smart contracts for Summa +- `backend` : Rust API to interact with Summa + +## License + +Licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](./LICENSE-MIT) or http://opensource.org/licenses/MIT) +at your option. diff --git a/tools/polyexen/circuit/solvency/backend/.gitignore b/tools/polyexen/circuit/solvency/backend/.gitignore new file mode 100644 index 0000000..5e48149 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/.gitignore @@ -0,0 +1,5 @@ +# Generated by Cargo +# will have compiled files and executables +/target +.env +*_proof.json diff --git a/tools/polyexen/circuit/solvency/backend/Cargo.lock b/tools/polyexen/circuit/solvency/backend/Cargo.lock new file mode 100644 index 0000000..fe65b93 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/Cargo.lock @@ -0,0 +1,4429 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "colored", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a0fc7dcf8bd4ead96b1d36b41df47c14beedf7b0301fc543d8f2384e66a2ec0" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.32", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c268a96e01a4c47c8c5c2472aaa570707e006a875ea63e819f75474ceedaf7b4" +dependencies = [ + "nom", +] + +[[package]] +name = "async-trait" +version = "0.1.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778" +dependencies = [ + "serde", +] + +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + +[[package]] +name = "bellperson" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93eaee4b4753554139ae52ecf0e8b8c128cbc561b32e1bfaa32f70cba8518c1f" +dependencies = [ + "bincode", + "blake2s_simd 1.0.1", + "blstrs", + "byteorder", + "crossbeam-channel", + "digest 0.10.7", + "ec-gpu", + "ec-gpu-gen", + "ff", + "group", + "log", + "memmap2", + "pairing", + "rand 0.8.5", + "rand_core 0.6.4", + "rayon", + "rustversion", + "serde", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium 0.7.0", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +dependencies = [ + "sha2 0.9.9", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] + +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +dependencies = [ + "android-tzdata", + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "coins-bip32" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30a84aab436fcb256a2ab3c80663d8aec686e6bae12827bb05fef3e1e439c9f" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.10.7", + "getrandom", + "hmac", + "k256", + "lazy_static", + "serde", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f4d04ee18e58356accd644896aeb2094ddeafb6a713e056cef0c0a8e468c15" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b949a1c63fb7eb591eb7ba438746326aedf0ae843e51ec92ba6bec5bb382c4f" +dependencies = [ + "base64 0.21.2", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.7", + "sha3 0.10.8", + "thiserror", +] + +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys", +] + +[[package]] +name = "const-oid" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ec-gpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45" + +[[package]] +name = "ec-gpu-gen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "892df2aa20abec5b816e15d5d6383892ca142077708efa3067dd3ac44b75c664" +dependencies = [ + "bitvec 1.0.1", + "crossbeam-channel", + "ec-gpu", + "execute", + "ff", + "group", + "hex", + "log", + "num_cpus", + "once_cell", + "rayon", + "sha2 0.10.7", + "thiserror", + "yastl", +] + +[[package]] +name = "ecdsa" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116" +dependencies = [ + "base64 0.13.1", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3 0.10.8", + "zeroize", +] + +[[package]] +name = "enumn" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9838a970f5de399d3070ae1739e131986b2f5dcc223c7423ca0927e3a878522" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.7", + "sha3 0.10.8", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a58ce802c65cf3d0756dee5a61094a92cde53c1583b246e9ee5b37226c7fc15" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b856b7b8ff5c961093cb8efe151fbcce724b451941ce20781de11a531ccd578" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e066a0d9cfc70c454672bf16bb433b0243427420076dc5b2f49c448fb5a10628" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c113e3e86b6bc16d98484b2c3bb2d01d6fed9f489fe2e592e5cc87c3024d616b" +dependencies = [ + "Inflector", + "dunce", + "ethers-core", + "eyre", + "hex", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.32", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3fb5adee25701c79ec58fcf2c63594cd8829bc9ad6037ff862d5a111101ed2" +dependencies = [ + "Inflector", + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.32", +] + +[[package]] +name = "ethers-core" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da5fa198af0d3be20c19192df2bd9590b92ce09a8421e793bec8851270f1b05" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata", + "chrono", + "elliptic-curve", + "ethabi", + "generic-array", + "hex", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.32", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84ebb401ba97c6f5af278c2c9936c4546cad75dec464b439ae6df249906f4caa" +dependencies = [ + "ethers-core", + "ethers-solc", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740f4a773c19dd6d6a68c8c2e0996c096488d38997d524e21dc612c55da3bd24" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56b498fd2a6c019d023e43e83488cd1fb0721f299055975aa6bac8dbf1e95f2c" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.2", + "bytes", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "hex", + "http", + "instant", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c4b7e15f212fa7cc2e1251868320221d4ff77a3d48068e69f47ce1c491df2d" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81c89f121595cf8959e746045bb8b25a6a38d72588561e1a3b7992fc213f674" +dependencies = [ + "cfg-if", + "dunce", + "ethers-core", + "glob", + "hex", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "execute" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d9a9ea4c04632c16bc5c71a2fcc63d308481f7fc67eb1a1ce6315c44a426ae" +dependencies = [ + "execute-command-macro", + "execute-command-tokens", + "generic-array", +] + +[[package]] +name = "execute-command-macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc65a0cf735106743f4c38c9a3671c1e734b5c2c20d21a3c93c696daa3157" +dependencies = [ + "execute-command-macro-impl", +] + +[[package]] +name = "execute-command-macro-impl" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a9a55d1dab3b07854648d48e366f684aefe2ac78ae28cec3bf65e3cd53d9a3" +dependencies = [ + "execute-command-tokens", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "execute-command-tokens" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba569491c70ec8471e34aa7e9c0b9e82bb5d2464c0398442d17d3c4af814e5a" + +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec 1.0.1", + "byteorder", + "ff_derive", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff_ce" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a682c12d0cc98a32ab7540401a5ea1ed21d11571eea11d5829cd721f85ff0" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ff_derive_ce" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b" +dependencies = [ + "num-bigint 0.2.6", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halo2_gadgets" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "arrayvec 0.7.4", + "bitvec 1.0.1", + "ff", + "group", + "halo2_proofs", + "halo2curves", + "lazy_static", + "rand 0.8.5", + "subtle", + "uint", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves", + "maybe-rayon", + "rand_chacha", + "rand_core 0.6.4", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2_solidity_verifier" +version = "0.1.0" +source = "git+https://github.com/summa-dev/halo2-solidity-verifier#d33972567f83f3218257b286b541ad97ba32928c" +dependencies = [ + "askama", + "blake2b_simd", + "halo2_proofs", + "hex", + "itertools 0.11.0", + "revm", + "ruint", + "sha3 0.10.8", +] + +[[package]] +name = "halo2curves" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint 0.4.3", + "num-traits", + "pasta_curves", + "paste", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "serde_arrays", + "static_assertions", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.11", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.7", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "neptune" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9a64337e6d214e2a48db5714ef18cf1e5a7bbff9043838fdf6e57ce5659335" +dependencies = [ + "bellperson", + "blake2s_simd 0.5.11", + "blstrs", + "byteorder", + "ff", + "generic-array", + "itertools 0.8.2", + "log", + "pasta_curves", + "serde", + "trait-set", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nova-scotia" +version = "0.5.0" +source = "git+https://github.com/nalinbhardwaj/Nova-Scotia#00085ece0e16c29a12f61866fa3588649620d7f7" +dependencies = [ + "anyhow", + "bellperson", + "byteorder", + "ff", + "hex-literal 0.3.4", + "itertools 0.9.0", + "js-sys", + "nova-snark", + "num-bigint 0.4.3", + "num-traits", + "pasta_curves", + "rayon", + "serde", + "serde_json", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-rayon", +] + +[[package]] +name = "nova-snark" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e12911ac9672ad436acfc992f09e26a5960513bbe81d1572005cadd8c1be8f4" +dependencies = [ + "bellperson", + "bincode", + "bitvec 1.0.1", + "byteorder", + "digest 0.10.7", + "ff", + "flate2", + "generic-array", + "getrandom", + "halo2curves", + "itertools 0.11.0", + "neptune", + "num-bigint 0.4.3", + "num-integer", + "num-traits", + "pasta-msm", + "pasta_curves", + "rand_chacha", + "rand_core 0.6.4", + "rayon", + "serde", + "sha3 0.10.8", + "subtle", + "thiserror", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint 0.4.3", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.3", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756d439303e94fae44f288ba881ad29670c65b0c4b0e05674ca81061bb65f2c5" +dependencies = [ + "arrayvec 0.7.4", + "bitvec 1.0.1", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d884d78fcf214d70b1e239fcd1c6e5e95aa3be1881918da2e488cc946c7a476" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pasta-msm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85d75eba3e7e9ee3bd11342b669185e194dadda3557934bc1000d9b87159d3" +dependencies = [ + "cc", + "pasta_curves", + "semolina", + "sppark", + "which", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "poseidon-rs" +version = "0.0.10" +source = "git+https://github.com/arnaucube/poseidon-rs#f4ba1f7c32905cd2ae5a71e7568564bb150a9862" +dependencies = [ + "ff_ce", + "rand 0.4.6", + "serde_json", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387" +dependencies = [ + "proc-macro2", + "syn 2.0.32", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-automata" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "revm" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f293f351c4c203d321744e54ed7eed3d2b6eef4c140228910dde3ac9a5ea8031" +dependencies = [ + "auto_impl", + "revm-interpreter", + "revm-precompile", +] + +[[package]] +name = "revm-interpreter" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53980a26f9b5a66d13511c35074d4b53631e157850a1d7cf1af4efc2c2b72c9" +dependencies = [ + "derive_more", + "enumn", + "revm-primitives", + "sha3 0.10.8", +] + +[[package]] +name = "revm-precompile" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41320af3bd6a65153d38eb1d3638ba89104cc9513c7feedb2d8510e8307dab29" +dependencies = [ + "k256", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2 0.10.7", + "sha3 0.10.8", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304d998f466ffef72d76c7f20b05bf08a96801736a6fb1fdef47d49a292618df" +dependencies = [ + "auto_impl", + "bitvec 1.0.1", + "bytes", + "derive_more", + "enumn", + "fixed-hash", + "hashbrown 0.13.2", + "hex", + "hex-literal 0.4.1", + "primitive-types", + "rlp", + "ruint", + "sha3 0.10.8", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ruint" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d470e29e933dac4101180fd6574971892315c414cf2961a192729089687cc9b" +dependencies = [ + "derive_more", + "primitive-types", + "rlp", + "ruint-macro", + "rustc_version", + "thiserror", +] + +[[package]] +name = "ruint-macro" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" + +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.7", +] + +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semolina" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0111fd4fa831becb0606b9a2285ef3bee3c6a70d690209b8ae9514e9befe23" +dependencies = [ + "cc", + "glob", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "serde_json" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "solang-parser" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a94494913728908efa7a25a2dd2e4f037e714897985c24273c40596638ed909" +dependencies = [ + "itertools 0.10.5", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spmc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a8428da277a8e3a15271d79943e80ccc2ef254e78813a166a08d65e4c3ece5" + +[[package]] +name = "sppark" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7a6d98937866ea8917015cd4a72d56d6e7feee8979dbccf83fc0c870053c46" +dependencies = [ + "cc", + "which", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "summa-backend" +version = "0.1.0" +dependencies = [ + "base64 0.13.1", + "csv", + "ethers", + "halo2_proofs", + "num-bigint 0.4.3", + "num-traits", + "reqwest", + "serde", + "serde_json", + "summa-solvency", + "tokio", +] + +[[package]] +name = "summa-solvency" +version = "0.1.0" +dependencies = [ + "ark-std", + "csv", + "ethers", + "ff_ce", + "halo2_gadgets", + "halo2_proofs", + "halo2_solidity_verifier", + "hex", + "itertools 0.11.0", + "nova-scotia", + "nova-snark", + "num-bigint 0.4.3", + "num-traits", + "num_cpus", + "poseidon-rs", + "rand 0.8.5", + "rayon", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +dependencies = [ + "autocfg", + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.37.23", + "windows-sys", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +dependencies = [ + "autocfg", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.32", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-rayon" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df87c67450805c305d3ae44a3ac537b0253d029153c25afc3ecd2edc36ccafb1" +dependencies = [ + "js-sys", + "rayon", + "spmc", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.11", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] diff --git a/tools/polyexen/circuit/solvency/backend/Cargo.toml b/tools/polyexen/circuit/solvency/backend/Cargo.toml new file mode 100644 index 0000000..34387e6 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "summa-backend" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +summa-solvency = { path = "../zk_prover" } +halo2_proofs = { git = "https://github.com/summa-dev/halo2"} +csv = "1.2.2" +num-bigint = "0.4.3" +serde = { version = "1.0.166", features = ["derive"] } +ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc", "legacy"] } +reqwest = { version = "0.11", features = ["json"] } +serde_json = "1.0.64" +tokio = { version = "1.7.1", features = ["full"] } +base64 = "0.13" +num-traits = "0.2.14" + +[build-dependencies] +ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc", "legacy"] } diff --git a/tools/polyexen/circuit/solvency/backend/README.md b/tools/polyexen/circuit/solvency/backend/README.md new file mode 100644 index 0000000..8a0e79c --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/README.md @@ -0,0 +1,152 @@ +# Backend + +This directory contains the backend implementation for the Summa Proof of Solvency protocol. + +## Core Components + +### Round + +The `Round` component represents a specific period or cycle in the Summa Proof of Solvency protocol. It encapsulates the state of the system at a given time, including the snapshot of assets and liabilities, as well as the associated proofs. +The `Round` struct integrates with the `Snapshot` and `SummaSigner` to facilitate the generation and submission of proofs to the contract. + +Key Features: + +- Initialization of a new round with specific parameters. +- Building a snapshot of the current state. +- Submitting commitment to the contract. +- Retrieving proofs of inclusion for specific users. + +### AddressOwnership + +The `AddressOwnership` component is responsible for managing and verifying the ownership of addresses. It ensures that addresses used in the protocol owned by the respective participants. This component interacts with the `SummaSigner` to submit proofs of address ownership to on-chain. + +Key Features: + +- Initialization with specific signer details. +- Dispatching proofs of address ownership to the contract. + +## Prerequisites + +The `ptau` file, containing the Powers of Tau trusted setup parameters needed to build the zk circuits, is already included. However, if you wish to test or run the code with a higher number of entries, you may choose to download a different `ptau` file. + +You can find the necessary files at https://github.com/han0110/halo2-kzg-srs. To download a specific file, you can use: + +``` +wget https://trusted-setup-halo2kzg.s3.eu-central-1.amazonaws.com/hermez-raw-11 +``` + +After downloading, pass the path to the desired file to the `Snapshot::new` method. If you are using the included `ptau` file, no additional steps are necessary. + +## Running Test + +To build the binary executable and test it + +``` +cargo build +cargo test --release -- --nocapture +``` + +## Important Notices + +### Generating and updating verifier contract for Backend + +The verifier contract in the backend were generated using a predefined set of parameters: `N_CURRENCIES = 2` and `N_BYTES=8`, as indicated [here](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_inclusion_verifier.rs#L21-L22). +If you intend to work with different parameters, you'll need to adjust these hard-coded values and then generate new verifier contract. + +The process described below assists in both generating the verifier and updating the Summa contract, which integrates the new verifier as constructors. + +#### Using the Bash Script + +We have provided a bash script to automate the process of updating the verifier contract and the Summa contract. To use the script: + +Ensure you have the necessary permissions to execute the script. + +``` +backend $ scripts/update_verifier_contract.sh +``` + +## Summa solvency flow example + +This example illustrates how Summa interacts with the Summa contract and the user side. + +To execute this example, use the command: + +``` +cargo run --release --example summa_solvency_flow +``` + +### 1. Submitting Address Ownership to the Summa Contract + +First, we submit proof of address ownership to the Summa contract. This is a critical step to register these proofs on-chain, facilitating the validation of asset ownership within Summa. + +Key points: + +- An instance of `AddressOwnership`, named `address_ownership_client`, is initialized with the `signatures.csv` file, which contains the signature data. + +- The `dispatch_proof_of_address_ownership` function sends a transaction to the Summa contract to register CEX-owned addresses. + +Note: This demonstration takes place in a test environment. In real-world production, always ensure that the Summa contract is correctly deployed on the target chain. + +If executed successfully, you'll see: + +``` +1. Ownership proofs are submitted successfully! +``` + +### 2. Submit Commitment + +The CEX must submit a commitment to the Summa contract for each round. This commitment consists of a `timestamp`, the root hash of the Merkle Sum Tree (`mst_root`), and `balances`. + +Without publishing the commitment, users cannot verify their inclusion proof on the Summa contract. This is because the inclusion verifier function internally requires the `mst_root`, but users only know the `timestamp` associated with the round and the verifier functions does not requre `mst_root` directly. + +In here, we'll introduce you through the process of submitting a commitment using the `Round` to the Summa contract. +The Round serves as the core of the backend in Summa, and we have briefly described it in the Components section. + +To initialize the `Round` instance, you'll need paths to the liabilities CSV file (`entry_16.csv`) and the `ptau/hermez-raw-11` file. The files serve the following purpose: + +- `entry_16.csv`: contains the username and liabilities entries for each CEX user (necessary to build the commitment). Liabilities column names have the following format: `balance__`, where and are the names of the cryptocurrencies and their corresponding blockchains. values are the same as in the Address Ownership Proof step; +- `ptau/hermez-raw-11`: contains parameters for constructing the zk circuits. + +Using the `Round` instance, the solvency proof is dispatched to the Summa contract with the `dispatch_solvency_proof` method. + +If this step successfully ran, you can see this message: + +``` +2. Solvency proof is submitted successfully! +``` + +### 3. Generating and Exporting Inclusion Proofs + +Assuming you're a CEX, after committing the `solvency` and `ownership` proofs to the Summa contract, you should generate inclusion proofs for every user. This proof verifies the presence of specific elements in the Merkle sum tree, which is part of the solvency proof. + +After generating the inclusion proof, it's transformed into a JSON format for easy sharing. + +Upon successful execution, you'll find a file named `user_0_proof.json` and see the following message: + +``` +3. Exported proof to user #0, as `user_0_proof.json` +``` + +### 4. Verify Proof of Inclusion + +This is the final step in the Summa process and the only part that occurs on the user side. + +Users receive the proof for a specific round and use methods available on the deployed Summa contract. Importantly, the Summa contract verifier function is a view function, meaning it doesn't consume gas or change the blockchain's state. + +In this step, the user has to: + +- Ensure the `leaf_hash` (public input of the proof) aligns with the Poseidon hash of the `username` and `balances` provided by the CEX. +- Submit the proof to the `verify_inclusion_proof` method on the Summa contract Which will: + - Retrieve the `mstRoot` from the Summa contract and match it with the `root_hash` in the proof. + - Retrieve the `rootBalances` from the Summa contract and match it with the `root_balances` in the proof + - Verify the zk Proof + +The result will display as: + +``` +4. Verifying the proof on contract verifier for User #0: true +``` + +**Note:** In a production environment, users can independently verify their proof using public interfaces, such as Etherscan, as shown below: +![Summa contract interface on Etherscan](summa_verifier_interface.png) +This offers an added layer of transparency and trust. diff --git a/tools/polyexen/circuit/solvency/backend/build.rs b/tools/polyexen/circuit/solvency/backend/build.rs new file mode 100644 index 0000000..0cc6e4a --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/build.rs @@ -0,0 +1,76 @@ +use ethers::prelude::Abigen; +use std::{fs::OpenOptions, io::Write, path::PathBuf}; + +fn main() { + let contracts = [ + ( + "src/contracts/generated/summa_contract.rs", + "Summa", + "Summa", + ), + ( + "src/contracts/generated/inclusion_verifier.rs", + "InclusionVerifier", + "InclusionVerifier", + ), + ]; + + let mut submodule_names = Vec::new(); + for (out_path, contract_name, abi_source) in contracts.iter() { + if let Some(submodule_name) = + generate_rust_contract_interface(out_path, contract_name, abi_source) + { + submodule_names.push(submodule_name); + } + } + + let mod_out_file: PathBuf = std::env::current_dir() + .unwrap() + .join("src/contracts/generated/mod.rs"); + if mod_out_file.exists() { + std::fs::remove_file(&mod_out_file).unwrap(); + } + + let mut mod_file = OpenOptions::new() + .write(true) + .create(true) + .open(mod_out_file) + .unwrap(); + + let final_content = submodule_names + .iter() + .map(|name| format!("pub mod {};", name)) + .collect::>() + .join("\n"); + + mod_file.write_all(final_content.as_bytes()).unwrap(); +} + +fn generate_rust_contract_interface<'a>( + out_path: &'a str, + contract_name: &str, + abi_source: &str, +) -> Option<&'a str> { + let contract_out_file = std::env::current_dir().unwrap().join(out_path); + if contract_out_file.exists() { + std::fs::remove_file(&contract_out_file).unwrap(); + } + + Abigen::new( + contract_name, + format!("./src/contracts/abi/{}.json", abi_source), + ) + .unwrap() + .format(true) + .generate() + .unwrap() + .write_to_file(contract_out_file) + .unwrap(); + + let submodule_name = out_path + .rsplit('/') // Split the string from the right at each / + .next() // Take the substring right after the last / + .and_then(|s| s.split('.').next()); // Take the substring before the first . (from the right) + + submodule_name +} diff --git a/tools/polyexen/circuit/solvency/backend/examples/summa_solvency_flow.rs b/tools/polyexen/circuit/solvency/backend/examples/summa_solvency_flow.rs new file mode 100644 index 0000000..bff04b8 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/examples/summa_solvency_flow.rs @@ -0,0 +1,135 @@ +#![feature(generic_const_exprs)] +use std::{error::Error, fs::File, io::BufReader, io::Write}; + +use ethers::types::U256; +use serde_json::{from_reader, to_string_pretty}; + +use summa_backend::{ + apis::{ + address_ownership::AddressOwnership, + leaf_hash_from_inputs, + round::{MstInclusionProof, Round}, + }, + contracts::signer::{AddressInput, SummaSigner}, + tests::initialize_test_env, +}; +use summa_solvency::merkle_sum_tree::MerkleSumTree; + +const N_CURRENCIES: usize = 2; +const USER_INDEX: usize = 0; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Initialize test environment without `address_ownership` instance from `initialize_test_env` function. + let (anvil, _, _, _, summa_contract) = initialize_test_env(None).await; + + // 1. Submit ownership proof + // + // The signer instance would be shared with `address_ownership` and `round` instances + // + // Using `AddressInput::Address`` to directly provide the summa_contract's address. + // + // If the address of a deployed contract is stored in a configuration file, + // you can use `AddressInput::Path` to provide the path to that file. + // + // For example, if the contract address is in "backend/src/contracts/deployments.json" located + // you would use `AddressInput::Path` as follows:`AddressInput::Path("backend/src/contracts/deployments.json".to_string())`. + // + let signer = SummaSigner::new( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + anvil.endpoint().as_str(), + AddressInput::Address(summa_contract.address()), + ) + .await?; + + // Each CEX prepares its own `signature` CSV file. + let signature_csv_path = "../csv/signatures.csv"; + let mut address_ownership_client = AddressOwnership::new(&signer, signature_csv_path).unwrap(); + + // Dispatch the proof of address ownership. + // the `dispatch_proof_of_address_ownership` function sends a transaction to the Summa contract. + address_ownership_client + .dispatch_proof_of_address_ownership() + .await?; + + println!("1. Ownership proofs are submitted successfully!"); + + // 2. Submit Commitment + // + // Initialize the `Round` instance to submit the liability commitment. + let params_path = "ptau/hermez-raw-11"; + let entry_csv = "../csv/entry_16.csv"; + let mst = MerkleSumTree::from_csv(entry_csv).unwrap(); + + // Using the `round` instance, the commitment is dispatched to the Summa contract with the `dispatch_commitment` method. + let timestamp = 1u64; + let mut round = Round::<4, 2, 8>::new(&signer, Box::new(mst), params_path, timestamp).unwrap(); + + // Sends the commitment, which should ideally complete without errors. + round.dispatch_commitment().await?; + + println!("2. Commitment is submitted successfully!"); + + // 3. Generate Inclusion Proof + // + // Generate and export the inclusion proof for the specified user to a JSON file. + let inclusion_proof = round.get_proof_of_inclusion(USER_INDEX).unwrap(); + + let filename = format!("user_{}_proof.json", USER_INDEX); + let mut file = File::create(filename.clone()).expect("Unable to create file"); + let output = to_string_pretty(&inclusion_proof).unwrap(); + file.write_all(output.as_bytes()) + .expect("Failed to write JSON to file"); + + println!( + "3. Exported proof to user #{}, as `{}`", + USER_INDEX, filename + ); + + // 4. Verify Inclusion Proof + // + // The `snapshot_time` denotes the specific moment when entries were created for the Merkle sum tree. + // This timestamp is established during the initialization of the Round instance. + let snapshot_time = U256::from(1); + + // When verifying the inclusion proof from the user's perspective, the user have to fetch `proof`. + // Assume that the `proof` file has been downloaded from the CEX. + let proof_file = File::open(format!("user_{}_proof.json", USER_INDEX))?; + let reader = BufReader::new(proof_file); + let downloaded_inclusion_proof: MstInclusionProof = from_reader(reader)?; + + let public_inputs = downloaded_inclusion_proof.get_public_inputs(); + + // Verify the `leaf_hash` from the proof file. + // It's assumed that both `user_name` and `balances` are provided by the CEX. + // The `balances` represent the user's balances on the CEX at `snapshot_time`. + let user_name = "dxGaEAii".to_string(); + let balances = vec!["11888".to_string(), "41163".to_string()]; + + let leaf_hash = public_inputs[0]; + assert_eq!( + leaf_hash, + leaf_hash_from_inputs::(user_name.clone(), balances.clone()) + ); + + // Get `mst_root` from contract. the `mst_root` is disptached by CEX with specific time `snapshot_time`. + let commitment = summa_contract.commitments(snapshot_time).call().await?; + + // Match the `mst_root` with the `root_hash` derived from the proof. + assert_eq!(commitment, public_inputs[1]); + + // Validate the inclusion proof using the contract verifier. + let proof = inclusion_proof.get_proof(); + let verification_result = summa_contract + .verify_inclusion_proof(proof.clone(), public_inputs.clone(), snapshot_time) + .await?; + + println!( + "4. Verifying the proof on contract veirifer for User #{}: {}", + USER_INDEX, verification_result + ); + + // Wrapping up + drop(anvil); + Ok(()) +} diff --git a/tools/polyexen/circuit/solvency/backend/ptau/hermez-raw-11 b/tools/polyexen/circuit/solvency/backend/ptau/hermez-raw-11 new file mode 100644 index 0000000..2205b72 Binary files /dev/null and b/tools/polyexen/circuit/solvency/backend/ptau/hermez-raw-11 differ diff --git a/tools/polyexen/circuit/solvency/backend/rust-toolchain b/tools/polyexen/circuit/solvency/backend/rust-toolchain new file mode 100644 index 0000000..4524b7c --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/rust-toolchain @@ -0,0 +1 @@ +nightly-2023-07-11 \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/backend/scripts/update_verifier_contract.sh b/tools/polyexen/circuit/solvency/backend/scripts/update_verifier_contract.sh new file mode 100755 index 0000000..ec0af6b --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/scripts/update_verifier_contract.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +# Build the verifier contracts +echo "1. Building verifier contracts" +cd ../zk_prover +cargo run --release --example gen_inclusion_verifier + +# Generate Commitment for Merkle Sum Tree +echo "2. Generate Commitment for Merkle Sum Tree" +cd ../zk_prover +cargo run --release --example gen_commitment + +# Deploy contracts to local environment +echo "3. Deploying contracts to local environment" +cd ../contracts +npm install +npx hardhat node & +HARDHAT_PID=$! +sleep 5 +npx hardhat run scripts/deploy.ts --network localhost + +# Generate interface files for Backend +echo "4. Generating interface files for Backend" +cd ../backend +cargo build + +# Wrap up +echo "Terminate hardhat node" +kill $HARDHAT_PID diff --git a/tools/polyexen/circuit/solvency/backend/src/apis/address_ownership.rs b/tools/polyexen/circuit/solvency/backend/src/apis/address_ownership.rs new file mode 100644 index 0000000..42a405d --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/apis/address_ownership.rs @@ -0,0 +1,38 @@ +use crate::contracts::{generated::summa_contract::AddressOwnershipProof, signer::SummaSigner}; +use std::{error::Error, result::Result}; + +use super::csv_parser::parse_signature_csv; + +pub struct AddressOwnership<'a> { + address_ownership_proofs: Vec, + signer: &'a SummaSigner, +} + +impl AddressOwnership<'_> { + pub fn new<'a>( + signer: &'a SummaSigner, + signature_csv_path: &str, + ) -> Result, Box> { + let address_ownership_proofs = parse_signature_csv(signature_csv_path)?; + + Ok(AddressOwnership { + address_ownership_proofs, + signer, + }) + } + + pub fn get_ownership_proofs(&self) -> &Vec { + &self.address_ownership_proofs + } + + // This function dispatches the proof of address ownership. Before calling this function, + // ensure externally that the provided `addresses` in `address_ownership_proof` are not already registered + // on the Summa contract. + pub async fn dispatch_proof_of_address_ownership(&mut self) -> Result<(), Box> { + self.signer + .submit_proof_of_address_ownership(self.address_ownership_proofs.clone()) + .await?; + + Ok(()) + } +} diff --git a/tools/polyexen/circuit/solvency/backend/src/apis/csv_parser.rs b/tools/polyexen/circuit/solvency/backend/src/apis/csv_parser.rs new file mode 100644 index 0000000..672fd14 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/apis/csv_parser.rs @@ -0,0 +1,68 @@ +use std::{error::Error, fs::File, path::Path}; + +use ethers::{abi::AbiEncode, types::Bytes}; +use serde::{Deserialize, Serialize}; + +use crate::contracts::generated::summa_contract::AddressOwnershipProof; + +#[derive(Debug, Deserialize, Serialize)] +pub struct SignatureRecord { + chain: String, + address: String, + signature: String, + message: String, +} + +impl SignatureRecord { + pub fn new(chain: String, address: String, signature: String, message: String) -> Self { + Self { + chain, + address, + signature, + message, + } + } +} + +pub fn parse_signature_csv>( + path: P, +) -> Result, Box> { + let file = File::open(path)?; + let mut rdr = csv::ReaderBuilder::new().delimiter(b';').from_reader(file); + + let mut address_ownership_proofs = Vec::::new(); + + for result in rdr.deserialize() { + let record: SignatureRecord = result?; + + address_ownership_proofs.push(AddressOwnershipProof { + cex_address: record.address.to_string(), + chain: record.chain.to_string(), + signature: record.signature.parse()?, + message: Bytes::from(record.message.encode()), + }); + } + + Ok(address_ownership_proofs) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_csv_to_signature() { + let path = "../csv/signatures.csv"; + let address_ownership = parse_signature_csv(path).unwrap(); + + let first_address_ownership = AddressOwnershipProof { + chain: "ETH".to_string(), + cex_address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8".to_string(), + signature: + ("0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b").parse().unwrap(), + message: "Summa proof of solvency for CryptoExchange".encode().into(), + }; + + assert_eq!(address_ownership[0], first_address_ownership); + } +} diff --git a/tools/polyexen/circuit/solvency/backend/src/apis/mod.rs b/tools/polyexen/circuit/solvency/backend/src/apis/mod.rs new file mode 100644 index 0000000..8cdc087 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/apis/mod.rs @@ -0,0 +1,28 @@ +pub mod address_ownership; +pub mod csv_parser; +pub mod round; + +use ethers::types::U256; +use num_bigint::BigUint; +use num_traits::Num; +use summa_solvency::merkle_sum_tree::Entry; + +pub fn leaf_hash_from_inputs( + username: String, + balances: Vec, +) -> U256 +where + [usize; N_CURRENCIES + 1]: Sized, +{ + // Convert balances to BigUint + let balances: Vec = balances + .iter() + .map(|balance| BigUint::from_str_radix(balance, 10).unwrap()) + .collect(); + + let entry: Entry = Entry::new(username, balances.try_into().unwrap()).unwrap(); + + // Convert Fp to U256 + let hash_str = format!("{:?}", entry.compute_leaf().hash); + U256::from_str_radix(&hash_str, 16).unwrap() +} diff --git a/tools/polyexen/circuit/solvency/backend/src/apis/round.rs b/tools/polyexen/circuit/solvency/backend/src/apis/round.rs new file mode 100644 index 0000000..865006a --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/apis/round.rs @@ -0,0 +1,175 @@ +use ethers::types::{Bytes, U256}; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + plonk::{ProvingKey, VerifyingKey}, + poly::kzg::commitment::ParamsKZG, +}; +use serde::{Deserialize, Serialize}; +use std::error::Error; + +use crate::contracts::{generated::summa_contract::summa::Cryptocurrency, signer::SummaSigner}; +use summa_solvency::{ + circuits::{ + merkle_sum_tree::MstInclusionCircuit, + utils::{gen_proof_solidity_calldata, generate_setup_artifacts}, + }, + merkle_sum_tree::Tree, +}; + +pub(crate) type SetupArtifacts = ( + ParamsKZG, + ProvingKey, + VerifyingKey, +); + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MstInclusionProof { + public_inputs: Vec, + proof_calldata: Bytes, +} + +impl MstInclusionProof { + pub fn get_public_inputs(&self) -> &Vec { + &self.public_inputs + } + + pub fn get_proof(&self) -> &Bytes { + &self.proof_calldata + } +} + +pub struct Snapshot { + pub mst: Box>, + trusted_setup: SetupArtifacts, +} + +pub struct Round<'a, const LEVELS: usize, const N_CURRENCIES: usize, const N_BYTES: usize> { + timestamp: u64, + snapshot: Snapshot, + signer: &'a SummaSigner, +} + +impl + Round<'_, LEVELS, N_CURRENCIES, N_BYTES> +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub fn new<'a>( + signer: &'a SummaSigner, + mst: Box>, + params_path: &str, + timestamp: u64, + ) -> Result, Box> + where + [(); N_CURRENCIES + 2]: Sized, + { + Ok(Round { + timestamp, + snapshot: Snapshot::::new(mst, params_path).unwrap(), + signer: &signer, + }) + } + + pub fn get_timestamp(&self) -> u64 { + self.timestamp + } + + pub async fn dispatch_commitment(&mut self) -> Result<(), Box> { + let root_str = format!("{:?}", self.snapshot.mst.root().hash); + let mst_root = U256::from_str_radix(&root_str, 16).unwrap(); + + let mut root_sums = Vec::::new(); + + for balance in self.snapshot.mst.root().balances.iter() { + let fp_str = format!("{:?}", balance); + root_sums.push(U256::from_str_radix(&fp_str, 16).unwrap()); + } + + self.signer + .submit_commitment( + mst_root, + root_sums, + self.snapshot + .mst + .cryptocurrencies() + .iter() + .map(|cryptocurrency| Cryptocurrency { + name: cryptocurrency.name.clone(), + chain: cryptocurrency.chain.clone(), + }) + .collect::>() + .as_slice() + .try_into() + .unwrap(), + U256::from(self.get_timestamp()), + ) + .await?; + + Ok(()) + } + + pub fn get_proof_of_inclusion( + &self, + user_index: usize, + ) -> Result + where + [(); N_CURRENCIES + 2]: Sized, + { + Ok(self + .snapshot + .generate_proof_of_inclusion(user_index) + .unwrap()) + } +} + +impl + Snapshot +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub fn new( + mst: Box>, + params_path: &str, + ) -> Result, Box> { + let mst_inclusion_circuit = + MstInclusionCircuit::::init_empty(); + + // get k from ptau file name + let parts: Vec<&str> = params_path.split("-").collect(); + let last_part = parts.last().unwrap(); + let k = last_part.parse::().unwrap(); + + let mst_inclusion_setup_artifacts: SetupArtifacts = + generate_setup_artifacts(k, Some(params_path), mst_inclusion_circuit).unwrap(); + + Ok(Snapshot { + mst, + trusted_setup: mst_inclusion_setup_artifacts, + }) + } + + pub fn generate_proof_of_inclusion( + &self, + user_index: usize, + ) -> Result + where + [(); N_CURRENCIES + 2]: Sized, + { + let merkle_proof = self.mst.generate_proof(user_index).unwrap(); + let circuit = MstInclusionCircuit::::init(merkle_proof); + + // Currently, default manner of generating a inclusion proof for solidity-verifier. + let calldata = gen_proof_solidity_calldata( + &self.trusted_setup.0, + &self.trusted_setup.1, + circuit.clone(), + ); + + Ok(MstInclusionProof { + proof_calldata: calldata.0, + public_inputs: calldata.1, + }) + } +} diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/abi/InclusionVerifier.json b/tools/polyexen/circuit/solvency/backend/src/contracts/abi/InclusionVerifier.json new file mode 100644 index 0000000..9e0b150 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/abi/InclusionVerifier.json @@ -0,0 +1 @@ +{"_format":"hh-sol-artifact-1","contractName":"Verifier","sourceName":"src/InclusionVerifier.sol","abi":[{"inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint256[]","name":"instances","type":"uint256[]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"bytecode":"0x6080806040523461001657614b95908161001c8239f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c631e8e1e131461002857600080fd5b346100a05760403660031901126100a05767ffffffffffffffff6004358181116100a357366023820112156100a35780600401358281116100ab57369101602401116100a7576024358181116100a357366023820112156100a35780600401359182116100a357602490369260051b010111156104b5575b80fd5b8280fd5b5080fd5b8380fd5b9290604080918035956020820135907f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780600381808c80098c0908818480091491818410918a10161616968652602086015201920190565b602091600020600080516020614ac0833981519152810682526000520190602090565b602090600182536021600020600080516020614ac0833981519152810682526000520190565b91909182610f2091825190610f40925b601f19810184106102145750600080516020614ac0833981519152809284519009602087526020808801526020604088015260608701527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808701528160a087015260208660c08160055afa1694805192601f19809201905b80610f40106101fa5750505080610f4051830991835190099152610f4052565b8280918580855189099782519009968152019101906101da565b959291600080516020614ac08339815191529083519009918284526020809101930195610160565b90610180916000516020915b61016083106102f957600080516020614ac0833981519152809284519009602086526020808701526020604087015260608601527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808601528160a086015260208560c08160055afa1693805192601f19809201905b806020106102df5750505080602051830991600051900990600052602052565b8280918580855189099782519009968152019101906102bf565b9391906020600080516020614ac08339815191528192845190099283855201920193610248565b9060a0916000516020915b608083106103db57600080516020614ac0833981519152809284519009602086526020808701526020604087015260608601527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808601528160a086015260208560c08160055afa1693805192601f19809201905b806020106103c15750505080602051830991600051900990600052602052565b8280918580855189099782519009968152019101906103a1565b9391906020600080516020614ac0833981519152819284519009928385520192019361032b565b91906040526060526040600060808160065afa1690565b906040526040600060608160075afa1690565b919060c05260e05260406080808060065afa1690565b9060c0526040608060608160075afa1690565b9392919060005260205261086051604052610880516060526108a0516080526108c05160a05260c05260e0526108e05161010052610900516101205261092051610140526109405161016052602060006101808160085afa166000511690565b60017f10f28bc710a8bdd00dd701df2f5fc4f5ccdb260238eba6f819db692f79dc3dc96106c052600b6106e0527f305e41e912d579f5b3193badcab128321c8ee1cb70aa396331b979553d820001610700527f14c60185e75885d674db4b3f7d4a5694fa6c01aa0f53557b060bc04a4172705f610720527f2afd4e77273f1cb3434a4a667929058c156b21573c3f1efc882e708597d7161a610740527f22b55603586d5fc42c6c14c2fc27a028c207da8b2c71cb33d549fa4a2be5d3026107605260046107805260006107a05260006107c05260006107e052600061080052600161082052600261084052610860907f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c282527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610880527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6108a0527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6108c0527f26186a2d65ee4d2f9c9a5b91f86597d35f192cd120caf7e935d8443d1938e23d6108e0527f30441fd1b5d3370482c42152a8899027716989a6996c2535bc9f7fee8aaef79e610900527f16f363f103c80d7bbc8ad3c6867e0822bbc6000be91a4689755c7df40221c145610920527f2b1cbb3e521edf5a622d82762a44a5e63f1e50b332d71154a4a7958d6011deff610940527f010920a3471867216dc9dd6b478c16842fb5aca434fe6c9bf1622c4abd70381a610960527f300e30930f1a05253b28b6b139f2c38025d99b7a54e641f1d6ff2797d113c118610980527f05e7899750f7abeae5d19c16666c47618fce810326b125d253dd41fb817dd65a6109a0527f1e0e399ce46f208ab3f43aad0222f4dd37b8327b9f7afffa9cf9ee214e2460dd6109c0527f22274e4efd4197dd6515994652d5beafcc7af94313d33e049cf5a1e464b523956109e0527f0ebb470e19409fcd84c0358c04300dc38cba0240141ddeb899ad9cca90167a64610a00527f162baf6245e2cec59bc93bc2302527d299cdb50e100f14895f170f316a2a2643610a20527f172a6f183e2ddc0607d23fd3daf4b23110b81d8a9d0a4e8d3d07ba24a007e04b610a40527f22e1cdbfffcfcf4f18cf4342edf1fb26c3b6e52ace3d5fadcf5cc2614333baa4610a60527f0e28df72dcc69cc6442d72f693661997480a913ac353890efd63a873959727c0610a80527f01021a51384124c6844f2ba0e40e2545f26f280a79745c9164b0a56f1ee54d56610aa0527f2533607ba6f153a0126a8450a3cf47946933c93eaf69c996236b45603179c914610ac0527f1f59be81b3fd7d290930430d204c1a866937862306d75be70fedfe13e565ce0b610ae0527f05931c531cd08b4aa937245293af81c4532fc4c01387d5b539d29f6c4ae00031610b00527f203b21a648fbfb96459640bbc5b41852dd1efc1209c89b635ba638dcb929da6b610b20527f04e7002f06f2091a44afcd311e93c22f46dd9f3207b5bcc34f0ca7652098f097610b40527f20ab7490b42f3f7b2b0bbe601a09d72ee93f924801d597f48cf2d443751d5f91610b60527f2bca2f1762946a05fb1632550c6cb12c02d18d9bee5bdd4212ca7342888720fd610b80527f2aaba546cdd9969ef0aecc85b2aaa19b6e9639879962661415c8f0df426bac0c610ba0527f12b15327bcfbe7d9e9de1bc648ba3bdf910087362179a0b403cf70bad1c093c8610bc0527f25909db723a8021ffe088c50525d6d260f9157be7a7c194b6f315386a46cdab8610be0527f25cbeae8ec2a8a2f74844f5e3276ed94079907bed6d7b1b26ed695328fe7bcae610c00527f26bffd26dd8f5f7679281f8d1a432690e07b15cbdf684fe456aa1277515e1730610c20527f015a3f09c82a770a69d67583d7049d83d69b7b8e03d38484497215cdc5979556610c40527f1ee4241e91ac391756b0b9893ac1e34ea95c6dd689e7dca12c62a6ce943960f1610c60527f10ad75f199bf1fb9335b91c20db6cd8958dcb2fe11983bc77cdb4036e57e59ca610c80527f05eb5d19e589c11e0bb2200d66da829955545481885cfbc9099ec6a53e266ed2610ca0527f25ac1d9849f9f448cecc7ead7d48670f66bbfe7df8e248bd818a954df6936c27610cc0527f0743ea40f14084db2673217283aa053f986896ee7c181f52118442e99c452974610ce0527f0203e3493a2594ece57d22cc75dd081ac68271ec7c758153cfd2152bfb5c19e3610d00527f1b95c5dc9bae0fb3f8208684042e57e0fcfbc3774af9ae0903ab9e9ddb4f89fd610d20527f1e8564e01419713739871224ce15f4c4b51e6af161d6e07a178e6545879035bf610d40527f1cefc889639cf98f94d831ea41c356929f9317778dda05ba0c5885401638db67610d60527f1e0466deb22a86d9122bc7180b7d293e47288244abf1450a5cd63a3289a457ca610d80526108c435600414916044351416167f10f28bc710a8bdd00dd701df2f5fc4f5ccdb260238eba6f819db692f79dc3dc96000526020906108e45b6109648110614a7957506064915b6101248310614a66576000908120600080516020614ac08339815191528106610da0529052610dc0916020608082015b808310614a4f5750610c4090610c4794610107565b939061012a565b926101008201935b848310614a3a5790610c6091610107565b610140830193915b848410614a295790610c7991610107565b929061046082015b808310614a005750610ca7610cb692610ca0610cbe96610cad94610107565b929061012a565b946100af565b90929193610107565b9290506100af565b5050806107a051614900575b508015614688576106e051610e20519081906000905b8082106148e25750506107205192610f2061078051926006840160051b80830194156148d6575b50610760515b8483106148b157505050610d5a600080516020614ac08339815191527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000008508918284526020840190610150565b93600080516020614ac0833981519152610f209261070051900991610760515b84821061488b5750505050610f4051610f60915b610fe0831061486b576000926108e4906107805160051b8201905b818310614843575050505191610f205191610fe0519085610f205284610f405283610f605280610f805281610fa05282610fc052610e00519283809281610de0519381610dc0519381610e2051600080516020614ac083398151915290870999818d600080516020614ac08339815191526108043581036107e43508600080516020614ac08339815191526108243581036107e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152908608600080516020614ac083398151915203600080516020614ac08339815191529060010890600080516020614ac083398151915291099d81600080516020614ac08339815191526108243581036107e43508600080516020614ac08339815191529085099d600080516020614ac08339815191528d61054435088b600080516020614ac08339815191526101006104243509600080516020614ac08339815191529081036103e43508600080516020614ac083398151915290610564350990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac0833981519152906107a43509600080516020614ac0833981519152038d6108243590600080516020614ac08339815191529108600080516020614ac08339815191528d6107e4350890600080516020614ac08339815191529109600080516020614ac0833981519152906107c4350990600080516020614ac08339815191529108600080516020614ac0833981519152848908600080516020614ac083398151915203600080516020614ac08339815191529060010890600080516020614ac083398151915291099c6107a435600080516020614ac083398151915281810391800990600080516020614ac08339815191529108600080516020614ac08339815191529085099b600080516020614ac08339815191526107a43581038809600080516020614ac08339815191529088089a600080516020614ac08339815191528a870883600080516020614ac0833981519152600080516020614b408339815191528709600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290840890600080516020614ac0833981519152910884600080516020614ac0833981519152600080516020614b408339815191528809600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610764350990600080516020614ac08339815191529109600080516020614ac083398151915203846106e435600080516020614ac0833981519152908609600080516020614ac083398151915290850890600080516020614ac0833981519152910885600080516020614ac08339815191526106c4358709600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610784350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac083398151915203908380600080516020614ac0833981519152600080516020614b408339815191528809600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290840890600080516020614ac0833981519152910881600080516020614ac0833981519152600080516020614b408339815191528909600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610764350990600080516020614ac08339815191529109600080516020614ac083398151915203916106e435600080516020614ac0833981519152908609600080516020614ac0833981519152910890600080516020614ac0833981519152910884600080516020614ac08339815191526106c4358609600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610784350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910898600080516020614ac083398151915290860882600080516020614ac0833981519152600080516020614b408339815191528609600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac0833981519152906104e4350890600080516020614ac0833981519152910883600080516020614ac0833981519152600080516020614b408339815191528709600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610404350890600080516020614ac0833981519152910884600080516020614ac0833981519152600080516020614b408339815191528809600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910885600080516020614ac0833981519152886104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610704350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ac083398151915203836106a435600080516020614ac0833981519152908509600080516020614ac0833981519152906104e4350890600080516020614ac0833981519152910884600080516020614ac0833981519152610684358609600080516020614ac083398151915290610404350890600080516020614ac0833981519152910885600080516020614ac0833981519152610664358709600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910886600080516020614ac0833981519152610644358809600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610724350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac0833981519152039282600080516020614ac0833981519152600080516020614b408339815191528309600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac0833981519152906104e4350890600080516020614ac083398151915291089083600080516020614ac0833981519152600080516020614b408339815191528309600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610404350890600080516020614ac08339815191529108908480600080516020614ac0833981519152600080516020614b408339815191528409600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910891600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610704350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ac08339815191520391806106a435600080516020614ac0833981519152908409600080516020614ac0833981519152906104e4350890600080516020614ac083398151915291089181600080516020614ac0833981519152610684358309600080516020614ac083398151915290610404350890600080516020614ac083398151915291089180600080516020614ac0833981519152610664358409600080516020614ac0833981519152906103e4350890600080516020614ac083398151915291089161064435600080516020614ac08339815191529109600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610724350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac083398151915291089381600080516020614ac08339815191526107443581036107643508600080516020614ac08339815191529083099361076435600080516020614ac083398151915281810391800990600080516020614ac08339815191529108600080516020614ac0833981519152910991600080516020614ac0833981519152610704358209600080516020614ac083398151915203600080516020614ac083398151915291088161046435600080516020614ac083398151915203610404356103e43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161046435600080516020614ac083398151915203610404356103e43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161044435600080516020614ac083398151915203610404356104643561040435600080516020614ac0833981519152036103e43590600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e435610464356103e435600080516020614ac0833981519152036104043590600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac083398151915261046435810360010861046435600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191526104443581036104843508600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e4356104a43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191527f16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be6104443509600080516020614ac08339815191527f0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104e435610524356104043590600080516020614ac08339815191529108600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614b00833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac083398151915290610604350981600080516020614ac08339815191527f1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe6104443509600080516020614ac08339815191527f13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104c435610524356104043590600080516020614ac08339815191529108600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac08339815191529061060435098161046435600080516020614ac083398151915203610504356103e43590600080516020614ac08339815191529108600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac08339815191529061060435098161044435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b00833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105e435098161042435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614aa0833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105e4350981600080516020614ac08339815191526104443581036104843508600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e4356104a43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191527f16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be6104443509600080516020614ac08339815191527f0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104e435610524356104043590600080516020614ac08339815191529108600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614b00833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105c4350981600080516020614ac08339815191527f1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe6104443509600080516020614ac08339815191527f13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104c435610524356104043590600080516020614ac08339815191529108600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac0833981519152906105c435098161046435600080516020614ac083398151915203610504356103e43590600080516020614ac08339815191529108600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac0833981519152906105c435098161044435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b00833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105a435098161042435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614aa0833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105a4350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109610fe0526103a4356000526103c435602052610364905b816102641061481b57826000516110005260205161102052600080516020614ac08339815191528080610e205181808061072051816107405180988188819997829896839709610420528061040052828282096103e0520909090909096103c052610e80516104406103c0905b6104c081106147f757836104605161048051906104a05180600080516020614ac083398151915284840990600080516020614ac083398151915291096104c0526104405191826104e0528260005281600080516020614ac083398151915282850990600080516020614ac08339815191529109610500528061052052600080516020614ac083398151915281840961054052600080516020614ac0833981519152828409610560526103e0519161040051938161042051918483600080516020614ac083398151915203600080516020614ac0833981519152908808600080516020614ac0833981519152898103890890600080516020614ac0833981519152910990600080516020614ac0833981519152910960205287600080516020614ac08339815191528481038908600080516020614ac08339815191528881038a0890600080516020614ac0833981519152910990600080516020614ac0833981519152910960405281600080516020614ac08339815191528881038508600080516020614ac0833981519152888103860890600080516020614ac0833981519152910990600080516020614ac08339815191529109606052600080516020614ac0833981519152886001096080526103c05190600080516020614ac08339815191528481038308600080516020614ac0833981519152898103840890600080516020614ac0833981519152910990600080516020614ac0833981519152910960a052600080516020614ac0833981519152038783600080516020614ac083398151915203600080516020614ac0833981519152908908600080516020614ac0833981519152838a0890600080516020614ac0833981519152910990600080516020614ac0833981519152910960c052600080516020614ac0833981519152878103840890600080516020614ac083398151915290840890600080516020614ac0833981519152910990600080516020614ac0833981519152910960e05285600080516020614ac0833981519152828103870890600080516020614ac083398151915291096101005284600080516020614ac083398151915203600080516020614ac0833981519152910890600080516020614ac0833981519152910961012052600080516020614ac0833981519152838103830890600080516020614ac0833981519152910961014052600080516020614ac083398151915203600080516020614ac0833981519152910890600080516020614ac0833981519152910961016052613fff9061023c565b600051806104e0526105005b61058081106147d957610e40516020516040516060518693600080516020614ac083398151915280610424358409818681868187818b81806103e43583099781808080806104a43586099a610444359009956104043590099261048435900960000808080908080861058052608051600080516020614ac083398151915280610fe05183098184818061062435870960000809086106e45b80610624106147b457506106045b806104a41061478f575061050051908380600080516020614ac083398151915261046435860992600080516020614ac083398151915261082435870991600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac083398151915291096105a05260a05160c05160e051926105205161072435600080516020614ac0833981519152908609600080516020614ac0833981519152610704358509600080516020614ac0833981519152610744358709600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096105c05261010051956101205195610540519061078435600080516020614ac083398151915290890990600080516020614ac0833981519152610764358b0990600080516020614ac08339815191526107c4358b09600080516020614ac08339815191526107a4358d09600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096105e05261014051986101605198610560516107e435600080516020614ac0833981519152908c09600080516020614ac0833981519152610804358e09600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910961060052600080516020614ac0833981519152910890600080516020614ac083398151915291086106205261064052600080516020614ac0833981519152910890600080516020614ac0833981519152910861066052600080516020614ac0833981519152910861068052600080516020614ac083398151915291086106a05261062060005b60a0811061477f576143c483610320565b600080516020614ac08339815191526106005160805109610e6051919060606105e05b60a08210614754578461444c61443d61442561441888886110405260a43560005260c435602052610e405190610419565b6084359060643590610402565b610264356080526102843560a052610e405190610442565b6110205190611000519061042c565b610d605b80610a201061472a5761467861461961453c6145f161453c6145c961453c89600080516020614ac0833981519152806145a861453c61459b61458c8f61456c61453c8761454961453c8c8361452f6145216144db6145126144db6145036144db6144f4889f6144e56144db6144cc6144db93610e405190610442565b6109c051906109a0519061042c565b610e405190610442565b6109805190610960519061042c565b610a405190610a20519061042c565b610a0051906109e0519061042c565b6101843590610164359061042c565b610104359060e4359061042c565b9161050051900990610442565b60a0519060805190610402565b9a610e60519009996101a4356080526101c43560a05283610520518c0990610442565b97610e6051900996610224356080526102443560a052610e405190610442565b61020435906101e4359061042c565b8361054051870990610442565b92610e60519009610124356080526101443560a05261056051900990610442565b610820516080526108405160a05261104051600080516020614ac08339815191520390610442565b610844356080526108643560a0526104c051600080516020614ac08339815191520390610442565b610884358060805261463a61453c6108a435938460a052610e805190610442565b906000519161106091838352602051611080948186526110a0968388526110c0938185526107a05161468d575b505050505193519251915190610455565b1561468857600160005260206000f35b600080fd5b9161470b9391614716959693610ea051600052610ec051602052610ee0938451604052610f0093845160605260805260a05260c05260e0526146f36146e8600080516020614ac0833981519152610100600020068095610419565b895190895190610402565b91600051885260205189525160005251602052610419565b825190865190610402565b906000518552602051815286808080614667565b9061473c61474a91610e405190610442565b60208301519083519061042c565b90603f1901614450565b9091600080516020614ac083398151915290818681855187510992090891601f1990810191016143e7565b81518152602091820191016143b3565b90600080516020614ac0833981519152908185818535870992090890601f19016140b1565b90600080516020614ac0833981519152908185818535870992090890601f19016140a3565b80600080516020614ac083398151915283602093510981520161400b565b60208091600080516020614ac0833981519152845181038608815201910190613c56565b909161482a8261483892610419565b602084013590843590610402565b91603f190190613be9565b9091946020600080516020614ac0833981519152819281893586510990089601929101610da9565b9190600080516020614ac083398151915260209183519008910191610d8e565b600080516020614ac0833981519152838282806020958751098809855209910190610d7a565b60209087600080516020614ac083398151915291828181038608865209920191610d0d565b610f4001935086610d07565b9092600080516020614ac08339815191528160019209930190610ce0565b90506107e0519061080051916107c05160051b806108e401918235926108e48260051b840101356108e48360061b85010135906108e460038560051b02860101359588965b846108e48760051b89010181101561499957906020808c93019384358b1b0194818960051b890101358b1b0195818960061b890101358b1b019660038960051b02010135891b019701969392919093614945565b50979450975093509350507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4790816003818087800987090882868009149180600381808a80098a09089084800914161693610ea052610ec052610ee052610f005281610cca565b9160208181923595600080516020614ac083398151915287101695875201940191939193610c81565b92614a33926100af565b9092610c68565b9291614a45926100af565b9192909190610c4f565b939291614a5b926100af565b929391929091610c2b565b9091614a71926100af565b919091610bfb565b9060208091600080516020614ac083398151915284351016928035855201920191610bed56fe066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad530644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c80cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff92b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e809226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2a2646970667358221220a0e58ae7dd3fb0f443e0d062395c088c727c1d4c080852f27a12ca461cdb486d64736f6c63430008120033","deployedBytecode":"0x6080604052600436101561001257600080fd5b6000803560e01c631e8e1e131461002857600080fd5b346100a05760403660031901126100a05767ffffffffffffffff6004358181116100a357366023820112156100a35780600401358281116100ab57369101602401116100a7576024358181116100a357366023820112156100a35780600401359182116100a357602490369260051b010111156104b5575b80fd5b8280fd5b5080fd5b8380fd5b9290604080918035956020820135907f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780600381808c80098c0908818480091491818410918a10161616968652602086015201920190565b602091600020600080516020614ac0833981519152810682526000520190602090565b602090600182536021600020600080516020614ac0833981519152810682526000520190565b91909182610f2091825190610f40925b601f19810184106102145750600080516020614ac0833981519152809284519009602087526020808801526020604088015260608701527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808701528160a087015260208660c08160055afa1694805192601f19809201905b80610f40106101fa5750505080610f4051830991835190099152610f4052565b8280918580855189099782519009968152019101906101da565b959291600080516020614ac08339815191529083519009918284526020809101930195610160565b90610180916000516020915b61016083106102f957600080516020614ac0833981519152809284519009602086526020808701526020604087015260608601527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808601528160a086015260208560c08160055afa1693805192601f19809201905b806020106102df5750505080602051830991600051900990600052602052565b8280918580855189099782519009968152019101906102bf565b9391906020600080516020614ac08339815191528192845190099283855201920193610248565b9060a0916000516020915b608083106103db57600080516020614ac0833981519152809284519009602086526020808701526020604087015260608601527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff60808601528160a086015260208560c08160055afa1693805192601f19809201905b806020106103c15750505080602051830991600051900990600052602052565b8280918580855189099782519009968152019101906103a1565b9391906020600080516020614ac0833981519152819284519009928385520192019361032b565b91906040526060526040600060808160065afa1690565b906040526040600060608160075afa1690565b919060c05260e05260406080808060065afa1690565b9060c0526040608060608160075afa1690565b9392919060005260205261086051604052610880516060526108a0516080526108c05160a05260c05260e0526108e05161010052610900516101205261092051610140526109405161016052602060006101808160085afa166000511690565b60017f10f28bc710a8bdd00dd701df2f5fc4f5ccdb260238eba6f819db692f79dc3dc96106c052600b6106e0527f305e41e912d579f5b3193badcab128321c8ee1cb70aa396331b979553d820001610700527f14c60185e75885d674db4b3f7d4a5694fa6c01aa0f53557b060bc04a4172705f610720527f2afd4e77273f1cb3434a4a667929058c156b21573c3f1efc882e708597d7161a610740527f22b55603586d5fc42c6c14c2fc27a028c207da8b2c71cb33d549fa4a2be5d3026107605260046107805260006107a05260006107c05260006107e052600061080052600161082052600261084052610860907f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c282527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610880527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6108a0527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6108c0527f26186a2d65ee4d2f9c9a5b91f86597d35f192cd120caf7e935d8443d1938e23d6108e0527f30441fd1b5d3370482c42152a8899027716989a6996c2535bc9f7fee8aaef79e610900527f16f363f103c80d7bbc8ad3c6867e0822bbc6000be91a4689755c7df40221c145610920527f2b1cbb3e521edf5a622d82762a44a5e63f1e50b332d71154a4a7958d6011deff610940527f010920a3471867216dc9dd6b478c16842fb5aca434fe6c9bf1622c4abd70381a610960527f300e30930f1a05253b28b6b139f2c38025d99b7a54e641f1d6ff2797d113c118610980527f05e7899750f7abeae5d19c16666c47618fce810326b125d253dd41fb817dd65a6109a0527f1e0e399ce46f208ab3f43aad0222f4dd37b8327b9f7afffa9cf9ee214e2460dd6109c0527f22274e4efd4197dd6515994652d5beafcc7af94313d33e049cf5a1e464b523956109e0527f0ebb470e19409fcd84c0358c04300dc38cba0240141ddeb899ad9cca90167a64610a00527f162baf6245e2cec59bc93bc2302527d299cdb50e100f14895f170f316a2a2643610a20527f172a6f183e2ddc0607d23fd3daf4b23110b81d8a9d0a4e8d3d07ba24a007e04b610a40527f22e1cdbfffcfcf4f18cf4342edf1fb26c3b6e52ace3d5fadcf5cc2614333baa4610a60527f0e28df72dcc69cc6442d72f693661997480a913ac353890efd63a873959727c0610a80527f01021a51384124c6844f2ba0e40e2545f26f280a79745c9164b0a56f1ee54d56610aa0527f2533607ba6f153a0126a8450a3cf47946933c93eaf69c996236b45603179c914610ac0527f1f59be81b3fd7d290930430d204c1a866937862306d75be70fedfe13e565ce0b610ae0527f05931c531cd08b4aa937245293af81c4532fc4c01387d5b539d29f6c4ae00031610b00527f203b21a648fbfb96459640bbc5b41852dd1efc1209c89b635ba638dcb929da6b610b20527f04e7002f06f2091a44afcd311e93c22f46dd9f3207b5bcc34f0ca7652098f097610b40527f20ab7490b42f3f7b2b0bbe601a09d72ee93f924801d597f48cf2d443751d5f91610b60527f2bca2f1762946a05fb1632550c6cb12c02d18d9bee5bdd4212ca7342888720fd610b80527f2aaba546cdd9969ef0aecc85b2aaa19b6e9639879962661415c8f0df426bac0c610ba0527f12b15327bcfbe7d9e9de1bc648ba3bdf910087362179a0b403cf70bad1c093c8610bc0527f25909db723a8021ffe088c50525d6d260f9157be7a7c194b6f315386a46cdab8610be0527f25cbeae8ec2a8a2f74844f5e3276ed94079907bed6d7b1b26ed695328fe7bcae610c00527f26bffd26dd8f5f7679281f8d1a432690e07b15cbdf684fe456aa1277515e1730610c20527f015a3f09c82a770a69d67583d7049d83d69b7b8e03d38484497215cdc5979556610c40527f1ee4241e91ac391756b0b9893ac1e34ea95c6dd689e7dca12c62a6ce943960f1610c60527f10ad75f199bf1fb9335b91c20db6cd8958dcb2fe11983bc77cdb4036e57e59ca610c80527f05eb5d19e589c11e0bb2200d66da829955545481885cfbc9099ec6a53e266ed2610ca0527f25ac1d9849f9f448cecc7ead7d48670f66bbfe7df8e248bd818a954df6936c27610cc0527f0743ea40f14084db2673217283aa053f986896ee7c181f52118442e99c452974610ce0527f0203e3493a2594ece57d22cc75dd081ac68271ec7c758153cfd2152bfb5c19e3610d00527f1b95c5dc9bae0fb3f8208684042e57e0fcfbc3774af9ae0903ab9e9ddb4f89fd610d20527f1e8564e01419713739871224ce15f4c4b51e6af161d6e07a178e6545879035bf610d40527f1cefc889639cf98f94d831ea41c356929f9317778dda05ba0c5885401638db67610d60527f1e0466deb22a86d9122bc7180b7d293e47288244abf1450a5cd63a3289a457ca610d80526108c435600414916044351416167f10f28bc710a8bdd00dd701df2f5fc4f5ccdb260238eba6f819db692f79dc3dc96000526020906108e45b6109648110614a7957506064915b6101248310614a66576000908120600080516020614ac08339815191528106610da0529052610dc0916020608082015b808310614a4f5750610c4090610c4794610107565b939061012a565b926101008201935b848310614a3a5790610c6091610107565b610140830193915b848410614a295790610c7991610107565b929061046082015b808310614a005750610ca7610cb692610ca0610cbe96610cad94610107565b929061012a565b946100af565b90929193610107565b9290506100af565b5050806107a051614900575b508015614688576106e051610e20519081906000905b8082106148e25750506107205192610f2061078051926006840160051b80830194156148d6575b50610760515b8483106148b157505050610d5a600080516020614ac08339815191527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000008508918284526020840190610150565b93600080516020614ac0833981519152610f209261070051900991610760515b84821061488b5750505050610f4051610f60915b610fe0831061486b576000926108e4906107805160051b8201905b818310614843575050505191610f205191610fe0519085610f205284610f405283610f605280610f805281610fa05282610fc052610e00519283809281610de0519381610dc0519381610e2051600080516020614ac083398151915290870999818d600080516020614ac08339815191526108043581036107e43508600080516020614ac08339815191526108243581036107e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152908608600080516020614ac083398151915203600080516020614ac08339815191529060010890600080516020614ac083398151915291099d81600080516020614ac08339815191526108243581036107e43508600080516020614ac08339815191529085099d600080516020614ac08339815191528d61054435088b600080516020614ac08339815191526101006104243509600080516020614ac08339815191529081036103e43508600080516020614ac083398151915290610564350990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac0833981519152906107a43509600080516020614ac0833981519152038d6108243590600080516020614ac08339815191529108600080516020614ac08339815191528d6107e4350890600080516020614ac08339815191529109600080516020614ac0833981519152906107c4350990600080516020614ac08339815191529108600080516020614ac0833981519152848908600080516020614ac083398151915203600080516020614ac08339815191529060010890600080516020614ac083398151915291099c6107a435600080516020614ac083398151915281810391800990600080516020614ac08339815191529108600080516020614ac08339815191529085099b600080516020614ac08339815191526107a43581038809600080516020614ac08339815191529088089a600080516020614ac08339815191528a870883600080516020614ac0833981519152600080516020614b408339815191528709600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290840890600080516020614ac0833981519152910884600080516020614ac0833981519152600080516020614b408339815191528809600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610764350990600080516020614ac08339815191529109600080516020614ac083398151915203846106e435600080516020614ac0833981519152908609600080516020614ac083398151915290850890600080516020614ac0833981519152910885600080516020614ac08339815191526106c4358709600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610784350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac083398151915203908380600080516020614ac0833981519152600080516020614b408339815191528809600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290840890600080516020614ac0833981519152910881600080516020614ac0833981519152600080516020614b408339815191528909600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610764350990600080516020614ac08339815191529109600080516020614ac083398151915203916106e435600080516020614ac0833981519152908609600080516020614ac0833981519152910890600080516020614ac0833981519152910884600080516020614ac08339815191526106c4358609600080516020614ac083398151915290610464350890600080516020614ac08339815191529108600080516020614ac083398151915290610784350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910898600080516020614ac083398151915290860882600080516020614ac0833981519152600080516020614b408339815191528609600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac0833981519152906104e4350890600080516020614ac0833981519152910883600080516020614ac0833981519152600080516020614b408339815191528709600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610404350890600080516020614ac0833981519152910884600080516020614ac0833981519152600080516020614b408339815191528809600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910885600080516020614ac0833981519152886104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610704350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ac083398151915203836106a435600080516020614ac0833981519152908509600080516020614ac0833981519152906104e4350890600080516020614ac0833981519152910884600080516020614ac0833981519152610684358609600080516020614ac083398151915290610404350890600080516020614ac0833981519152910885600080516020614ac0833981519152610664358709600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910886600080516020614ac0833981519152610644358809600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610724350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109600080516020614ac0833981519152039282600080516020614ac0833981519152600080516020614b408339815191528309600080516020614b40833981519152600080516020614ac08339815191529109600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac0833981519152906104e4350890600080516020614ac083398151915291089083600080516020614ac0833981519152600080516020614b408339815191528309600080516020614b40833981519152600080516020614ac08339815191529109600080516020614ac083398151915290610404350890600080516020614ac08339815191529108908480600080516020614ac0833981519152600080516020614b408339815191528409600080516020614ac0833981519152906103e4350890600080516020614ac0833981519152910891600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610704350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ac08339815191520391806106a435600080516020614ac0833981519152908409600080516020614ac0833981519152906104e4350890600080516020614ac083398151915291089181600080516020614ac0833981519152610684358309600080516020614ac083398151915290610404350890600080516020614ac083398151915291089180600080516020614ac0833981519152610664358409600080516020614ac0833981519152906103e4350890600080516020614ac083398151915291089161064435600080516020614ac08339815191529109600080516020614ac0833981519152906104c4350890600080516020614ac08339815191529108600080516020614ac083398151915290610724350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac083398151915291089381600080516020614ac08339815191526107443581036107643508600080516020614ac08339815191529083099361076435600080516020614ac083398151915281810391800990600080516020614ac08339815191529108600080516020614ac0833981519152910991600080516020614ac0833981519152610704358209600080516020614ac083398151915203600080516020614ac083398151915291088161046435600080516020614ac083398151915203610404356103e43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161046435600080516020614ac083398151915203610404356103e43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161044435600080516020614ac083398151915203610404356104643561040435600080516020614ac0833981519152036103e43590600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e435610464356103e435600080516020614ac0833981519152036104043590600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac083398151915261046435810360010861046435600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191526104443581036104843508600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e4356104a43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600308600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191527f16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be6104443509600080516020614ac08339815191527f0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104e435610524356104043590600080516020614ac08339815191529108600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614b00833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac083398151915290610604350981600080516020614ac08339815191527f1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe6104443509600080516020614ac08339815191527f13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104c435610524356104043590600080516020614ac08339815191529108600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac08339815191529061060435098161046435600080516020614ac083398151915203610504356103e43590600080516020614ac08339815191529108600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac08339815191529061060435098161044435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b00833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105e435098161042435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614aa0833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105e4350981600080516020614ac08339815191526104443581036104843508600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac083398151915291098161042435600080516020614ac0833981519152036103e4356104a43590600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152610584358103600408600080516020614ac0833981519152610584358103600208600080516020614ac0833981519152610584358103600108600080516020614ac083398151915290610584350990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910981600080516020614ac08339815191527f16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be6104443509600080516020614ac08339815191527f0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104e435610524356104043590600080516020614ac08339815191529108600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614b00833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105c4350981600080516020614ac08339815191527f1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe6104443509600080516020614ac08339815191527f13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66610424350990600080516020614ac08339815191529108600080516020614ac0833981519152036104c435610524356104043590600080516020614ac08339815191529108600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac083398151915291086104c435600080516020614ac0833981519152610524356104043508600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152600080516020614aa0833981519152610464350990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac0833981519152906105c435098161046435600080516020614ac083398151915203610504356103e43590600080516020614ac08339815191529108600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529108600080516020614ac0833981519152906105c435098161044435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614ae0833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b00833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105a435098161042435600080516020614ac083398151915203610524356104043590600080516020614ac08339815191529108600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac08339815191529109600080516020614ac0833981519152610524356104043508600080516020614ac083398151915261052435610404350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614b20833981519152600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac08339815191529109600080516020614ac0833981519152610504356103e43508600080516020614ac0833981519152610504356103e4350890600080516020614ac0833981519152910990600080516020614ac0833981519152910990600080516020614ac08339815191529109600080516020614aa0833981519152600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529108600080516020614ac0833981519152906105a4350990600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac08339815191529109610fe0526103a4356000526103c435602052610364905b816102641061481b57826000516110005260205161102052600080516020614ac08339815191528080610e205181808061072051816107405180988188819997829896839709610420528061040052828282096103e0520909090909096103c052610e80516104406103c0905b6104c081106147f757836104605161048051906104a05180600080516020614ac083398151915284840990600080516020614ac083398151915291096104c0526104405191826104e0528260005281600080516020614ac083398151915282850990600080516020614ac08339815191529109610500528061052052600080516020614ac083398151915281840961054052600080516020614ac0833981519152828409610560526103e0519161040051938161042051918483600080516020614ac083398151915203600080516020614ac0833981519152908808600080516020614ac0833981519152898103890890600080516020614ac0833981519152910990600080516020614ac0833981519152910960205287600080516020614ac08339815191528481038908600080516020614ac08339815191528881038a0890600080516020614ac0833981519152910990600080516020614ac0833981519152910960405281600080516020614ac08339815191528881038508600080516020614ac0833981519152888103860890600080516020614ac0833981519152910990600080516020614ac08339815191529109606052600080516020614ac0833981519152886001096080526103c05190600080516020614ac08339815191528481038308600080516020614ac0833981519152898103840890600080516020614ac0833981519152910990600080516020614ac0833981519152910960a052600080516020614ac0833981519152038783600080516020614ac083398151915203600080516020614ac0833981519152908908600080516020614ac0833981519152838a0890600080516020614ac0833981519152910990600080516020614ac0833981519152910960c052600080516020614ac0833981519152878103840890600080516020614ac083398151915290840890600080516020614ac0833981519152910990600080516020614ac0833981519152910960e05285600080516020614ac0833981519152828103870890600080516020614ac083398151915291096101005284600080516020614ac083398151915203600080516020614ac0833981519152910890600080516020614ac0833981519152910961012052600080516020614ac0833981519152838103830890600080516020614ac0833981519152910961014052600080516020614ac083398151915203600080516020614ac0833981519152910890600080516020614ac0833981519152910961016052613fff9061023c565b600051806104e0526105005b61058081106147d957610e40516020516040516060518693600080516020614ac083398151915280610424358409818681868187818b81806103e43583099781808080806104a43586099a610444359009956104043590099261048435900960000808080908080861058052608051600080516020614ac083398151915280610fe05183098184818061062435870960000809086106e45b80610624106147b457506106045b806104a41061478f575061050051908380600080516020614ac083398151915261046435860992600080516020614ac083398151915261082435870991600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac083398151915291096105a05260a05160c05160e051926105205161072435600080516020614ac0833981519152908609600080516020614ac0833981519152610704358509600080516020614ac0833981519152610744358709600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096105c05261010051956101205195610540519061078435600080516020614ac083398151915290890990600080516020614ac0833981519152610764358b0990600080516020614ac08339815191526107c4358b09600080516020614ac08339815191526107a4358d09600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910990600080516020614ac0833981519152910890600080516020614ac0833981519152910890600080516020614ac083398151915291096105e05261014051986101605198610560516107e435600080516020614ac0833981519152908c09600080516020614ac0833981519152610804358e09600080516020614ac08339815191529060000890600080516020614ac0833981519152910890600080516020614ac0833981519152910961060052600080516020614ac0833981519152910890600080516020614ac083398151915291086106205261064052600080516020614ac0833981519152910890600080516020614ac0833981519152910861066052600080516020614ac0833981519152910861068052600080516020614ac083398151915291086106a05261062060005b60a0811061477f576143c483610320565b600080516020614ac08339815191526106005160805109610e6051919060606105e05b60a08210614754578461444c61443d61442561441888886110405260a43560005260c435602052610e405190610419565b6084359060643590610402565b610264356080526102843560a052610e405190610442565b6110205190611000519061042c565b610d605b80610a201061472a5761467861461961453c6145f161453c6145c961453c89600080516020614ac0833981519152806145a861453c61459b61458c8f61456c61453c8761454961453c8c8361452f6145216144db6145126144db6145036144db6144f4889f6144e56144db6144cc6144db93610e405190610442565b6109c051906109a0519061042c565b610e405190610442565b6109805190610960519061042c565b610a405190610a20519061042c565b610a0051906109e0519061042c565b6101843590610164359061042c565b610104359060e4359061042c565b9161050051900990610442565b60a0519060805190610402565b9a610e60519009996101a4356080526101c43560a05283610520518c0990610442565b97610e6051900996610224356080526102443560a052610e405190610442565b61020435906101e4359061042c565b8361054051870990610442565b92610e60519009610124356080526101443560a05261056051900990610442565b610820516080526108405160a05261104051600080516020614ac08339815191520390610442565b610844356080526108643560a0526104c051600080516020614ac08339815191520390610442565b610884358060805261463a61453c6108a435938460a052610e805190610442565b906000519161106091838352602051611080948186526110a0968388526110c0938185526107a05161468d575b505050505193519251915190610455565b1561468857600160005260206000f35b600080fd5b9161470b9391614716959693610ea051600052610ec051602052610ee0938451604052610f0093845160605260805260a05260c05260e0526146f36146e8600080516020614ac0833981519152610100600020068095610419565b895190895190610402565b91600051885260205189525160005251602052610419565b825190865190610402565b906000518552602051815286808080614667565b9061473c61474a91610e405190610442565b60208301519083519061042c565b90603f1901614450565b9091600080516020614ac083398151915290818681855187510992090891601f1990810191016143e7565b81518152602091820191016143b3565b90600080516020614ac0833981519152908185818535870992090890601f19016140b1565b90600080516020614ac0833981519152908185818535870992090890601f19016140a3565b80600080516020614ac083398151915283602093510981520161400b565b60208091600080516020614ac0833981519152845181038608815201910190613c56565b909161482a8261483892610419565b602084013590843590610402565b91603f190190613be9565b9091946020600080516020614ac0833981519152819281893586510990089601929101610da9565b9190600080516020614ac083398151915260209183519008910191610d8e565b600080516020614ac0833981519152838282806020958751098809855209910190610d7a565b60209087600080516020614ac083398151915291828181038608865209920191610d0d565b610f4001935086610d07565b9092600080516020614ac08339815191528160019209930190610ce0565b90506107e0519061080051916107c05160051b806108e401918235926108e48260051b840101356108e48360061b85010135906108e460038560051b02860101359588965b846108e48760051b89010181101561499957906020808c93019384358b1b0194818960051b890101358b1b0195818960061b890101358b1b019660038960051b02010135891b019701969392919093614945565b50979450975093509350507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4790816003818087800987090882868009149180600381808a80098a09089084800914161693610ea052610ec052610ee052610f005281610cca565b9160208181923595600080516020614ac083398151915287101695875201940191939193610c81565b92614a33926100af565b9092610c68565b9291614a45926100af565b9192909190610c4f565b939291614a5b926100af565b929391929091610c2b565b9091614a71926100af565b919091610bfb565b9060208091600080516020614ac083398151915284351016928035855201920191610bed56fe066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad530644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c80cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff92b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e809226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2a2646970667358221220a0e58ae7dd3fb0f443e0d062395c088c727c1d4c080852f27a12ca461cdb486d64736f6c63430008120033","linkReferences":{},"deployedLinkReferences":{}} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/abi/Summa.json b/tools/polyexen/circuit/solvency/backend/src/contracts/abi/Summa.json new file mode 100644 index 0000000..1d46d56 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/abi/Summa.json @@ -0,0 +1 @@ +{"_format":"hh-sol-artifact-1","contractName":"Summa","sourceName":"src/Summa.sol","abi":[{"inputs":[{"internalType":"contract IVerifier","name":"_inclusionVerifier","type":"address"},{"internalType":"uint16","name":"mstLevels","type":"uint16"},{"internalType":"uint16","name":"currenciesCount","type":"uint16"},{"internalType":"uint8","name":"balanceByteRange","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"components":[{"internalType":"string","name":"cexAddress","type":"string"},{"internalType":"string","name":"chain","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"indexed":false,"internalType":"struct Summa.AddressOwnershipProof[]","name":"addressOwnershipProofs","type":"tuple[]"}],"name":"AddressOwnershipProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mstRoot","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"rootBalances","type":"uint256[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"chain","type":"string"}],"indexed":false,"internalType":"struct Summa.Cryptocurrency[]","name":"cryptocurrencies","type":"tuple[]"}],"name":"LiabilitiesCommitmentSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addressOwnershipProofs","outputs":[{"internalType":"string","name":"cexAddress","type":"string"},{"internalType":"string","name":"chain","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"commitments","outputs":[{"internalType":"uint256","name":"mstRoot","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"uint16","name":"mstLevels","type":"uint16"},{"internalType":"uint16","name":"currenciesCount","type":"uint16"},{"internalType":"uint8","name":"balanceByteRange","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"addressHash","type":"bytes32"}],"name":"getAddressOwnershipProof","outputs":[{"components":[{"internalType":"string","name":"cexAddress","type":"string"},{"internalType":"string","name":"chain","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct Summa.AddressOwnershipProof","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mstRoot","type":"uint256"},{"internalType":"uint256[]","name":"rootBalances","type":"uint256[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"chain","type":"string"}],"internalType":"struct Summa.Cryptocurrency[]","name":"cryptocurrencies","type":"tuple[]"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"submitCommitment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"cexAddress","type":"string"},{"internalType":"string","name":"chain","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"message","type":"bytes"}],"internalType":"struct Summa.AddressOwnershipProof[]","name":"_addressOwnershipProofs","type":"tuple[]"}],"name":"submitProofOfAddressOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint256[]","name":"publicInputs","type":"uint256[]"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"verifyInclusionProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"bytecode":"0x60a0346200014a57601f62001bf538819003918201601f19168301926001600160401b03929091838511838610176200014f5781608092849260409788528339810103126200014a5780516001600160a01b039081811681036200014a576200006b6020840162000165565b9160606200007b87860162000165565b9401519460ff8616928387036200014a5760008054336001600160a01b03198216811783559194167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a3608052865191606083019182118383101762000136575063ffff00009392918791825261ffff8094169384825286166020820152015264ff000000006001549460201b169364ffffffffff1916179160101b16171760015551611a7f90816200017682396080518161188b0152f35b634e487b7160e01b81526041600452602490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b519061ffff821682036200014a5756fe608080604052600436101561001357600080fd5b60003560e01c90816319b33968146112635750806349ce899714611237578063715018a6146111de57806379502c55146111a55780638da5cb5b1461117c578063a3c4bcf8146110a8578063c7ddca0e146109b0578063c8e581471461094d578063da64a7501461015d5763f2fde38b1461008d57600080fd5b34610158576020366003190112610158576004356001600160a01b0381811691829003610158576100bc611675565b811561010457600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b34610158576080366003190112610158576024356001600160401b0381116101585761018d903690600401611617565b6001600160401b03604435116101585736602360443501121561015857604435600401356101ba8161159e565b6101c7604051918261157d565b8181526020810180923660248260051b60443501011161015857602460443501915b60248260051b6044350101831061089d57505050610205611675565b610212600435151561174e565b825181510361083a57610225815161178d565b90610230815161178d565b9360005b825181101561036957602061024982856116dc565b51015151151580610354575b156103165761026481836116dc565b51156102bf57806102786102ba92856116dc565b515161028482876116dc565b5261028f81866116dc565b50602061029c82866116dc565b5101516102a982896116dc565b526102b481886116dc565b506116cd565b610234565b60405162461bcd60e51b815260206004820152602960248201527f416c6c20726f6f742073756d732073686f756c642062652067726561746572206044820152687468616e207a65726f60b81b6064820152608490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e76616c69642063727970746f63757272656e637960501b6044820152606490fd5b5061035f81846116dc565b5151511515610255565b5091846040519061037982611562565b6004358252602082019285845260408301526060820152606435600052600460205260406000209181518355518051906001600160401b03821161062157600160401b821161062157602090600185015483600187015580841061081a575b500160018401600052602060002060005b83811061080657505050506040810151805190600160401b821161062157600284015482600286015580831061078d575b5060200190600284016000526020600020916000905b8282106106b0575050505060600151805190600160401b8211610621576003830154826003850155808310610637575b5060206003910192016000526020600020916000905b82821061053e575050505061049e6040519260043584526060602085015260608401906117d7565b90828203604084015251808252602082019160208260051b82010194926000915b8383106104f1576064357f88bfc7389cb831ea0208ff106da6f5c9f88036ba084f1eb008d2788d3d45998d87890388a2005b909192939560208061052f600193601f198682030187528a51908361051f83516040845260408401906113c6565b92015190848184039101526113c6565b980193019301919392906104bf565b80518051906001600160401b038211610621576105658261055f8854611492565b88611707565b602090601f83116001146105b15792826001949360209386956000926105a6575b5050600019600383901b1c191690841b1787555b01940191019092610476565b015190508c80610586565b908660005260206000209160005b601f1985168110610609575083602093600196938796938794601f198116106105f0575b505050811b01875561059a565b015160001960f88460031b161c191690558c80806105e3565b919260206001819286850151815501940192016105bf565b634e487b7160e01b600052604160045260246000fd5b600384016000526020600020908382015b8183018110610658575050610460565b8061066560019254611492565b80610672575b5001610648565b601f90818111841461068b575050600081555b8a61066b565b6106a760009284845260208420920160051c82018583016116f0565b81835555610685565b80518051906001600160401b038211610621576106d18261055f8854611492565b602090601f831160011461071d579282600194936020938695600092610712575b5050600019600383901b1c191690841b1787555b01940191019092610430565b015190508e806106f2565b908660005260206000209160005b601f1985168110610775575083602093600196938796938794601f1981161061075c575b505050811b018755610706565b015160001960f88460031b161c191690558e808061074f565b9192602060018192868501518155019401920161072b565b600285016000526020600020908382015b81830181106107ae57505061041a565b806107bb60019254611492565b806107c8575b500161079e565b601f9081811184146107e1575050600081555b8b6107c1565b6107fd60009284845260208420920160051c82018583016116f0565b818355556107db565b6001906020845194019381840155016103e9565b6108349060018701600052848460002091820191016116f0565b886103d8565b60405162461bcd60e51b815260206004820152603560248201527f526f6f74206c696162696c69746965732073756d7320616e64206c696162696c6044820152740d2e8d2cae640dceadac4cae440dad2e6dac2e8c6d605b1b6064820152608490fd5b8235906001600160401b0382116101585760406044358301360360231901126101585760405191604083018381106001600160401b03821117610621576040526001600160401b03602482604435010135116101585761090936602460443584018181013501016115d0565b83526044818135010135916001600160401b0383116101585760249361093c6020949386869536926044350101016115d0565b8382015281520193019290506101e9565b34610158576060366003190112610158576001600160401b036004358181116101585761097e9036906004016115d0565b906024359081116101585760209161099d6109a6923690600401611617565b6044359161180b565b6040519015158152f35b34610158576020366003190112610158576004356001600160401b0381116101585736602382011215610158578060040135906109ec8261159e565b906109fa604051928361157d565b82825260208201906024829460051b820101903682116101585760248101925b828410610fce578585610a2b611675565b60005b8151811015610f4e57610a4181836116dc565b5151604051610a6d60208281610a6081830196878151938492016113a3565b810103808452018261157d565b519020806000526003602052604060002054610f0957610a8d82846116dc565b51600254600160401b81101561062157806001610aad9201600255611442565b919091610ef35780518051906001600160401b038211610621578190610add82610ad78754611492565b87611707565b602090601f8311600114610e8757600092610e7c575b50508160011b916000199060031b1c19161782555b60208101518051906001600160401b038211610621578190610b3a82610b316001880154611492565b60018801611707565b602090601f8311600114610e0a57600092610dff575b50508160011b916000199060031b1c19161760018301555b60408101518051906001600160401b03821161062157610b9882610b8f6002870154611492565b60028701611707565b602090601f8311600114610d8c57606093929160009183610d81575b50508160011b916000199060031b1c19161760028401555b01518051906001600160401b03821161062157610bf982610bf06003860154611492565b60038601611707565b602090601f8311600114610d12576003929160009183610d07575b50508160011b9160001990841b1c1916179101555b600254906000526003602052604060002055610c4581836116dc565b515151151580610cef575b80610cd7575b80610cbf575b15610c6f57610c6a906116cd565b610a2e565b60405162461bcd60e51b815260206004820152602260248201527f496e76616c69642070726f6f66206f662061646472657373206f776e65727368604482015261069760f41b6064820152608490fd5b506060610ccc82846116dc565b510151511515610c5c565b506040610ce482846116dc565b510151511515610c56565b506020610cfc82846116dc565b510151511515610c50565b015190508880610c14565b906003840160005260206000209160005b601f1985168110610d695750918391600193600395601f19811610610d51575b505050811b01910155610c29565b015160001983861b60f8161c19169055888080610d43565b91926020600181928685015181550194019201610d23565b015190508980610bb4565b906002850160005260206000209160005b601f1985168110610de7575091839160019360609695601f19811610610dce575b505050811b016002840155610bcc565b015160001960f88460031b161c19169055898080610dbe565b91926020600181928685015181550194019201610d9d565b015190508880610b50565b9250600185016000526020600020906000935b601f1984168510610e61576001945083601f19811610610e48575b505050811b016001830155610b68565b015160001960f88460031b161c19169055888080610e38565b81810151835560209485019460019093019290910190610e1d565b015190508880610af3565b9250846000526020600020906000935b601f1984168510610ed8576001945083601f19811610610ebf575b505050811b018255610b08565b015160001960f88460031b161c19169055888080610eb2565b81810151835560209485019460019093019290910190610e97565b634e487b7160e01b600052600060045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527f4164647265737320616c726561647920766572696669656400000000000000006044820152606490fd5b506040519060208201906020835251809152604082019060408160051b84010193916000905b828210610fa3577f382315d4d56a6035e1899bffe77d9becefaf5f2650e4323b27854857a045465885870386a1005b90919294602080610fc0600193603f1989820301865289516113eb565b970192019201909291610f74565b83356001600160401b038111610158578201608060231982360301126101585760405191610ffb83611562565b60248201356001600160401b0381116101585761101e90602436918501016115d0565b835260448201356001600160401b0381116101585761104390602436918501016115d0565b602084015260648201356001600160401b0381116101585761106b90602436918501016115d0565b60408401526084820135926001600160401b038411610158576110986020949360248695369201016115d0565b6060820152815201930192610a1a565b3461015857602036600319011261015857600435600254811015610158576110d261114e91611442565b50611178600361116a604051936110f4856110ed81846114cc565b038661157d565b61115c6040516111128161110b81600187016114cc565b038261157d565b61113a6040519361112a856110ed81600285016114cc565b6110ed60405180988193016114cc565b6040519788976080895260808901906113c6565b9087820360208901526113c6565b9085820360408701526113c6565b9083820360608501526113c6565b0390f35b34610158576000366003190112610158576000546040516001600160a01b039091168152602090f35b3461015857600036600319011261015857606060015460ff6040519161ffff80821684528160101c16602084015260201c166040820152f35b34610158576000366003190112610158576111f7611675565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101585760203660031901126101585760043560005260046020526020604060002054604051908152f35b34610158576020806003193601126101585760043561128183611562565b60608084818096528185820152816040820152015280600052600382526040600020541561136757600052600381526040600020546000198101908111611351576112cd600391611442565b509261133a604051946112df86611562565b6040516112f08161110b81856114cc565b86526040516113068161110b81600186016114cc565b8587015260405161131e8161110b81600286016114cc565b604087015261133360405180958193016114cc565b038361157d565b8301526111786040519282849384528301906113eb565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b81526004810183905260146024820152731059191c995cdcc81b9bdd081d995c9a599a595960621b6044820152606490fd5b60005b8381106113b65750506000910152565b81810151838201526020016113a6565b906020916113df815180928185528580860191016113a3565b601f01601f1916010190565b61143f91606061142e61141c61140a85516080865260808601906113c6565b602086015185820360208701526113c6565b604085015184820360408601526113c6565b9201519060608184039101526113c6565b90565b60025481101561147c57600260005260021b7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0190600090565b634e487b7160e01b600052603260045260246000fd5b90600182811c921680156114c2575b60208310146114ac57565b634e487b7160e01b600052602260045260246000fd5b91607f16916114a1565b90600092918054916114dd83611492565b91828252600193848116908160001461153f57506001146114ff575b50505050565b90919394506000526020928360002092846000945b83861061152b5750505050010190388080806114f9565b805485870183015294019385908201611514565b9294505050602093945060ff191683830152151560051b010190388080806114f9565b608081019081106001600160401b0382111761062157604052565b90601f801991011681019081106001600160401b0382111761062157604052565b6001600160401b0381116106215760051b60200190565b6001600160401b03811161062157601f01601f191660200190565b81601f82011215610158578035906115e7826115b5565b926115f5604051948561157d565b8284526020838301011161015857816000926020809301838601378301015290565b81601f820112156101585780359161162e8361159e565b9261163c604051948561157d565b808452602092838086019260051b820101928311610158578301905b828210611666575050505090565b81358152908301908301611658565b6000546001600160a01b0316330361168957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60001981146113515760010190565b805182101561147c5760209160051b010190565b8181106116fb575050565b600081556001016116f0565b9190601f811161171657505050565b611742926000526020600020906020601f840160051c83019310611744575b601f0160051c01906116f0565b565b9091508190611735565b1561175557565b60405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081354d5081c9bdbdd60821b6044820152606490fd5b906117978261159e565b6117a4604051918261157d565b82815280926117b5601f199161159e565b019060005b8281106117c657505050565b8060606020809385010152016117ba565b90815180825260208080930193019160005b8281106117f7575050505090565b8351855293810193928101926001016117e9565b909160008181526004936020938585526040938484205490835191600192831015611a36579061184288949392888701511461174e565b6002825b611974575b5050506118759061188786519485938493631e8e1e1360e01b8552898c86015260448501906113c6565b838103600319016024850152906117d7565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa829181611938575b506119305750606494503d1561192a573d906118d8826115b5565b916118e58451938461157d565b8252833d92013e5b5162461bcd60e51b815291820152601760248201527f496e76616c696420696e636c7573696f6e2070726f6f660000000000000000006044820152fd5b506118ed565b935050505090565b9091508481813d831161196d575b611950818361157d565b81010312611969575180151581036119695790386118bd565b8280fd5b503d611946565b909192938551821015611a2f5750818652888852868620600119908401828201838111611a1c5781541115611a09578752818988200101546119b682876116dc565b51036119cf57906119c783926116cd565b889493611846565b865162461bcd60e51b8152808a018990526014602482015273496e76616c696420726f6f742062616c616e636560601b6044820152606490fd5b634e487b7160e01b885260328b52602488fd5b634e487b7160e01b895260118c52602489fd5b939261184b565b634e487b7160e01b865260328952602486fdfea26469706673582212204c697500976b80ebfdb94c86197130f85b4277c7496208d402a9e627925053f264736f6c63430008120033","deployedBytecode":"0x608080604052600436101561001357600080fd5b60003560e01c90816319b33968146112635750806349ce899714611237578063715018a6146111de57806379502c55146111a55780638da5cb5b1461117c578063a3c4bcf8146110a8578063c7ddca0e146109b0578063c8e581471461094d578063da64a7501461015d5763f2fde38b1461008d57600080fd5b34610158576020366003190112610158576004356001600160a01b0381811691829003610158576100bc611675565b811561010457600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b34610158576080366003190112610158576024356001600160401b0381116101585761018d903690600401611617565b6001600160401b03604435116101585736602360443501121561015857604435600401356101ba8161159e565b6101c7604051918261157d565b8181526020810180923660248260051b60443501011161015857602460443501915b60248260051b6044350101831061089d57505050610205611675565b610212600435151561174e565b825181510361083a57610225815161178d565b90610230815161178d565b9360005b825181101561036957602061024982856116dc565b51015151151580610354575b156103165761026481836116dc565b51156102bf57806102786102ba92856116dc565b515161028482876116dc565b5261028f81866116dc565b50602061029c82866116dc565b5101516102a982896116dc565b526102b481886116dc565b506116cd565b610234565b60405162461bcd60e51b815260206004820152602960248201527f416c6c20726f6f742073756d732073686f756c642062652067726561746572206044820152687468616e207a65726f60b81b6064820152608490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e76616c69642063727970746f63757272656e637960501b6044820152606490fd5b5061035f81846116dc565b5151511515610255565b5091846040519061037982611562565b6004358252602082019285845260408301526060820152606435600052600460205260406000209181518355518051906001600160401b03821161062157600160401b821161062157602090600185015483600187015580841061081a575b500160018401600052602060002060005b83811061080657505050506040810151805190600160401b821161062157600284015482600286015580831061078d575b5060200190600284016000526020600020916000905b8282106106b0575050505060600151805190600160401b8211610621576003830154826003850155808310610637575b5060206003910192016000526020600020916000905b82821061053e575050505061049e6040519260043584526060602085015260608401906117d7565b90828203604084015251808252602082019160208260051b82010194926000915b8383106104f1576064357f88bfc7389cb831ea0208ff106da6f5c9f88036ba084f1eb008d2788d3d45998d87890388a2005b909192939560208061052f600193601f198682030187528a51908361051f83516040845260408401906113c6565b92015190848184039101526113c6565b980193019301919392906104bf565b80518051906001600160401b038211610621576105658261055f8854611492565b88611707565b602090601f83116001146105b15792826001949360209386956000926105a6575b5050600019600383901b1c191690841b1787555b01940191019092610476565b015190508c80610586565b908660005260206000209160005b601f1985168110610609575083602093600196938796938794601f198116106105f0575b505050811b01875561059a565b015160001960f88460031b161c191690558c80806105e3565b919260206001819286850151815501940192016105bf565b634e487b7160e01b600052604160045260246000fd5b600384016000526020600020908382015b8183018110610658575050610460565b8061066560019254611492565b80610672575b5001610648565b601f90818111841461068b575050600081555b8a61066b565b6106a760009284845260208420920160051c82018583016116f0565b81835555610685565b80518051906001600160401b038211610621576106d18261055f8854611492565b602090601f831160011461071d579282600194936020938695600092610712575b5050600019600383901b1c191690841b1787555b01940191019092610430565b015190508e806106f2565b908660005260206000209160005b601f1985168110610775575083602093600196938796938794601f1981161061075c575b505050811b018755610706565b015160001960f88460031b161c191690558e808061074f565b9192602060018192868501518155019401920161072b565b600285016000526020600020908382015b81830181106107ae57505061041a565b806107bb60019254611492565b806107c8575b500161079e565b601f9081811184146107e1575050600081555b8b6107c1565b6107fd60009284845260208420920160051c82018583016116f0565b818355556107db565b6001906020845194019381840155016103e9565b6108349060018701600052848460002091820191016116f0565b886103d8565b60405162461bcd60e51b815260206004820152603560248201527f526f6f74206c696162696c69746965732073756d7320616e64206c696162696c6044820152740d2e8d2cae640dceadac4cae440dad2e6dac2e8c6d605b1b6064820152608490fd5b8235906001600160401b0382116101585760406044358301360360231901126101585760405191604083018381106001600160401b03821117610621576040526001600160401b03602482604435010135116101585761090936602460443584018181013501016115d0565b83526044818135010135916001600160401b0383116101585760249361093c6020949386869536926044350101016115d0565b8382015281520193019290506101e9565b34610158576060366003190112610158576001600160401b036004358181116101585761097e9036906004016115d0565b906024359081116101585760209161099d6109a6923690600401611617565b6044359161180b565b6040519015158152f35b34610158576020366003190112610158576004356001600160401b0381116101585736602382011215610158578060040135906109ec8261159e565b906109fa604051928361157d565b82825260208201906024829460051b820101903682116101585760248101925b828410610fce578585610a2b611675565b60005b8151811015610f4e57610a4181836116dc565b5151604051610a6d60208281610a6081830196878151938492016113a3565b810103808452018261157d565b519020806000526003602052604060002054610f0957610a8d82846116dc565b51600254600160401b81101561062157806001610aad9201600255611442565b919091610ef35780518051906001600160401b038211610621578190610add82610ad78754611492565b87611707565b602090601f8311600114610e8757600092610e7c575b50508160011b916000199060031b1c19161782555b60208101518051906001600160401b038211610621578190610b3a82610b316001880154611492565b60018801611707565b602090601f8311600114610e0a57600092610dff575b50508160011b916000199060031b1c19161760018301555b60408101518051906001600160401b03821161062157610b9882610b8f6002870154611492565b60028701611707565b602090601f8311600114610d8c57606093929160009183610d81575b50508160011b916000199060031b1c19161760028401555b01518051906001600160401b03821161062157610bf982610bf06003860154611492565b60038601611707565b602090601f8311600114610d12576003929160009183610d07575b50508160011b9160001990841b1c1916179101555b600254906000526003602052604060002055610c4581836116dc565b515151151580610cef575b80610cd7575b80610cbf575b15610c6f57610c6a906116cd565b610a2e565b60405162461bcd60e51b815260206004820152602260248201527f496e76616c69642070726f6f66206f662061646472657373206f776e65727368604482015261069760f41b6064820152608490fd5b506060610ccc82846116dc565b510151511515610c5c565b506040610ce482846116dc565b510151511515610c56565b506020610cfc82846116dc565b510151511515610c50565b015190508880610c14565b906003840160005260206000209160005b601f1985168110610d695750918391600193600395601f19811610610d51575b505050811b01910155610c29565b015160001983861b60f8161c19169055888080610d43565b91926020600181928685015181550194019201610d23565b015190508980610bb4565b906002850160005260206000209160005b601f1985168110610de7575091839160019360609695601f19811610610dce575b505050811b016002840155610bcc565b015160001960f88460031b161c19169055898080610dbe565b91926020600181928685015181550194019201610d9d565b015190508880610b50565b9250600185016000526020600020906000935b601f1984168510610e61576001945083601f19811610610e48575b505050811b016001830155610b68565b015160001960f88460031b161c19169055888080610e38565b81810151835560209485019460019093019290910190610e1d565b015190508880610af3565b9250846000526020600020906000935b601f1984168510610ed8576001945083601f19811610610ebf575b505050811b018255610b08565b015160001960f88460031b161c19169055888080610eb2565b81810151835560209485019460019093019290910190610e97565b634e487b7160e01b600052600060045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527f4164647265737320616c726561647920766572696669656400000000000000006044820152606490fd5b506040519060208201906020835251809152604082019060408160051b84010193916000905b828210610fa3577f382315d4d56a6035e1899bffe77d9becefaf5f2650e4323b27854857a045465885870386a1005b90919294602080610fc0600193603f1989820301865289516113eb565b970192019201909291610f74565b83356001600160401b038111610158578201608060231982360301126101585760405191610ffb83611562565b60248201356001600160401b0381116101585761101e90602436918501016115d0565b835260448201356001600160401b0381116101585761104390602436918501016115d0565b602084015260648201356001600160401b0381116101585761106b90602436918501016115d0565b60408401526084820135926001600160401b038411610158576110986020949360248695369201016115d0565b6060820152815201930192610a1a565b3461015857602036600319011261015857600435600254811015610158576110d261114e91611442565b50611178600361116a604051936110f4856110ed81846114cc565b038661157d565b61115c6040516111128161110b81600187016114cc565b038261157d565b61113a6040519361112a856110ed81600285016114cc565b6110ed60405180988193016114cc565b6040519788976080895260808901906113c6565b9087820360208901526113c6565b9085820360408701526113c6565b9083820360608501526113c6565b0390f35b34610158576000366003190112610158576000546040516001600160a01b039091168152602090f35b3461015857600036600319011261015857606060015460ff6040519161ffff80821684528160101c16602084015260201c166040820152f35b34610158576000366003190112610158576111f7611675565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101585760203660031901126101585760043560005260046020526020604060002054604051908152f35b34610158576020806003193601126101585760043561128183611562565b60608084818096528185820152816040820152015280600052600382526040600020541561136757600052600381526040600020546000198101908111611351576112cd600391611442565b509261133a604051946112df86611562565b6040516112f08161110b81856114cc565b86526040516113068161110b81600186016114cc565b8587015260405161131e8161110b81600286016114cc565b604087015261133360405180958193016114cc565b038361157d565b8301526111786040519282849384528301906113eb565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b81526004810183905260146024820152731059191c995cdcc81b9bdd081d995c9a599a595960621b6044820152606490fd5b60005b8381106113b65750506000910152565b81810151838201526020016113a6565b906020916113df815180928185528580860191016113a3565b601f01601f1916010190565b61143f91606061142e61141c61140a85516080865260808601906113c6565b602086015185820360208701526113c6565b604085015184820360408601526113c6565b9201519060608184039101526113c6565b90565b60025481101561147c57600260005260021b7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0190600090565b634e487b7160e01b600052603260045260246000fd5b90600182811c921680156114c2575b60208310146114ac57565b634e487b7160e01b600052602260045260246000fd5b91607f16916114a1565b90600092918054916114dd83611492565b91828252600193848116908160001461153f57506001146114ff575b50505050565b90919394506000526020928360002092846000945b83861061152b5750505050010190388080806114f9565b805485870183015294019385908201611514565b9294505050602093945060ff191683830152151560051b010190388080806114f9565b608081019081106001600160401b0382111761062157604052565b90601f801991011681019081106001600160401b0382111761062157604052565b6001600160401b0381116106215760051b60200190565b6001600160401b03811161062157601f01601f191660200190565b81601f82011215610158578035906115e7826115b5565b926115f5604051948561157d565b8284526020838301011161015857816000926020809301838601378301015290565b81601f820112156101585780359161162e8361159e565b9261163c604051948561157d565b808452602092838086019260051b820101928311610158578301905b828210611666575050505090565b81358152908301908301611658565b6000546001600160a01b0316330361168957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60001981146113515760010190565b805182101561147c5760209160051b010190565b8181106116fb575050565b600081556001016116f0565b9190601f811161171657505050565b611742926000526020600020906020601f840160051c83019310611744575b601f0160051c01906116f0565b565b9091508190611735565b1561175557565b60405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a59081354d5081c9bdbdd60821b6044820152606490fd5b906117978261159e565b6117a4604051918261157d565b82815280926117b5601f199161159e565b019060005b8281106117c657505050565b8060606020809385010152016117ba565b90815180825260208080930193019160005b8281106117f7575050505090565b8351855293810193928101926001016117e9565b909160008181526004936020938585526040938484205490835191600192831015611a36579061184288949392888701511461174e565b6002825b611974575b5050506118759061188786519485938493631e8e1e1360e01b8552898c86015260448501906113c6565b838103600319016024850152906117d7565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa829181611938575b506119305750606494503d1561192a573d906118d8826115b5565b916118e58451938461157d565b8252833d92013e5b5162461bcd60e51b815291820152601760248201527f496e76616c696420696e636c7573696f6e2070726f6f660000000000000000006044820152fd5b506118ed565b935050505090565b9091508481813d831161196d575b611950818361157d565b81010312611969575180151581036119695790386118bd565b8280fd5b503d611946565b909192938551821015611a2f5750818652888852868620600119908401828201838111611a1c5781541115611a09578752818988200101546119b682876116dc565b51036119cf57906119c783926116cd565b889493611846565b865162461bcd60e51b8152808a018990526014602482015273496e76616c696420726f6f742062616c616e636560601b6044820152606490fd5b634e487b7160e01b885260328b52602488fd5b634e487b7160e01b895260118c52602489fd5b939261184b565b634e487b7160e01b865260328952602486fdfea26469706673582212204c697500976b80ebfdb94c86197130f85b4277c7496208d402a9e627925053f264736f6c63430008120033","linkReferences":{},"deployedLinkReferences":{}} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/deployments.json b/tools/polyexen/circuit/solvency/backend/src/contracts/deployments.json new file mode 100644 index 0000000..6896ec0 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/deployments.json @@ -0,0 +1 @@ +{"31337":{"address":"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"}} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/generated/inclusion_verifier.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/inclusion_verifier.rs new file mode 100644 index 0000000..00061bf --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/inclusion_verifier.rs @@ -0,0 +1,38883 @@ +pub use inclusion_verifier::*; +/// 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 inclusion_verifier { + #[rustfmt::skip] + const __ABI: &str = "[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"uint256[]\",\"name\":\"instances\",\"type\":\"uint256[]\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"verifyProof\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]}]"; + ///The parsed JSON ABI of the contract. + pub static INCLUSIONVERIFIER_ABI: ::ethers::contract::Lazy< + ::ethers::core::abi::Abi, + > = ::ethers::contract::Lazy::new(|| { + ::ethers::core::utils::__serde_json::from_str(__ABI) + .expect("ABI is always valid") + }); + #[rustfmt::skip] + const __BYTECODE: &[u8] = &[ + 96, + 128, + 128, + 96, + 64, + 82, + 52, + 97, + 0, + 22, + 87, + 97, + 75, + 149, + 144, + 129, + 97, + 0, + 28, + 130, + 57, + 243, + 91, + 96, + 0, + 128, + 253, + 254, + 96, + 128, + 96, + 64, + 82, + 96, + 4, + 54, + 16, + 21, + 97, + 0, + 18, + 87, + 96, + 0, + 128, + 253, + 91, + 96, + 0, + 128, + 53, + 96, + 224, + 28, + 99, + 30, + 142, + 30, + 19, + 20, + 97, + 0, + 40, + 87, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 0, + 160, + 87, + 96, + 64, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 0, + 160, + 87, + 103, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 96, + 4, + 53, + 129, + 129, + 17, + 97, + 0, + 163, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 0, + 163, + 87, + 128, + 96, + 4, + 1, + 53, + 130, + 129, + 17, + 97, + 0, + 171, + 87, + 54, + 145, + 1, + 96, + 36, + 1, + 17, + 97, + 0, + 167, + 87, + 96, + 36, + 53, + 129, + 129, + 17, + 97, + 0, + 163, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 0, + 163, + 87, + 128, + 96, + 4, + 1, + 53, + 145, + 130, + 17, + 97, + 0, + 163, + 87, + 96, + 36, + 144, + 54, + 146, + 96, + 5, + 27, + 1, + 1, + 17, + 21, + 97, + 4, + 181, + 87, + 91, + 128, + 253, + 91, + 130, + 128, + 253, + 91, + 80, + 128, + 253, + 91, + 131, + 128, + 253, + 91, + 146, + 144, + 96, + 64, + 128, + 145, + 128, + 53, + 149, + 96, + 32, + 130, + 1, + 53, + 144, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 151, + 129, + 106, + 145, + 104, + 113, + 202, + 141, + 60, + 32, + 140, + 22, + 216, + 124, + 253, + 71, + 128, + 96, + 3, + 129, + 128, + 140, + 128, + 9, + 140, + 9, + 8, + 129, + 132, + 128, + 9, + 20, + 145, + 129, + 132, + 16, + 145, + 138, + 16, + 22, + 22, + 22, + 150, + 134, + 82, + 96, + 32, + 134, + 1, + 82, + 1, + 146, + 1, + 144, + 86, + 91, + 96, + 32, + 145, + 96, + 0, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 130, + 82, + 96, + 0, + 82, + 1, + 144, + 96, + 32, + 144, + 86, + 91, + 96, + 32, + 144, + 96, + 1, + 130, + 83, + 96, + 33, + 96, + 0, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 130, + 82, + 96, + 0, + 82, + 1, + 144, + 86, + 91, + 145, + 144, + 145, + 130, + 97, + 15, + 32, + 145, + 130, + 81, + 144, + 97, + 15, + 64, + 146, + 91, + 96, + 31, + 25, + 129, + 1, + 132, + 16, + 97, + 2, + 20, + 87, + 80, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 135, + 82, + 96, + 32, + 128, + 136, + 1, + 82, + 96, + 32, + 96, + 64, + 136, + 1, + 82, + 96, + 96, + 135, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 135, + 1, + 82, + 129, + 96, + 160, + 135, + 1, + 82, + 96, + 32, + 134, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 148, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 97, + 15, + 64, + 16, + 97, + 1, + 250, + 87, + 80, + 80, + 80, + 128, + 97, + 15, + 64, + 81, + 131, + 9, + 145, + 131, + 81, + 144, + 9, + 145, + 82, + 97, + 15, + 64, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 1, + 218, + 86, + 91, + 149, + 146, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 131, + 81, + 144, + 9, + 145, + 130, + 132, + 82, + 96, + 32, + 128, + 145, + 1, + 147, + 1, + 149, + 97, + 1, + 96, + 86, + 91, + 144, + 97, + 1, + 128, + 145, + 96, + 0, + 81, + 96, + 32, + 145, + 91, + 97, + 1, + 96, + 131, + 16, + 97, + 2, + 249, + 87, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 134, + 82, + 96, + 32, + 128, + 135, + 1, + 82, + 96, + 32, + 96, + 64, + 135, + 1, + 82, + 96, + 96, + 134, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 134, + 1, + 82, + 129, + 96, + 160, + 134, + 1, + 82, + 96, + 32, + 133, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 147, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 96, + 32, + 16, + 97, + 2, + 223, + 87, + 80, + 80, + 80, + 128, + 96, + 32, + 81, + 131, + 9, + 145, + 96, + 0, + 81, + 144, + 9, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 2, + 191, + 86, + 91, + 147, + 145, + 144, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 132, + 81, + 144, + 9, + 146, + 131, + 133, + 82, + 1, + 146, + 1, + 147, + 97, + 2, + 72, + 86, + 91, + 144, + 96, + 160, + 145, + 96, + 0, + 81, + 96, + 32, + 145, + 91, + 96, + 128, + 131, + 16, + 97, + 3, + 219, + 87, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 134, + 82, + 96, + 32, + 128, + 135, + 1, + 82, + 96, + 32, + 96, + 64, + 135, + 1, + 82, + 96, + 96, + 134, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 134, + 1, + 82, + 129, + 96, + 160, + 134, + 1, + 82, + 96, + 32, + 133, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 147, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 96, + 32, + 16, + 97, + 3, + 193, + 87, + 80, + 80, + 80, + 128, + 96, + 32, + 81, + 131, + 9, + 145, + 96, + 0, + 81, + 144, + 9, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 3, + 161, + 86, + 91, + 147, + 145, + 144, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 132, + 81, + 144, + 9, + 146, + 131, + 133, + 82, + 1, + 146, + 1, + 147, + 97, + 3, + 43, + 86, + 91, + 145, + 144, + 96, + 64, + 82, + 96, + 96, + 82, + 96, + 64, + 96, + 0, + 96, + 128, + 129, + 96, + 6, + 90, + 250, + 22, + 144, + 86, + 91, + 144, + 96, + 64, + 82, + 96, + 64, + 96, + 0, + 96, + 96, + 129, + 96, + 7, + 90, + 250, + 22, + 144, + 86, + 91, + 145, + 144, + 96, + 192, + 82, + 96, + 224, + 82, + 96, + 64, + 96, + 128, + 128, + 128, + 96, + 6, + 90, + 250, + 22, + 144, + 86, + 91, + 144, + 96, + 192, + 82, + 96, + 64, + 96, + 128, + 96, + 96, + 129, + 96, + 7, + 90, + 250, + 22, + 144, + 86, + 91, + 147, + 146, + 145, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 97, + 8, + 96, + 81, + 96, + 64, + 82, + 97, + 8, + 128, + 81, + 96, + 96, + 82, + 97, + 8, + 160, + 81, + 96, + 128, + 82, + 97, + 8, + 192, + 81, + 96, + 160, + 82, + 96, + 192, + 82, + 96, + 224, + 82, + 97, + 8, + 224, + 81, + 97, + 1, + 0, + 82, + 97, + 9, + 0, + 81, + 97, + 1, + 32, + 82, + 97, + 9, + 32, + 81, + 97, + 1, + 64, + 82, + 97, + 9, + 64, + 81, + 97, + 1, + 96, + 82, + 96, + 32, + 96, + 0, + 97, + 1, + 128, + 129, + 96, + 8, + 90, + 250, + 22, + 96, + 0, + 81, + 22, + 144, + 86, + 91, + 96, + 1, + 127, + 16, + 242, + 139, + 199, + 16, + 168, + 189, + 208, + 13, + 215, + 1, + 223, + 47, + 95, + 196, + 245, + 204, + 219, + 38, + 2, + 56, + 235, + 166, + 248, + 25, + 219, + 105, + 47, + 121, + 220, + 61, + 201, + 97, + 6, + 192, + 82, + 96, + 11, + 97, + 6, + 224, + 82, + 127, + 48, + 94, + 65, + 233, + 18, + 213, + 121, + 245, + 179, + 25, + 59, + 173, + 202, + 177, + 40, + 50, + 28, + 142, + 225, + 203, + 112, + 170, + 57, + 99, + 49, + 185, + 121, + 85, + 61, + 130, + 0, + 1, + 97, + 7, + 0, + 82, + 127, + 20, + 198, + 1, + 133, + 231, + 88, + 133, + 214, + 116, + 219, + 75, + 63, + 125, + 74, + 86, + 148, + 250, + 108, + 1, + 170, + 15, + 83, + 85, + 123, + 6, + 11, + 192, + 74, + 65, + 114, + 112, + 95, + 97, + 7, + 32, + 82, + 127, + 42, + 253, + 78, + 119, + 39, + 63, + 28, + 179, + 67, + 74, + 74, + 102, + 121, + 41, + 5, + 140, + 21, + 107, + 33, + 87, + 60, + 63, + 30, + 252, + 136, + 46, + 112, + 133, + 151, + 215, + 22, + 26, + 97, + 7, + 64, + 82, + 127, + 34, + 181, + 86, + 3, + 88, + 109, + 95, + 196, + 44, + 108, + 20, + 194, + 252, + 39, + 160, + 40, + 194, + 7, + 218, + 139, + 44, + 113, + 203, + 51, + 213, + 73, + 250, + 74, + 43, + 229, + 211, + 2, + 97, + 7, + 96, + 82, + 96, + 4, + 97, + 7, + 128, + 82, + 96, + 0, + 97, + 7, + 160, + 82, + 96, + 0, + 97, + 7, + 192, + 82, + 96, + 0, + 97, + 7, + 224, + 82, + 96, + 0, + 97, + 8, + 0, + 82, + 96, + 1, + 97, + 8, + 32, + 82, + 96, + 2, + 97, + 8, + 64, + 82, + 97, + 8, + 96, + 144, + 127, + 25, + 142, + 147, + 147, + 146, + 13, + 72, + 58, + 114, + 96, + 191, + 183, + 49, + 251, + 93, + 37, + 241, + 170, + 73, + 51, + 53, + 169, + 231, + 18, + 151, + 228, + 133, + 183, + 174, + 243, + 18, + 194, + 130, + 82, + 127, + 24, + 0, + 222, + 239, + 18, + 31, + 30, + 118, + 66, + 106, + 0, + 102, + 94, + 92, + 68, + 121, + 103, + 67, + 34, + 212, + 247, + 94, + 218, + 221, + 70, + 222, + 189, + 92, + 217, + 146, + 246, + 237, + 97, + 8, + 128, + 82, + 127, + 9, + 6, + 137, + 208, + 88, + 95, + 240, + 117, + 236, + 158, + 153, + 173, + 105, + 12, + 51, + 149, + 188, + 75, + 49, + 51, + 112, + 179, + 142, + 243, + 85, + 172, + 218, + 220, + 209, + 34, + 151, + 91, + 97, + 8, + 160, + 82, + 127, + 18, + 200, + 94, + 165, + 219, + 140, + 109, + 235, + 74, + 171, + 113, + 128, + 141, + 203, + 64, + 143, + 227, + 209, + 231, + 105, + 12, + 67, + 211, + 123, + 76, + 230, + 204, + 1, + 102, + 250, + 125, + 170, + 97, + 8, + 192, + 82, + 127, + 38, + 24, + 106, + 45, + 101, + 238, + 77, + 47, + 156, + 154, + 91, + 145, + 248, + 101, + 151, + 211, + 95, + 25, + 44, + 209, + 32, + 202, + 247, + 233, + 53, + 216, + 68, + 61, + 25, + 56, + 226, + 61, + 97, + 8, + 224, + 82, + 127, + 48, + 68, + 31, + 209, + 181, + 211, + 55, + 4, + 130, + 196, + 33, + 82, + 168, + 137, + 144, + 39, + 113, + 105, + 137, + 166, + 153, + 108, + 37, + 53, + 188, + 159, + 127, + 238, + 138, + 174, + 247, + 158, + 97, + 9, + 0, + 82, + 127, + 22, + 243, + 99, + 241, + 3, + 200, + 13, + 123, + 188, + 138, + 211, + 198, + 134, + 126, + 8, + 34, + 187, + 198, + 0, + 11, + 233, + 26, + 70, + 137, + 117, + 92, + 125, + 244, + 2, + 33, + 193, + 69, + 97, + 9, + 32, + 82, + 127, + 43, + 28, + 187, + 62, + 82, + 30, + 223, + 90, + 98, + 45, + 130, + 118, + 42, + 68, + 165, + 230, + 63, + 30, + 80, + 179, + 50, + 215, + 17, + 84, + 164, + 167, + 149, + 141, + 96, + 17, + 222, + 255, + 97, + 9, + 64, + 82, + 127, + 1, + 9, + 32, + 163, + 71, + 24, + 103, + 33, + 109, + 201, + 221, + 107, + 71, + 140, + 22, + 132, + 47, + 181, + 172, + 164, + 52, + 254, + 108, + 155, + 241, + 98, + 44, + 74, + 189, + 112, + 56, + 26, + 97, + 9, + 96, + 82, + 127, + 48, + 14, + 48, + 147, + 15, + 26, + 5, + 37, + 59, + 40, + 182, + 177, + 57, + 242, + 195, + 128, + 37, + 217, + 155, + 122, + 84, + 230, + 65, + 241, + 214, + 255, + 39, + 151, + 209, + 19, + 193, + 24, + 97, + 9, + 128, + 82, + 127, + 5, + 231, + 137, + 151, + 80, + 247, + 171, + 234, + 229, + 209, + 156, + 22, + 102, + 108, + 71, + 97, + 143, + 206, + 129, + 3, + 38, + 177, + 37, + 210, + 83, + 221, + 65, + 251, + 129, + 125, + 214, + 90, + 97, + 9, + 160, + 82, + 127, + 30, + 14, + 57, + 156, + 228, + 111, + 32, + 138, + 179, + 244, + 58, + 173, + 2, + 34, + 244, + 221, + 55, + 184, + 50, + 123, + 159, + 122, + 255, + 250, + 156, + 249, + 238, + 33, + 78, + 36, + 96, + 221, + 97, + 9, + 192, + 82, + 127, + 34, + 39, + 78, + 78, + 253, + 65, + 151, + 221, + 101, + 21, + 153, + 70, + 82, + 213, + 190, + 175, + 204, + 122, + 249, + 67, + 19, + 211, + 62, + 4, + 156, + 245, + 161, + 228, + 100, + 181, + 35, + 149, + 97, + 9, + 224, + 82, + 127, + 14, + 187, + 71, + 14, + 25, + 64, + 159, + 205, + 132, + 192, + 53, + 140, + 4, + 48, + 13, + 195, + 140, + 186, + 2, + 64, + 20, + 29, + 222, + 184, + 153, + 173, + 156, + 202, + 144, + 22, + 122, + 100, + 97, + 10, + 0, + 82, + 127, + 22, + 43, + 175, + 98, + 69, + 226, + 206, + 197, + 155, + 201, + 59, + 194, + 48, + 37, + 39, + 210, + 153, + 205, + 181, + 14, + 16, + 15, + 20, + 137, + 95, + 23, + 15, + 49, + 106, + 42, + 38, + 67, + 97, + 10, + 32, + 82, + 127, + 23, + 42, + 111, + 24, + 62, + 45, + 220, + 6, + 7, + 210, + 63, + 211, + 218, + 244, + 178, + 49, + 16, + 184, + 29, + 138, + 157, + 10, + 78, + 141, + 61, + 7, + 186, + 36, + 160, + 7, + 224, + 75, + 97, + 10, + 64, + 82, + 127, + 34, + 225, + 205, + 191, + 255, + 207, + 207, + 79, + 24, + 207, + 67, + 66, + 237, + 241, + 251, + 38, + 195, + 182, + 229, + 42, + 206, + 61, + 95, + 173, + 207, + 92, + 194, + 97, + 67, + 51, + 186, + 164, + 97, + 10, + 96, + 82, + 127, + 14, + 40, + 223, + 114, + 220, + 198, + 156, + 198, + 68, + 45, + 114, + 246, + 147, + 102, + 25, + 151, + 72, + 10, + 145, + 58, + 195, + 83, + 137, + 14, + 253, + 99, + 168, + 115, + 149, + 151, + 39, + 192, + 97, + 10, + 128, + 82, + 127, + 1, + 2, + 26, + 81, + 56, + 65, + 36, + 198, + 132, + 79, + 43, + 160, + 228, + 14, + 37, + 69, + 242, + 111, + 40, + 10, + 121, + 116, + 92, + 145, + 100, + 176, + 165, + 111, + 30, + 229, + 77, + 86, + 97, + 10, + 160, + 82, + 127, + 37, + 51, + 96, + 123, + 166, + 241, + 83, + 160, + 18, + 106, + 132, + 80, + 163, + 207, + 71, + 148, + 105, + 51, + 201, + 62, + 175, + 105, + 201, + 150, + 35, + 107, + 69, + 96, + 49, + 121, + 201, + 20, + 97, + 10, + 192, + 82, + 127, + 31, + 89, + 190, + 129, + 179, + 253, + 125, + 41, + 9, + 48, + 67, + 13, + 32, + 76, + 26, + 134, + 105, + 55, + 134, + 35, + 6, + 215, + 91, + 231, + 15, + 237, + 254, + 19, + 229, + 101, + 206, + 11, + 97, + 10, + 224, + 82, + 127, + 5, + 147, + 28, + 83, + 28, + 208, + 139, + 74, + 169, + 55, + 36, + 82, + 147, + 175, + 129, + 196, + 83, + 47, + 196, + 192, + 19, + 135, + 213, + 181, + 57, + 210, + 159, + 108, + 74, + 224, + 0, + 49, + 97, + 11, + 0, + 82, + 127, + 32, + 59, + 33, + 166, + 72, + 251, + 251, + 150, + 69, + 150, + 64, + 187, + 197, + 180, + 24, + 82, + 221, + 30, + 252, + 18, + 9, + 200, + 155, + 99, + 91, + 166, + 56, + 220, + 185, + 41, + 218, + 107, + 97, + 11, + 32, + 82, + 127, + 4, + 231, + 0, + 47, + 6, + 242, + 9, + 26, + 68, + 175, + 205, + 49, + 30, + 147, + 194, + 47, + 70, + 221, + 159, + 50, + 7, + 181, + 188, + 195, + 79, + 12, + 167, + 101, + 32, + 152, + 240, + 151, + 97, + 11, + 64, + 82, + 127, + 32, + 171, + 116, + 144, + 180, + 47, + 63, + 123, + 43, + 11, + 190, + 96, + 26, + 9, + 215, + 46, + 233, + 63, + 146, + 72, + 1, + 213, + 151, + 244, + 140, + 242, + 212, + 67, + 117, + 29, + 95, + 145, + 97, + 11, + 96, + 82, + 127, + 43, + 202, + 47, + 23, + 98, + 148, + 106, + 5, + 251, + 22, + 50, + 85, + 12, + 108, + 177, + 44, + 2, + 209, + 141, + 155, + 238, + 91, + 221, + 66, + 18, + 202, + 115, + 66, + 136, + 135, + 32, + 253, + 97, + 11, + 128, + 82, + 127, + 42, + 171, + 165, + 70, + 205, + 217, + 150, + 158, + 240, + 174, + 204, + 133, + 178, + 170, + 161, + 155, + 110, + 150, + 57, + 135, + 153, + 98, + 102, + 20, + 21, + 200, + 240, + 223, + 66, + 107, + 172, + 12, + 97, + 11, + 160, + 82, + 127, + 18, + 177, + 83, + 39, + 188, + 251, + 231, + 217, + 233, + 222, + 27, + 198, + 72, + 186, + 59, + 223, + 145, + 0, + 135, + 54, + 33, + 121, + 160, + 180, + 3, + 207, + 112, + 186, + 209, + 192, + 147, + 200, + 97, + 11, + 192, + 82, + 127, + 37, + 144, + 157, + 183, + 35, + 168, + 2, + 31, + 254, + 8, + 140, + 80, + 82, + 93, + 109, + 38, + 15, + 145, + 87, + 190, + 122, + 124, + 25, + 75, + 111, + 49, + 83, + 134, + 164, + 108, + 218, + 184, + 97, + 11, + 224, + 82, + 127, + 37, + 203, + 234, + 232, + 236, + 42, + 138, + 47, + 116, + 132, + 79, + 94, + 50, + 118, + 237, + 148, + 7, + 153, + 7, + 190, + 214, + 215, + 177, + 178, + 110, + 214, + 149, + 50, + 143, + 231, + 188, + 174, + 97, + 12, + 0, + 82, + 127, + 38, + 191, + 253, + 38, + 221, + 143, + 95, + 118, + 121, + 40, + 31, + 141, + 26, + 67, + 38, + 144, + 224, + 123, + 21, + 203, + 223, + 104, + 79, + 228, + 86, + 170, + 18, + 119, + 81, + 94, + 23, + 48, + 97, + 12, + 32, + 82, + 127, + 1, + 90, + 63, + 9, + 200, + 42, + 119, + 10, + 105, + 214, + 117, + 131, + 215, + 4, + 157, + 131, + 214, + 155, + 123, + 142, + 3, + 211, + 132, + 132, + 73, + 114, + 21, + 205, + 197, + 151, + 149, + 86, + 97, + 12, + 64, + 82, + 127, + 30, + 228, + 36, + 30, + 145, + 172, + 57, + 23, + 86, + 176, + 185, + 137, + 58, + 193, + 227, + 78, + 169, + 92, + 109, + 214, + 137, + 231, + 220, + 161, + 44, + 98, + 166, + 206, + 148, + 57, + 96, + 241, + 97, + 12, + 96, + 82, + 127, + 16, + 173, + 117, + 241, + 153, + 191, + 31, + 185, + 51, + 91, + 145, + 194, + 13, + 182, + 205, + 137, + 88, + 220, + 178, + 254, + 17, + 152, + 59, + 199, + 124, + 219, + 64, + 54, + 229, + 126, + 89, + 202, + 97, + 12, + 128, + 82, + 127, + 5, + 235, + 93, + 25, + 229, + 137, + 193, + 30, + 11, + 178, + 32, + 13, + 102, + 218, + 130, + 153, + 85, + 84, + 84, + 129, + 136, + 92, + 251, + 201, + 9, + 158, + 198, + 165, + 62, + 38, + 110, + 210, + 97, + 12, + 160, + 82, + 127, + 37, + 172, + 29, + 152, + 73, + 249, + 244, + 72, + 206, + 204, + 126, + 173, + 125, + 72, + 103, + 15, + 102, + 187, + 254, + 125, + 248, + 226, + 72, + 189, + 129, + 138, + 149, + 77, + 246, + 147, + 108, + 39, + 97, + 12, + 192, + 82, + 127, + 7, + 67, + 234, + 64, + 241, + 64, + 132, + 219, + 38, + 115, + 33, + 114, + 131, + 170, + 5, + 63, + 152, + 104, + 150, + 238, + 124, + 24, + 31, + 82, + 17, + 132, + 66, + 233, + 156, + 69, + 41, + 116, + 97, + 12, + 224, + 82, + 127, + 2, + 3, + 227, + 73, + 58, + 37, + 148, + 236, + 229, + 125, + 34, + 204, + 117, + 221, + 8, + 26, + 198, + 130, + 113, + 236, + 124, + 117, + 129, + 83, + 207, + 210, + 21, + 43, + 251, + 92, + 25, + 227, + 97, + 13, + 0, + 82, + 127, + 27, + 149, + 197, + 220, + 155, + 174, + 15, + 179, + 248, + 32, + 134, + 132, + 4, + 46, + 87, + 224, + 252, + 251, + 195, + 119, + 74, + 249, + 174, + 9, + 3, + 171, + 158, + 157, + 219, + 79, + 137, + 253, + 97, + 13, + 32, + 82, + 127, + 30, + 133, + 100, + 224, + 20, + 25, + 113, + 55, + 57, + 135, + 18, + 36, + 206, + 21, + 244, + 196, + 181, + 30, + 106, + 241, + 97, + 214, + 224, + 122, + 23, + 142, + 101, + 69, + 135, + 144, + 53, + 191, + 97, + 13, + 64, + 82, + 127, + 28, + 239, + 200, + 137, + 99, + 156, + 249, + 143, + 148, + 216, + 49, + 234, + 65, + 195, + 86, + 146, + 159, + 147, + 23, + 119, + 141, + 218, + 5, + 186, + 12, + 88, + 133, + 64, + 22, + 56, + 219, + 103, + 97, + 13, + 96, + 82, + 127, + 30, + 4, + 102, + 222, + 178, + 42, + 134, + 217, + 18, + 43, + 199, + 24, + 11, + 125, + 41, + 62, + 71, + 40, + 130, + 68, + 171, + 241, + 69, + 10, + 92, + 214, + 58, + 50, + 137, + 164, + 87, + 202, + 97, + 13, + 128, + 82, + 97, + 8, + 196, + 53, + 96, + 4, + 20, + 145, + 96, + 68, + 53, + 20, + 22, + 22, + 127, + 16, + 242, + 139, + 199, + 16, + 168, + 189, + 208, + 13, + 215, + 1, + 223, + 47, + 95, + 196, + 245, + 204, + 219, + 38, + 2, + 56, + 235, + 166, + 248, + 25, + 219, + 105, + 47, + 121, + 220, + 61, + 201, + 96, + 0, + 82, + 96, + 32, + 144, + 97, + 8, + 228, + 91, + 97, + 9, + 100, + 129, + 16, + 97, + 74, + 121, + 87, + 80, + 96, + 100, + 145, + 91, + 97, + 1, + 36, + 131, + 16, + 97, + 74, + 102, + 87, + 96, + 0, + 144, + 129, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 97, + 13, + 160, + 82, + 144, + 82, + 97, + 13, + 192, + 145, + 96, + 32, + 96, + 128, + 130, + 1, + 91, + 128, + 131, + 16, + 97, + 74, + 79, + 87, + 80, + 97, + 12, + 64, + 144, + 97, + 12, + 71, + 148, + 97, + 1, + 7, + 86, + 91, + 147, + 144, + 97, + 1, + 42, + 86, + 91, + 146, + 97, + 1, + 0, + 130, + 1, + 147, + 91, + 132, + 131, + 16, + 97, + 74, + 58, + 87, + 144, + 97, + 12, + 96, + 145, + 97, + 1, + 7, + 86, + 91, + 97, + 1, + 64, + 131, + 1, + 147, + 145, + 91, + 132, + 132, + 16, + 97, + 74, + 41, + 87, + 144, + 97, + 12, + 121, + 145, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 97, + 4, + 96, + 130, + 1, + 91, + 128, + 131, + 16, + 97, + 74, + 0, + 87, + 80, + 97, + 12, + 167, + 97, + 12, + 182, + 146, + 97, + 12, + 160, + 97, + 12, + 190, + 150, + 97, + 12, + 173, + 148, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 97, + 1, + 42, + 86, + 91, + 148, + 97, + 0, + 175, + 86, + 91, + 144, + 146, + 145, + 147, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 80, + 97, + 0, + 175, + 86, + 91, + 80, + 80, + 128, + 97, + 7, + 160, + 81, + 97, + 73, + 0, + 87, + 91, + 80, + 128, + 21, + 97, + 70, + 136, + 87, + 97, + 6, + 224, + 81, + 97, + 14, + 32, + 81, + 144, + 129, + 144, + 96, + 0, + 144, + 91, + 128, + 130, + 16, + 97, + 72, + 226, + 87, + 80, + 80, + 97, + 7, + 32, + 81, + 146, + 97, + 15, + 32, + 97, + 7, + 128, + 81, + 146, + 96, + 6, + 132, + 1, + 96, + 5, + 27, + 128, + 131, + 1, + 148, + 21, + 97, + 72, + 214, + 87, + 91, + 80, + 97, + 7, + 96, + 81, + 91, + 132, + 131, + 16, + 97, + 72, + 177, + 87, + 80, + 80, + 80, + 97, + 13, + 90, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 240, + 0, + 0, + 0, + 133, + 8, + 145, + 130, + 132, + 82, + 96, + 32, + 132, + 1, + 144, + 97, + 1, + 80, + 86, + 91, + 147, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 15, + 32, + 146, + 97, + 7, + 0, + 81, + 144, + 9, + 145, + 97, + 7, + 96, + 81, + 91, + 132, + 130, + 16, + 97, + 72, + 139, + 87, + 80, + 80, + 80, + 80, + 97, + 15, + 64, + 81, + 97, + 15, + 96, + 145, + 91, + 97, + 15, + 224, + 131, + 16, + 97, + 72, + 107, + 87, + 96, + 0, + 146, + 97, + 8, + 228, + 144, + 97, + 7, + 128, + 81, + 96, + 5, + 27, + 130, + 1, + 144, + 91, + 129, + 131, + 16, + 97, + 72, + 67, + 87, + 80, + 80, + 80, + 81, + 145, + 97, + 15, + 32, + 81, + 145, + 97, + 15, + 224, + 81, + 144, + 133, + 97, + 15, + 32, + 82, + 132, + 97, + 15, + 64, + 82, + 131, + 97, + 15, + 96, + 82, + 128, + 97, + 15, + 128, + 82, + 129, + 97, + 15, + 160, + 82, + 130, + 97, + 15, + 192, + 82, + 97, + 14, + 0, + 81, + 146, + 131, + 128, + 146, + 129, + 97, + 13, + 224, + 81, + 147, + 129, + 97, + 13, + 192, + 81, + 147, + 129, + 97, + 14, + 32, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 135, + 9, + 153, + 129, + 141, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 4, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 1, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 157, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 157, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 141, + 97, + 5, + 68, + 53, + 8, + 139, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 1, + 0, + 97, + 4, + 36, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 3, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 164, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 141, + 97, + 8, + 36, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 141, + 97, + 7, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 196, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 1, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 156, + 97, + 7, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 129, + 3, + 145, + 128, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 155, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 164, + 53, + 129, + 3, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 136, + 8, + 154, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 138, + 135, + 8, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 132, + 97, + 6, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 196, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 131, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 145, + 97, + 6, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 196, + 53, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 152, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 8, + 130, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 4, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 131, + 97, + 6, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 132, + 53, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 100, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 134, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 68, + 53, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 146, + 130, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 132, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 4, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 145, + 128, + 97, + 6, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 132, + 53, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 100, + 53, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 97, + 6, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 147, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 68, + 53, + 129, + 3, + 97, + 7, + 100, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 131, + 9, + 147, + 97, + 7, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 129, + 3, + 145, + 128, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 4, + 53, + 130, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 4, + 100, + 53, + 97, + 4, + 4, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 100, + 53, + 97, + 3, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 129, + 3, + 96, + 1, + 8, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 68, + 53, + 129, + 3, + 97, + 4, + 132, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 164, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 22, + 169, + 233, + 140, + 73, + 58, + 144, + 43, + 149, + 2, + 5, + 78, + 220, + 3, + 231, + 178, + 43, + 126, + 172, + 52, + 52, + 89, + 97, + 188, + 138, + 188, + 237, + 107, + 209, + 71, + 200, + 190, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 15, + 193, + 201, + 57, + 77, + 184, + 155, + 178, + 96, + 26, + 188, + 73, + 253, + 173, + 79, + 3, + 140, + 229, + 22, + 144, + 48, + 162, + 173, + 105, + 118, + 63, + 120, + 117, + 3, + 107, + 203, + 2, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 228, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 30, + 185, + 225, + 220, + 25, + 163, + 58, + 98, + 76, + 152, + 98, + 161, + 217, + 125, + 21, + 16, + 189, + 82, + 30, + 173, + 93, + 254, + 3, + 69, + 170, + 246, + 24, + 91, + 26, + 30, + 96, + 254, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 19, + 171, + 236, + 57, + 10, + 218, + 127, + 67, + 112, + 129, + 154, + 177, + 199, + 132, + 111, + 33, + 5, + 84, + 86, + 157, + 155, + 41, + 209, + 234, + 141, + 190, + 189, + 15, + 168, + 197, + 62, + 102, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 196, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 228, + 53, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 228, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 68, + 53, + 129, + 3, + 97, + 4, + 132, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 164, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 22, + 169, + 233, + 140, + 73, + 58, + 144, + 43, + 149, + 2, + 5, + 78, + 220, + 3, + 231, + 178, + 43, + 126, + 172, + 52, + 52, + 89, + 97, + 188, + 138, + 188, + 237, + 107, + 209, + 71, + 200, + 190, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 15, + 193, + 201, + 57, + 77, + 184, + 155, + 178, + 96, + 26, + 188, + 73, + 253, + 173, + 79, + 3, + 140, + 229, + 22, + 144, + 48, + 162, + 173, + 105, + 118, + 63, + 120, + 117, + 3, + 107, + 203, + 2, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 228, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 30, + 185, + 225, + 220, + 25, + 163, + 58, + 98, + 76, + 152, + 98, + 161, + 217, + 125, + 21, + 16, + 189, + 82, + 30, + 173, + 93, + 254, + 3, + 69, + 170, + 246, + 24, + 91, + 26, + 30, + 96, + 254, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 19, + 171, + 236, + 57, + 10, + 218, + 127, + 67, + 112, + 129, + 154, + 177, + 199, + 132, + 111, + 33, + 5, + 84, + 86, + 157, + 155, + 41, + 209, + 234, + 141, + 190, + 189, + 15, + 168, + 197, + 62, + 102, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 196, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 164, + 53, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 164, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 15, + 224, + 82, + 97, + 3, + 164, + 53, + 96, + 0, + 82, + 97, + 3, + 196, + 53, + 96, + 32, + 82, + 97, + 3, + 100, + 144, + 91, + 129, + 97, + 2, + 100, + 16, + 97, + 72, + 27, + 87, + 130, + 96, + 0, + 81, + 97, + 16, + 0, + 82, + 96, + 32, + 81, + 97, + 16, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 128, + 97, + 14, + 32, + 81, + 129, + 128, + 128, + 97, + 7, + 32, + 81, + 129, + 97, + 7, + 64, + 81, + 128, + 152, + 129, + 136, + 129, + 153, + 151, + 130, + 152, + 150, + 131, + 151, + 9, + 97, + 4, + 32, + 82, + 128, + 97, + 4, + 0, + 82, + 130, + 130, + 130, + 9, + 97, + 3, + 224, + 82, + 9, + 9, + 9, + 9, + 9, + 9, + 97, + 3, + 192, + 82, + 97, + 14, + 128, + 81, + 97, + 4, + 64, + 97, + 3, + 192, + 144, + 91, + 97, + 4, + 192, + 129, + 16, + 97, + 71, + 247, + 87, + 131, + 97, + 4, + 96, + 81, + 97, + 4, + 128, + 81, + 144, + 97, + 4, + 160, + 81, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 132, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 192, + 82, + 97, + 4, + 64, + 81, + 145, + 130, + 97, + 4, + 224, + 82, + 130, + 96, + 0, + 82, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 133, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 0, + 82, + 128, + 97, + 5, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 132, + 9, + 97, + 5, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 132, + 9, + 97, + 5, + 96, + 82, + 97, + 3, + 224, + 81, + 145, + 97, + 4, + 0, + 81, + 147, + 129, + 97, + 4, + 32, + 81, + 145, + 132, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 136, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 129, + 3, + 137, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 32, + 82, + 135, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 129, + 3, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 138, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 64, + 82, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 133, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 134, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 96, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 96, + 1, + 9, + 96, + 128, + 82, + 97, + 3, + 192, + 81, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 129, + 3, + 131, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 129, + 3, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 160, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 135, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 138, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 192, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 129, + 3, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 224, + 82, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 129, + 3, + 135, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 0, + 82, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 129, + 3, + 131, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 96, + 82, + 97, + 63, + 255, + 144, + 97, + 2, + 60, + 86, + 91, + 96, + 0, + 81, + 128, + 97, + 4, + 224, + 82, + 97, + 5, + 0, + 91, + 97, + 5, + 128, + 129, + 16, + 97, + 71, + 217, + 87, + 97, + 14, + 64, + 81, + 96, + 32, + 81, + 96, + 64, + 81, + 96, + 96, + 81, + 134, + 147, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 4, + 36, + 53, + 132, + 9, + 129, + 134, + 129, + 134, + 129, + 135, + 129, + 139, + 129, + 128, + 97, + 3, + 228, + 53, + 131, + 9, + 151, + 129, + 128, + 128, + 128, + 128, + 97, + 4, + 164, + 53, + 134, + 9, + 154, + 97, + 4, + 68, + 53, + 144, + 9, + 149, + 97, + 4, + 4, + 53, + 144, + 9, + 146, + 97, + 4, + 132, + 53, + 144, + 9, + 96, + 0, + 8, + 8, + 8, + 9, + 8, + 8, + 8, + 97, + 5, + 128, + 82, + 96, + 128, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 15, + 224, + 81, + 131, + 9, + 129, + 132, + 129, + 128, + 97, + 6, + 36, + 53, + 135, + 9, + 96, + 0, + 8, + 9, + 8, + 97, + 6, + 228, + 91, + 128, + 97, + 6, + 36, + 16, + 97, + 71, + 180, + 87, + 80, + 97, + 6, + 4, + 91, + 128, + 97, + 4, + 164, + 16, + 97, + 71, + 143, + 87, + 80, + 97, + 5, + 0, + 81, + 144, + 131, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 134, + 9, + 146, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 135, + 9, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 160, + 82, + 96, + 160, + 81, + 96, + 192, + 81, + 96, + 224, + 81, + 146, + 97, + 5, + 32, + 81, + 97, + 7, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 4, + 53, + 133, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 68, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 192, + 82, + 97, + 1, + 0, + 81, + 149, + 97, + 1, + 32, + 81, + 149, + 97, + 5, + 64, + 81, + 144, + 97, + 7, + 132, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 137, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 100, + 53, + 139, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 196, + 53, + 139, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 164, + 53, + 141, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 224, + 82, + 97, + 1, + 64, + 81, + 152, + 97, + 1, + 96, + 81, + 152, + 97, + 5, + 96, + 81, + 97, + 7, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 140, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 4, + 53, + 142, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 6, + 0, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 32, + 82, + 97, + 6, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 96, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 128, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 160, + 82, + 97, + 6, + 32, + 96, + 0, + 91, + 96, + 160, + 129, + 16, + 97, + 71, + 127, + 87, + 97, + 67, + 196, + 131, + 97, + 3, + 32, + 86, + 91, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 0, + 81, + 96, + 128, + 81, + 9, + 97, + 14, + 96, + 81, + 145, + 144, + 96, + 96, + 97, + 5, + 224, + 91, + 96, + 160, + 130, + 16, + 97, + 71, + 84, + 87, + 132, + 97, + 68, + 76, + 97, + 68, + 61, + 97, + 68, + 37, + 97, + 68, + 24, + 136, + 136, + 97, + 16, + 64, + 82, + 96, + 164, + 53, + 96, + 0, + 82, + 96, + 196, + 53, + 96, + 32, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 25, + 86, + 91, + 96, + 132, + 53, + 144, + 96, + 100, + 53, + 144, + 97, + 4, + 2, + 86, + 91, + 97, + 2, + 100, + 53, + 96, + 128, + 82, + 97, + 2, + 132, + 53, + 96, + 160, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 16, + 32, + 81, + 144, + 97, + 16, + 0, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 13, + 96, + 91, + 128, + 97, + 10, + 32, + 16, + 97, + 71, + 42, + 87, + 97, + 70, + 120, + 97, + 70, + 25, + 97, + 69, + 60, + 97, + 69, + 241, + 97, + 69, + 60, + 97, + 69, + 201, + 97, + 69, + 60, + 137, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 69, + 168, + 97, + 69, + 60, + 97, + 69, + 155, + 97, + 69, + 140, + 143, + 97, + 69, + 108, + 97, + 69, + 60, + 135, + 97, + 69, + 73, + 97, + 69, + 60, + 140, + 131, + 97, + 69, + 47, + 97, + 69, + 33, + 97, + 68, + 219, + 97, + 69, + 18, + 97, + 68, + 219, + 97, + 69, + 3, + 97, + 68, + 219, + 97, + 68, + 244, + 136, + 159, + 97, + 68, + 229, + 97, + 68, + 219, + 97, + 68, + 204, + 97, + 68, + 219, + 147, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 9, + 192, + 81, + 144, + 97, + 9, + 160, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 9, + 128, + 81, + 144, + 97, + 9, + 96, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 10, + 64, + 81, + 144, + 97, + 10, + 32, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 10, + 0, + 81, + 144, + 97, + 9, + 224, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 1, + 132, + 53, + 144, + 97, + 1, + 100, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 1, + 4, + 53, + 144, + 96, + 228, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 145, + 97, + 5, + 0, + 81, + 144, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 96, + 160, + 81, + 144, + 96, + 128, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 154, + 97, + 14, + 96, + 81, + 144, + 9, + 153, + 97, + 1, + 164, + 53, + 96, + 128, + 82, + 97, + 1, + 196, + 53, + 96, + 160, + 82, + 131, + 97, + 5, + 32, + 81, + 140, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 151, + 97, + 14, + 96, + 81, + 144, + 9, + 150, + 97, + 2, + 36, + 53, + 96, + 128, + 82, + 97, + 2, + 68, + 53, + 96, + 160, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 2, + 4, + 53, + 144, + 97, + 1, + 228, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 131, + 97, + 5, + 64, + 81, + 135, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 146, + 97, + 14, + 96, + 81, + 144, + 9, + 97, + 1, + 36, + 53, + 96, + 128, + 82, + 97, + 1, + 68, + 53, + 96, + 160, + 82, + 97, + 5, + 96, + 81, + 144, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 32, + 81, + 96, + 128, + 82, + 97, + 8, + 64, + 81, + 96, + 160, + 82, + 97, + 16, + 64, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 68, + 53, + 96, + 128, + 82, + 97, + 8, + 100, + 53, + 96, + 160, + 82, + 97, + 4, + 192, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 132, + 53, + 128, + 96, + 128, + 82, + 97, + 70, + 58, + 97, + 69, + 60, + 97, + 8, + 164, + 53, + 147, + 132, + 96, + 160, + 82, + 97, + 14, + 128, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 144, + 96, + 0, + 81, + 145, + 97, + 16, + 96, + 145, + 131, + 131, + 82, + 96, + 32, + 81, + 97, + 16, + 128, + 148, + 129, + 134, + 82, + 97, + 16, + 160, + 150, + 131, + 136, + 82, + 97, + 16, + 192, + 147, + 129, + 133, + 82, + 97, + 7, + 160, + 81, + 97, + 70, + 141, + 87, + 91, + 80, + 80, + 80, + 80, + 81, + 147, + 81, + 146, + 81, + 145, + 81, + 144, + 97, + 4, + 85, + 86, + 91, + 21, + 97, + 70, + 136, + 87, + 96, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 243, + 91, + 96, + 0, + 128, + 253, + 91, + 145, + 97, + 71, + 11, + 147, + 145, + 97, + 71, + 22, + 149, + 150, + 147, + 97, + 14, + 160, + 81, + 96, + 0, + 82, + 97, + 14, + 192, + 81, + 96, + 32, + 82, + 97, + 14, + 224, + 147, + 132, + 81, + 96, + 64, + 82, + 97, + 15, + 0, + 147, + 132, + 81, + 96, + 96, + 82, + 96, + 128, + 82, + 96, + 160, + 82, + 96, + 192, + 82, + 96, + 224, + 82, + 97, + 70, + 243, + 97, + 70, + 232, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 1, + 0, + 96, + 0, + 32, + 6, + 128, + 149, + 97, + 4, + 25, + 86, + 91, + 137, + 81, + 144, + 137, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 145, + 96, + 0, + 81, + 136, + 82, + 96, + 32, + 81, + 137, + 82, + 81, + 96, + 0, + 82, + 81, + 96, + 32, + 82, + 97, + 4, + 25, + 86, + 91, + 130, + 81, + 144, + 134, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 144, + 96, + 0, + 81, + 133, + 82, + 96, + 32, + 81, + 129, + 82, + 134, + 128, + 128, + 128, + 97, + 70, + 103, + 86, + 91, + 144, + 97, + 71, + 60, + 97, + 71, + 74, + 145, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 96, + 32, + 131, + 1, + 81, + 144, + 131, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 144, + 96, + 63, + 25, + 1, + 97, + 68, + 80, + 86, + 91, + 144, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 134, + 129, + 133, + 81, + 135, + 81, + 9, + 146, + 9, + 8, + 145, + 96, + 31, + 25, + 144, + 129, + 1, + 145, + 1, + 97, + 67, + 231, + 86, + 91, + 129, + 81, + 129, + 82, + 96, + 32, + 145, + 130, + 1, + 145, + 1, + 97, + 67, + 179, + 86, + 91, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 133, + 129, + 133, + 53, + 135, + 9, + 146, + 9, + 8, + 144, + 96, + 31, + 25, + 1, + 97, + 64, + 177, + 86, + 91, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 133, + 129, + 133, + 53, + 135, + 9, + 146, + 9, + 8, + 144, + 96, + 31, + 25, + 1, + 97, + 64, + 163, + 86, + 91, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 96, + 32, + 147, + 81, + 9, + 129, + 82, + 1, + 97, + 64, + 11, + 86, + 91, + 96, + 32, + 128, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 81, + 129, + 3, + 134, + 8, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 60, + 86, + 86, + 91, + 144, + 145, + 97, + 72, + 42, + 130, + 97, + 72, + 56, + 146, + 97, + 4, + 25, + 86, + 91, + 96, + 32, + 132, + 1, + 53, + 144, + 132, + 53, + 144, + 97, + 4, + 2, + 86, + 91, + 145, + 96, + 63, + 25, + 1, + 144, + 97, + 59, + 233, + 86, + 91, + 144, + 145, + 148, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 129, + 137, + 53, + 134, + 81, + 9, + 144, + 8, + 150, + 1, + 146, + 145, + 1, + 97, + 13, + 169, + 86, + 91, + 145, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 32, + 145, + 131, + 81, + 144, + 8, + 145, + 1, + 145, + 97, + 13, + 142, + 86, + 91, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 130, + 130, + 128, + 96, + 32, + 149, + 135, + 81, + 9, + 136, + 9, + 133, + 82, + 9, + 145, + 1, + 144, + 97, + 13, + 122, + 86, + 91, + 96, + 32, + 144, + 135, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 130, + 129, + 129, + 3, + 134, + 8, + 134, + 82, + 9, + 146, + 1, + 145, + 97, + 13, + 13, + 86, + 91, + 97, + 15, + 64, + 1, + 147, + 80, + 134, + 97, + 13, + 7, + 86, + 91, + 144, + 146, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 96, + 1, + 146, + 9, + 147, + 1, + 144, + 97, + 12, + 224, + 86, + 91, + 144, + 80, + 97, + 7, + 224, + 81, + 144, + 97, + 8, + 0, + 81, + 145, + 97, + 7, + 192, + 81, + 96, + 5, + 27, + 128, + 97, + 8, + 228, + 1, + 145, + 130, + 53, + 146, + 97, + 8, + 228, + 130, + 96, + 5, + 27, + 132, + 1, + 1, + 53, + 97, + 8, + 228, + 131, + 96, + 6, + 27, + 133, + 1, + 1, + 53, + 144, + 97, + 8, + 228, + 96, + 3, + 133, + 96, + 5, + 27, + 2, + 134, + 1, + 1, + 53, + 149, + 136, + 150, + 91, + 132, + 97, + 8, + 228, + 135, + 96, + 5, + 27, + 137, + 1, + 1, + 129, + 16, + 21, + 97, + 73, + 153, + 87, + 144, + 96, + 32, + 128, + 140, + 147, + 1, + 147, + 132, + 53, + 139, + 27, + 1, + 148, + 129, + 137, + 96, + 5, + 27, + 137, + 1, + 1, + 53, + 139, + 27, + 1, + 149, + 129, + 137, + 96, + 6, + 27, + 137, + 1, + 1, + 53, + 139, + 27, + 1, + 150, + 96, + 3, + 137, + 96, + 5, + 27, + 2, + 1, + 1, + 53, + 137, + 27, + 1, + 151, + 1, + 150, + 147, + 146, + 145, + 144, + 147, + 97, + 73, + 69, + 86, + 91, + 80, + 151, + 148, + 80, + 151, + 80, + 147, + 80, + 147, + 80, + 80, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 151, + 129, + 106, + 145, + 104, + 113, + 202, + 141, + 60, + 32, + 140, + 22, + 216, + 124, + 253, + 71, + 144, + 129, + 96, + 3, + 129, + 128, + 135, + 128, + 9, + 135, + 9, + 8, + 130, + 134, + 128, + 9, + 20, + 145, + 128, + 96, + 3, + 129, + 128, + 138, + 128, + 9, + 138, + 9, + 8, + 144, + 132, + 128, + 9, + 20, + 22, + 22, + 147, + 97, + 14, + 160, + 82, + 97, + 14, + 192, + 82, + 97, + 14, + 224, + 82, + 97, + 15, + 0, + 82, + 129, + 97, + 12, + 202, + 86, + 91, + 145, + 96, + 32, + 129, + 129, + 146, + 53, + 149, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 16, + 22, + 149, + 135, + 82, + 1, + 148, + 1, + 145, + 147, + 145, + 147, + 97, + 12, + 129, + 86, + 91, + 146, + 97, + 74, + 51, + 146, + 97, + 0, + 175, + 86, + 91, + 144, + 146, + 97, + 12, + 104, + 86, + 91, + 146, + 145, + 97, + 74, + 69, + 146, + 97, + 0, + 175, + 86, + 91, + 145, + 146, + 144, + 145, + 144, + 97, + 12, + 79, + 86, + 91, + 147, + 146, + 145, + 97, + 74, + 91, + 146, + 97, + 0, + 175, + 86, + 91, + 146, + 147, + 145, + 146, + 144, + 145, + 97, + 12, + 43, + 86, + 91, + 144, + 145, + 97, + 74, + 113, + 146, + 97, + 0, + 175, + 86, + 91, + 145, + 144, + 145, + 97, + 11, + 251, + 86, + 91, + 144, + 96, + 32, + 128, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 53, + 16, + 22, + 146, + 128, + 53, + 133, + 82, + 1, + 146, + 1, + 145, + 97, + 11, + 237, + 86, + 254, + 6, + 111, + 111, + 133, + 214, + 246, + 138, + 133, + 236, + 16, + 52, + 83, + 81, + 162, + 58, + 58, + 175, + 7, + 243, + 138, + 248, + 201, + 82, + 167, + 188, + 236, + 167, + 11, + 210, + 175, + 122, + 213, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 240, + 0, + 0, + 1, + 18, + 116, + 230, + 73, + 163, + 46, + 211, + 85, + 163, + 26, + 110, + 214, + 151, + 36, + 225, + 173, + 173, + 232, + 87, + 232, + 110, + 181, + 195, + 161, + 33, + 188, + 209, + 71, + 148, + 50, + 3, + 200, + 12, + 197, + 124, + 219, + 176, + 133, + 7, + 214, + 43, + 246, + 122, + 68, + 147, + 204, + 38, + 47, + 182, + 192, + 157, + 85, + 112, + 19, + 255, + 241, + 245, + 115, + 244, + 49, + 34, + 31, + 143, + 249, + 43, + 157, + 75, + 65, + 16, + 201, + 174, + 153, + 119, + 130, + 225, + 80, + 155, + 29, + 15, + 219, + 32, + 167, + 192, + 43, + 189, + 139, + 234, + 115, + 5, + 70, + 43, + 159, + 129, + 37, + 177, + 232, + 9, + 34, + 107, + 110, + 34, + 198, + 240, + 202, + 100, + 236, + 38, + 170, + 212, + 200, + 110, + 113, + 91, + 95, + 137, + 142, + 94, + 150, + 63, + 37, + 135, + 14, + 86, + 187, + 229, + 51, + 233, + 162, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 160, + 229, + 138, + 231, + 221, + 63, + 176, + 244, + 67, + 224, + 208, + 98, + 57, + 92, + 8, + 140, + 114, + 124, + 29, + 76, + 8, + 8, + 82, + 242, + 122, + 18, + 202, + 70, + 28, + 219, + 72, + 109, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The bytecode of the contract. + pub static INCLUSIONVERIFIER_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = &[ + 96, + 128, + 96, + 64, + 82, + 96, + 4, + 54, + 16, + 21, + 97, + 0, + 18, + 87, + 96, + 0, + 128, + 253, + 91, + 96, + 0, + 128, + 53, + 96, + 224, + 28, + 99, + 30, + 142, + 30, + 19, + 20, + 97, + 0, + 40, + 87, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 0, + 160, + 87, + 96, + 64, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 0, + 160, + 87, + 103, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 96, + 4, + 53, + 129, + 129, + 17, + 97, + 0, + 163, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 0, + 163, + 87, + 128, + 96, + 4, + 1, + 53, + 130, + 129, + 17, + 97, + 0, + 171, + 87, + 54, + 145, + 1, + 96, + 36, + 1, + 17, + 97, + 0, + 167, + 87, + 96, + 36, + 53, + 129, + 129, + 17, + 97, + 0, + 163, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 0, + 163, + 87, + 128, + 96, + 4, + 1, + 53, + 145, + 130, + 17, + 97, + 0, + 163, + 87, + 96, + 36, + 144, + 54, + 146, + 96, + 5, + 27, + 1, + 1, + 17, + 21, + 97, + 4, + 181, + 87, + 91, + 128, + 253, + 91, + 130, + 128, + 253, + 91, + 80, + 128, + 253, + 91, + 131, + 128, + 253, + 91, + 146, + 144, + 96, + 64, + 128, + 145, + 128, + 53, + 149, + 96, + 32, + 130, + 1, + 53, + 144, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 151, + 129, + 106, + 145, + 104, + 113, + 202, + 141, + 60, + 32, + 140, + 22, + 216, + 124, + 253, + 71, + 128, + 96, + 3, + 129, + 128, + 140, + 128, + 9, + 140, + 9, + 8, + 129, + 132, + 128, + 9, + 20, + 145, + 129, + 132, + 16, + 145, + 138, + 16, + 22, + 22, + 22, + 150, + 134, + 82, + 96, + 32, + 134, + 1, + 82, + 1, + 146, + 1, + 144, + 86, + 91, + 96, + 32, + 145, + 96, + 0, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 130, + 82, + 96, + 0, + 82, + 1, + 144, + 96, + 32, + 144, + 86, + 91, + 96, + 32, + 144, + 96, + 1, + 130, + 83, + 96, + 33, + 96, + 0, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 130, + 82, + 96, + 0, + 82, + 1, + 144, + 86, + 91, + 145, + 144, + 145, + 130, + 97, + 15, + 32, + 145, + 130, + 81, + 144, + 97, + 15, + 64, + 146, + 91, + 96, + 31, + 25, + 129, + 1, + 132, + 16, + 97, + 2, + 20, + 87, + 80, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 135, + 82, + 96, + 32, + 128, + 136, + 1, + 82, + 96, + 32, + 96, + 64, + 136, + 1, + 82, + 96, + 96, + 135, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 135, + 1, + 82, + 129, + 96, + 160, + 135, + 1, + 82, + 96, + 32, + 134, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 148, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 97, + 15, + 64, + 16, + 97, + 1, + 250, + 87, + 80, + 80, + 80, + 128, + 97, + 15, + 64, + 81, + 131, + 9, + 145, + 131, + 81, + 144, + 9, + 145, + 82, + 97, + 15, + 64, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 1, + 218, + 86, + 91, + 149, + 146, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 131, + 81, + 144, + 9, + 145, + 130, + 132, + 82, + 96, + 32, + 128, + 145, + 1, + 147, + 1, + 149, + 97, + 1, + 96, + 86, + 91, + 144, + 97, + 1, + 128, + 145, + 96, + 0, + 81, + 96, + 32, + 145, + 91, + 97, + 1, + 96, + 131, + 16, + 97, + 2, + 249, + 87, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 134, + 82, + 96, + 32, + 128, + 135, + 1, + 82, + 96, + 32, + 96, + 64, + 135, + 1, + 82, + 96, + 96, + 134, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 134, + 1, + 82, + 129, + 96, + 160, + 134, + 1, + 82, + 96, + 32, + 133, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 147, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 96, + 32, + 16, + 97, + 2, + 223, + 87, + 80, + 80, + 80, + 128, + 96, + 32, + 81, + 131, + 9, + 145, + 96, + 0, + 81, + 144, + 9, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 2, + 191, + 86, + 91, + 147, + 145, + 144, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 132, + 81, + 144, + 9, + 146, + 131, + 133, + 82, + 1, + 146, + 1, + 147, + 97, + 2, + 72, + 86, + 91, + 144, + 96, + 160, + 145, + 96, + 0, + 81, + 96, + 32, + 145, + 91, + 96, + 128, + 131, + 16, + 97, + 3, + 219, + 87, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 146, + 132, + 81, + 144, + 9, + 96, + 32, + 134, + 82, + 96, + 32, + 128, + 135, + 1, + 82, + 96, + 32, + 96, + 64, + 135, + 1, + 82, + 96, + 96, + 134, + 1, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 239, + 255, + 255, + 255, + 96, + 128, + 134, + 1, + 82, + 129, + 96, + 160, + 134, + 1, + 82, + 96, + 32, + 133, + 96, + 192, + 129, + 96, + 5, + 90, + 250, + 22, + 147, + 128, + 81, + 146, + 96, + 31, + 25, + 128, + 146, + 1, + 144, + 91, + 128, + 96, + 32, + 16, + 97, + 3, + 193, + 87, + 80, + 80, + 80, + 128, + 96, + 32, + 81, + 131, + 9, + 145, + 96, + 0, + 81, + 144, + 9, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 86, + 91, + 130, + 128, + 145, + 133, + 128, + 133, + 81, + 137, + 9, + 151, + 130, + 81, + 144, + 9, + 150, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 3, + 161, + 86, + 91, + 147, + 145, + 144, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 132, + 81, + 144, + 9, + 146, + 131, + 133, + 82, + 1, + 146, + 1, + 147, + 97, + 3, + 43, + 86, + 91, + 145, + 144, + 96, + 64, + 82, + 96, + 96, + 82, + 96, + 64, + 96, + 0, + 96, + 128, + 129, + 96, + 6, + 90, + 250, + 22, + 144, + 86, + 91, + 144, + 96, + 64, + 82, + 96, + 64, + 96, + 0, + 96, + 96, + 129, + 96, + 7, + 90, + 250, + 22, + 144, + 86, + 91, + 145, + 144, + 96, + 192, + 82, + 96, + 224, + 82, + 96, + 64, + 96, + 128, + 128, + 128, + 96, + 6, + 90, + 250, + 22, + 144, + 86, + 91, + 144, + 96, + 192, + 82, + 96, + 64, + 96, + 128, + 96, + 96, + 129, + 96, + 7, + 90, + 250, + 22, + 144, + 86, + 91, + 147, + 146, + 145, + 144, + 96, + 0, + 82, + 96, + 32, + 82, + 97, + 8, + 96, + 81, + 96, + 64, + 82, + 97, + 8, + 128, + 81, + 96, + 96, + 82, + 97, + 8, + 160, + 81, + 96, + 128, + 82, + 97, + 8, + 192, + 81, + 96, + 160, + 82, + 96, + 192, + 82, + 96, + 224, + 82, + 97, + 8, + 224, + 81, + 97, + 1, + 0, + 82, + 97, + 9, + 0, + 81, + 97, + 1, + 32, + 82, + 97, + 9, + 32, + 81, + 97, + 1, + 64, + 82, + 97, + 9, + 64, + 81, + 97, + 1, + 96, + 82, + 96, + 32, + 96, + 0, + 97, + 1, + 128, + 129, + 96, + 8, + 90, + 250, + 22, + 96, + 0, + 81, + 22, + 144, + 86, + 91, + 96, + 1, + 127, + 16, + 242, + 139, + 199, + 16, + 168, + 189, + 208, + 13, + 215, + 1, + 223, + 47, + 95, + 196, + 245, + 204, + 219, + 38, + 2, + 56, + 235, + 166, + 248, + 25, + 219, + 105, + 47, + 121, + 220, + 61, + 201, + 97, + 6, + 192, + 82, + 96, + 11, + 97, + 6, + 224, + 82, + 127, + 48, + 94, + 65, + 233, + 18, + 213, + 121, + 245, + 179, + 25, + 59, + 173, + 202, + 177, + 40, + 50, + 28, + 142, + 225, + 203, + 112, + 170, + 57, + 99, + 49, + 185, + 121, + 85, + 61, + 130, + 0, + 1, + 97, + 7, + 0, + 82, + 127, + 20, + 198, + 1, + 133, + 231, + 88, + 133, + 214, + 116, + 219, + 75, + 63, + 125, + 74, + 86, + 148, + 250, + 108, + 1, + 170, + 15, + 83, + 85, + 123, + 6, + 11, + 192, + 74, + 65, + 114, + 112, + 95, + 97, + 7, + 32, + 82, + 127, + 42, + 253, + 78, + 119, + 39, + 63, + 28, + 179, + 67, + 74, + 74, + 102, + 121, + 41, + 5, + 140, + 21, + 107, + 33, + 87, + 60, + 63, + 30, + 252, + 136, + 46, + 112, + 133, + 151, + 215, + 22, + 26, + 97, + 7, + 64, + 82, + 127, + 34, + 181, + 86, + 3, + 88, + 109, + 95, + 196, + 44, + 108, + 20, + 194, + 252, + 39, + 160, + 40, + 194, + 7, + 218, + 139, + 44, + 113, + 203, + 51, + 213, + 73, + 250, + 74, + 43, + 229, + 211, + 2, + 97, + 7, + 96, + 82, + 96, + 4, + 97, + 7, + 128, + 82, + 96, + 0, + 97, + 7, + 160, + 82, + 96, + 0, + 97, + 7, + 192, + 82, + 96, + 0, + 97, + 7, + 224, + 82, + 96, + 0, + 97, + 8, + 0, + 82, + 96, + 1, + 97, + 8, + 32, + 82, + 96, + 2, + 97, + 8, + 64, + 82, + 97, + 8, + 96, + 144, + 127, + 25, + 142, + 147, + 147, + 146, + 13, + 72, + 58, + 114, + 96, + 191, + 183, + 49, + 251, + 93, + 37, + 241, + 170, + 73, + 51, + 53, + 169, + 231, + 18, + 151, + 228, + 133, + 183, + 174, + 243, + 18, + 194, + 130, + 82, + 127, + 24, + 0, + 222, + 239, + 18, + 31, + 30, + 118, + 66, + 106, + 0, + 102, + 94, + 92, + 68, + 121, + 103, + 67, + 34, + 212, + 247, + 94, + 218, + 221, + 70, + 222, + 189, + 92, + 217, + 146, + 246, + 237, + 97, + 8, + 128, + 82, + 127, + 9, + 6, + 137, + 208, + 88, + 95, + 240, + 117, + 236, + 158, + 153, + 173, + 105, + 12, + 51, + 149, + 188, + 75, + 49, + 51, + 112, + 179, + 142, + 243, + 85, + 172, + 218, + 220, + 209, + 34, + 151, + 91, + 97, + 8, + 160, + 82, + 127, + 18, + 200, + 94, + 165, + 219, + 140, + 109, + 235, + 74, + 171, + 113, + 128, + 141, + 203, + 64, + 143, + 227, + 209, + 231, + 105, + 12, + 67, + 211, + 123, + 76, + 230, + 204, + 1, + 102, + 250, + 125, + 170, + 97, + 8, + 192, + 82, + 127, + 38, + 24, + 106, + 45, + 101, + 238, + 77, + 47, + 156, + 154, + 91, + 145, + 248, + 101, + 151, + 211, + 95, + 25, + 44, + 209, + 32, + 202, + 247, + 233, + 53, + 216, + 68, + 61, + 25, + 56, + 226, + 61, + 97, + 8, + 224, + 82, + 127, + 48, + 68, + 31, + 209, + 181, + 211, + 55, + 4, + 130, + 196, + 33, + 82, + 168, + 137, + 144, + 39, + 113, + 105, + 137, + 166, + 153, + 108, + 37, + 53, + 188, + 159, + 127, + 238, + 138, + 174, + 247, + 158, + 97, + 9, + 0, + 82, + 127, + 22, + 243, + 99, + 241, + 3, + 200, + 13, + 123, + 188, + 138, + 211, + 198, + 134, + 126, + 8, + 34, + 187, + 198, + 0, + 11, + 233, + 26, + 70, + 137, + 117, + 92, + 125, + 244, + 2, + 33, + 193, + 69, + 97, + 9, + 32, + 82, + 127, + 43, + 28, + 187, + 62, + 82, + 30, + 223, + 90, + 98, + 45, + 130, + 118, + 42, + 68, + 165, + 230, + 63, + 30, + 80, + 179, + 50, + 215, + 17, + 84, + 164, + 167, + 149, + 141, + 96, + 17, + 222, + 255, + 97, + 9, + 64, + 82, + 127, + 1, + 9, + 32, + 163, + 71, + 24, + 103, + 33, + 109, + 201, + 221, + 107, + 71, + 140, + 22, + 132, + 47, + 181, + 172, + 164, + 52, + 254, + 108, + 155, + 241, + 98, + 44, + 74, + 189, + 112, + 56, + 26, + 97, + 9, + 96, + 82, + 127, + 48, + 14, + 48, + 147, + 15, + 26, + 5, + 37, + 59, + 40, + 182, + 177, + 57, + 242, + 195, + 128, + 37, + 217, + 155, + 122, + 84, + 230, + 65, + 241, + 214, + 255, + 39, + 151, + 209, + 19, + 193, + 24, + 97, + 9, + 128, + 82, + 127, + 5, + 231, + 137, + 151, + 80, + 247, + 171, + 234, + 229, + 209, + 156, + 22, + 102, + 108, + 71, + 97, + 143, + 206, + 129, + 3, + 38, + 177, + 37, + 210, + 83, + 221, + 65, + 251, + 129, + 125, + 214, + 90, + 97, + 9, + 160, + 82, + 127, + 30, + 14, + 57, + 156, + 228, + 111, + 32, + 138, + 179, + 244, + 58, + 173, + 2, + 34, + 244, + 221, + 55, + 184, + 50, + 123, + 159, + 122, + 255, + 250, + 156, + 249, + 238, + 33, + 78, + 36, + 96, + 221, + 97, + 9, + 192, + 82, + 127, + 34, + 39, + 78, + 78, + 253, + 65, + 151, + 221, + 101, + 21, + 153, + 70, + 82, + 213, + 190, + 175, + 204, + 122, + 249, + 67, + 19, + 211, + 62, + 4, + 156, + 245, + 161, + 228, + 100, + 181, + 35, + 149, + 97, + 9, + 224, + 82, + 127, + 14, + 187, + 71, + 14, + 25, + 64, + 159, + 205, + 132, + 192, + 53, + 140, + 4, + 48, + 13, + 195, + 140, + 186, + 2, + 64, + 20, + 29, + 222, + 184, + 153, + 173, + 156, + 202, + 144, + 22, + 122, + 100, + 97, + 10, + 0, + 82, + 127, + 22, + 43, + 175, + 98, + 69, + 226, + 206, + 197, + 155, + 201, + 59, + 194, + 48, + 37, + 39, + 210, + 153, + 205, + 181, + 14, + 16, + 15, + 20, + 137, + 95, + 23, + 15, + 49, + 106, + 42, + 38, + 67, + 97, + 10, + 32, + 82, + 127, + 23, + 42, + 111, + 24, + 62, + 45, + 220, + 6, + 7, + 210, + 63, + 211, + 218, + 244, + 178, + 49, + 16, + 184, + 29, + 138, + 157, + 10, + 78, + 141, + 61, + 7, + 186, + 36, + 160, + 7, + 224, + 75, + 97, + 10, + 64, + 82, + 127, + 34, + 225, + 205, + 191, + 255, + 207, + 207, + 79, + 24, + 207, + 67, + 66, + 237, + 241, + 251, + 38, + 195, + 182, + 229, + 42, + 206, + 61, + 95, + 173, + 207, + 92, + 194, + 97, + 67, + 51, + 186, + 164, + 97, + 10, + 96, + 82, + 127, + 14, + 40, + 223, + 114, + 220, + 198, + 156, + 198, + 68, + 45, + 114, + 246, + 147, + 102, + 25, + 151, + 72, + 10, + 145, + 58, + 195, + 83, + 137, + 14, + 253, + 99, + 168, + 115, + 149, + 151, + 39, + 192, + 97, + 10, + 128, + 82, + 127, + 1, + 2, + 26, + 81, + 56, + 65, + 36, + 198, + 132, + 79, + 43, + 160, + 228, + 14, + 37, + 69, + 242, + 111, + 40, + 10, + 121, + 116, + 92, + 145, + 100, + 176, + 165, + 111, + 30, + 229, + 77, + 86, + 97, + 10, + 160, + 82, + 127, + 37, + 51, + 96, + 123, + 166, + 241, + 83, + 160, + 18, + 106, + 132, + 80, + 163, + 207, + 71, + 148, + 105, + 51, + 201, + 62, + 175, + 105, + 201, + 150, + 35, + 107, + 69, + 96, + 49, + 121, + 201, + 20, + 97, + 10, + 192, + 82, + 127, + 31, + 89, + 190, + 129, + 179, + 253, + 125, + 41, + 9, + 48, + 67, + 13, + 32, + 76, + 26, + 134, + 105, + 55, + 134, + 35, + 6, + 215, + 91, + 231, + 15, + 237, + 254, + 19, + 229, + 101, + 206, + 11, + 97, + 10, + 224, + 82, + 127, + 5, + 147, + 28, + 83, + 28, + 208, + 139, + 74, + 169, + 55, + 36, + 82, + 147, + 175, + 129, + 196, + 83, + 47, + 196, + 192, + 19, + 135, + 213, + 181, + 57, + 210, + 159, + 108, + 74, + 224, + 0, + 49, + 97, + 11, + 0, + 82, + 127, + 32, + 59, + 33, + 166, + 72, + 251, + 251, + 150, + 69, + 150, + 64, + 187, + 197, + 180, + 24, + 82, + 221, + 30, + 252, + 18, + 9, + 200, + 155, + 99, + 91, + 166, + 56, + 220, + 185, + 41, + 218, + 107, + 97, + 11, + 32, + 82, + 127, + 4, + 231, + 0, + 47, + 6, + 242, + 9, + 26, + 68, + 175, + 205, + 49, + 30, + 147, + 194, + 47, + 70, + 221, + 159, + 50, + 7, + 181, + 188, + 195, + 79, + 12, + 167, + 101, + 32, + 152, + 240, + 151, + 97, + 11, + 64, + 82, + 127, + 32, + 171, + 116, + 144, + 180, + 47, + 63, + 123, + 43, + 11, + 190, + 96, + 26, + 9, + 215, + 46, + 233, + 63, + 146, + 72, + 1, + 213, + 151, + 244, + 140, + 242, + 212, + 67, + 117, + 29, + 95, + 145, + 97, + 11, + 96, + 82, + 127, + 43, + 202, + 47, + 23, + 98, + 148, + 106, + 5, + 251, + 22, + 50, + 85, + 12, + 108, + 177, + 44, + 2, + 209, + 141, + 155, + 238, + 91, + 221, + 66, + 18, + 202, + 115, + 66, + 136, + 135, + 32, + 253, + 97, + 11, + 128, + 82, + 127, + 42, + 171, + 165, + 70, + 205, + 217, + 150, + 158, + 240, + 174, + 204, + 133, + 178, + 170, + 161, + 155, + 110, + 150, + 57, + 135, + 153, + 98, + 102, + 20, + 21, + 200, + 240, + 223, + 66, + 107, + 172, + 12, + 97, + 11, + 160, + 82, + 127, + 18, + 177, + 83, + 39, + 188, + 251, + 231, + 217, + 233, + 222, + 27, + 198, + 72, + 186, + 59, + 223, + 145, + 0, + 135, + 54, + 33, + 121, + 160, + 180, + 3, + 207, + 112, + 186, + 209, + 192, + 147, + 200, + 97, + 11, + 192, + 82, + 127, + 37, + 144, + 157, + 183, + 35, + 168, + 2, + 31, + 254, + 8, + 140, + 80, + 82, + 93, + 109, + 38, + 15, + 145, + 87, + 190, + 122, + 124, + 25, + 75, + 111, + 49, + 83, + 134, + 164, + 108, + 218, + 184, + 97, + 11, + 224, + 82, + 127, + 37, + 203, + 234, + 232, + 236, + 42, + 138, + 47, + 116, + 132, + 79, + 94, + 50, + 118, + 237, + 148, + 7, + 153, + 7, + 190, + 214, + 215, + 177, + 178, + 110, + 214, + 149, + 50, + 143, + 231, + 188, + 174, + 97, + 12, + 0, + 82, + 127, + 38, + 191, + 253, + 38, + 221, + 143, + 95, + 118, + 121, + 40, + 31, + 141, + 26, + 67, + 38, + 144, + 224, + 123, + 21, + 203, + 223, + 104, + 79, + 228, + 86, + 170, + 18, + 119, + 81, + 94, + 23, + 48, + 97, + 12, + 32, + 82, + 127, + 1, + 90, + 63, + 9, + 200, + 42, + 119, + 10, + 105, + 214, + 117, + 131, + 215, + 4, + 157, + 131, + 214, + 155, + 123, + 142, + 3, + 211, + 132, + 132, + 73, + 114, + 21, + 205, + 197, + 151, + 149, + 86, + 97, + 12, + 64, + 82, + 127, + 30, + 228, + 36, + 30, + 145, + 172, + 57, + 23, + 86, + 176, + 185, + 137, + 58, + 193, + 227, + 78, + 169, + 92, + 109, + 214, + 137, + 231, + 220, + 161, + 44, + 98, + 166, + 206, + 148, + 57, + 96, + 241, + 97, + 12, + 96, + 82, + 127, + 16, + 173, + 117, + 241, + 153, + 191, + 31, + 185, + 51, + 91, + 145, + 194, + 13, + 182, + 205, + 137, + 88, + 220, + 178, + 254, + 17, + 152, + 59, + 199, + 124, + 219, + 64, + 54, + 229, + 126, + 89, + 202, + 97, + 12, + 128, + 82, + 127, + 5, + 235, + 93, + 25, + 229, + 137, + 193, + 30, + 11, + 178, + 32, + 13, + 102, + 218, + 130, + 153, + 85, + 84, + 84, + 129, + 136, + 92, + 251, + 201, + 9, + 158, + 198, + 165, + 62, + 38, + 110, + 210, + 97, + 12, + 160, + 82, + 127, + 37, + 172, + 29, + 152, + 73, + 249, + 244, + 72, + 206, + 204, + 126, + 173, + 125, + 72, + 103, + 15, + 102, + 187, + 254, + 125, + 248, + 226, + 72, + 189, + 129, + 138, + 149, + 77, + 246, + 147, + 108, + 39, + 97, + 12, + 192, + 82, + 127, + 7, + 67, + 234, + 64, + 241, + 64, + 132, + 219, + 38, + 115, + 33, + 114, + 131, + 170, + 5, + 63, + 152, + 104, + 150, + 238, + 124, + 24, + 31, + 82, + 17, + 132, + 66, + 233, + 156, + 69, + 41, + 116, + 97, + 12, + 224, + 82, + 127, + 2, + 3, + 227, + 73, + 58, + 37, + 148, + 236, + 229, + 125, + 34, + 204, + 117, + 221, + 8, + 26, + 198, + 130, + 113, + 236, + 124, + 117, + 129, + 83, + 207, + 210, + 21, + 43, + 251, + 92, + 25, + 227, + 97, + 13, + 0, + 82, + 127, + 27, + 149, + 197, + 220, + 155, + 174, + 15, + 179, + 248, + 32, + 134, + 132, + 4, + 46, + 87, + 224, + 252, + 251, + 195, + 119, + 74, + 249, + 174, + 9, + 3, + 171, + 158, + 157, + 219, + 79, + 137, + 253, + 97, + 13, + 32, + 82, + 127, + 30, + 133, + 100, + 224, + 20, + 25, + 113, + 55, + 57, + 135, + 18, + 36, + 206, + 21, + 244, + 196, + 181, + 30, + 106, + 241, + 97, + 214, + 224, + 122, + 23, + 142, + 101, + 69, + 135, + 144, + 53, + 191, + 97, + 13, + 64, + 82, + 127, + 28, + 239, + 200, + 137, + 99, + 156, + 249, + 143, + 148, + 216, + 49, + 234, + 65, + 195, + 86, + 146, + 159, + 147, + 23, + 119, + 141, + 218, + 5, + 186, + 12, + 88, + 133, + 64, + 22, + 56, + 219, + 103, + 97, + 13, + 96, + 82, + 127, + 30, + 4, + 102, + 222, + 178, + 42, + 134, + 217, + 18, + 43, + 199, + 24, + 11, + 125, + 41, + 62, + 71, + 40, + 130, + 68, + 171, + 241, + 69, + 10, + 92, + 214, + 58, + 50, + 137, + 164, + 87, + 202, + 97, + 13, + 128, + 82, + 97, + 8, + 196, + 53, + 96, + 4, + 20, + 145, + 96, + 68, + 53, + 20, + 22, + 22, + 127, + 16, + 242, + 139, + 199, + 16, + 168, + 189, + 208, + 13, + 215, + 1, + 223, + 47, + 95, + 196, + 245, + 204, + 219, + 38, + 2, + 56, + 235, + 166, + 248, + 25, + 219, + 105, + 47, + 121, + 220, + 61, + 201, + 96, + 0, + 82, + 96, + 32, + 144, + 97, + 8, + 228, + 91, + 97, + 9, + 100, + 129, + 16, + 97, + 74, + 121, + 87, + 80, + 96, + 100, + 145, + 91, + 97, + 1, + 36, + 131, + 16, + 97, + 74, + 102, + 87, + 96, + 0, + 144, + 129, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 6, + 97, + 13, + 160, + 82, + 144, + 82, + 97, + 13, + 192, + 145, + 96, + 32, + 96, + 128, + 130, + 1, + 91, + 128, + 131, + 16, + 97, + 74, + 79, + 87, + 80, + 97, + 12, + 64, + 144, + 97, + 12, + 71, + 148, + 97, + 1, + 7, + 86, + 91, + 147, + 144, + 97, + 1, + 42, + 86, + 91, + 146, + 97, + 1, + 0, + 130, + 1, + 147, + 91, + 132, + 131, + 16, + 97, + 74, + 58, + 87, + 144, + 97, + 12, + 96, + 145, + 97, + 1, + 7, + 86, + 91, + 97, + 1, + 64, + 131, + 1, + 147, + 145, + 91, + 132, + 132, + 16, + 97, + 74, + 41, + 87, + 144, + 97, + 12, + 121, + 145, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 97, + 4, + 96, + 130, + 1, + 91, + 128, + 131, + 16, + 97, + 74, + 0, + 87, + 80, + 97, + 12, + 167, + 97, + 12, + 182, + 146, + 97, + 12, + 160, + 97, + 12, + 190, + 150, + 97, + 12, + 173, + 148, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 97, + 1, + 42, + 86, + 91, + 148, + 97, + 0, + 175, + 86, + 91, + 144, + 146, + 145, + 147, + 97, + 1, + 7, + 86, + 91, + 146, + 144, + 80, + 97, + 0, + 175, + 86, + 91, + 80, + 80, + 128, + 97, + 7, + 160, + 81, + 97, + 73, + 0, + 87, + 91, + 80, + 128, + 21, + 97, + 70, + 136, + 87, + 97, + 6, + 224, + 81, + 97, + 14, + 32, + 81, + 144, + 129, + 144, + 96, + 0, + 144, + 91, + 128, + 130, + 16, + 97, + 72, + 226, + 87, + 80, + 80, + 97, + 7, + 32, + 81, + 146, + 97, + 15, + 32, + 97, + 7, + 128, + 81, + 146, + 96, + 6, + 132, + 1, + 96, + 5, + 27, + 128, + 131, + 1, + 148, + 21, + 97, + 72, + 214, + 87, + 91, + 80, + 97, + 7, + 96, + 81, + 91, + 132, + 131, + 16, + 97, + 72, + 177, + 87, + 80, + 80, + 80, + 97, + 13, + 90, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 240, + 0, + 0, + 0, + 133, + 8, + 145, + 130, + 132, + 82, + 96, + 32, + 132, + 1, + 144, + 97, + 1, + 80, + 86, + 91, + 147, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 15, + 32, + 146, + 97, + 7, + 0, + 81, + 144, + 9, + 145, + 97, + 7, + 96, + 81, + 91, + 132, + 130, + 16, + 97, + 72, + 139, + 87, + 80, + 80, + 80, + 80, + 97, + 15, + 64, + 81, + 97, + 15, + 96, + 145, + 91, + 97, + 15, + 224, + 131, + 16, + 97, + 72, + 107, + 87, + 96, + 0, + 146, + 97, + 8, + 228, + 144, + 97, + 7, + 128, + 81, + 96, + 5, + 27, + 130, + 1, + 144, + 91, + 129, + 131, + 16, + 97, + 72, + 67, + 87, + 80, + 80, + 80, + 81, + 145, + 97, + 15, + 32, + 81, + 145, + 97, + 15, + 224, + 81, + 144, + 133, + 97, + 15, + 32, + 82, + 132, + 97, + 15, + 64, + 82, + 131, + 97, + 15, + 96, + 82, + 128, + 97, + 15, + 128, + 82, + 129, + 97, + 15, + 160, + 82, + 130, + 97, + 15, + 192, + 82, + 97, + 14, + 0, + 81, + 146, + 131, + 128, + 146, + 129, + 97, + 13, + 224, + 81, + 147, + 129, + 97, + 13, + 192, + 81, + 147, + 129, + 97, + 14, + 32, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 135, + 9, + 153, + 129, + 141, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 4, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 1, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 157, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 129, + 3, + 97, + 7, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 157, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 141, + 97, + 5, + 68, + 53, + 8, + 139, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 1, + 0, + 97, + 4, + 36, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 3, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 164, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 141, + 97, + 8, + 36, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 141, + 97, + 7, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 196, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 1, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 156, + 97, + 7, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 129, + 3, + 145, + 128, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 155, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 164, + 53, + 129, + 3, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 136, + 8, + 154, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 138, + 135, + 8, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 132, + 97, + 6, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 196, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 131, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 145, + 97, + 6, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 196, + 53, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 100, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 152, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 8, + 130, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 4, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 131, + 97, + 6, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 133, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 132, + 53, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 100, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 134, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 68, + 53, + 136, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 146, + 130, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 132, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 64, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 4, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 145, + 128, + 97, + 6, + 164, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 132, + 53, + 131, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 100, + 53, + 132, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 145, + 97, + 6, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 4, + 196, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 7, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 147, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 68, + 53, + 129, + 3, + 97, + 7, + 100, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 131, + 9, + 147, + 97, + 7, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 129, + 3, + 145, + 128, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 4, + 53, + 130, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 97, + 4, + 100, + 53, + 97, + 4, + 4, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 100, + 53, + 97, + 3, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 129, + 3, + 96, + 1, + 8, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 68, + 53, + 129, + 3, + 97, + 4, + 132, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 164, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 3, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 22, + 169, + 233, + 140, + 73, + 58, + 144, + 43, + 149, + 2, + 5, + 78, + 220, + 3, + 231, + 178, + 43, + 126, + 172, + 52, + 52, + 89, + 97, + 188, + 138, + 188, + 237, + 107, + 209, + 71, + 200, + 190, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 15, + 193, + 201, + 57, + 77, + 184, + 155, + 178, + 96, + 26, + 188, + 73, + 253, + 173, + 79, + 3, + 140, + 229, + 22, + 144, + 48, + 162, + 173, + 105, + 118, + 63, + 120, + 117, + 3, + 107, + 203, + 2, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 228, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 30, + 185, + 225, + 220, + 25, + 163, + 58, + 98, + 76, + 152, + 98, + 161, + 217, + 125, + 21, + 16, + 189, + 82, + 30, + 173, + 93, + 254, + 3, + 69, + 170, + 246, + 24, + 91, + 26, + 30, + 96, + 254, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 19, + 171, + 236, + 57, + 10, + 218, + 127, + 67, + 112, + 129, + 154, + 177, + 199, + 132, + 111, + 33, + 5, + 84, + 86, + 157, + 155, + 41, + 209, + 234, + 141, + 190, + 189, + 15, + 168, + 197, + 62, + 102, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 196, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 6, + 4, + 53, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 228, + 53, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 228, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 68, + 53, + 129, + 3, + 97, + 4, + 132, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 3, + 228, + 53, + 97, + 4, + 164, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 4, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 2, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 132, + 53, + 129, + 3, + 96, + 1, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 132, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 22, + 169, + 233, + 140, + 73, + 58, + 144, + 43, + 149, + 2, + 5, + 78, + 220, + 3, + 231, + 178, + 43, + 126, + 172, + 52, + 52, + 89, + 97, + 188, + 138, + 188, + 237, + 107, + 209, + 71, + 200, + 190, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 15, + 193, + 201, + 57, + 77, + 184, + 155, + 178, + 96, + 26, + 188, + 73, + 253, + 173, + 79, + 3, + 140, + 229, + 22, + 144, + 48, + 162, + 173, + 105, + 118, + 63, + 120, + 117, + 3, + 107, + 203, + 2, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 228, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 30, + 185, + 225, + 220, + 25, + 163, + 58, + 98, + 76, + 152, + 98, + 161, + 217, + 125, + 21, + 16, + 189, + 82, + 30, + 173, + 93, + 254, + 3, + 69, + 170, + 246, + 24, + 91, + 26, + 30, + 96, + 254, + 97, + 4, + 68, + 53, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 127, + 19, + 171, + 236, + 57, + 10, + 218, + 127, + 67, + 112, + 129, + 154, + 177, + 199, + 132, + 111, + 33, + 5, + 84, + 86, + 157, + 155, + 41, + 209, + 234, + 141, + 190, + 189, + 15, + 168, + 197, + 62, + 102, + 97, + 4, + 36, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 4, + 196, + 53, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 4, + 196, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 97, + 4, + 100, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 196, + 53, + 9, + 129, + 97, + 4, + 68, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 224, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 0, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 164, + 53, + 9, + 129, + 97, + 4, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 36, + 53, + 97, + 4, + 4, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 75, + 32, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 5, + 4, + 53, + 97, + 3, + 228, + 53, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 160, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 97, + 5, + 164, + 53, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 15, + 224, + 82, + 97, + 3, + 164, + 53, + 96, + 0, + 82, + 97, + 3, + 196, + 53, + 96, + 32, + 82, + 97, + 3, + 100, + 144, + 91, + 129, + 97, + 2, + 100, + 16, + 97, + 72, + 27, + 87, + 130, + 96, + 0, + 81, + 97, + 16, + 0, + 82, + 96, + 32, + 81, + 97, + 16, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 128, + 97, + 14, + 32, + 81, + 129, + 128, + 128, + 97, + 7, + 32, + 81, + 129, + 97, + 7, + 64, + 81, + 128, + 152, + 129, + 136, + 129, + 153, + 151, + 130, + 152, + 150, + 131, + 151, + 9, + 97, + 4, + 32, + 82, + 128, + 97, + 4, + 0, + 82, + 130, + 130, + 130, + 9, + 97, + 3, + 224, + 82, + 9, + 9, + 9, + 9, + 9, + 9, + 97, + 3, + 192, + 82, + 97, + 14, + 128, + 81, + 97, + 4, + 64, + 97, + 3, + 192, + 144, + 91, + 97, + 4, + 192, + 129, + 16, + 97, + 71, + 247, + 87, + 131, + 97, + 4, + 96, + 81, + 97, + 4, + 128, + 81, + 144, + 97, + 4, + 160, + 81, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 132, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 4, + 192, + 82, + 97, + 4, + 64, + 81, + 145, + 130, + 97, + 4, + 224, + 82, + 130, + 96, + 0, + 82, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 133, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 0, + 82, + 128, + 97, + 5, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 132, + 9, + 97, + 5, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 132, + 9, + 97, + 5, + 96, + 82, + 97, + 3, + 224, + 81, + 145, + 97, + 4, + 0, + 81, + 147, + 129, + 97, + 4, + 32, + 81, + 145, + 132, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 136, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 129, + 3, + 137, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 32, + 82, + 135, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 129, + 3, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 138, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 64, + 82, + 129, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 133, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 129, + 3, + 134, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 96, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 136, + 96, + 1, + 9, + 96, + 128, + 82, + 97, + 3, + 192, + 81, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 129, + 3, + 131, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 137, + 129, + 3, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 160, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 135, + 131, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 137, + 8, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 138, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 192, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 129, + 3, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 132, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 96, + 224, + 82, + 133, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 130, + 129, + 3, + 135, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 0, + 82, + 132, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 32, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 129, + 3, + 131, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 1, + 96, + 82, + 97, + 63, + 255, + 144, + 97, + 2, + 60, + 86, + 91, + 96, + 0, + 81, + 128, + 97, + 4, + 224, + 82, + 97, + 5, + 0, + 91, + 97, + 5, + 128, + 129, + 16, + 97, + 71, + 217, + 87, + 97, + 14, + 64, + 81, + 96, + 32, + 81, + 96, + 64, + 81, + 96, + 96, + 81, + 134, + 147, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 4, + 36, + 53, + 132, + 9, + 129, + 134, + 129, + 134, + 129, + 135, + 129, + 139, + 129, + 128, + 97, + 3, + 228, + 53, + 131, + 9, + 151, + 129, + 128, + 128, + 128, + 128, + 97, + 4, + 164, + 53, + 134, + 9, + 154, + 97, + 4, + 68, + 53, + 144, + 9, + 149, + 97, + 4, + 4, + 53, + 144, + 9, + 146, + 97, + 4, + 132, + 53, + 144, + 9, + 96, + 0, + 8, + 8, + 8, + 9, + 8, + 8, + 8, + 97, + 5, + 128, + 82, + 96, + 128, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 15, + 224, + 81, + 131, + 9, + 129, + 132, + 129, + 128, + 97, + 6, + 36, + 53, + 135, + 9, + 96, + 0, + 8, + 9, + 8, + 97, + 6, + 228, + 91, + 128, + 97, + 6, + 36, + 16, + 97, + 71, + 180, + 87, + 80, + 97, + 6, + 4, + 91, + 128, + 97, + 4, + 164, + 16, + 97, + 71, + 143, + 87, + 80, + 97, + 5, + 0, + 81, + 144, + 131, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 4, + 100, + 53, + 134, + 9, + 146, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 36, + 53, + 135, + 9, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 160, + 82, + 96, + 160, + 81, + 96, + 192, + 81, + 96, + 224, + 81, + 146, + 97, + 5, + 32, + 81, + 97, + 7, + 36, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 134, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 4, + 53, + 133, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 68, + 53, + 135, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 192, + 82, + 97, + 1, + 0, + 81, + 149, + 97, + 1, + 32, + 81, + 149, + 97, + 5, + 64, + 81, + 144, + 97, + 7, + 132, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 137, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 100, + 53, + 139, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 196, + 53, + 139, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 7, + 164, + 53, + 141, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 5, + 224, + 82, + 97, + 1, + 64, + 81, + 152, + 97, + 1, + 96, + 81, + 152, + 97, + 5, + 96, + 81, + 97, + 7, + 228, + 53, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 140, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 8, + 4, + 53, + 142, + 9, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 96, + 0, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 9, + 97, + 6, + 0, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 32, + 82, + 97, + 6, + 64, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 96, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 128, + 82, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 8, + 97, + 6, + 160, + 82, + 97, + 6, + 32, + 96, + 0, + 91, + 96, + 160, + 129, + 16, + 97, + 71, + 127, + 87, + 97, + 67, + 196, + 131, + 97, + 3, + 32, + 86, + 91, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 6, + 0, + 81, + 96, + 128, + 81, + 9, + 97, + 14, + 96, + 81, + 145, + 144, + 96, + 96, + 97, + 5, + 224, + 91, + 96, + 160, + 130, + 16, + 97, + 71, + 84, + 87, + 132, + 97, + 68, + 76, + 97, + 68, + 61, + 97, + 68, + 37, + 97, + 68, + 24, + 136, + 136, + 97, + 16, + 64, + 82, + 96, + 164, + 53, + 96, + 0, + 82, + 96, + 196, + 53, + 96, + 32, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 25, + 86, + 91, + 96, + 132, + 53, + 144, + 96, + 100, + 53, + 144, + 97, + 4, + 2, + 86, + 91, + 97, + 2, + 100, + 53, + 96, + 128, + 82, + 97, + 2, + 132, + 53, + 96, + 160, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 16, + 32, + 81, + 144, + 97, + 16, + 0, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 13, + 96, + 91, + 128, + 97, + 10, + 32, + 16, + 97, + 71, + 42, + 87, + 97, + 70, + 120, + 97, + 70, + 25, + 97, + 69, + 60, + 97, + 69, + 241, + 97, + 69, + 60, + 97, + 69, + 201, + 97, + 69, + 60, + 137, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 128, + 97, + 69, + 168, + 97, + 69, + 60, + 97, + 69, + 155, + 97, + 69, + 140, + 143, + 97, + 69, + 108, + 97, + 69, + 60, + 135, + 97, + 69, + 73, + 97, + 69, + 60, + 140, + 131, + 97, + 69, + 47, + 97, + 69, + 33, + 97, + 68, + 219, + 97, + 69, + 18, + 97, + 68, + 219, + 97, + 69, + 3, + 97, + 68, + 219, + 97, + 68, + 244, + 136, + 159, + 97, + 68, + 229, + 97, + 68, + 219, + 97, + 68, + 204, + 97, + 68, + 219, + 147, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 9, + 192, + 81, + 144, + 97, + 9, + 160, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 9, + 128, + 81, + 144, + 97, + 9, + 96, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 10, + 64, + 81, + 144, + 97, + 10, + 32, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 10, + 0, + 81, + 144, + 97, + 9, + 224, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 1, + 132, + 53, + 144, + 97, + 1, + 100, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 97, + 1, + 4, + 53, + 144, + 96, + 228, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 145, + 97, + 5, + 0, + 81, + 144, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 96, + 160, + 81, + 144, + 96, + 128, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 154, + 97, + 14, + 96, + 81, + 144, + 9, + 153, + 97, + 1, + 164, + 53, + 96, + 128, + 82, + 97, + 1, + 196, + 53, + 96, + 160, + 82, + 131, + 97, + 5, + 32, + 81, + 140, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 151, + 97, + 14, + 96, + 81, + 144, + 9, + 150, + 97, + 2, + 36, + 53, + 96, + 128, + 82, + 97, + 2, + 68, + 53, + 96, + 160, + 82, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 2, + 4, + 53, + 144, + 97, + 1, + 228, + 53, + 144, + 97, + 4, + 44, + 86, + 91, + 131, + 97, + 5, + 64, + 81, + 135, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 146, + 97, + 14, + 96, + 81, + 144, + 9, + 97, + 1, + 36, + 53, + 96, + 128, + 82, + 97, + 1, + 68, + 53, + 96, + 160, + 82, + 97, + 5, + 96, + 81, + 144, + 9, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 32, + 81, + 96, + 128, + 82, + 97, + 8, + 64, + 81, + 96, + 160, + 82, + 97, + 16, + 64, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 68, + 53, + 96, + 128, + 82, + 97, + 8, + 100, + 53, + 96, + 160, + 82, + 97, + 4, + 192, + 81, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 3, + 144, + 97, + 4, + 66, + 86, + 91, + 97, + 8, + 132, + 53, + 128, + 96, + 128, + 82, + 97, + 70, + 58, + 97, + 69, + 60, + 97, + 8, + 164, + 53, + 147, + 132, + 96, + 160, + 82, + 97, + 14, + 128, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 144, + 96, + 0, + 81, + 145, + 97, + 16, + 96, + 145, + 131, + 131, + 82, + 96, + 32, + 81, + 97, + 16, + 128, + 148, + 129, + 134, + 82, + 97, + 16, + 160, + 150, + 131, + 136, + 82, + 97, + 16, + 192, + 147, + 129, + 133, + 82, + 97, + 7, + 160, + 81, + 97, + 70, + 141, + 87, + 91, + 80, + 80, + 80, + 80, + 81, + 147, + 81, + 146, + 81, + 145, + 81, + 144, + 97, + 4, + 85, + 86, + 91, + 21, + 97, + 70, + 136, + 87, + 96, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 243, + 91, + 96, + 0, + 128, + 253, + 91, + 145, + 97, + 71, + 11, + 147, + 145, + 97, + 71, + 22, + 149, + 150, + 147, + 97, + 14, + 160, + 81, + 96, + 0, + 82, + 97, + 14, + 192, + 81, + 96, + 32, + 82, + 97, + 14, + 224, + 147, + 132, + 81, + 96, + 64, + 82, + 97, + 15, + 0, + 147, + 132, + 81, + 96, + 96, + 82, + 96, + 128, + 82, + 96, + 160, + 82, + 96, + 192, + 82, + 96, + 224, + 82, + 97, + 70, + 243, + 97, + 70, + 232, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 97, + 1, + 0, + 96, + 0, + 32, + 6, + 128, + 149, + 97, + 4, + 25, + 86, + 91, + 137, + 81, + 144, + 137, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 145, + 96, + 0, + 81, + 136, + 82, + 96, + 32, + 81, + 137, + 82, + 81, + 96, + 0, + 82, + 81, + 96, + 32, + 82, + 97, + 4, + 25, + 86, + 91, + 130, + 81, + 144, + 134, + 81, + 144, + 97, + 4, + 2, + 86, + 91, + 144, + 96, + 0, + 81, + 133, + 82, + 96, + 32, + 81, + 129, + 82, + 134, + 128, + 128, + 128, + 97, + 70, + 103, + 86, + 91, + 144, + 97, + 71, + 60, + 97, + 71, + 74, + 145, + 97, + 14, + 64, + 81, + 144, + 97, + 4, + 66, + 86, + 91, + 96, + 32, + 131, + 1, + 81, + 144, + 131, + 81, + 144, + 97, + 4, + 44, + 86, + 91, + 144, + 96, + 63, + 25, + 1, + 97, + 68, + 80, + 86, + 91, + 144, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 134, + 129, + 133, + 81, + 135, + 81, + 9, + 146, + 9, + 8, + 145, + 96, + 31, + 25, + 144, + 129, + 1, + 145, + 1, + 97, + 67, + 231, + 86, + 91, + 129, + 81, + 129, + 82, + 96, + 32, + 145, + 130, + 1, + 145, + 1, + 97, + 67, + 179, + 86, + 91, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 133, + 129, + 133, + 53, + 135, + 9, + 146, + 9, + 8, + 144, + 96, + 31, + 25, + 1, + 97, + 64, + 177, + 86, + 91, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 144, + 129, + 133, + 129, + 133, + 53, + 135, + 9, + 146, + 9, + 8, + 144, + 96, + 31, + 25, + 1, + 97, + 64, + 163, + 86, + 91, + 128, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 96, + 32, + 147, + 81, + 9, + 129, + 82, + 1, + 97, + 64, + 11, + 86, + 91, + 96, + 32, + 128, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 81, + 129, + 3, + 134, + 8, + 129, + 82, + 1, + 145, + 1, + 144, + 97, + 60, + 86, + 86, + 91, + 144, + 145, + 97, + 72, + 42, + 130, + 97, + 72, + 56, + 146, + 97, + 4, + 25, + 86, + 91, + 96, + 32, + 132, + 1, + 53, + 144, + 132, + 53, + 144, + 97, + 4, + 2, + 86, + 91, + 145, + 96, + 63, + 25, + 1, + 144, + 97, + 59, + 233, + 86, + 91, + 144, + 145, + 148, + 96, + 32, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 146, + 129, + 137, + 53, + 134, + 81, + 9, + 144, + 8, + 150, + 1, + 146, + 145, + 1, + 97, + 13, + 169, + 86, + 91, + 145, + 144, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 96, + 32, + 145, + 131, + 81, + 144, + 8, + 145, + 1, + 145, + 97, + 13, + 142, + 86, + 91, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 131, + 130, + 130, + 128, + 96, + 32, + 149, + 135, + 81, + 9, + 136, + 9, + 133, + 82, + 9, + 145, + 1, + 144, + 97, + 13, + 122, + 86, + 91, + 96, + 32, + 144, + 135, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 145, + 130, + 129, + 129, + 3, + 134, + 8, + 134, + 82, + 9, + 146, + 1, + 145, + 97, + 13, + 13, + 86, + 91, + 97, + 15, + 64, + 1, + 147, + 80, + 134, + 97, + 13, + 7, + 86, + 91, + 144, + 146, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 129, + 96, + 1, + 146, + 9, + 147, + 1, + 144, + 97, + 12, + 224, + 86, + 91, + 144, + 80, + 97, + 7, + 224, + 81, + 144, + 97, + 8, + 0, + 81, + 145, + 97, + 7, + 192, + 81, + 96, + 5, + 27, + 128, + 97, + 8, + 228, + 1, + 145, + 130, + 53, + 146, + 97, + 8, + 228, + 130, + 96, + 5, + 27, + 132, + 1, + 1, + 53, + 97, + 8, + 228, + 131, + 96, + 6, + 27, + 133, + 1, + 1, + 53, + 144, + 97, + 8, + 228, + 96, + 3, + 133, + 96, + 5, + 27, + 2, + 134, + 1, + 1, + 53, + 149, + 136, + 150, + 91, + 132, + 97, + 8, + 228, + 135, + 96, + 5, + 27, + 137, + 1, + 1, + 129, + 16, + 21, + 97, + 73, + 153, + 87, + 144, + 96, + 32, + 128, + 140, + 147, + 1, + 147, + 132, + 53, + 139, + 27, + 1, + 148, + 129, + 137, + 96, + 5, + 27, + 137, + 1, + 1, + 53, + 139, + 27, + 1, + 149, + 129, + 137, + 96, + 6, + 27, + 137, + 1, + 1, + 53, + 139, + 27, + 1, + 150, + 96, + 3, + 137, + 96, + 5, + 27, + 2, + 1, + 1, + 53, + 137, + 27, + 1, + 151, + 1, + 150, + 147, + 146, + 145, + 144, + 147, + 97, + 73, + 69, + 86, + 91, + 80, + 151, + 148, + 80, + 151, + 80, + 147, + 80, + 147, + 80, + 80, + 127, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 151, + 129, + 106, + 145, + 104, + 113, + 202, + 141, + 60, + 32, + 140, + 22, + 216, + 124, + 253, + 71, + 144, + 129, + 96, + 3, + 129, + 128, + 135, + 128, + 9, + 135, + 9, + 8, + 130, + 134, + 128, + 9, + 20, + 145, + 128, + 96, + 3, + 129, + 128, + 138, + 128, + 9, + 138, + 9, + 8, + 144, + 132, + 128, + 9, + 20, + 22, + 22, + 147, + 97, + 14, + 160, + 82, + 97, + 14, + 192, + 82, + 97, + 14, + 224, + 82, + 97, + 15, + 0, + 82, + 129, + 97, + 12, + 202, + 86, + 91, + 145, + 96, + 32, + 129, + 129, + 146, + 53, + 149, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 135, + 16, + 22, + 149, + 135, + 82, + 1, + 148, + 1, + 145, + 147, + 145, + 147, + 97, + 12, + 129, + 86, + 91, + 146, + 97, + 74, + 51, + 146, + 97, + 0, + 175, + 86, + 91, + 144, + 146, + 97, + 12, + 104, + 86, + 91, + 146, + 145, + 97, + 74, + 69, + 146, + 97, + 0, + 175, + 86, + 91, + 145, + 146, + 144, + 145, + 144, + 97, + 12, + 79, + 86, + 91, + 147, + 146, + 145, + 97, + 74, + 91, + 146, + 97, + 0, + 175, + 86, + 91, + 146, + 147, + 145, + 146, + 144, + 145, + 97, + 12, + 43, + 86, + 91, + 144, + 145, + 97, + 74, + 113, + 146, + 97, + 0, + 175, + 86, + 91, + 145, + 144, + 145, + 97, + 11, + 251, + 86, + 91, + 144, + 96, + 32, + 128, + 145, + 96, + 0, + 128, + 81, + 96, + 32, + 97, + 74, + 192, + 131, + 57, + 129, + 81, + 145, + 82, + 132, + 53, + 16, + 22, + 146, + 128, + 53, + 133, + 82, + 1, + 146, + 1, + 145, + 97, + 11, + 237, + 86, + 254, + 6, + 111, + 111, + 133, + 214, + 246, + 138, + 133, + 236, + 16, + 52, + 83, + 81, + 162, + 58, + 58, + 175, + 7, + 243, + 138, + 248, + 201, + 82, + 167, + 188, + 236, + 167, + 11, + 210, + 175, + 122, + 213, + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 240, + 0, + 0, + 1, + 18, + 116, + 230, + 73, + 163, + 46, + 211, + 85, + 163, + 26, + 110, + 214, + 151, + 36, + 225, + 173, + 173, + 232, + 87, + 232, + 110, + 181, + 195, + 161, + 33, + 188, + 209, + 71, + 148, + 50, + 3, + 200, + 12, + 197, + 124, + 219, + 176, + 133, + 7, + 214, + 43, + 246, + 122, + 68, + 147, + 204, + 38, + 47, + 182, + 192, + 157, + 85, + 112, + 19, + 255, + 241, + 245, + 115, + 244, + 49, + 34, + 31, + 143, + 249, + 43, + 157, + 75, + 65, + 16, + 201, + 174, + 153, + 119, + 130, + 225, + 80, + 155, + 29, + 15, + 219, + 32, + 167, + 192, + 43, + 189, + 139, + 234, + 115, + 5, + 70, + 43, + 159, + 129, + 37, + 177, + 232, + 9, + 34, + 107, + 110, + 34, + 198, + 240, + 202, + 100, + 236, + 38, + 170, + 212, + 200, + 110, + 113, + 91, + 95, + 137, + 142, + 94, + 150, + 63, + 37, + 135, + 14, + 86, + 187, + 229, + 51, + 233, + 162, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 160, + 229, + 138, + 231, + 221, + 63, + 176, + 244, + 67, + 224, + 208, + 98, + 57, + 92, + 8, + 140, + 114, + 124, + 29, + 76, + 8, + 8, + 82, + 242, + 122, + 18, + 202, + 70, + 28, + 219, + 72, + 109, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The deployed bytecode of the contract. + pub static INCLUSIONVERIFIER_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct InclusionVerifier(::ethers::contract::Contract); + impl ::core::clone::Clone for InclusionVerifier { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for InclusionVerifier { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for InclusionVerifier { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for InclusionVerifier { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(stringify!(InclusionVerifier)).field(&self.address()).finish() + } + } + impl InclusionVerifier { + /// 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(), + INCLUSIONVERIFIER_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( + INCLUSIONVERIFIER_ABI.clone(), + INCLUSIONVERIFIER_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `verifyProof` (0x1e8e1e13) function + pub fn verify_proof( + &self, + proof: ::ethers::core::types::Bytes, + instances: ::std::vec::Vec<::ethers::core::types::U256>, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([30, 142, 30, 19], (proof, instances)) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for InclusionVerifier { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `verifyProof` function with signature `verifyProof(bytes,uint256[])` and selector `0x1e8e1e13` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "verifyProof", abi = "verifyProof(bytes,uint256[])")] + pub struct VerifyProofCall { + pub proof: ::ethers::core::types::Bytes, + pub instances: ::std::vec::Vec<::ethers::core::types::U256>, + } + ///Container type for all return fields from the `verifyProof` function with signature `verifyProof(bytes,uint256[])` and selector `0x1e8e1e13` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct VerifyProofReturn(pub bool); +} diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/generated/mod.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/mod.rs new file mode 100644 index 0000000..467f80f --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/mod.rs @@ -0,0 +1,2 @@ +pub mod summa_contract; +pub mod inclusion_verifier; \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/generated/summa_contract.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/summa_contract.rs new file mode 100644 index 0000000..31c24b1 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/generated/summa_contract.rs @@ -0,0 +1,14762 @@ +pub use summa::*; +/// 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 summa { + #[rustfmt::skip] + const __ABI: &str = "[{\"inputs\":[{\"internalType\":\"contract IVerifier\",\"name\":\"_inclusionVerifier\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint16\",\"name\":\"mstLevels\",\"type\":\"uint16\",\"components\":[]},{\"internalType\":\"uint16\",\"name\":\"currenciesCount\",\"type\":\"uint16\",\"components\":[]},{\"internalType\":\"uint8\",\"name\":\"balanceByteRange\",\"type\":\"uint8\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"struct Summa.AddressOwnershipProof[]\",\"name\":\"addressOwnershipProofs\",\"type\":\"tuple[]\",\"components\":[{\"internalType\":\"string\",\"name\":\"cexAddress\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\",\"components\":[]}],\"indexed\":false}],\"type\":\"event\",\"name\":\"AddressOwnershipProofSubmitted\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\",\"components\":[],\"indexed\":true},{\"internalType\":\"uint256\",\"name\":\"mstRoot\",\"type\":\"uint256\",\"components\":[],\"indexed\":false},{\"internalType\":\"uint256[]\",\"name\":\"rootBalances\",\"type\":\"uint256[]\",\"components\":[],\"indexed\":false},{\"internalType\":\"struct Summa.Cryptocurrency[]\",\"name\":\"cryptocurrencies\",\"type\":\"tuple[]\",\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]}],\"indexed\":false}],\"type\":\"event\",\"name\":\"LiabilitiesCommitmentSubmitted\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\",\"components\":[],\"indexed\":true}],\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"addressOwnershipProofs\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"cexAddress\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"commitments\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"mstRoot\",\"type\":\"uint256\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"mstLevels\",\"type\":\"uint16\",\"components\":[]},{\"internalType\":\"uint16\",\"name\":\"currenciesCount\",\"type\":\"uint16\",\"components\":[]},{\"internalType\":\"uint8\",\"name\":\"balanceByteRange\",\"type\":\"uint8\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"addressHash\",\"type\":\"bytes32\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"getAddressOwnershipProof\",\"outputs\":[{\"internalType\":\"struct Summa.AddressOwnershipProof\",\"name\":\"\",\"type\":\"tuple\",\"components\":[{\"internalType\":\"string\",\"name\":\"cexAddress\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\",\"components\":[]}]}]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"renounceOwnership\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"mstRoot\",\"type\":\"uint256\",\"components\":[]},{\"internalType\":\"uint256[]\",\"name\":\"rootBalances\",\"type\":\"uint256[]\",\"components\":[]},{\"internalType\":\"struct Summa.Cryptocurrency[]\",\"name\":\"cryptocurrencies\",\"type\":\"tuple[]\",\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]}]},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"submitCommitment\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"struct Summa.AddressOwnershipProof[]\",\"name\":\"_addressOwnershipProofs\",\"type\":\"tuple[]\",\"components\":[{\"internalType\":\"string\",\"name\":\"cexAddress\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"string\",\"name\":\"chain\",\"type\":\"string\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\",\"components\":[]}]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"submitProofOfAddressOwnership\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"transferOwnership\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\",\"components\":[]},{\"internalType\":\"uint256[]\",\"name\":\"publicInputs\",\"type\":\"uint256[]\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"verifyInclusionProof\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]}]"; + ///The parsed JSON ABI of the contract. + pub static SUMMA_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(|| + ::ethers::core::utils::__serde_json::from_str(__ABI).expect("ABI is always valid")); + #[rustfmt::skip] + const __BYTECODE: &[u8] = &[ + 96, + 160, + 52, + 98, + 0, + 1, + 74, + 87, + 96, + 31, + 98, + 0, + 27, + 245, + 56, + 129, + 144, + 3, + 145, + 130, + 1, + 96, + 31, + 25, + 22, + 131, + 1, + 146, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 146, + 144, + 145, + 131, + 133, + 17, + 131, + 134, + 16, + 23, + 98, + 0, + 1, + 79, + 87, + 129, + 96, + 128, + 146, + 132, + 146, + 96, + 64, + 151, + 136, + 82, + 131, + 57, + 129, + 1, + 3, + 18, + 98, + 0, + 1, + 74, + 87, + 128, + 81, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 144, + 129, + 129, + 22, + 129, + 3, + 98, + 0, + 1, + 74, + 87, + 98, + 0, + 0, + 107, + 96, + 32, + 132, + 1, + 98, + 0, + 1, + 101, + 86, + 91, + 145, + 96, + 96, + 98, + 0, + 0, + 123, + 135, + 134, + 1, + 98, + 0, + 1, + 101, + 86, + 91, + 148, + 1, + 81, + 148, + 96, + 255, + 134, + 22, + 146, + 131, + 135, + 3, + 98, + 0, + 1, + 74, + 87, + 96, + 0, + 128, + 84, + 51, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 130, + 22, + 129, + 23, + 131, + 85, + 145, + 148, + 22, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 133, + 128, + 163, + 96, + 128, + 82, + 134, + 81, + 145, + 96, + 96, + 131, + 1, + 145, + 130, + 17, + 131, + 131, + 16, + 23, + 98, + 0, + 1, + 54, + 87, + 80, + 99, + 255, + 255, + 0, + 0, + 147, + 146, + 145, + 135, + 145, + 130, + 82, + 97, + 255, + 255, + 128, + 148, + 22, + 147, + 132, + 130, + 82, + 134, + 22, + 96, + 32, + 130, + 1, + 82, + 1, + 82, + 100, + 255, + 0, + 0, + 0, + 0, + 96, + 1, + 84, + 148, + 96, + 32, + 27, + 22, + 147, + 100, + 255, + 255, + 255, + 255, + 255, + 25, + 22, + 23, + 145, + 96, + 16, + 27, + 22, + 23, + 23, + 96, + 1, + 85, + 81, + 97, + 26, + 127, + 144, + 129, + 98, + 0, + 1, + 118, + 130, + 57, + 96, + 128, + 81, + 129, + 97, + 24, + 139, + 1, + 82, + 243, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 129, + 82, + 96, + 65, + 96, + 4, + 82, + 96, + 36, + 144, + 253, + 91, + 96, + 0, + 128, + 253, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 65, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 81, + 144, + 97, + 255, + 255, + 130, + 22, + 130, + 3, + 98, + 0, + 1, + 74, + 87, + 86, + 254, + 96, + 128, + 128, + 96, + 64, + 82, + 96, + 4, + 54, + 16, + 21, + 97, + 0, + 19, + 87, + 96, + 0, + 128, + 253, + 91, + 96, + 0, + 53, + 96, + 224, + 28, + 144, + 129, + 99, + 25, + 179, + 57, + 104, + 20, + 97, + 18, + 99, + 87, + 80, + 128, + 99, + 73, + 206, + 137, + 151, + 20, + 97, + 18, + 55, + 87, + 128, + 99, + 113, + 80, + 24, + 166, + 20, + 97, + 17, + 222, + 87, + 128, + 99, + 121, + 80, + 44, + 85, + 20, + 97, + 17, + 165, + 87, + 128, + 99, + 141, + 165, + 203, + 91, + 20, + 97, + 17, + 124, + 87, + 128, + 99, + 163, + 196, + 188, + 248, + 20, + 97, + 16, + 168, + 87, + 128, + 99, + 199, + 221, + 202, + 14, + 20, + 97, + 9, + 176, + 87, + 128, + 99, + 200, + 229, + 129, + 71, + 20, + 97, + 9, + 77, + 87, + 128, + 99, + 218, + 100, + 167, + 80, + 20, + 97, + 1, + 93, + 87, + 99, + 242, + 253, + 227, + 139, + 20, + 97, + 0, + 141, + 87, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 129, + 22, + 145, + 130, + 144, + 3, + 97, + 1, + 88, + 87, + 97, + 0, + 188, + 97, + 22, + 117, + 86, + 91, + 129, + 21, + 97, + 1, + 4, + 87, + 96, + 0, + 84, + 130, + 107, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 96, + 160, + 27, + 130, + 22, + 23, + 96, + 0, + 85, + 22, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 96, + 0, + 128, + 163, + 0, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 110, + 101, + 119, + 32, + 111, + 119, + 110, + 101, + 114, + 32, + 105, + 115, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 96, + 68, + 130, + 1, + 82, + 101, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 128, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 36, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 1, + 141, + 144, + 54, + 144, + 96, + 4, + 1, + 97, + 22, + 23, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 68, + 53, + 17, + 97, + 1, + 88, + 87, + 54, + 96, + 35, + 96, + 68, + 53, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 96, + 68, + 53, + 96, + 4, + 1, + 53, + 97, + 1, + 186, + 129, + 97, + 21, + 158, + 86, + 91, + 97, + 1, + 199, + 96, + 64, + 81, + 145, + 130, + 97, + 21, + 125, + 86, + 91, + 129, + 129, + 82, + 96, + 32, + 129, + 1, + 128, + 146, + 54, + 96, + 36, + 130, + 96, + 5, + 27, + 96, + 68, + 53, + 1, + 1, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 96, + 68, + 53, + 1, + 145, + 91, + 96, + 36, + 130, + 96, + 5, + 27, + 96, + 68, + 53, + 1, + 1, + 131, + 16, + 97, + 8, + 157, + 87, + 80, + 80, + 80, + 97, + 2, + 5, + 97, + 22, + 117, + 86, + 91, + 97, + 2, + 18, + 96, + 4, + 53, + 21, + 21, + 97, + 23, + 78, + 86, + 91, + 130, + 81, + 129, + 81, + 3, + 97, + 8, + 58, + 87, + 97, + 2, + 37, + 129, + 81, + 97, + 23, + 141, + 86, + 91, + 144, + 97, + 2, + 48, + 129, + 81, + 97, + 23, + 141, + 86, + 91, + 147, + 96, + 0, + 91, + 130, + 81, + 129, + 16, + 21, + 97, + 3, + 105, + 87, + 96, + 32, + 97, + 2, + 73, + 130, + 133, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 128, + 97, + 3, + 84, + 87, + 91, + 21, + 97, + 3, + 22, + 87, + 97, + 2, + 100, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 21, + 97, + 2, + 191, + 87, + 128, + 97, + 2, + 120, + 97, + 2, + 186, + 146, + 133, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 97, + 2, + 132, + 130, + 135, + 97, + 22, + 220, + 86, + 91, + 82, + 97, + 2, + 143, + 129, + 134, + 97, + 22, + 220, + 86, + 91, + 80, + 96, + 32, + 97, + 2, + 156, + 130, + 134, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 97, + 2, + 169, + 130, + 137, + 97, + 22, + 220, + 86, + 91, + 82, + 97, + 2, + 180, + 129, + 136, + 97, + 22, + 220, + 86, + 91, + 80, + 97, + 22, + 205, + 86, + 91, + 97, + 2, + 52, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 41, + 96, + 36, + 130, + 1, + 82, + 127, + 65, + 108, + 108, + 32, + 114, + 111, + 111, + 116, + 32, + 115, + 117, + 109, + 115, + 32, + 115, + 104, + 111, + 117, + 108, + 100, + 32, + 98, + 101, + 32, + 103, + 114, + 101, + 97, + 116, + 101, + 114, + 32, + 96, + 68, + 130, + 1, + 82, + 104, + 116, + 104, + 97, + 110, + 32, + 122, + 101, + 114, + 111, + 96, + 184, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 22, + 96, + 36, + 130, + 1, + 82, + 117, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 99, + 114, + 121, + 112, + 116, + 111, + 99, + 117, + 114, + 114, + 101, + 110, + 99, + 121, + 96, + 80, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 80, + 97, + 3, + 95, + 129, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 81, + 21, + 21, + 97, + 2, + 85, + 86, + 91, + 80, + 145, + 132, + 96, + 64, + 81, + 144, + 97, + 3, + 121, + 130, + 97, + 21, + 98, + 86, + 91, + 96, + 4, + 53, + 130, + 82, + 96, + 32, + 130, + 1, + 146, + 133, + 132, + 82, + 96, + 64, + 131, + 1, + 82, + 96, + 96, + 130, + 1, + 82, + 96, + 100, + 53, + 96, + 0, + 82, + 96, + 4, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 145, + 129, + 81, + 131, + 85, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 32, + 144, + 96, + 1, + 133, + 1, + 84, + 131, + 96, + 1, + 135, + 1, + 85, + 128, + 132, + 16, + 97, + 8, + 26, + 87, + 91, + 80, + 1, + 96, + 1, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 96, + 0, + 91, + 131, + 129, + 16, + 97, + 8, + 6, + 87, + 80, + 80, + 80, + 80, + 96, + 64, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 2, + 132, + 1, + 84, + 130, + 96, + 2, + 134, + 1, + 85, + 128, + 131, + 16, + 97, + 7, + 141, + 87, + 91, + 80, + 96, + 32, + 1, + 144, + 96, + 2, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 6, + 176, + 87, + 80, + 80, + 80, + 80, + 96, + 96, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 3, + 131, + 1, + 84, + 130, + 96, + 3, + 133, + 1, + 85, + 128, + 131, + 16, + 97, + 6, + 55, + 87, + 91, + 80, + 96, + 32, + 96, + 3, + 145, + 1, + 146, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 5, + 62, + 87, + 80, + 80, + 80, + 80, + 97, + 4, + 158, + 96, + 64, + 81, + 146, + 96, + 4, + 53, + 132, + 82, + 96, + 96, + 96, + 32, + 133, + 1, + 82, + 96, + 96, + 132, + 1, + 144, + 97, + 23, + 215, + 86, + 91, + 144, + 130, + 130, + 3, + 96, + 64, + 132, + 1, + 82, + 81, + 128, + 130, + 82, + 96, + 32, + 130, + 1, + 145, + 96, + 32, + 130, + 96, + 5, + 27, + 130, + 1, + 1, + 148, + 146, + 96, + 0, + 145, + 91, + 131, + 131, + 16, + 97, + 4, + 241, + 87, + 96, + 100, + 53, + 127, + 136, + 191, + 199, + 56, + 156, + 184, + 49, + 234, + 2, + 8, + 255, + 16, + 109, + 166, + 245, + 201, + 248, + 128, + 54, + 186, + 8, + 79, + 30, + 176, + 8, + 210, + 120, + 141, + 61, + 69, + 153, + 141, + 135, + 137, + 3, + 136, + 162, + 0, + 91, + 144, + 145, + 146, + 147, + 149, + 96, + 32, + 128, + 97, + 5, + 47, + 96, + 1, + 147, + 96, + 31, + 25, + 134, + 130, + 3, + 1, + 135, + 82, + 138, + 81, + 144, + 131, + 97, + 5, + 31, + 131, + 81, + 96, + 64, + 132, + 82, + 96, + 64, + 132, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 146, + 1, + 81, + 144, + 132, + 129, + 132, + 3, + 145, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 152, + 1, + 147, + 1, + 147, + 1, + 145, + 147, + 146, + 144, + 97, + 4, + 191, + 86, + 91, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 5, + 101, + 130, + 97, + 5, + 95, + 136, + 84, + 97, + 20, + 146, + 86, + 91, + 136, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 5, + 177, + 87, + 146, + 130, + 96, + 1, + 148, + 147, + 96, + 32, + 147, + 134, + 149, + 96, + 0, + 146, + 97, + 5, + 166, + 87, + 91, + 80, + 80, + 96, + 0, + 25, + 96, + 3, + 131, + 144, + 27, + 28, + 25, + 22, + 144, + 132, + 27, + 23, + 135, + 85, + 91, + 1, + 148, + 1, + 145, + 1, + 144, + 146, + 97, + 4, + 118, + 86, + 91, + 1, + 81, + 144, + 80, + 140, + 128, + 97, + 5, + 134, + 86, + 91, + 144, + 134, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 6, + 9, + 87, + 80, + 131, + 96, + 32, + 147, + 96, + 1, + 150, + 147, + 135, + 150, + 147, + 135, + 148, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 5, + 240, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 135, + 85, + 97, + 5, + 154, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 140, + 128, + 128, + 97, + 5, + 227, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 5, + 191, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 65, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 3, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 131, + 130, + 1, + 91, + 129, + 131, + 1, + 129, + 16, + 97, + 6, + 88, + 87, + 80, + 80, + 97, + 4, + 96, + 86, + 91, + 128, + 97, + 6, + 101, + 96, + 1, + 146, + 84, + 97, + 20, + 146, + 86, + 91, + 128, + 97, + 6, + 114, + 87, + 91, + 80, + 1, + 97, + 6, + 72, + 86, + 91, + 96, + 31, + 144, + 129, + 129, + 17, + 132, + 20, + 97, + 6, + 139, + 87, + 80, + 80, + 96, + 0, + 129, + 85, + 91, + 138, + 97, + 6, + 107, + 86, + 91, + 97, + 6, + 167, + 96, + 0, + 146, + 132, + 132, + 82, + 96, + 32, + 132, + 32, + 146, + 1, + 96, + 5, + 28, + 130, + 1, + 133, + 131, + 1, + 97, + 22, + 240, + 86, + 91, + 129, + 131, + 85, + 85, + 97, + 6, + 133, + 86, + 91, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 6, + 209, + 130, + 97, + 5, + 95, + 136, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 7, + 29, + 87, + 146, + 130, + 96, + 1, + 148, + 147, + 96, + 32, + 147, + 134, + 149, + 96, + 0, + 146, + 97, + 7, + 18, + 87, + 91, + 80, + 80, + 96, + 0, + 25, + 96, + 3, + 131, + 144, + 27, + 28, + 25, + 22, + 144, + 132, + 27, + 23, + 135, + 85, + 91, + 1, + 148, + 1, + 145, + 1, + 144, + 146, + 97, + 4, + 48, + 86, + 91, + 1, + 81, + 144, + 80, + 142, + 128, + 97, + 6, + 242, + 86, + 91, + 144, + 134, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 7, + 117, + 87, + 80, + 131, + 96, + 32, + 147, + 96, + 1, + 150, + 147, + 135, + 150, + 147, + 135, + 148, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 7, + 92, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 135, + 85, + 97, + 7, + 6, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 142, + 128, + 128, + 97, + 7, + 79, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 7, + 43, + 86, + 91, + 96, + 2, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 131, + 130, + 1, + 91, + 129, + 131, + 1, + 129, + 16, + 97, + 7, + 174, + 87, + 80, + 80, + 97, + 4, + 26, + 86, + 91, + 128, + 97, + 7, + 187, + 96, + 1, + 146, + 84, + 97, + 20, + 146, + 86, + 91, + 128, + 97, + 7, + 200, + 87, + 91, + 80, + 1, + 97, + 7, + 158, + 86, + 91, + 96, + 31, + 144, + 129, + 129, + 17, + 132, + 20, + 97, + 7, + 225, + 87, + 80, + 80, + 96, + 0, + 129, + 85, + 91, + 139, + 97, + 7, + 193, + 86, + 91, + 97, + 7, + 253, + 96, + 0, + 146, + 132, + 132, + 82, + 96, + 32, + 132, + 32, + 146, + 1, + 96, + 5, + 28, + 130, + 1, + 133, + 131, + 1, + 97, + 22, + 240, + 86, + 91, + 129, + 131, + 85, + 85, + 97, + 7, + 219, + 86, + 91, + 96, + 1, + 144, + 96, + 32, + 132, + 81, + 148, + 1, + 147, + 129, + 132, + 1, + 85, + 1, + 97, + 3, + 233, + 86, + 91, + 97, + 8, + 52, + 144, + 96, + 1, + 135, + 1, + 96, + 0, + 82, + 132, + 132, + 96, + 0, + 32, + 145, + 130, + 1, + 145, + 1, + 97, + 22, + 240, + 86, + 91, + 136, + 97, + 3, + 216, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 53, + 96, + 36, + 130, + 1, + 82, + 127, + 82, + 111, + 111, + 116, + 32, + 108, + 105, + 97, + 98, + 105, + 108, + 105, + 116, + 105, + 101, + 115, + 32, + 115, + 117, + 109, + 115, + 32, + 97, + 110, + 100, + 32, + 108, + 105, + 97, + 98, + 105, + 108, + 96, + 68, + 130, + 1, + 82, + 116, + 13, + 46, + 141, + 44, + 174, + 100, + 13, + 206, + 173, + 172, + 76, + 174, + 68, + 13, + 173, + 46, + 109, + 172, + 46, + 140, + 109, + 96, + 91, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 130, + 53, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 1, + 88, + 87, + 96, + 64, + 96, + 68, + 53, + 131, + 1, + 54, + 3, + 96, + 35, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 64, + 81, + 145, + 96, + 64, + 131, + 1, + 131, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 36, + 130, + 96, + 68, + 53, + 1, + 1, + 53, + 17, + 97, + 1, + 88, + 87, + 97, + 9, + 9, + 54, + 96, + 36, + 96, + 68, + 53, + 132, + 1, + 129, + 129, + 1, + 53, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 82, + 96, + 68, + 129, + 129, + 53, + 1, + 1, + 53, + 145, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 131, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 147, + 97, + 9, + 60, + 96, + 32, + 148, + 147, + 134, + 134, + 149, + 54, + 146, + 96, + 68, + 53, + 1, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 130, + 1, + 82, + 129, + 82, + 1, + 147, + 1, + 146, + 144, + 80, + 97, + 1, + 233, + 86, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 96, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 4, + 53, + 129, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 9, + 126, + 144, + 54, + 144, + 96, + 4, + 1, + 97, + 21, + 208, + 86, + 91, + 144, + 96, + 36, + 53, + 144, + 129, + 17, + 97, + 1, + 88, + 87, + 96, + 32, + 145, + 97, + 9, + 157, + 97, + 9, + 166, + 146, + 54, + 144, + 96, + 4, + 1, + 97, + 22, + 23, + 86, + 91, + 96, + 68, + 53, + 145, + 97, + 24, + 11, + 86, + 91, + 96, + 64, + 81, + 144, + 21, + 21, + 129, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 96, + 4, + 1, + 53, + 144, + 97, + 9, + 236, + 130, + 97, + 21, + 158, + 86, + 91, + 144, + 97, + 9, + 250, + 96, + 64, + 81, + 146, + 131, + 97, + 21, + 125, + 86, + 91, + 130, + 130, + 82, + 96, + 32, + 130, + 1, + 144, + 96, + 36, + 130, + 148, + 96, + 5, + 27, + 130, + 1, + 1, + 144, + 54, + 130, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 129, + 1, + 146, + 91, + 130, + 132, + 16, + 97, + 15, + 206, + 87, + 133, + 133, + 97, + 10, + 43, + 97, + 22, + 117, + 86, + 91, + 96, + 0, + 91, + 129, + 81, + 129, + 16, + 21, + 97, + 15, + 78, + 87, + 97, + 10, + 65, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 96, + 64, + 81, + 97, + 10, + 109, + 96, + 32, + 130, + 129, + 97, + 10, + 96, + 129, + 131, + 1, + 150, + 135, + 129, + 81, + 147, + 132, + 146, + 1, + 97, + 19, + 163, + 86, + 91, + 129, + 1, + 3, + 128, + 132, + 82, + 1, + 130, + 97, + 21, + 125, + 86, + 91, + 81, + 144, + 32, + 128, + 96, + 0, + 82, + 96, + 3, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 97, + 15, + 9, + 87, + 97, + 10, + 141, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 96, + 2, + 84, + 96, + 1, + 96, + 64, + 27, + 129, + 16, + 21, + 97, + 6, + 33, + 87, + 128, + 96, + 1, + 97, + 10, + 173, + 146, + 1, + 96, + 2, + 85, + 97, + 20, + 66, + 86, + 91, + 145, + 144, + 145, + 97, + 14, + 243, + 87, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 129, + 144, + 97, + 10, + 221, + 130, + 97, + 10, + 215, + 135, + 84, + 97, + 20, + 146, + 86, + 91, + 135, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 14, + 135, + 87, + 96, + 0, + 146, + 97, + 14, + 124, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 130, + 85, + 91, + 96, + 32, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 129, + 144, + 97, + 11, + 58, + 130, + 97, + 11, + 49, + 96, + 1, + 136, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 1, + 136, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 14, + 10, + 87, + 96, + 0, + 146, + 97, + 13, + 255, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 96, + 1, + 131, + 1, + 85, + 91, + 96, + 64, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 11, + 152, + 130, + 97, + 11, + 143, + 96, + 2, + 135, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 2, + 135, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 13, + 140, + 87, + 96, + 96, + 147, + 146, + 145, + 96, + 0, + 145, + 131, + 97, + 13, + 129, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 96, + 2, + 132, + 1, + 85, + 91, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 11, + 249, + 130, + 97, + 11, + 240, + 96, + 3, + 134, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 3, + 134, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 13, + 18, + 87, + 96, + 3, + 146, + 145, + 96, + 0, + 145, + 131, + 97, + 13, + 7, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 132, + 27, + 28, + 25, + 22, + 23, + 145, + 1, + 85, + 91, + 96, + 2, + 84, + 144, + 96, + 0, + 82, + 96, + 3, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 85, + 97, + 12, + 69, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 81, + 21, + 21, + 128, + 97, + 12, + 239, + 87, + 91, + 128, + 97, + 12, + 215, + 87, + 91, + 128, + 97, + 12, + 191, + 87, + 91, + 21, + 97, + 12, + 111, + 87, + 97, + 12, + 106, + 144, + 97, + 22, + 205, + 86, + 91, + 97, + 10, + 46, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 34, + 96, + 36, + 130, + 1, + 82, + 127, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 112, + 114, + 111, + 111, + 102, + 32, + 111, + 102, + 32, + 97, + 100, + 100, + 114, + 101, + 115, + 115, + 32, + 111, + 119, + 110, + 101, + 114, + 115, + 104, + 96, + 68, + 130, + 1, + 82, + 97, + 6, + 151, + 96, + 244, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 80, + 96, + 96, + 97, + 12, + 204, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 92, + 86, + 91, + 80, + 96, + 64, + 97, + 12, + 228, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 86, + 86, + 91, + 80, + 96, + 32, + 97, + 12, + 252, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 80, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 12, + 20, + 86, + 91, + 144, + 96, + 3, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 13, + 105, + 87, + 80, + 145, + 131, + 145, + 96, + 1, + 147, + 96, + 3, + 149, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 13, + 81, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 145, + 1, + 85, + 97, + 12, + 41, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 131, + 134, + 27, + 96, + 248, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 13, + 67, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 13, + 35, + 86, + 91, + 1, + 81, + 144, + 80, + 137, + 128, + 97, + 11, + 180, + 86, + 91, + 144, + 96, + 2, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 13, + 231, + 87, + 80, + 145, + 131, + 145, + 96, + 1, + 147, + 96, + 96, + 150, + 149, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 13, + 206, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 96, + 2, + 132, + 1, + 85, + 97, + 11, + 204, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 137, + 128, + 128, + 97, + 13, + 190, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 13, + 157, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 11, + 80, + 86, + 91, + 146, + 80, + 96, + 1, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 0, + 147, + 91, + 96, + 31, + 25, + 132, + 22, + 133, + 16, + 97, + 14, + 97, + 87, + 96, + 1, + 148, + 80, + 131, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 14, + 72, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 96, + 1, + 131, + 1, + 85, + 97, + 11, + 104, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 14, + 56, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 85, + 96, + 32, + 148, + 133, + 1, + 148, + 96, + 1, + 144, + 147, + 1, + 146, + 144, + 145, + 1, + 144, + 97, + 14, + 29, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 10, + 243, + 86, + 91, + 146, + 80, + 132, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 0, + 147, + 91, + 96, + 31, + 25, + 132, + 22, + 133, + 16, + 97, + 14, + 216, + 87, + 96, + 1, + 148, + 80, + 131, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 14, + 191, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 130, + 85, + 97, + 11, + 8, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 14, + 178, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 85, + 96, + 32, + 148, + 133, + 1, + 148, + 96, + 1, + 144, + 147, + 1, + 146, + 144, + 145, + 1, + 144, + 97, + 14, + 151, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 0, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 24, + 96, + 36, + 130, + 1, + 82, + 127, + 65, + 100, + 100, + 114, + 101, + 115, + 115, + 32, + 97, + 108, + 114, + 101, + 97, + 100, + 121, + 32, + 118, + 101, + 114, + 105, + 102, + 105, + 101, + 100, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 80, + 96, + 64, + 81, + 144, + 96, + 32, + 130, + 1, + 144, + 96, + 32, + 131, + 82, + 81, + 128, + 145, + 82, + 96, + 64, + 130, + 1, + 144, + 96, + 64, + 129, + 96, + 5, + 27, + 132, + 1, + 1, + 147, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 15, + 163, + 87, + 127, + 56, + 35, + 21, + 212, + 213, + 106, + 96, + 53, + 225, + 137, + 155, + 255, + 231, + 125, + 155, + 236, + 239, + 175, + 95, + 38, + 80, + 228, + 50, + 59, + 39, + 133, + 72, + 87, + 160, + 69, + 70, + 88, + 133, + 135, + 3, + 134, + 161, + 0, + 91, + 144, + 145, + 146, + 148, + 96, + 32, + 128, + 97, + 15, + 192, + 96, + 1, + 147, + 96, + 63, + 25, + 137, + 130, + 3, + 1, + 134, + 82, + 137, + 81, + 97, + 19, + 235, + 86, + 91, + 151, + 1, + 146, + 1, + 146, + 1, + 144, + 146, + 145, + 97, + 15, + 116, + 86, + 91, + 131, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 130, + 1, + 96, + 128, + 96, + 35, + 25, + 130, + 54, + 3, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 64, + 81, + 145, + 97, + 15, + 251, + 131, + 97, + 21, + 98, + 86, + 91, + 96, + 36, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 30, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 82, + 96, + 68, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 67, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 32, + 132, + 1, + 82, + 96, + 100, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 107, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 64, + 132, + 1, + 82, + 96, + 132, + 130, + 1, + 53, + 146, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 132, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 152, + 96, + 32, + 148, + 147, + 96, + 36, + 134, + 149, + 54, + 146, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 96, + 130, + 1, + 82, + 129, + 82, + 1, + 147, + 1, + 146, + 97, + 10, + 26, + 86, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 2, + 84, + 129, + 16, + 21, + 97, + 1, + 88, + 87, + 97, + 16, + 210, + 97, + 17, + 78, + 145, + 97, + 20, + 66, + 86, + 91, + 80, + 97, + 17, + 120, + 96, + 3, + 97, + 17, + 106, + 96, + 64, + 81, + 147, + 97, + 16, + 244, + 133, + 97, + 16, + 237, + 129, + 132, + 97, + 20, + 204, + 86, + 91, + 3, + 134, + 97, + 21, + 125, + 86, + 91, + 97, + 17, + 92, + 96, + 64, + 81, + 97, + 17, + 18, + 129, + 97, + 17, + 11, + 129, + 96, + 1, + 135, + 1, + 97, + 20, + 204, + 86, + 91, + 3, + 130, + 97, + 21, + 125, + 86, + 91, + 97, + 17, + 58, + 96, + 64, + 81, + 147, + 97, + 17, + 42, + 133, + 97, + 16, + 237, + 129, + 96, + 2, + 133, + 1, + 97, + 20, + 204, + 86, + 91, + 97, + 16, + 237, + 96, + 64, + 81, + 128, + 152, + 129, + 147, + 1, + 97, + 20, + 204, + 86, + 91, + 96, + 64, + 81, + 151, + 136, + 151, + 96, + 128, + 137, + 82, + 96, + 128, + 137, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 144, + 135, + 130, + 3, + 96, + 32, + 137, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 133, + 130, + 3, + 96, + 64, + 135, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 131, + 130, + 3, + 96, + 96, + 133, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 3, + 144, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 0, + 84, + 96, + 64, + 81, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 144, + 145, + 22, + 129, + 82, + 96, + 32, + 144, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 96, + 96, + 1, + 84, + 96, + 255, + 96, + 64, + 81, + 145, + 97, + 255, + 255, + 128, + 130, + 22, + 132, + 82, + 129, + 96, + 16, + 28, + 22, + 96, + 32, + 132, + 1, + 82, + 96, + 32, + 28, + 22, + 96, + 64, + 130, + 1, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 97, + 17, + 247, + 97, + 22, + 117, + 86, + 91, + 96, + 0, + 128, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 129, + 22, + 130, + 85, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 130, + 128, + 163, + 0, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 0, + 82, + 96, + 4, + 96, + 32, + 82, + 96, + 32, + 96, + 64, + 96, + 0, + 32, + 84, + 96, + 64, + 81, + 144, + 129, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 128, + 96, + 3, + 25, + 54, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 97, + 18, + 129, + 131, + 97, + 21, + 98, + 86, + 91, + 96, + 96, + 128, + 132, + 129, + 128, + 150, + 82, + 129, + 133, + 130, + 1, + 82, + 129, + 96, + 64, + 130, + 1, + 82, + 1, + 82, + 128, + 96, + 0, + 82, + 96, + 3, + 130, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 21, + 97, + 19, + 103, + 87, + 96, + 0, + 82, + 96, + 3, + 129, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 96, + 0, + 25, + 129, + 1, + 144, + 129, + 17, + 97, + 19, + 81, + 87, + 97, + 18, + 205, + 96, + 3, + 145, + 97, + 20, + 66, + 86, + 91, + 80, + 146, + 97, + 19, + 58, + 96, + 64, + 81, + 148, + 97, + 18, + 223, + 134, + 97, + 21, + 98, + 86, + 91, + 96, + 64, + 81, + 97, + 18, + 240, + 129, + 97, + 17, + 11, + 129, + 133, + 97, + 20, + 204, + 86, + 91, + 134, + 82, + 96, + 64, + 81, + 97, + 19, + 6, + 129, + 97, + 17, + 11, + 129, + 96, + 1, + 134, + 1, + 97, + 20, + 204, + 86, + 91, + 133, + 135, + 1, + 82, + 96, + 64, + 81, + 97, + 19, + 30, + 129, + 97, + 17, + 11, + 129, + 96, + 2, + 134, + 1, + 97, + 20, + 204, + 86, + 91, + 96, + 64, + 135, + 1, + 82, + 97, + 19, + 51, + 96, + 64, + 81, + 128, + 149, + 129, + 147, + 1, + 97, + 20, + 204, + 86, + 91, + 3, + 131, + 97, + 21, + 125, + 86, + 91, + 131, + 1, + 82, + 97, + 17, + 120, + 96, + 64, + 81, + 146, + 130, + 132, + 147, + 132, + 82, + 131, + 1, + 144, + 97, + 19, + 235, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 17, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 4, + 129, + 1, + 131, + 144, + 82, + 96, + 20, + 96, + 36, + 130, + 1, + 82, + 115, + 16, + 89, + 25, + 28, + 153, + 92, + 220, + 200, + 27, + 155, + 221, + 8, + 29, + 153, + 92, + 154, + 89, + 154, + 89, + 89, + 96, + 98, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 96, + 0, + 91, + 131, + 129, + 16, + 97, + 19, + 182, + 87, + 80, + 80, + 96, + 0, + 145, + 1, + 82, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 130, + 1, + 82, + 96, + 32, + 1, + 97, + 19, + 166, + 86, + 91, + 144, + 96, + 32, + 145, + 97, + 19, + 223, + 129, + 81, + 128, + 146, + 129, + 133, + 82, + 133, + 128, + 134, + 1, + 145, + 1, + 97, + 19, + 163, + 86, + 91, + 96, + 31, + 1, + 96, + 31, + 25, + 22, + 1, + 1, + 144, + 86, + 91, + 97, + 20, + 63, + 145, + 96, + 96, + 97, + 20, + 46, + 97, + 20, + 28, + 97, + 20, + 10, + 133, + 81, + 96, + 128, + 134, + 82, + 96, + 128, + 134, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 96, + 32, + 134, + 1, + 81, + 133, + 130, + 3, + 96, + 32, + 135, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 96, + 64, + 133, + 1, + 81, + 132, + 130, + 3, + 96, + 64, + 134, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 146, + 1, + 81, + 144, + 96, + 96, + 129, + 132, + 3, + 145, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 86, + 91, + 96, + 2, + 84, + 129, + 16, + 21, + 97, + 20, + 124, + 87, + 96, + 2, + 96, + 0, + 82, + 96, + 2, + 27, + 127, + 64, + 87, + 135, + 250, + 18, + 168, + 35, + 224, + 242, + 183, + 99, + 28, + 196, + 27, + 59, + 168, + 130, + 139, + 51, + 33, + 202, + 129, + 17, + 17, + 250, + 117, + 205, + 58, + 163, + 187, + 90, + 206, + 1, + 144, + 96, + 0, + 144, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 50, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 144, + 96, + 1, + 130, + 129, + 28, + 146, + 22, + 128, + 21, + 97, + 20, + 194, + 87, + 91, + 96, + 32, + 131, + 16, + 20, + 97, + 20, + 172, + 87, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 34, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 145, + 96, + 127, + 22, + 145, + 97, + 20, + 161, + 86, + 91, + 144, + 96, + 0, + 146, + 145, + 128, + 84, + 145, + 97, + 20, + 221, + 131, + 97, + 20, + 146, + 86, + 91, + 145, + 130, + 130, + 82, + 96, + 1, + 147, + 132, + 129, + 22, + 144, + 129, + 96, + 0, + 20, + 97, + 21, + 63, + 87, + 80, + 96, + 1, + 20, + 97, + 20, + 255, + 87, + 91, + 80, + 80, + 80, + 80, + 86, + 91, + 144, + 145, + 147, + 148, + 80, + 96, + 0, + 82, + 96, + 32, + 146, + 131, + 96, + 0, + 32, + 146, + 132, + 96, + 0, + 148, + 91, + 131, + 134, + 16, + 97, + 21, + 43, + 87, + 80, + 80, + 80, + 80, + 1, + 1, + 144, + 56, + 128, + 128, + 128, + 97, + 20, + 249, + 86, + 91, + 128, + 84, + 133, + 135, + 1, + 131, + 1, + 82, + 148, + 1, + 147, + 133, + 144, + 130, + 1, + 97, + 21, + 20, + 86, + 91, + 146, + 148, + 80, + 80, + 80, + 96, + 32, + 147, + 148, + 80, + 96, + 255, + 25, + 22, + 131, + 131, + 1, + 82, + 21, + 21, + 96, + 5, + 27, + 1, + 1, + 144, + 56, + 128, + 128, + 128, + 97, + 20, + 249, + 86, + 91, + 96, + 128, + 129, + 1, + 144, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 86, + 91, + 144, + 96, + 31, + 128, + 25, + 145, + 1, + 22, + 129, + 1, + 144, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 6, + 33, + 87, + 96, + 5, + 27, + 96, + 32, + 1, + 144, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 6, + 33, + 87, + 96, + 31, + 1, + 96, + 31, + 25, + 22, + 96, + 32, + 1, + 144, + 86, + 91, + 129, + 96, + 31, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 53, + 144, + 97, + 21, + 231, + 130, + 97, + 21, + 181, + 86, + 91, + 146, + 97, + 21, + 245, + 96, + 64, + 81, + 148, + 133, + 97, + 21, + 125, + 86, + 91, + 130, + 132, + 82, + 96, + 32, + 131, + 131, + 1, + 1, + 17, + 97, + 1, + 88, + 87, + 129, + 96, + 0, + 146, + 96, + 32, + 128, + 147, + 1, + 131, + 134, + 1, + 55, + 131, + 1, + 1, + 82, + 144, + 86, + 91, + 129, + 96, + 31, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 53, + 145, + 97, + 22, + 46, + 131, + 97, + 21, + 158, + 86, + 91, + 146, + 97, + 22, + 60, + 96, + 64, + 81, + 148, + 133, + 97, + 21, + 125, + 86, + 91, + 128, + 132, + 82, + 96, + 32, + 146, + 131, + 128, + 134, + 1, + 146, + 96, + 5, + 27, + 130, + 1, + 1, + 146, + 131, + 17, + 97, + 1, + 88, + 87, + 131, + 1, + 144, + 91, + 130, + 130, + 16, + 97, + 22, + 102, + 87, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 129, + 53, + 129, + 82, + 144, + 131, + 1, + 144, + 131, + 1, + 97, + 22, + 88, + 86, + 91, + 96, + 0, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 51, + 3, + 97, + 22, + 137, + 87, + 86, + 91, + 96, + 100, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 32, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 99, + 97, + 108, + 108, + 101, + 114, + 32, + 105, + 115, + 32, + 110, + 111, + 116, + 32, + 116, + 104, + 101, + 32, + 111, + 119, + 110, + 101, + 114, + 96, + 68, + 130, + 1, + 82, + 253, + 91, + 96, + 0, + 25, + 129, + 20, + 97, + 19, + 81, + 87, + 96, + 1, + 1, + 144, + 86, + 91, + 128, + 81, + 130, + 16, + 21, + 97, + 20, + 124, + 87, + 96, + 32, + 145, + 96, + 5, + 27, + 1, + 1, + 144, + 86, + 91, + 129, + 129, + 16, + 97, + 22, + 251, + 87, + 80, + 80, + 86, + 91, + 96, + 0, + 129, + 85, + 96, + 1, + 1, + 97, + 22, + 240, + 86, + 91, + 145, + 144, + 96, + 31, + 129, + 17, + 97, + 23, + 22, + 87, + 80, + 80, + 80, + 86, + 91, + 97, + 23, + 66, + 146, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 32, + 96, + 31, + 132, + 1, + 96, + 5, + 28, + 131, + 1, + 147, + 16, + 97, + 23, + 68, + 87, + 91, + 96, + 31, + 1, + 96, + 5, + 28, + 1, + 144, + 97, + 22, + 240, + 86, + 91, + 86, + 91, + 144, + 145, + 80, + 129, + 144, + 97, + 23, + 53, + 86, + 91, + 21, + 97, + 23, + 85, + 87, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 16, + 96, + 36, + 130, + 1, + 82, + 111, + 18, + 91, + 157, + 152, + 91, + 26, + 89, + 8, + 19, + 84, + 213, + 8, + 28, + 155, + 219, + 221, + 96, + 130, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 144, + 97, + 23, + 151, + 130, + 97, + 21, + 158, + 86, + 91, + 97, + 23, + 164, + 96, + 64, + 81, + 145, + 130, + 97, + 21, + 125, + 86, + 91, + 130, + 129, + 82, + 128, + 146, + 97, + 23, + 181, + 96, + 31, + 25, + 145, + 97, + 21, + 158, + 86, + 91, + 1, + 144, + 96, + 0, + 91, + 130, + 129, + 16, + 97, + 23, + 198, + 87, + 80, + 80, + 80, + 86, + 91, + 128, + 96, + 96, + 96, + 32, + 128, + 147, + 133, + 1, + 1, + 82, + 1, + 97, + 23, + 186, + 86, + 91, + 144, + 129, + 81, + 128, + 130, + 82, + 96, + 32, + 128, + 128, + 147, + 1, + 147, + 1, + 145, + 96, + 0, + 91, + 130, + 129, + 16, + 97, + 23, + 247, + 87, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 131, + 81, + 133, + 82, + 147, + 129, + 1, + 147, + 146, + 129, + 1, + 146, + 96, + 1, + 1, + 97, + 23, + 233, + 86, + 91, + 144, + 145, + 96, + 0, + 129, + 129, + 82, + 96, + 4, + 147, + 96, + 32, + 147, + 133, + 133, + 82, + 96, + 64, + 147, + 132, + 132, + 32, + 84, + 144, + 131, + 81, + 145, + 96, + 1, + 146, + 131, + 16, + 21, + 97, + 26, + 54, + 87, + 144, + 97, + 24, + 66, + 136, + 148, + 147, + 146, + 136, + 135, + 1, + 81, + 20, + 97, + 23, + 78, + 86, + 91, + 96, + 2, + 130, + 91, + 97, + 25, + 116, + 87, + 91, + 80, + 80, + 80, + 97, + 24, + 117, + 144, + 97, + 24, + 135, + 134, + 81, + 148, + 133, + 147, + 132, + 147, + 99, + 30, + 142, + 30, + 19, + 96, + 224, + 27, + 133, + 82, + 137, + 140, + 134, + 1, + 82, + 96, + 68, + 133, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 131, + 129, + 3, + 96, + 3, + 25, + 1, + 96, + 36, + 133, + 1, + 82, + 144, + 97, + 23, + 215, + 86, + 91, + 3, + 129, + 127, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 90, + 250, + 130, + 145, + 129, + 97, + 25, + 56, + 87, + 91, + 80, + 97, + 25, + 48, + 87, + 80, + 96, + 100, + 148, + 80, + 61, + 21, + 97, + 25, + 42, + 87, + 61, + 144, + 97, + 24, + 216, + 130, + 97, + 21, + 181, + 86, + 91, + 145, + 97, + 24, + 229, + 132, + 81, + 147, + 132, + 97, + 21, + 125, + 86, + 91, + 130, + 82, + 131, + 61, + 146, + 1, + 62, + 91, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 145, + 130, + 1, + 82, + 96, + 23, + 96, + 36, + 130, + 1, + 82, + 127, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 105, + 110, + 99, + 108, + 117, + 115, + 105, + 111, + 110, + 32, + 112, + 114, + 111, + 111, + 102, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 253, + 91, + 80, + 97, + 24, + 237, + 86, + 91, + 147, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 144, + 145, + 80, + 132, + 129, + 129, + 61, + 131, + 17, + 97, + 25, + 109, + 87, + 91, + 97, + 25, + 80, + 129, + 131, + 97, + 21, + 125, + 86, + 91, + 129, + 1, + 3, + 18, + 97, + 25, + 105, + 87, + 81, + 128, + 21, + 21, + 129, + 3, + 97, + 25, + 105, + 87, + 144, + 56, + 97, + 24, + 189, + 86, + 91, + 130, + 128, + 253, + 91, + 80, + 61, + 97, + 25, + 70, + 86, + 91, + 144, + 145, + 146, + 147, + 133, + 81, + 130, + 16, + 21, + 97, + 26, + 47, + 87, + 80, + 129, + 134, + 82, + 136, + 136, + 82, + 134, + 134, + 32, + 96, + 1, + 25, + 144, + 132, + 1, + 130, + 130, + 1, + 131, + 129, + 17, + 97, + 26, + 28, + 87, + 129, + 84, + 17, + 21, + 97, + 26, + 9, + 87, + 135, + 82, + 129, + 137, + 136, + 32, + 1, + 1, + 84, + 97, + 25, + 182, + 130, + 135, + 97, + 22, + 220, + 86, + 91, + 81, + 3, + 97, + 25, + 207, + 87, + 144, + 97, + 25, + 199, + 131, + 146, + 97, + 22, + 205, + 86, + 91, + 136, + 148, + 147, + 97, + 24, + 70, + 86, + 91, + 134, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 128, + 138, + 1, + 137, + 144, + 82, + 96, + 20, + 96, + 36, + 130, + 1, + 82, + 115, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 114, + 111, + 111, + 116, + 32, + 98, + 97, + 108, + 97, + 110, + 99, + 101, + 96, + 96, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 136, + 82, + 96, + 50, + 139, + 82, + 96, + 36, + 136, + 253, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 137, + 82, + 96, + 17, + 140, + 82, + 96, + 36, + 137, + 253, + 91, + 147, + 146, + 97, + 24, + 75, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 134, + 82, + 96, + 50, + 137, + 82, + 96, + 36, + 134, + 253, + 254, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 76, + 105, + 117, + 0, + 151, + 107, + 128, + 235, + 253, + 185, + 76, + 134, + 25, + 113, + 48, + 248, + 91, + 66, + 119, + 199, + 73, + 98, + 8, + 212, + 2, + 169, + 230, + 39, + 146, + 80, + 83, + 242, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The bytecode of the contract. + pub static SUMMA_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = &[ + 96, + 128, + 128, + 96, + 64, + 82, + 96, + 4, + 54, + 16, + 21, + 97, + 0, + 19, + 87, + 96, + 0, + 128, + 253, + 91, + 96, + 0, + 53, + 96, + 224, + 28, + 144, + 129, + 99, + 25, + 179, + 57, + 104, + 20, + 97, + 18, + 99, + 87, + 80, + 128, + 99, + 73, + 206, + 137, + 151, + 20, + 97, + 18, + 55, + 87, + 128, + 99, + 113, + 80, + 24, + 166, + 20, + 97, + 17, + 222, + 87, + 128, + 99, + 121, + 80, + 44, + 85, + 20, + 97, + 17, + 165, + 87, + 128, + 99, + 141, + 165, + 203, + 91, + 20, + 97, + 17, + 124, + 87, + 128, + 99, + 163, + 196, + 188, + 248, + 20, + 97, + 16, + 168, + 87, + 128, + 99, + 199, + 221, + 202, + 14, + 20, + 97, + 9, + 176, + 87, + 128, + 99, + 200, + 229, + 129, + 71, + 20, + 97, + 9, + 77, + 87, + 128, + 99, + 218, + 100, + 167, + 80, + 20, + 97, + 1, + 93, + 87, + 99, + 242, + 253, + 227, + 139, + 20, + 97, + 0, + 141, + 87, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 129, + 22, + 145, + 130, + 144, + 3, + 97, + 1, + 88, + 87, + 97, + 0, + 188, + 97, + 22, + 117, + 86, + 91, + 129, + 21, + 97, + 1, + 4, + 87, + 96, + 0, + 84, + 130, + 107, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 96, + 160, + 27, + 130, + 22, + 23, + 96, + 0, + 85, + 22, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 96, + 0, + 128, + 163, + 0, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 110, + 101, + 119, + 32, + 111, + 119, + 110, + 101, + 114, + 32, + 105, + 115, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 96, + 68, + 130, + 1, + 82, + 101, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 96, + 0, + 128, + 253, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 128, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 36, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 1, + 141, + 144, + 54, + 144, + 96, + 4, + 1, + 97, + 22, + 23, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 68, + 53, + 17, + 97, + 1, + 88, + 87, + 54, + 96, + 35, + 96, + 68, + 53, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 96, + 68, + 53, + 96, + 4, + 1, + 53, + 97, + 1, + 186, + 129, + 97, + 21, + 158, + 86, + 91, + 97, + 1, + 199, + 96, + 64, + 81, + 145, + 130, + 97, + 21, + 125, + 86, + 91, + 129, + 129, + 82, + 96, + 32, + 129, + 1, + 128, + 146, + 54, + 96, + 36, + 130, + 96, + 5, + 27, + 96, + 68, + 53, + 1, + 1, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 96, + 68, + 53, + 1, + 145, + 91, + 96, + 36, + 130, + 96, + 5, + 27, + 96, + 68, + 53, + 1, + 1, + 131, + 16, + 97, + 8, + 157, + 87, + 80, + 80, + 80, + 97, + 2, + 5, + 97, + 22, + 117, + 86, + 91, + 97, + 2, + 18, + 96, + 4, + 53, + 21, + 21, + 97, + 23, + 78, + 86, + 91, + 130, + 81, + 129, + 81, + 3, + 97, + 8, + 58, + 87, + 97, + 2, + 37, + 129, + 81, + 97, + 23, + 141, + 86, + 91, + 144, + 97, + 2, + 48, + 129, + 81, + 97, + 23, + 141, + 86, + 91, + 147, + 96, + 0, + 91, + 130, + 81, + 129, + 16, + 21, + 97, + 3, + 105, + 87, + 96, + 32, + 97, + 2, + 73, + 130, + 133, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 128, + 97, + 3, + 84, + 87, + 91, + 21, + 97, + 3, + 22, + 87, + 97, + 2, + 100, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 21, + 97, + 2, + 191, + 87, + 128, + 97, + 2, + 120, + 97, + 2, + 186, + 146, + 133, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 97, + 2, + 132, + 130, + 135, + 97, + 22, + 220, + 86, + 91, + 82, + 97, + 2, + 143, + 129, + 134, + 97, + 22, + 220, + 86, + 91, + 80, + 96, + 32, + 97, + 2, + 156, + 130, + 134, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 97, + 2, + 169, + 130, + 137, + 97, + 22, + 220, + 86, + 91, + 82, + 97, + 2, + 180, + 129, + 136, + 97, + 22, + 220, + 86, + 91, + 80, + 97, + 22, + 205, + 86, + 91, + 97, + 2, + 52, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 41, + 96, + 36, + 130, + 1, + 82, + 127, + 65, + 108, + 108, + 32, + 114, + 111, + 111, + 116, + 32, + 115, + 117, + 109, + 115, + 32, + 115, + 104, + 111, + 117, + 108, + 100, + 32, + 98, + 101, + 32, + 103, + 114, + 101, + 97, + 116, + 101, + 114, + 32, + 96, + 68, + 130, + 1, + 82, + 104, + 116, + 104, + 97, + 110, + 32, + 122, + 101, + 114, + 111, + 96, + 184, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 22, + 96, + 36, + 130, + 1, + 82, + 117, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 99, + 114, + 121, + 112, + 116, + 111, + 99, + 117, + 114, + 114, + 101, + 110, + 99, + 121, + 96, + 80, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 80, + 97, + 3, + 95, + 129, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 81, + 21, + 21, + 97, + 2, + 85, + 86, + 91, + 80, + 145, + 132, + 96, + 64, + 81, + 144, + 97, + 3, + 121, + 130, + 97, + 21, + 98, + 86, + 91, + 96, + 4, + 53, + 130, + 82, + 96, + 32, + 130, + 1, + 146, + 133, + 132, + 82, + 96, + 64, + 131, + 1, + 82, + 96, + 96, + 130, + 1, + 82, + 96, + 100, + 53, + 96, + 0, + 82, + 96, + 4, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 145, + 129, + 81, + 131, + 85, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 32, + 144, + 96, + 1, + 133, + 1, + 84, + 131, + 96, + 1, + 135, + 1, + 85, + 128, + 132, + 16, + 97, + 8, + 26, + 87, + 91, + 80, + 1, + 96, + 1, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 96, + 0, + 91, + 131, + 129, + 16, + 97, + 8, + 6, + 87, + 80, + 80, + 80, + 80, + 96, + 64, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 2, + 132, + 1, + 84, + 130, + 96, + 2, + 134, + 1, + 85, + 128, + 131, + 16, + 97, + 7, + 141, + 87, + 91, + 80, + 96, + 32, + 1, + 144, + 96, + 2, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 6, + 176, + 87, + 80, + 80, + 80, + 80, + 96, + 96, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 64, + 27, + 130, + 17, + 97, + 6, + 33, + 87, + 96, + 3, + 131, + 1, + 84, + 130, + 96, + 3, + 133, + 1, + 85, + 128, + 131, + 16, + 97, + 6, + 55, + 87, + 91, + 80, + 96, + 32, + 96, + 3, + 145, + 1, + 146, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 5, + 62, + 87, + 80, + 80, + 80, + 80, + 97, + 4, + 158, + 96, + 64, + 81, + 146, + 96, + 4, + 53, + 132, + 82, + 96, + 96, + 96, + 32, + 133, + 1, + 82, + 96, + 96, + 132, + 1, + 144, + 97, + 23, + 215, + 86, + 91, + 144, + 130, + 130, + 3, + 96, + 64, + 132, + 1, + 82, + 81, + 128, + 130, + 82, + 96, + 32, + 130, + 1, + 145, + 96, + 32, + 130, + 96, + 5, + 27, + 130, + 1, + 1, + 148, + 146, + 96, + 0, + 145, + 91, + 131, + 131, + 16, + 97, + 4, + 241, + 87, + 96, + 100, + 53, + 127, + 136, + 191, + 199, + 56, + 156, + 184, + 49, + 234, + 2, + 8, + 255, + 16, + 109, + 166, + 245, + 201, + 248, + 128, + 54, + 186, + 8, + 79, + 30, + 176, + 8, + 210, + 120, + 141, + 61, + 69, + 153, + 141, + 135, + 137, + 3, + 136, + 162, + 0, + 91, + 144, + 145, + 146, + 147, + 149, + 96, + 32, + 128, + 97, + 5, + 47, + 96, + 1, + 147, + 96, + 31, + 25, + 134, + 130, + 3, + 1, + 135, + 82, + 138, + 81, + 144, + 131, + 97, + 5, + 31, + 131, + 81, + 96, + 64, + 132, + 82, + 96, + 64, + 132, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 146, + 1, + 81, + 144, + 132, + 129, + 132, + 3, + 145, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 152, + 1, + 147, + 1, + 147, + 1, + 145, + 147, + 146, + 144, + 97, + 4, + 191, + 86, + 91, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 5, + 101, + 130, + 97, + 5, + 95, + 136, + 84, + 97, + 20, + 146, + 86, + 91, + 136, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 5, + 177, + 87, + 146, + 130, + 96, + 1, + 148, + 147, + 96, + 32, + 147, + 134, + 149, + 96, + 0, + 146, + 97, + 5, + 166, + 87, + 91, + 80, + 80, + 96, + 0, + 25, + 96, + 3, + 131, + 144, + 27, + 28, + 25, + 22, + 144, + 132, + 27, + 23, + 135, + 85, + 91, + 1, + 148, + 1, + 145, + 1, + 144, + 146, + 97, + 4, + 118, + 86, + 91, + 1, + 81, + 144, + 80, + 140, + 128, + 97, + 5, + 134, + 86, + 91, + 144, + 134, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 6, + 9, + 87, + 80, + 131, + 96, + 32, + 147, + 96, + 1, + 150, + 147, + 135, + 150, + 147, + 135, + 148, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 5, + 240, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 135, + 85, + 97, + 5, + 154, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 140, + 128, + 128, + 97, + 5, + 227, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 5, + 191, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 65, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 3, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 131, + 130, + 1, + 91, + 129, + 131, + 1, + 129, + 16, + 97, + 6, + 88, + 87, + 80, + 80, + 97, + 4, + 96, + 86, + 91, + 128, + 97, + 6, + 101, + 96, + 1, + 146, + 84, + 97, + 20, + 146, + 86, + 91, + 128, + 97, + 6, + 114, + 87, + 91, + 80, + 1, + 97, + 6, + 72, + 86, + 91, + 96, + 31, + 144, + 129, + 129, + 17, + 132, + 20, + 97, + 6, + 139, + 87, + 80, + 80, + 96, + 0, + 129, + 85, + 91, + 138, + 97, + 6, + 107, + 86, + 91, + 97, + 6, + 167, + 96, + 0, + 146, + 132, + 132, + 82, + 96, + 32, + 132, + 32, + 146, + 1, + 96, + 5, + 28, + 130, + 1, + 133, + 131, + 1, + 97, + 22, + 240, + 86, + 91, + 129, + 131, + 85, + 85, + 97, + 6, + 133, + 86, + 91, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 6, + 209, + 130, + 97, + 5, + 95, + 136, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 7, + 29, + 87, + 146, + 130, + 96, + 1, + 148, + 147, + 96, + 32, + 147, + 134, + 149, + 96, + 0, + 146, + 97, + 7, + 18, + 87, + 91, + 80, + 80, + 96, + 0, + 25, + 96, + 3, + 131, + 144, + 27, + 28, + 25, + 22, + 144, + 132, + 27, + 23, + 135, + 85, + 91, + 1, + 148, + 1, + 145, + 1, + 144, + 146, + 97, + 4, + 48, + 86, + 91, + 1, + 81, + 144, + 80, + 142, + 128, + 97, + 6, + 242, + 86, + 91, + 144, + 134, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 7, + 117, + 87, + 80, + 131, + 96, + 32, + 147, + 96, + 1, + 150, + 147, + 135, + 150, + 147, + 135, + 148, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 7, + 92, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 135, + 85, + 97, + 7, + 6, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 142, + 128, + 128, + 97, + 7, + 79, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 7, + 43, + 86, + 91, + 96, + 2, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 131, + 130, + 1, + 91, + 129, + 131, + 1, + 129, + 16, + 97, + 7, + 174, + 87, + 80, + 80, + 97, + 4, + 26, + 86, + 91, + 128, + 97, + 7, + 187, + 96, + 1, + 146, + 84, + 97, + 20, + 146, + 86, + 91, + 128, + 97, + 7, + 200, + 87, + 91, + 80, + 1, + 97, + 7, + 158, + 86, + 91, + 96, + 31, + 144, + 129, + 129, + 17, + 132, + 20, + 97, + 7, + 225, + 87, + 80, + 80, + 96, + 0, + 129, + 85, + 91, + 139, + 97, + 7, + 193, + 86, + 91, + 97, + 7, + 253, + 96, + 0, + 146, + 132, + 132, + 82, + 96, + 32, + 132, + 32, + 146, + 1, + 96, + 5, + 28, + 130, + 1, + 133, + 131, + 1, + 97, + 22, + 240, + 86, + 91, + 129, + 131, + 85, + 85, + 97, + 7, + 219, + 86, + 91, + 96, + 1, + 144, + 96, + 32, + 132, + 81, + 148, + 1, + 147, + 129, + 132, + 1, + 85, + 1, + 97, + 3, + 233, + 86, + 91, + 97, + 8, + 52, + 144, + 96, + 1, + 135, + 1, + 96, + 0, + 82, + 132, + 132, + 96, + 0, + 32, + 145, + 130, + 1, + 145, + 1, + 97, + 22, + 240, + 86, + 91, + 136, + 97, + 3, + 216, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 53, + 96, + 36, + 130, + 1, + 82, + 127, + 82, + 111, + 111, + 116, + 32, + 108, + 105, + 97, + 98, + 105, + 108, + 105, + 116, + 105, + 101, + 115, + 32, + 115, + 117, + 109, + 115, + 32, + 97, + 110, + 100, + 32, + 108, + 105, + 97, + 98, + 105, + 108, + 96, + 68, + 130, + 1, + 82, + 116, + 13, + 46, + 141, + 44, + 174, + 100, + 13, + 206, + 173, + 172, + 76, + 174, + 68, + 13, + 173, + 46, + 109, + 172, + 46, + 140, + 109, + 96, + 91, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 130, + 53, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 1, + 88, + 87, + 96, + 64, + 96, + 68, + 53, + 131, + 1, + 54, + 3, + 96, + 35, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 64, + 81, + 145, + 96, + 64, + 131, + 1, + 131, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 36, + 130, + 96, + 68, + 53, + 1, + 1, + 53, + 17, + 97, + 1, + 88, + 87, + 97, + 9, + 9, + 54, + 96, + 36, + 96, + 68, + 53, + 132, + 1, + 129, + 129, + 1, + 53, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 82, + 96, + 68, + 129, + 129, + 53, + 1, + 1, + 53, + 145, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 131, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 147, + 97, + 9, + 60, + 96, + 32, + 148, + 147, + 134, + 134, + 149, + 54, + 146, + 96, + 68, + 53, + 1, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 130, + 1, + 82, + 129, + 82, + 1, + 147, + 1, + 146, + 144, + 80, + 97, + 1, + 233, + 86, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 96, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 96, + 4, + 53, + 129, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 9, + 126, + 144, + 54, + 144, + 96, + 4, + 1, + 97, + 21, + 208, + 86, + 91, + 144, + 96, + 36, + 53, + 144, + 129, + 17, + 97, + 1, + 88, + 87, + 96, + 32, + 145, + 97, + 9, + 157, + 97, + 9, + 166, + 146, + 54, + 144, + 96, + 4, + 1, + 97, + 22, + 23, + 86, + 91, + 96, + 68, + 53, + 145, + 97, + 24, + 11, + 86, + 91, + 96, + 64, + 81, + 144, + 21, + 21, + 129, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 54, + 96, + 35, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 96, + 4, + 1, + 53, + 144, + 97, + 9, + 236, + 130, + 97, + 21, + 158, + 86, + 91, + 144, + 97, + 9, + 250, + 96, + 64, + 81, + 146, + 131, + 97, + 21, + 125, + 86, + 91, + 130, + 130, + 82, + 96, + 32, + 130, + 1, + 144, + 96, + 36, + 130, + 148, + 96, + 5, + 27, + 130, + 1, + 1, + 144, + 54, + 130, + 17, + 97, + 1, + 88, + 87, + 96, + 36, + 129, + 1, + 146, + 91, + 130, + 132, + 16, + 97, + 15, + 206, + 87, + 133, + 133, + 97, + 10, + 43, + 97, + 22, + 117, + 86, + 91, + 96, + 0, + 91, + 129, + 81, + 129, + 16, + 21, + 97, + 15, + 78, + 87, + 97, + 10, + 65, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 96, + 64, + 81, + 97, + 10, + 109, + 96, + 32, + 130, + 129, + 97, + 10, + 96, + 129, + 131, + 1, + 150, + 135, + 129, + 81, + 147, + 132, + 146, + 1, + 97, + 19, + 163, + 86, + 91, + 129, + 1, + 3, + 128, + 132, + 82, + 1, + 130, + 97, + 21, + 125, + 86, + 91, + 81, + 144, + 32, + 128, + 96, + 0, + 82, + 96, + 3, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 97, + 15, + 9, + 87, + 97, + 10, + 141, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 96, + 2, + 84, + 96, + 1, + 96, + 64, + 27, + 129, + 16, + 21, + 97, + 6, + 33, + 87, + 128, + 96, + 1, + 97, + 10, + 173, + 146, + 1, + 96, + 2, + 85, + 97, + 20, + 66, + 86, + 91, + 145, + 144, + 145, + 97, + 14, + 243, + 87, + 128, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 129, + 144, + 97, + 10, + 221, + 130, + 97, + 10, + 215, + 135, + 84, + 97, + 20, + 146, + 86, + 91, + 135, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 14, + 135, + 87, + 96, + 0, + 146, + 97, + 14, + 124, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 130, + 85, + 91, + 96, + 32, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 129, + 144, + 97, + 11, + 58, + 130, + 97, + 11, + 49, + 96, + 1, + 136, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 1, + 136, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 14, + 10, + 87, + 96, + 0, + 146, + 97, + 13, + 255, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 96, + 1, + 131, + 1, + 85, + 91, + 96, + 64, + 129, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 11, + 152, + 130, + 97, + 11, + 143, + 96, + 2, + 135, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 2, + 135, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 13, + 140, + 87, + 96, + 96, + 147, + 146, + 145, + 96, + 0, + 145, + 131, + 97, + 13, + 129, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 96, + 3, + 27, + 28, + 25, + 22, + 23, + 96, + 2, + 132, + 1, + 85, + 91, + 1, + 81, + 128, + 81, + 144, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 97, + 6, + 33, + 87, + 97, + 11, + 249, + 130, + 97, + 11, + 240, + 96, + 3, + 134, + 1, + 84, + 97, + 20, + 146, + 86, + 91, + 96, + 3, + 134, + 1, + 97, + 23, + 7, + 86, + 91, + 96, + 32, + 144, + 96, + 31, + 131, + 17, + 96, + 1, + 20, + 97, + 13, + 18, + 87, + 96, + 3, + 146, + 145, + 96, + 0, + 145, + 131, + 97, + 13, + 7, + 87, + 91, + 80, + 80, + 129, + 96, + 1, + 27, + 145, + 96, + 0, + 25, + 144, + 132, + 27, + 28, + 25, + 22, + 23, + 145, + 1, + 85, + 91, + 96, + 2, + 84, + 144, + 96, + 0, + 82, + 96, + 3, + 96, + 32, + 82, + 96, + 64, + 96, + 0, + 32, + 85, + 97, + 12, + 69, + 129, + 131, + 97, + 22, + 220, + 86, + 91, + 81, + 81, + 81, + 21, + 21, + 128, + 97, + 12, + 239, + 87, + 91, + 128, + 97, + 12, + 215, + 87, + 91, + 128, + 97, + 12, + 191, + 87, + 91, + 21, + 97, + 12, + 111, + 87, + 97, + 12, + 106, + 144, + 97, + 22, + 205, + 86, + 91, + 97, + 10, + 46, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 34, + 96, + 36, + 130, + 1, + 82, + 127, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 112, + 114, + 111, + 111, + 102, + 32, + 111, + 102, + 32, + 97, + 100, + 100, + 114, + 101, + 115, + 115, + 32, + 111, + 119, + 110, + 101, + 114, + 115, + 104, + 96, + 68, + 130, + 1, + 82, + 97, + 6, + 151, + 96, + 244, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 144, + 253, + 91, + 80, + 96, + 96, + 97, + 12, + 204, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 92, + 86, + 91, + 80, + 96, + 64, + 97, + 12, + 228, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 86, + 86, + 91, + 80, + 96, + 32, + 97, + 12, + 252, + 130, + 132, + 97, + 22, + 220, + 86, + 91, + 81, + 1, + 81, + 81, + 21, + 21, + 97, + 12, + 80, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 12, + 20, + 86, + 91, + 144, + 96, + 3, + 132, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 13, + 105, + 87, + 80, + 145, + 131, + 145, + 96, + 1, + 147, + 96, + 3, + 149, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 13, + 81, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 145, + 1, + 85, + 97, + 12, + 41, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 131, + 134, + 27, + 96, + 248, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 13, + 67, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 13, + 35, + 86, + 91, + 1, + 81, + 144, + 80, + 137, + 128, + 97, + 11, + 180, + 86, + 91, + 144, + 96, + 2, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 145, + 96, + 0, + 91, + 96, + 31, + 25, + 133, + 22, + 129, + 16, + 97, + 13, + 231, + 87, + 80, + 145, + 131, + 145, + 96, + 1, + 147, + 96, + 96, + 150, + 149, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 13, + 206, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 96, + 2, + 132, + 1, + 85, + 97, + 11, + 204, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 137, + 128, + 128, + 97, + 13, + 190, + 86, + 91, + 145, + 146, + 96, + 32, + 96, + 1, + 129, + 146, + 134, + 133, + 1, + 81, + 129, + 85, + 1, + 148, + 1, + 146, + 1, + 97, + 13, + 157, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 11, + 80, + 86, + 91, + 146, + 80, + 96, + 1, + 133, + 1, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 0, + 147, + 91, + 96, + 31, + 25, + 132, + 22, + 133, + 16, + 97, + 14, + 97, + 87, + 96, + 1, + 148, + 80, + 131, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 14, + 72, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 96, + 1, + 131, + 1, + 85, + 97, + 11, + 104, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 14, + 56, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 85, + 96, + 32, + 148, + 133, + 1, + 148, + 96, + 1, + 144, + 147, + 1, + 146, + 144, + 145, + 1, + 144, + 97, + 14, + 29, + 86, + 91, + 1, + 81, + 144, + 80, + 136, + 128, + 97, + 10, + 243, + 86, + 91, + 146, + 80, + 132, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 0, + 147, + 91, + 96, + 31, + 25, + 132, + 22, + 133, + 16, + 97, + 14, + 216, + 87, + 96, + 1, + 148, + 80, + 131, + 96, + 31, + 25, + 129, + 22, + 16, + 97, + 14, + 191, + 87, + 91, + 80, + 80, + 80, + 129, + 27, + 1, + 130, + 85, + 97, + 11, + 8, + 86, + 91, + 1, + 81, + 96, + 0, + 25, + 96, + 248, + 132, + 96, + 3, + 27, + 22, + 28, + 25, + 22, + 144, + 85, + 136, + 128, + 128, + 97, + 14, + 178, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 85, + 96, + 32, + 148, + 133, + 1, + 148, + 96, + 1, + 144, + 147, + 1, + 146, + 144, + 145, + 1, + 144, + 97, + 14, + 151, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 0, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 24, + 96, + 36, + 130, + 1, + 82, + 127, + 65, + 100, + 100, + 114, + 101, + 115, + 115, + 32, + 97, + 108, + 114, + 101, + 97, + 100, + 121, + 32, + 118, + 101, + 114, + 105, + 102, + 105, + 101, + 100, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 80, + 96, + 64, + 81, + 144, + 96, + 32, + 130, + 1, + 144, + 96, + 32, + 131, + 82, + 81, + 128, + 145, + 82, + 96, + 64, + 130, + 1, + 144, + 96, + 64, + 129, + 96, + 5, + 27, + 132, + 1, + 1, + 147, + 145, + 96, + 0, + 144, + 91, + 130, + 130, + 16, + 97, + 15, + 163, + 87, + 127, + 56, + 35, + 21, + 212, + 213, + 106, + 96, + 53, + 225, + 137, + 155, + 255, + 231, + 125, + 155, + 236, + 239, + 175, + 95, + 38, + 80, + 228, + 50, + 59, + 39, + 133, + 72, + 87, + 160, + 69, + 70, + 88, + 133, + 135, + 3, + 134, + 161, + 0, + 91, + 144, + 145, + 146, + 148, + 96, + 32, + 128, + 97, + 15, + 192, + 96, + 1, + 147, + 96, + 63, + 25, + 137, + 130, + 3, + 1, + 134, + 82, + 137, + 81, + 97, + 19, + 235, + 86, + 91, + 151, + 1, + 146, + 1, + 146, + 1, + 144, + 146, + 145, + 97, + 15, + 116, + 86, + 91, + 131, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 130, + 1, + 96, + 128, + 96, + 35, + 25, + 130, + 54, + 3, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 64, + 81, + 145, + 97, + 15, + 251, + 131, + 97, + 21, + 98, + 86, + 91, + 96, + 36, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 30, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 131, + 82, + 96, + 68, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 67, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 32, + 132, + 1, + 82, + 96, + 100, + 130, + 1, + 53, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 107, + 144, + 96, + 36, + 54, + 145, + 133, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 64, + 132, + 1, + 82, + 96, + 132, + 130, + 1, + 53, + 146, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 132, + 17, + 97, + 1, + 88, + 87, + 97, + 16, + 152, + 96, + 32, + 148, + 147, + 96, + 36, + 134, + 149, + 54, + 146, + 1, + 1, + 97, + 21, + 208, + 86, + 91, + 96, + 96, + 130, + 1, + 82, + 129, + 82, + 1, + 147, + 1, + 146, + 97, + 10, + 26, + 86, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 2, + 84, + 129, + 16, + 21, + 97, + 1, + 88, + 87, + 97, + 16, + 210, + 97, + 17, + 78, + 145, + 97, + 20, + 66, + 86, + 91, + 80, + 97, + 17, + 120, + 96, + 3, + 97, + 17, + 106, + 96, + 64, + 81, + 147, + 97, + 16, + 244, + 133, + 97, + 16, + 237, + 129, + 132, + 97, + 20, + 204, + 86, + 91, + 3, + 134, + 97, + 21, + 125, + 86, + 91, + 97, + 17, + 92, + 96, + 64, + 81, + 97, + 17, + 18, + 129, + 97, + 17, + 11, + 129, + 96, + 1, + 135, + 1, + 97, + 20, + 204, + 86, + 91, + 3, + 130, + 97, + 21, + 125, + 86, + 91, + 97, + 17, + 58, + 96, + 64, + 81, + 147, + 97, + 17, + 42, + 133, + 97, + 16, + 237, + 129, + 96, + 2, + 133, + 1, + 97, + 20, + 204, + 86, + 91, + 97, + 16, + 237, + 96, + 64, + 81, + 128, + 152, + 129, + 147, + 1, + 97, + 20, + 204, + 86, + 91, + 96, + 64, + 81, + 151, + 136, + 151, + 96, + 128, + 137, + 82, + 96, + 128, + 137, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 144, + 135, + 130, + 3, + 96, + 32, + 137, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 133, + 130, + 3, + 96, + 64, + 135, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 131, + 130, + 3, + 96, + 96, + 133, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 3, + 144, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 0, + 84, + 96, + 64, + 81, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 144, + 145, + 22, + 129, + 82, + 96, + 32, + 144, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 96, + 96, + 1, + 84, + 96, + 255, + 96, + 64, + 81, + 145, + 97, + 255, + 255, + 128, + 130, + 22, + 132, + 82, + 129, + 96, + 16, + 28, + 22, + 96, + 32, + 132, + 1, + 82, + 96, + 32, + 28, + 22, + 96, + 64, + 130, + 1, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 0, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 97, + 17, + 247, + 97, + 22, + 117, + 86, + 91, + 96, + 0, + 128, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 129, + 22, + 130, + 85, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 130, + 128, + 163, + 0, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 54, + 96, + 3, + 25, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 96, + 0, + 82, + 96, + 4, + 96, + 32, + 82, + 96, + 32, + 96, + 64, + 96, + 0, + 32, + 84, + 96, + 64, + 81, + 144, + 129, + 82, + 243, + 91, + 52, + 97, + 1, + 88, + 87, + 96, + 32, + 128, + 96, + 3, + 25, + 54, + 1, + 18, + 97, + 1, + 88, + 87, + 96, + 4, + 53, + 97, + 18, + 129, + 131, + 97, + 21, + 98, + 86, + 91, + 96, + 96, + 128, + 132, + 129, + 128, + 150, + 82, + 129, + 133, + 130, + 1, + 82, + 129, + 96, + 64, + 130, + 1, + 82, + 1, + 82, + 128, + 96, + 0, + 82, + 96, + 3, + 130, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 21, + 97, + 19, + 103, + 87, + 96, + 0, + 82, + 96, + 3, + 129, + 82, + 96, + 64, + 96, + 0, + 32, + 84, + 96, + 0, + 25, + 129, + 1, + 144, + 129, + 17, + 97, + 19, + 81, + 87, + 97, + 18, + 205, + 96, + 3, + 145, + 97, + 20, + 66, + 86, + 91, + 80, + 146, + 97, + 19, + 58, + 96, + 64, + 81, + 148, + 97, + 18, + 223, + 134, + 97, + 21, + 98, + 86, + 91, + 96, + 64, + 81, + 97, + 18, + 240, + 129, + 97, + 17, + 11, + 129, + 133, + 97, + 20, + 204, + 86, + 91, + 134, + 82, + 96, + 64, + 81, + 97, + 19, + 6, + 129, + 97, + 17, + 11, + 129, + 96, + 1, + 134, + 1, + 97, + 20, + 204, + 86, + 91, + 133, + 135, + 1, + 82, + 96, + 64, + 81, + 97, + 19, + 30, + 129, + 97, + 17, + 11, + 129, + 96, + 2, + 134, + 1, + 97, + 20, + 204, + 86, + 91, + 96, + 64, + 135, + 1, + 82, + 97, + 19, + 51, + 96, + 64, + 81, + 128, + 149, + 129, + 147, + 1, + 97, + 20, + 204, + 86, + 91, + 3, + 131, + 97, + 21, + 125, + 86, + 91, + 131, + 1, + 82, + 97, + 17, + 120, + 96, + 64, + 81, + 146, + 130, + 132, + 147, + 132, + 82, + 131, + 1, + 144, + 97, + 19, + 235, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 17, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 4, + 129, + 1, + 131, + 144, + 82, + 96, + 20, + 96, + 36, + 130, + 1, + 82, + 115, + 16, + 89, + 25, + 28, + 153, + 92, + 220, + 200, + 27, + 155, + 221, + 8, + 29, + 153, + 92, + 154, + 89, + 154, + 89, + 89, + 96, + 98, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 96, + 0, + 91, + 131, + 129, + 16, + 97, + 19, + 182, + 87, + 80, + 80, + 96, + 0, + 145, + 1, + 82, + 86, + 91, + 129, + 129, + 1, + 81, + 131, + 130, + 1, + 82, + 96, + 32, + 1, + 97, + 19, + 166, + 86, + 91, + 144, + 96, + 32, + 145, + 97, + 19, + 223, + 129, + 81, + 128, + 146, + 129, + 133, + 82, + 133, + 128, + 134, + 1, + 145, + 1, + 97, + 19, + 163, + 86, + 91, + 96, + 31, + 1, + 96, + 31, + 25, + 22, + 1, + 1, + 144, + 86, + 91, + 97, + 20, + 63, + 145, + 96, + 96, + 97, + 20, + 46, + 97, + 20, + 28, + 97, + 20, + 10, + 133, + 81, + 96, + 128, + 134, + 82, + 96, + 128, + 134, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 96, + 32, + 134, + 1, + 81, + 133, + 130, + 3, + 96, + 32, + 135, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 96, + 64, + 133, + 1, + 81, + 132, + 130, + 3, + 96, + 64, + 134, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 146, + 1, + 81, + 144, + 96, + 96, + 129, + 132, + 3, + 145, + 1, + 82, + 97, + 19, + 198, + 86, + 91, + 144, + 86, + 91, + 96, + 2, + 84, + 129, + 16, + 21, + 97, + 20, + 124, + 87, + 96, + 2, + 96, + 0, + 82, + 96, + 2, + 27, + 127, + 64, + 87, + 135, + 250, + 18, + 168, + 35, + 224, + 242, + 183, + 99, + 28, + 196, + 27, + 59, + 168, + 130, + 139, + 51, + 33, + 202, + 129, + 17, + 17, + 250, + 117, + 205, + 58, + 163, + 187, + 90, + 206, + 1, + 144, + 96, + 0, + 144, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 50, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 144, + 96, + 1, + 130, + 129, + 28, + 146, + 22, + 128, + 21, + 97, + 20, + 194, + 87, + 91, + 96, + 32, + 131, + 16, + 20, + 97, + 20, + 172, + 87, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 34, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 145, + 96, + 127, + 22, + 145, + 97, + 20, + 161, + 86, + 91, + 144, + 96, + 0, + 146, + 145, + 128, + 84, + 145, + 97, + 20, + 221, + 131, + 97, + 20, + 146, + 86, + 91, + 145, + 130, + 130, + 82, + 96, + 1, + 147, + 132, + 129, + 22, + 144, + 129, + 96, + 0, + 20, + 97, + 21, + 63, + 87, + 80, + 96, + 1, + 20, + 97, + 20, + 255, + 87, + 91, + 80, + 80, + 80, + 80, + 86, + 91, + 144, + 145, + 147, + 148, + 80, + 96, + 0, + 82, + 96, + 32, + 146, + 131, + 96, + 0, + 32, + 146, + 132, + 96, + 0, + 148, + 91, + 131, + 134, + 16, + 97, + 21, + 43, + 87, + 80, + 80, + 80, + 80, + 1, + 1, + 144, + 56, + 128, + 128, + 128, + 97, + 20, + 249, + 86, + 91, + 128, + 84, + 133, + 135, + 1, + 131, + 1, + 82, + 148, + 1, + 147, + 133, + 144, + 130, + 1, + 97, + 21, + 20, + 86, + 91, + 146, + 148, + 80, + 80, + 80, + 96, + 32, + 147, + 148, + 80, + 96, + 255, + 25, + 22, + 131, + 131, + 1, + 82, + 21, + 21, + 96, + 5, + 27, + 1, + 1, + 144, + 56, + 128, + 128, + 128, + 97, + 20, + 249, + 86, + 91, + 96, + 128, + 129, + 1, + 144, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 86, + 91, + 144, + 96, + 31, + 128, + 25, + 145, + 1, + 22, + 129, + 1, + 144, + 129, + 16, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 130, + 17, + 23, + 97, + 6, + 33, + 87, + 96, + 64, + 82, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 6, + 33, + 87, + 96, + 5, + 27, + 96, + 32, + 1, + 144, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 97, + 6, + 33, + 87, + 96, + 31, + 1, + 96, + 31, + 25, + 22, + 96, + 32, + 1, + 144, + 86, + 91, + 129, + 96, + 31, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 53, + 144, + 97, + 21, + 231, + 130, + 97, + 21, + 181, + 86, + 91, + 146, + 97, + 21, + 245, + 96, + 64, + 81, + 148, + 133, + 97, + 21, + 125, + 86, + 91, + 130, + 132, + 82, + 96, + 32, + 131, + 131, + 1, + 1, + 17, + 97, + 1, + 88, + 87, + 129, + 96, + 0, + 146, + 96, + 32, + 128, + 147, + 1, + 131, + 134, + 1, + 55, + 131, + 1, + 1, + 82, + 144, + 86, + 91, + 129, + 96, + 31, + 130, + 1, + 18, + 21, + 97, + 1, + 88, + 87, + 128, + 53, + 145, + 97, + 22, + 46, + 131, + 97, + 21, + 158, + 86, + 91, + 146, + 97, + 22, + 60, + 96, + 64, + 81, + 148, + 133, + 97, + 21, + 125, + 86, + 91, + 128, + 132, + 82, + 96, + 32, + 146, + 131, + 128, + 134, + 1, + 146, + 96, + 5, + 27, + 130, + 1, + 1, + 146, + 131, + 17, + 97, + 1, + 88, + 87, + 131, + 1, + 144, + 91, + 130, + 130, + 16, + 97, + 22, + 102, + 87, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 129, + 53, + 129, + 82, + 144, + 131, + 1, + 144, + 131, + 1, + 97, + 22, + 88, + 86, + 91, + 96, + 0, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 51, + 3, + 97, + 22, + 137, + 87, + 86, + 91, + 96, + 100, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 32, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 99, + 97, + 108, + 108, + 101, + 114, + 32, + 105, + 115, + 32, + 110, + 111, + 116, + 32, + 116, + 104, + 101, + 32, + 111, + 119, + 110, + 101, + 114, + 96, + 68, + 130, + 1, + 82, + 253, + 91, + 96, + 0, + 25, + 129, + 20, + 97, + 19, + 81, + 87, + 96, + 1, + 1, + 144, + 86, + 91, + 128, + 81, + 130, + 16, + 21, + 97, + 20, + 124, + 87, + 96, + 32, + 145, + 96, + 5, + 27, + 1, + 1, + 144, + 86, + 91, + 129, + 129, + 16, + 97, + 22, + 251, + 87, + 80, + 80, + 86, + 91, + 96, + 0, + 129, + 85, + 96, + 1, + 1, + 97, + 22, + 240, + 86, + 91, + 145, + 144, + 96, + 31, + 129, + 17, + 97, + 23, + 22, + 87, + 80, + 80, + 80, + 86, + 91, + 97, + 23, + 66, + 146, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 96, + 32, + 96, + 31, + 132, + 1, + 96, + 5, + 28, + 131, + 1, + 147, + 16, + 97, + 23, + 68, + 87, + 91, + 96, + 31, + 1, + 96, + 5, + 28, + 1, + 144, + 97, + 22, + 240, + 86, + 91, + 86, + 91, + 144, + 145, + 80, + 129, + 144, + 97, + 23, + 53, + 86, + 91, + 21, + 97, + 23, + 85, + 87, + 86, + 91, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 16, + 96, + 36, + 130, + 1, + 82, + 111, + 18, + 91, + 157, + 152, + 91, + 26, + 89, + 8, + 19, + 84, + 213, + 8, + 28, + 155, + 219, + 221, + 96, + 130, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 144, + 97, + 23, + 151, + 130, + 97, + 21, + 158, + 86, + 91, + 97, + 23, + 164, + 96, + 64, + 81, + 145, + 130, + 97, + 21, + 125, + 86, + 91, + 130, + 129, + 82, + 128, + 146, + 97, + 23, + 181, + 96, + 31, + 25, + 145, + 97, + 21, + 158, + 86, + 91, + 1, + 144, + 96, + 0, + 91, + 130, + 129, + 16, + 97, + 23, + 198, + 87, + 80, + 80, + 80, + 86, + 91, + 128, + 96, + 96, + 96, + 32, + 128, + 147, + 133, + 1, + 1, + 82, + 1, + 97, + 23, + 186, + 86, + 91, + 144, + 129, + 81, + 128, + 130, + 82, + 96, + 32, + 128, + 128, + 147, + 1, + 147, + 1, + 145, + 96, + 0, + 91, + 130, + 129, + 16, + 97, + 23, + 247, + 87, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 131, + 81, + 133, + 82, + 147, + 129, + 1, + 147, + 146, + 129, + 1, + 146, + 96, + 1, + 1, + 97, + 23, + 233, + 86, + 91, + 144, + 145, + 96, + 0, + 129, + 129, + 82, + 96, + 4, + 147, + 96, + 32, + 147, + 133, + 133, + 82, + 96, + 64, + 147, + 132, + 132, + 32, + 84, + 144, + 131, + 81, + 145, + 96, + 1, + 146, + 131, + 16, + 21, + 97, + 26, + 54, + 87, + 144, + 97, + 24, + 66, + 136, + 148, + 147, + 146, + 136, + 135, + 1, + 81, + 20, + 97, + 23, + 78, + 86, + 91, + 96, + 2, + 130, + 91, + 97, + 25, + 116, + 87, + 91, + 80, + 80, + 80, + 97, + 24, + 117, + 144, + 97, + 24, + 135, + 134, + 81, + 148, + 133, + 147, + 132, + 147, + 99, + 30, + 142, + 30, + 19, + 96, + 224, + 27, + 133, + 82, + 137, + 140, + 134, + 1, + 82, + 96, + 68, + 133, + 1, + 144, + 97, + 19, + 198, + 86, + 91, + 131, + 129, + 3, + 96, + 3, + 25, + 1, + 96, + 36, + 133, + 1, + 82, + 144, + 97, + 23, + 215, + 86, + 91, + 3, + 129, + 127, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 90, + 250, + 130, + 145, + 129, + 97, + 25, + 56, + 87, + 91, + 80, + 97, + 25, + 48, + 87, + 80, + 96, + 100, + 148, + 80, + 61, + 21, + 97, + 25, + 42, + 87, + 61, + 144, + 97, + 24, + 216, + 130, + 97, + 21, + 181, + 86, + 91, + 145, + 97, + 24, + 229, + 132, + 81, + 147, + 132, + 97, + 21, + 125, + 86, + 91, + 130, + 82, + 131, + 61, + 146, + 1, + 62, + 91, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 145, + 130, + 1, + 82, + 96, + 23, + 96, + 36, + 130, + 1, + 82, + 127, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 105, + 110, + 99, + 108, + 117, + 115, + 105, + 111, + 110, + 32, + 112, + 114, + 111, + 111, + 102, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 253, + 91, + 80, + 97, + 24, + 237, + 86, + 91, + 147, + 80, + 80, + 80, + 80, + 144, + 86, + 91, + 144, + 145, + 80, + 132, + 129, + 129, + 61, + 131, + 17, + 97, + 25, + 109, + 87, + 91, + 97, + 25, + 80, + 129, + 131, + 97, + 21, + 125, + 86, + 91, + 129, + 1, + 3, + 18, + 97, + 25, + 105, + 87, + 81, + 128, + 21, + 21, + 129, + 3, + 97, + 25, + 105, + 87, + 144, + 56, + 97, + 24, + 189, + 86, + 91, + 130, + 128, + 253, + 91, + 80, + 61, + 97, + 25, + 70, + 86, + 91, + 144, + 145, + 146, + 147, + 133, + 81, + 130, + 16, + 21, + 97, + 26, + 47, + 87, + 80, + 129, + 134, + 82, + 136, + 136, + 82, + 134, + 134, + 32, + 96, + 1, + 25, + 144, + 132, + 1, + 130, + 130, + 1, + 131, + 129, + 17, + 97, + 26, + 28, + 87, + 129, + 84, + 17, + 21, + 97, + 26, + 9, + 87, + 135, + 82, + 129, + 137, + 136, + 32, + 1, + 1, + 84, + 97, + 25, + 182, + 130, + 135, + 97, + 22, + 220, + 86, + 91, + 81, + 3, + 97, + 25, + 207, + 87, + 144, + 97, + 25, + 199, + 131, + 146, + 97, + 22, + 205, + 86, + 91, + 136, + 148, + 147, + 97, + 24, + 70, + 86, + 91, + 134, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 128, + 138, + 1, + 137, + 144, + 82, + 96, + 20, + 96, + 36, + 130, + 1, + 82, + 115, + 73, + 110, + 118, + 97, + 108, + 105, + 100, + 32, + 114, + 111, + 111, + 116, + 32, + 98, + 97, + 108, + 97, + 110, + 99, + 101, + 96, + 96, + 27, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 144, + 253, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 136, + 82, + 96, + 50, + 139, + 82, + 96, + 36, + 136, + 253, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 137, + 82, + 96, + 17, + 140, + 82, + 96, + 36, + 137, + 253, + 91, + 147, + 146, + 97, + 24, + 75, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 134, + 82, + 96, + 50, + 137, + 82, + 96, + 36, + 134, + 253, + 254, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 76, + 105, + 117, + 0, + 151, + 107, + 128, + 235, + 253, + 185, + 76, + 134, + 25, + 113, + 48, + 248, + 91, + 66, + 119, + 199, + 73, + 98, + 8, + 212, + 2, + 169, + 230, + 39, + 146, + 80, + 83, + 242, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The deployed bytecode of the contract. + pub static SUMMA_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct Summa(::ethers::contract::Contract); + impl ::core::clone::Clone for Summa { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Summa { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Summa { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Summa { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(stringify!(Summa)).field(&self.address()).finish() + } + } + impl Summa { + /// 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(), + SUMMA_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( + SUMMA_ABI.clone(), + SUMMA_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `addressOwnershipProofs` (0xa3c4bcf8) function + pub fn address_ownership_proofs( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall< + M, + ( + ::std::string::String, + ::std::string::String, + ::ethers::core::types::Bytes, + ::ethers::core::types::Bytes, + ), + > { + self.0 + .method_hash([163, 196, 188, 248], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `commitments` (0x49ce8997) function + pub fn commitments( + &self, + p0: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([73, 206, 137, 151], p0) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `config` (0x79502c55) function + pub fn config( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([121, 80, 44, 85], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `getAddressOwnershipProof` (0x19b33968) function + pub fn get_address_ownership_proof( + &self, + address_hash: [u8; 32], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([25, 179, 57, 104], address_hash) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `renounceOwnership` (0x715018a6) function + pub fn renounce_ownership( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([113, 80, 24, 166], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `submitCommitment` (0xda64a750) function + pub fn submit_commitment( + &self, + mst_root: ::ethers::core::types::U256, + root_balances: ::std::vec::Vec<::ethers::core::types::U256>, + cryptocurrencies: ::std::vec::Vec, + timestamp: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [218, 100, 167, 80], + (mst_root, root_balances, cryptocurrencies, timestamp), + ) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `submitProofOfAddressOwnership` (0xc7ddca0e) function + pub fn submit_proof_of_address_ownership( + &self, + address_ownership_proofs: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([199, 221, 202, 14], address_ownership_proofs) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transferOwnership` (0xf2fde38b) function + pub fn transfer_ownership( + &self, + new_owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([242, 253, 227, 139], new_owner) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `verifyInclusionProof` (0xc8e58147) function + pub fn verify_inclusion_proof( + &self, + proof: ::ethers::core::types::Bytes, + public_inputs: ::std::vec::Vec<::ethers::core::types::U256>, + timestamp: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([200, 229, 129, 71], (proof, public_inputs, timestamp)) + .expect("method not found (this should never happen)") + } + ///Gets the contract's `AddressOwnershipProofSubmitted` event + pub fn address_ownership_proof_submitted_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + AddressOwnershipProofSubmittedFilter, + > { + self.0.event() + } + ///Gets the contract's `LiabilitiesCommitmentSubmitted` event + pub fn liabilities_commitment_submitted_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + LiabilitiesCommitmentSubmittedFilter, + > { + self.0.event() + } + ///Gets the contract's `OwnershipTransferred` event + pub fn ownership_transferred_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + OwnershipTransferredFilter, + > { + self.0.event() + } + /// Returns an `Event` builder for all the events of this contract. + pub fn events( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, SummaEvents> { + self.0.event_with_filter(::core::default::Default::default()) + } + } + impl From<::ethers::contract::Contract> + for Summa { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent( + name = "AddressOwnershipProofSubmitted", + abi = "AddressOwnershipProofSubmitted((string,string,bytes,bytes)[])" + )] + pub struct AddressOwnershipProofSubmittedFilter { + pub address_ownership_proofs: ::std::vec::Vec, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent( + name = "LiabilitiesCommitmentSubmitted", + abi = "LiabilitiesCommitmentSubmitted(uint256,uint256,uint256[],(string,string)[])" + )] + pub struct LiabilitiesCommitmentSubmittedFilter { + #[ethevent(indexed)] + pub timestamp: ::ethers::core::types::U256, + pub mst_root: ::ethers::core::types::U256, + pub root_balances: ::std::vec::Vec<::ethers::core::types::U256>, + pub cryptocurrencies: ::std::vec::Vec, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent( + name = "OwnershipTransferred", + abi = "OwnershipTransferred(address,address)" + )] + pub struct OwnershipTransferredFilter { + #[ethevent(indexed)] + pub previous_owner: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all of the contract's events + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum SummaEvents { + AddressOwnershipProofSubmittedFilter(AddressOwnershipProofSubmittedFilter), + LiabilitiesCommitmentSubmittedFilter(LiabilitiesCommitmentSubmittedFilter), + OwnershipTransferredFilter(OwnershipTransferredFilter), + } + impl ::ethers::contract::EthLogDecode for SummaEvents { + fn decode_log( + log: &::ethers::core::abi::RawLog, + ) -> ::core::result::Result { + if let Ok(decoded) = AddressOwnershipProofSubmittedFilter::decode_log(log) { + return Ok(SummaEvents::AddressOwnershipProofSubmittedFilter(decoded)); + } + if let Ok(decoded) = LiabilitiesCommitmentSubmittedFilter::decode_log(log) { + return Ok(SummaEvents::LiabilitiesCommitmentSubmittedFilter(decoded)); + } + if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { + return Ok(SummaEvents::OwnershipTransferredFilter(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData) + } + } + impl ::core::fmt::Display for SummaEvents { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::AddressOwnershipProofSubmittedFilter(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::LiabilitiesCommitmentSubmittedFilter(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::OwnershipTransferredFilter(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for SummaEvents { + fn from(value: AddressOwnershipProofSubmittedFilter) -> Self { + Self::AddressOwnershipProofSubmittedFilter(value) + } + } + impl ::core::convert::From for SummaEvents { + fn from(value: LiabilitiesCommitmentSubmittedFilter) -> Self { + Self::LiabilitiesCommitmentSubmittedFilter(value) + } + } + impl ::core::convert::From for SummaEvents { + fn from(value: OwnershipTransferredFilter) -> Self { + Self::OwnershipTransferredFilter(value) + } + } + ///Container type for all input parameters for the `addressOwnershipProofs` function with signature `addressOwnershipProofs(uint256)` and selector `0xa3c4bcf8` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "addressOwnershipProofs", abi = "addressOwnershipProofs(uint256)")] + pub struct AddressOwnershipProofsCall(pub ::ethers::core::types::U256); + ///Container type for all input parameters for the `commitments` function with signature `commitments(uint256)` and selector `0x49ce8997` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "commitments", abi = "commitments(uint256)")] + pub struct CommitmentsCall(pub ::ethers::core::types::U256); + ///Container type for all input parameters for the `config` function with signature `config()` and selector `0x79502c55` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "config", abi = "config()")] + pub struct ConfigCall; + ///Container type for all input parameters for the `getAddressOwnershipProof` function with signature `getAddressOwnershipProof(bytes32)` and selector `0x19b33968` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall( + name = "getAddressOwnershipProof", + abi = "getAddressOwnershipProof(bytes32)" + )] + pub struct GetAddressOwnershipProofCall { + pub address_hash: [u8; 32], + } + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] + pub struct RenounceOwnershipCall; + ///Container type for all input parameters for the `submitCommitment` function with signature `submitCommitment(uint256,uint256[],(string,string)[],uint256)` and selector `0xda64a750` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall( + name = "submitCommitment", + abi = "submitCommitment(uint256,uint256[],(string,string)[],uint256)" + )] + pub struct SubmitCommitmentCall { + pub mst_root: ::ethers::core::types::U256, + pub root_balances: ::std::vec::Vec<::ethers::core::types::U256>, + pub cryptocurrencies: ::std::vec::Vec, + pub timestamp: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `submitProofOfAddressOwnership` function with signature `submitProofOfAddressOwnership((string,string,bytes,bytes)[])` and selector `0xc7ddca0e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall( + name = "submitProofOfAddressOwnership", + abi = "submitProofOfAddressOwnership((string,string,bytes,bytes)[])" + )] + pub struct SubmitProofOfAddressOwnershipCall { + pub address_ownership_proofs: ::std::vec::Vec, + } + ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] + pub struct TransferOwnershipCall { + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `verifyInclusionProof` function with signature `verifyInclusionProof(bytes,uint256[],uint256)` and selector `0xc8e58147` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall( + name = "verifyInclusionProof", + abi = "verifyInclusionProof(bytes,uint256[],uint256)" + )] + pub struct VerifyInclusionProofCall { + pub proof: ::ethers::core::types::Bytes, + pub public_inputs: ::std::vec::Vec<::ethers::core::types::U256>, + pub timestamp: ::ethers::core::types::U256, + } + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum SummaCalls { + AddressOwnershipProofs(AddressOwnershipProofsCall), + Commitments(CommitmentsCall), + Config(ConfigCall), + GetAddressOwnershipProof(GetAddressOwnershipProofCall), + Owner(OwnerCall), + RenounceOwnership(RenounceOwnershipCall), + SubmitCommitment(SubmitCommitmentCall), + SubmitProofOfAddressOwnership(SubmitProofOfAddressOwnershipCall), + TransferOwnership(TransferOwnershipCall), + VerifyInclusionProof(VerifyInclusionProofCall), + } + impl ::ethers::core::abi::AbiDecode for SummaCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::AddressOwnershipProofs(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Commitments(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Config(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::GetAddressOwnershipProof(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::RenounceOwnership(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::SubmitCommitment(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::SubmitProofOfAddressOwnership(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::TransferOwnership(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::VerifyInclusionProof(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for SummaCalls { + fn encode(self) -> Vec { + match self { + Self::AddressOwnershipProofs(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Commitments(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Config(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::GetAddressOwnershipProof(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RenounceOwnership(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::SubmitCommitment(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::SubmitProofOfAddressOwnership(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::TransferOwnership(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::VerifyInclusionProof(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for SummaCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::AddressOwnershipProofs(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Commitments(element) => ::core::fmt::Display::fmt(element, f), + Self::Config(element) => ::core::fmt::Display::fmt(element, f), + Self::GetAddressOwnershipProof(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::SubmitCommitment(element) => ::core::fmt::Display::fmt(element, f), + Self::SubmitProofOfAddressOwnership(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::VerifyInclusionProof(element) => { + ::core::fmt::Display::fmt(element, f) + } + } + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: AddressOwnershipProofsCall) -> Self { + Self::AddressOwnershipProofs(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: CommitmentsCall) -> Self { + Self::Commitments(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: ConfigCall) -> Self { + Self::Config(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: GetAddressOwnershipProofCall) -> Self { + Self::GetAddressOwnershipProof(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: RenounceOwnershipCall) -> Self { + Self::RenounceOwnership(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: SubmitCommitmentCall) -> Self { + Self::SubmitCommitment(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: SubmitProofOfAddressOwnershipCall) -> Self { + Self::SubmitProofOfAddressOwnership(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: TransferOwnershipCall) -> Self { + Self::TransferOwnership(value) + } + } + impl ::core::convert::From for SummaCalls { + fn from(value: VerifyInclusionProofCall) -> Self { + Self::VerifyInclusionProof(value) + } + } + ///Container type for all return fields from the `addressOwnershipProofs` function with signature `addressOwnershipProofs(uint256)` and selector `0xa3c4bcf8` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct AddressOwnershipProofsReturn { + pub cex_address: ::std::string::String, + pub chain: ::std::string::String, + pub signature: ::ethers::core::types::Bytes, + pub message: ::ethers::core::types::Bytes, + } + ///Container type for all return fields from the `commitments` function with signature `commitments(uint256)` and selector `0x49ce8997` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct CommitmentsReturn { + pub mst_root: ::ethers::core::types::U256, + } + ///Container type for all return fields from the `config` function with signature `config()` and selector `0x79502c55` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct ConfigReturn { + pub mst_levels: u16, + pub currencies_count: u16, + pub balance_byte_range: u8, + } + ///Container type for all return fields from the `getAddressOwnershipProof` function with signature `getAddressOwnershipProof(bytes32)` and selector `0x19b33968` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct GetAddressOwnershipProofReturn(pub AddressOwnershipProof); + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the `verifyInclusionProof` function with signature `verifyInclusionProof(bytes,uint256[],uint256)` and selector `0xc8e58147` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct VerifyInclusionProofReturn(pub bool); + ///`AddressOwnershipProof(string,string,bytes,bytes)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct AddressOwnershipProof { + pub cex_address: ::std::string::String, + pub chain: ::std::string::String, + pub signature: ::ethers::core::types::Bytes, + pub message: ::ethers::core::types::Bytes, + } + ///`Cryptocurrency(string,string)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct Cryptocurrency { + pub name: ::std::string::String, + pub chain: ::std::string::String, + } +} diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mock_erc20.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mock_erc20.rs new file mode 100644 index 0000000..78c06fd --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mock_erc20.rs @@ -0,0 +1,7227 @@ +pub use mock_erc20::*; +/// 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 mock_erc20 { + #[rustfmt::skip] + const __ABI: &str = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\",\"outputs\":[]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\",\"components\":[],\"indexed\":false}],\"type\":\"event\",\"name\":\"Approval\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\",\"components\":[],\"indexed\":true}],\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\",\"components\":[],\"indexed\":true},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\",\"components\":[],\"indexed\":false}],\"type\":\"event\",\"name\":\"Transfer\",\"outputs\":[],\"anonymous\":false},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\",\"components\":[]}],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"mint\",\"outputs\":[]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"renounceOwnership\",\"outputs\":[]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\",\"components\":[]}]},{\"inputs\":[],\"stateMutability\":\"view\",\"type\":\"function\",\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\",\"components\":[]},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\",\"components\":[]}]},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\",\"components\":[]}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"name\":\"transferOwnership\",\"outputs\":[]}]"; + ///The parsed JSON ABI of the contract. + pub static MOCKERC20_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(|| + ::ethers::core::utils::__serde_json::from_str(__ABI).expect("ABI is always valid")); + #[rustfmt::skip] + const __BYTECODE: &[u8] = &[ + 96, + 128, + 96, + 64, + 82, + 52, + 128, + 21, + 98, + 0, + 0, + 17, + 87, + 96, + 0, + 128, + 253, + 91, + 80, + 96, + 64, + 81, + 128, + 96, + 64, + 1, + 96, + 64, + 82, + 128, + 96, + 9, + 129, + 82, + 96, + 32, + 1, + 104, + 4, + 214, + 246, + 54, + 180, + 85, + 36, + 51, + 35, + 96, + 188, + 27, + 129, + 82, + 80, + 96, + 64, + 81, + 128, + 96, + 64, + 1, + 96, + 64, + 82, + 128, + 96, + 3, + 129, + 82, + 96, + 32, + 1, + 98, + 77, + 84, + 75, + 96, + 232, + 27, + 129, + 82, + 80, + 129, + 96, + 3, + 144, + 129, + 98, + 0, + 0, + 97, + 145, + 144, + 98, + 0, + 1, + 142, + 86, + 91, + 80, + 96, + 4, + 98, + 0, + 0, + 112, + 130, + 130, + 98, + 0, + 1, + 142, + 86, + 91, + 80, + 80, + 80, + 98, + 0, + 0, + 141, + 98, + 0, + 0, + 135, + 98, + 0, + 0, + 147, + 96, + 32, + 27, + 96, + 32, + 28, + 86, + 91, + 98, + 0, + 0, + 151, + 86, + 91, + 98, + 0, + 2, + 90, + 86, + 91, + 51, + 144, + 86, + 91, + 96, + 5, + 128, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 129, + 22, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 131, + 22, + 129, + 23, + 144, + 147, + 85, + 96, + 64, + 81, + 145, + 22, + 145, + 144, + 130, + 144, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 144, + 96, + 0, + 144, + 163, + 80, + 80, + 86, + 91, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 65, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 96, + 1, + 129, + 129, + 28, + 144, + 130, + 22, + 128, + 98, + 0, + 1, + 20, + 87, + 96, + 127, + 130, + 22, + 145, + 80, + 91, + 96, + 32, + 130, + 16, + 129, + 3, + 98, + 0, + 1, + 53, + 87, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 34, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 80, + 145, + 144, + 80, + 86, + 91, + 96, + 31, + 130, + 17, + 21, + 98, + 0, + 1, + 137, + 87, + 96, + 0, + 129, + 129, + 82, + 96, + 32, + 129, + 32, + 96, + 31, + 133, + 1, + 96, + 5, + 28, + 129, + 1, + 96, + 32, + 134, + 16, + 21, + 98, + 0, + 1, + 100, + 87, + 80, + 128, + 91, + 96, + 31, + 133, + 1, + 96, + 5, + 28, + 130, + 1, + 145, + 80, + 91, + 129, + 129, + 16, + 21, + 98, + 0, + 1, + 133, + 87, + 130, + 129, + 85, + 96, + 1, + 1, + 98, + 0, + 1, + 112, + 86, + 91, + 80, + 80, + 80, + 91, + 80, + 80, + 80, + 86, + 91, + 129, + 81, + 96, + 1, + 96, + 1, + 96, + 64, + 27, + 3, + 129, + 17, + 21, + 98, + 0, + 1, + 170, + 87, + 98, + 0, + 1, + 170, + 98, + 0, + 0, + 233, + 86, + 91, + 98, + 0, + 1, + 194, + 129, + 98, + 0, + 1, + 187, + 132, + 84, + 98, + 0, + 0, + 255, + 86, + 91, + 132, + 98, + 0, + 1, + 59, + 86, + 91, + 96, + 32, + 128, + 96, + 31, + 131, + 17, + 96, + 1, + 129, + 20, + 98, + 0, + 1, + 250, + 87, + 96, + 0, + 132, + 21, + 98, + 0, + 1, + 225, + 87, + 80, + 133, + 131, + 1, + 81, + 91, + 96, + 0, + 25, + 96, + 3, + 134, + 144, + 27, + 28, + 25, + 22, + 96, + 1, + 133, + 144, + 27, + 23, + 133, + 85, + 98, + 0, + 1, + 133, + 86, + 91, + 96, + 0, + 133, + 129, + 82, + 96, + 32, + 129, + 32, + 96, + 31, + 25, + 134, + 22, + 145, + 91, + 130, + 129, + 16, + 21, + 98, + 0, + 2, + 43, + 87, + 136, + 134, + 1, + 81, + 130, + 85, + 148, + 132, + 1, + 148, + 96, + 1, + 144, + 145, + 1, + 144, + 132, + 1, + 98, + 0, + 2, + 10, + 86, + 91, + 80, + 133, + 130, + 16, + 21, + 98, + 0, + 2, + 74, + 87, + 135, + 133, + 1, + 81, + 96, + 0, + 25, + 96, + 3, + 136, + 144, + 27, + 96, + 248, + 22, + 28, + 25, + 22, + 129, + 85, + 91, + 80, + 80, + 80, + 80, + 80, + 96, + 1, + 144, + 129, + 27, + 1, + 144, + 85, + 80, + 86, + 91, + 97, + 10, + 247, + 128, + 98, + 0, + 2, + 106, + 96, + 0, + 57, + 96, + 0, + 243, + 254, + 96, + 128, + 96, + 64, + 82, + 52, + 128, + 21, + 97, + 0, + 16, + 87, + 96, + 0, + 128, + 253, + 91, + 80, + 96, + 4, + 54, + 16, + 97, + 0, + 245, + 87, + 96, + 0, + 53, + 96, + 224, + 28, + 128, + 99, + 112, + 160, + 130, + 49, + 17, + 97, + 0, + 151, + 87, + 128, + 99, + 164, + 87, + 194, + 215, + 17, + 97, + 0, + 102, + 87, + 128, + 99, + 164, + 87, + 194, + 215, + 20, + 97, + 1, + 235, + 87, + 128, + 99, + 169, + 5, + 156, + 187, + 20, + 97, + 1, + 254, + 87, + 128, + 99, + 221, + 98, + 237, + 62, + 20, + 97, + 2, + 17, + 87, + 128, + 99, + 242, + 253, + 227, + 139, + 20, + 97, + 2, + 36, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 112, + 160, + 130, + 49, + 20, + 97, + 1, + 151, + 87, + 128, + 99, + 113, + 80, + 24, + 166, + 20, + 97, + 1, + 192, + 87, + 128, + 99, + 141, + 165, + 203, + 91, + 20, + 97, + 1, + 200, + 87, + 128, + 99, + 149, + 216, + 155, + 65, + 20, + 97, + 1, + 227, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 35, + 184, + 114, + 221, + 17, + 97, + 0, + 211, + 87, + 128, + 99, + 35, + 184, + 114, + 221, + 20, + 97, + 1, + 77, + 87, + 128, + 99, + 49, + 60, + 229, + 103, + 20, + 97, + 1, + 96, + 87, + 128, + 99, + 57, + 80, + 147, + 81, + 20, + 97, + 1, + 111, + 87, + 128, + 99, + 64, + 193, + 15, + 25, + 20, + 97, + 1, + 130, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 6, + 253, + 222, + 3, + 20, + 97, + 0, + 250, + 87, + 128, + 99, + 9, + 94, + 167, + 179, + 20, + 97, + 1, + 24, + 87, + 128, + 99, + 24, + 22, + 13, + 221, + 20, + 97, + 1, + 59, + 87, + 91, + 96, + 0, + 128, + 253, + 91, + 97, + 1, + 2, + 97, + 2, + 55, + 86, + 91, + 96, + 64, + 81, + 97, + 1, + 15, + 145, + 144, + 97, + 9, + 65, + 86, + 91, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 243, + 91, + 97, + 1, + 43, + 97, + 1, + 38, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 2, + 201, + 86, + 91, + 96, + 64, + 81, + 144, + 21, + 21, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 96, + 2, + 84, + 91, + 96, + 64, + 81, + 144, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 91, + 54, + 96, + 4, + 97, + 9, + 213, + 86, + 91, + 97, + 2, + 227, + 86, + 91, + 96, + 64, + 81, + 96, + 18, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 125, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 7, + 86, + 91, + 97, + 1, + 149, + 97, + 1, + 144, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 41, + 86, + 91, + 0, + 91, + 97, + 1, + 63, + 97, + 1, + 165, + 54, + 96, + 4, + 97, + 10, + 17, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 32, + 129, + 144, + 82, + 96, + 64, + 144, + 32, + 84, + 144, + 86, + 91, + 97, + 1, + 149, + 97, + 3, + 63, + 86, + 91, + 96, + 5, + 84, + 96, + 64, + 81, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 144, + 145, + 22, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 2, + 97, + 3, + 83, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 249, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 98, + 86, + 91, + 97, + 1, + 43, + 97, + 2, + 12, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 226, + 86, + 91, + 97, + 1, + 63, + 97, + 2, + 31, + 54, + 96, + 4, + 97, + 10, + 51, + 86, + 91, + 97, + 3, + 240, + 86, + 91, + 97, + 1, + 149, + 97, + 2, + 50, + 54, + 96, + 4, + 97, + 10, + 17, + 86, + 91, + 97, + 4, + 27, + 86, + 91, + 96, + 96, + 96, + 3, + 128, + 84, + 97, + 2, + 70, + 144, + 97, + 10, + 102, + 86, + 91, + 128, + 96, + 31, + 1, + 96, + 32, + 128, + 145, + 4, + 2, + 96, + 32, + 1, + 96, + 64, + 81, + 144, + 129, + 1, + 96, + 64, + 82, + 128, + 146, + 145, + 144, + 129, + 129, + 82, + 96, + 32, + 1, + 130, + 128, + 84, + 97, + 2, + 114, + 144, + 97, + 10, + 102, + 86, + 91, + 128, + 21, + 97, + 2, + 191, + 87, + 128, + 96, + 31, + 16, + 97, + 2, + 148, + 87, + 97, + 1, + 0, + 128, + 131, + 84, + 4, + 2, + 131, + 82, + 145, + 96, + 32, + 1, + 145, + 97, + 2, + 191, + 86, + 91, + 130, + 1, + 145, + 144, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 91, + 129, + 84, + 129, + 82, + 144, + 96, + 1, + 1, + 144, + 96, + 32, + 1, + 128, + 131, + 17, + 97, + 2, + 162, + 87, + 130, + 144, + 3, + 96, + 31, + 22, + 130, + 1, + 145, + 91, + 80, + 80, + 80, + 80, + 80, + 144, + 80, + 144, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 4, + 148, + 86, + 91, + 96, + 1, + 145, + 80, + 80, + 91, + 146, + 145, + 80, + 80, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 241, + 133, + 130, + 133, + 97, + 5, + 184, + 86, + 91, + 97, + 2, + 252, + 133, + 133, + 133, + 97, + 6, + 50, + 86, + 91, + 80, + 96, + 1, + 148, + 147, + 80, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 3, + 26, + 131, + 131, + 97, + 3, + 240, + 86, + 91, + 97, + 3, + 36, + 145, + 144, + 97, + 10, + 160, + 86, + 91, + 97, + 4, + 148, + 86, + 91, + 97, + 3, + 49, + 97, + 7, + 214, + 86, + 91, + 97, + 3, + 59, + 130, + 130, + 97, + 8, + 48, + 86, + 91, + 80, + 80, + 86, + 91, + 97, + 3, + 71, + 97, + 7, + 214, + 86, + 91, + 97, + 3, + 81, + 96, + 0, + 97, + 8, + 239, + 86, + 91, + 86, + 91, + 96, + 96, + 96, + 4, + 128, + 84, + 97, + 2, + 70, + 144, + 97, + 10, + 102, + 86, + 91, + 96, + 0, + 51, + 129, + 97, + 3, + 112, + 130, + 134, + 97, + 3, + 240, + 86, + 91, + 144, + 80, + 131, + 129, + 16, + 21, + 97, + 3, + 213, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 37, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 100, + 101, + 99, + 114, + 101, + 97, + 115, + 101, + 100, + 32, + 97, + 108, + 108, + 111, + 119, + 97, + 110, + 99, + 101, + 32, + 98, + 101, + 108, + 111, + 119, + 96, + 68, + 130, + 1, + 82, + 100, + 32, + 122, + 101, + 114, + 111, + 96, + 216, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 91, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 253, + 91, + 97, + 2, + 252, + 130, + 134, + 134, + 132, + 3, + 97, + 4, + 148, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 6, + 50, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 145, + 130, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 1, + 96, + 32, + 144, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 147, + 144, + 148, + 22, + 130, + 82, + 145, + 144, + 145, + 82, + 32, + 84, + 144, + 86, + 91, + 97, + 4, + 35, + 97, + 7, + 214, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 22, + 97, + 4, + 136, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 110, + 101, + 119, + 32, + 111, + 119, + 110, + 101, + 114, + 32, + 105, + 115, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 96, + 68, + 130, + 1, + 82, + 101, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 97, + 4, + 145, + 129, + 97, + 8, + 239, + 86, + 91, + 80, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 97, + 4, + 246, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 36, + 128, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 97, + 112, + 112, + 114, + 111, + 118, + 101, + 32, + 102, + 114, + 111, + 109, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 96, + 68, + 130, + 1, + 82, + 99, + 114, + 101, + 115, + 115, + 96, + 224, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 5, + 87, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 34, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 97, + 112, + 112, + 114, + 111, + 118, + 101, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 101, + 96, + 68, + 130, + 1, + 82, + 97, + 115, + 115, + 96, + 240, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 129, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 1, + 96, + 32, + 144, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 148, + 135, + 22, + 128, + 132, + 82, + 148, + 130, + 82, + 145, + 130, + 144, + 32, + 133, + 144, + 85, + 144, + 81, + 132, + 129, + 82, + 127, + 140, + 91, + 225, + 229, + 235, + 236, + 125, + 91, + 209, + 79, + 113, + 66, + 125, + 30, + 132, + 243, + 221, + 3, + 20, + 192, + 247, + 178, + 41, + 30, + 91, + 32, + 10, + 200, + 199, + 195, + 185, + 37, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 97, + 5, + 196, + 132, + 132, + 97, + 3, + 240, + 86, + 91, + 144, + 80, + 96, + 0, + 25, + 129, + 20, + 97, + 6, + 44, + 87, + 129, + 129, + 16, + 21, + 97, + 6, + 31, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 29, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 105, + 110, + 115, + 117, + 102, + 102, + 105, + 99, + 105, + 101, + 110, + 116, + 32, + 97, + 108, + 108, + 111, + 119, + 97, + 110, + 99, + 101, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 97, + 6, + 44, + 132, + 132, + 132, + 132, + 3, + 97, + 4, + 148, + 86, + 91, + 80, + 80, + 80, + 80, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 97, + 6, + 150, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 37, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 102, + 114, + 111, + 109, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 96, + 68, + 130, + 1, + 82, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 216, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 6, + 248, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 35, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 96, + 68, + 130, + 1, + 82, + 98, + 101, + 115, + 115, + 96, + 232, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 32, + 129, + 144, + 82, + 96, + 64, + 144, + 32, + 84, + 129, + 129, + 16, + 21, + 97, + 7, + 112, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 97, + 109, + 111, + 117, + 110, + 116, + 32, + 101, + 120, + 99, + 101, + 101, + 100, + 115, + 32, + 98, + 96, + 68, + 130, + 1, + 82, + 101, + 97, + 108, + 97, + 110, + 99, + 101, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 132, + 129, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 32, + 129, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 135, + 135, + 3, + 144, + 85, + 147, + 135, + 22, + 128, + 131, + 82, + 145, + 132, + 144, + 32, + 128, + 84, + 135, + 1, + 144, + 85, + 146, + 81, + 133, + 129, + 82, + 144, + 146, + 127, + 221, + 242, + 82, + 173, + 27, + 226, + 200, + 155, + 105, + 194, + 176, + 104, + 252, + 55, + 141, + 170, + 149, + 43, + 167, + 241, + 99, + 196, + 161, + 22, + 40, + 245, + 90, + 77, + 245, + 35, + 179, + 239, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 97, + 6, + 44, + 86, + 91, + 96, + 5, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 51, + 20, + 97, + 3, + 81, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 129, + 144, + 82, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 99, + 97, + 108, + 108, + 101, + 114, + 32, + 105, + 115, + 32, + 110, + 111, + 116, + 32, + 116, + 104, + 101, + 32, + 111, + 119, + 110, + 101, + 114, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 8, + 134, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 31, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 109, + 105, + 110, + 116, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 101, + 115, + 115, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 128, + 96, + 2, + 96, + 0, + 130, + 130, + 84, + 97, + 8, + 152, + 145, + 144, + 97, + 10, + 160, + 86, + 91, + 144, + 145, + 85, + 80, + 80, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 32, + 129, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 128, + 84, + 134, + 1, + 144, + 85, + 81, + 132, + 129, + 82, + 127, + 221, + 242, + 82, + 173, + 27, + 226, + 200, + 155, + 105, + 194, + 176, + 104, + 252, + 55, + 141, + 170, + 149, + 43, + 167, + 241, + 99, + 196, + 161, + 22, + 40, + 245, + 90, + 77, + 245, + 35, + 179, + 239, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 80, + 80, + 86, + 91, + 96, + 5, + 128, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 129, + 22, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 131, + 22, + 129, + 23, + 144, + 147, + 85, + 96, + 64, + 81, + 145, + 22, + 145, + 144, + 130, + 144, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 144, + 96, + 0, + 144, + 163, + 80, + 80, + 86, + 91, + 96, + 0, + 96, + 32, + 128, + 131, + 82, + 131, + 81, + 128, + 130, + 133, + 1, + 82, + 96, + 0, + 91, + 129, + 129, + 16, + 21, + 97, + 9, + 110, + 87, + 133, + 129, + 1, + 131, + 1, + 81, + 133, + 130, + 1, + 96, + 64, + 1, + 82, + 130, + 1, + 97, + 9, + 82, + 86, + 91, + 80, + 96, + 0, + 96, + 64, + 130, + 134, + 1, + 1, + 82, + 96, + 64, + 96, + 31, + 25, + 96, + 31, + 131, + 1, + 22, + 133, + 1, + 1, + 146, + 80, + 80, + 80, + 146, + 145, + 80, + 80, + 86, + 91, + 128, + 53, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 22, + 129, + 20, + 97, + 9, + 166, + 87, + 96, + 0, + 128, + 253, + 91, + 145, + 144, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 64, + 131, + 133, + 3, + 18, + 21, + 97, + 9, + 190, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 9, + 199, + 131, + 97, + 9, + 143, + 86, + 91, + 148, + 96, + 32, + 147, + 144, + 147, + 1, + 53, + 147, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 0, + 96, + 96, + 132, + 134, + 3, + 18, + 21, + 97, + 9, + 234, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 9, + 243, + 132, + 97, + 9, + 143, + 86, + 91, + 146, + 80, + 97, + 10, + 1, + 96, + 32, + 133, + 1, + 97, + 9, + 143, + 86, + 91, + 145, + 80, + 96, + 64, + 132, + 1, + 53, + 144, + 80, + 146, + 80, + 146, + 80, + 146, + 86, + 91, + 96, + 0, + 96, + 32, + 130, + 132, + 3, + 18, + 21, + 97, + 10, + 35, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 10, + 44, + 130, + 97, + 9, + 143, + 86, + 91, + 147, + 146, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 64, + 131, + 133, + 3, + 18, + 21, + 97, + 10, + 70, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 10, + 79, + 131, + 97, + 9, + 143, + 86, + 91, + 145, + 80, + 97, + 10, + 93, + 96, + 32, + 132, + 1, + 97, + 9, + 143, + 86, + 91, + 144, + 80, + 146, + 80, + 146, + 144, + 80, + 86, + 91, + 96, + 1, + 129, + 129, + 28, + 144, + 130, + 22, + 128, + 97, + 10, + 122, + 87, + 96, + 127, + 130, + 22, + 145, + 80, + 91, + 96, + 32, + 130, + 16, + 129, + 3, + 97, + 10, + 154, + 87, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 34, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 80, + 145, + 144, + 80, + 86, + 91, + 128, + 130, + 1, + 128, + 130, + 17, + 21, + 97, + 2, + 221, + 87, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 17, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 254, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 253, + 219, + 133, + 110, + 73, + 92, + 0, + 147, + 166, + 78, + 244, + 255, + 131, + 246, + 4, + 122, + 242, + 74, + 188, + 163, + 116, + 209, + 16, + 33, + 154, + 27, + 110, + 123, + 34, + 163, + 47, + 138, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The bytecode of the contract. + pub static MOCKERC20_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __BYTECODE, + ); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = &[ + 96, + 128, + 96, + 64, + 82, + 52, + 128, + 21, + 97, + 0, + 16, + 87, + 96, + 0, + 128, + 253, + 91, + 80, + 96, + 4, + 54, + 16, + 97, + 0, + 245, + 87, + 96, + 0, + 53, + 96, + 224, + 28, + 128, + 99, + 112, + 160, + 130, + 49, + 17, + 97, + 0, + 151, + 87, + 128, + 99, + 164, + 87, + 194, + 215, + 17, + 97, + 0, + 102, + 87, + 128, + 99, + 164, + 87, + 194, + 215, + 20, + 97, + 1, + 235, + 87, + 128, + 99, + 169, + 5, + 156, + 187, + 20, + 97, + 1, + 254, + 87, + 128, + 99, + 221, + 98, + 237, + 62, + 20, + 97, + 2, + 17, + 87, + 128, + 99, + 242, + 253, + 227, + 139, + 20, + 97, + 2, + 36, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 112, + 160, + 130, + 49, + 20, + 97, + 1, + 151, + 87, + 128, + 99, + 113, + 80, + 24, + 166, + 20, + 97, + 1, + 192, + 87, + 128, + 99, + 141, + 165, + 203, + 91, + 20, + 97, + 1, + 200, + 87, + 128, + 99, + 149, + 216, + 155, + 65, + 20, + 97, + 1, + 227, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 35, + 184, + 114, + 221, + 17, + 97, + 0, + 211, + 87, + 128, + 99, + 35, + 184, + 114, + 221, + 20, + 97, + 1, + 77, + 87, + 128, + 99, + 49, + 60, + 229, + 103, + 20, + 97, + 1, + 96, + 87, + 128, + 99, + 57, + 80, + 147, + 81, + 20, + 97, + 1, + 111, + 87, + 128, + 99, + 64, + 193, + 15, + 25, + 20, + 97, + 1, + 130, + 87, + 96, + 0, + 128, + 253, + 91, + 128, + 99, + 6, + 253, + 222, + 3, + 20, + 97, + 0, + 250, + 87, + 128, + 99, + 9, + 94, + 167, + 179, + 20, + 97, + 1, + 24, + 87, + 128, + 99, + 24, + 22, + 13, + 221, + 20, + 97, + 1, + 59, + 87, + 91, + 96, + 0, + 128, + 253, + 91, + 97, + 1, + 2, + 97, + 2, + 55, + 86, + 91, + 96, + 64, + 81, + 97, + 1, + 15, + 145, + 144, + 97, + 9, + 65, + 86, + 91, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 243, + 91, + 97, + 1, + 43, + 97, + 1, + 38, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 2, + 201, + 86, + 91, + 96, + 64, + 81, + 144, + 21, + 21, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 96, + 2, + 84, + 91, + 96, + 64, + 81, + 144, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 91, + 54, + 96, + 4, + 97, + 9, + 213, + 86, + 91, + 97, + 2, + 227, + 86, + 91, + 96, + 64, + 81, + 96, + 18, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 125, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 7, + 86, + 91, + 97, + 1, + 149, + 97, + 1, + 144, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 41, + 86, + 91, + 0, + 91, + 97, + 1, + 63, + 97, + 1, + 165, + 54, + 96, + 4, + 97, + 10, + 17, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 32, + 129, + 144, + 82, + 96, + 64, + 144, + 32, + 84, + 144, + 86, + 91, + 97, + 1, + 149, + 97, + 3, + 63, + 86, + 91, + 96, + 5, + 84, + 96, + 64, + 81, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 144, + 145, + 22, + 129, + 82, + 96, + 32, + 1, + 97, + 1, + 15, + 86, + 91, + 97, + 1, + 2, + 97, + 3, + 83, + 86, + 91, + 97, + 1, + 43, + 97, + 1, + 249, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 98, + 86, + 91, + 97, + 1, + 43, + 97, + 2, + 12, + 54, + 96, + 4, + 97, + 9, + 171, + 86, + 91, + 97, + 3, + 226, + 86, + 91, + 97, + 1, + 63, + 97, + 2, + 31, + 54, + 96, + 4, + 97, + 10, + 51, + 86, + 91, + 97, + 3, + 240, + 86, + 91, + 97, + 1, + 149, + 97, + 2, + 50, + 54, + 96, + 4, + 97, + 10, + 17, + 86, + 91, + 97, + 4, + 27, + 86, + 91, + 96, + 96, + 96, + 3, + 128, + 84, + 97, + 2, + 70, + 144, + 97, + 10, + 102, + 86, + 91, + 128, + 96, + 31, + 1, + 96, + 32, + 128, + 145, + 4, + 2, + 96, + 32, + 1, + 96, + 64, + 81, + 144, + 129, + 1, + 96, + 64, + 82, + 128, + 146, + 145, + 144, + 129, + 129, + 82, + 96, + 32, + 1, + 130, + 128, + 84, + 97, + 2, + 114, + 144, + 97, + 10, + 102, + 86, + 91, + 128, + 21, + 97, + 2, + 191, + 87, + 128, + 96, + 31, + 16, + 97, + 2, + 148, + 87, + 97, + 1, + 0, + 128, + 131, + 84, + 4, + 2, + 131, + 82, + 145, + 96, + 32, + 1, + 145, + 97, + 2, + 191, + 86, + 91, + 130, + 1, + 145, + 144, + 96, + 0, + 82, + 96, + 32, + 96, + 0, + 32, + 144, + 91, + 129, + 84, + 129, + 82, + 144, + 96, + 1, + 1, + 144, + 96, + 32, + 1, + 128, + 131, + 17, + 97, + 2, + 162, + 87, + 130, + 144, + 3, + 96, + 31, + 22, + 130, + 1, + 145, + 91, + 80, + 80, + 80, + 80, + 80, + 144, + 80, + 144, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 4, + 148, + 86, + 91, + 96, + 1, + 145, + 80, + 80, + 91, + 146, + 145, + 80, + 80, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 241, + 133, + 130, + 133, + 97, + 5, + 184, + 86, + 91, + 97, + 2, + 252, + 133, + 133, + 133, + 97, + 6, + 50, + 86, + 91, + 80, + 96, + 1, + 148, + 147, + 80, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 3, + 26, + 131, + 131, + 97, + 3, + 240, + 86, + 91, + 97, + 3, + 36, + 145, + 144, + 97, + 10, + 160, + 86, + 91, + 97, + 4, + 148, + 86, + 91, + 97, + 3, + 49, + 97, + 7, + 214, + 86, + 91, + 97, + 3, + 59, + 130, + 130, + 97, + 8, + 48, + 86, + 91, + 80, + 80, + 86, + 91, + 97, + 3, + 71, + 97, + 7, + 214, + 86, + 91, + 97, + 3, + 81, + 96, + 0, + 97, + 8, + 239, + 86, + 91, + 86, + 91, + 96, + 96, + 96, + 4, + 128, + 84, + 97, + 2, + 70, + 144, + 97, + 10, + 102, + 86, + 91, + 96, + 0, + 51, + 129, + 97, + 3, + 112, + 130, + 134, + 97, + 3, + 240, + 86, + 91, + 144, + 80, + 131, + 129, + 16, + 21, + 97, + 3, + 213, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 37, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 100, + 101, + 99, + 114, + 101, + 97, + 115, + 101, + 100, + 32, + 97, + 108, + 108, + 111, + 119, + 97, + 110, + 99, + 101, + 32, + 98, + 101, + 108, + 111, + 119, + 96, + 68, + 130, + 1, + 82, + 100, + 32, + 122, + 101, + 114, + 111, + 96, + 216, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 91, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 253, + 91, + 97, + 2, + 252, + 130, + 134, + 134, + 132, + 3, + 97, + 4, + 148, + 86, + 91, + 96, + 0, + 51, + 97, + 2, + 215, + 129, + 133, + 133, + 97, + 6, + 50, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 145, + 130, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 1, + 96, + 32, + 144, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 147, + 144, + 148, + 22, + 130, + 82, + 145, + 144, + 145, + 82, + 32, + 84, + 144, + 86, + 91, + 97, + 4, + 35, + 97, + 7, + 214, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 22, + 97, + 4, + 136, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 110, + 101, + 119, + 32, + 111, + 119, + 110, + 101, + 114, + 32, + 105, + 115, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 96, + 68, + 130, + 1, + 82, + 101, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 97, + 4, + 145, + 129, + 97, + 8, + 239, + 86, + 91, + 80, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 97, + 4, + 246, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 36, + 128, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 97, + 112, + 112, + 114, + 111, + 118, + 101, + 32, + 102, + 114, + 111, + 109, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 96, + 68, + 130, + 1, + 82, + 99, + 114, + 101, + 115, + 115, + 96, + 224, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 5, + 87, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 34, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 97, + 112, + 112, + 114, + 111, + 118, + 101, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 101, + 96, + 68, + 130, + 1, + 82, + 97, + 115, + 115, + 96, + 240, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 129, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 1, + 96, + 32, + 144, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 148, + 135, + 22, + 128, + 132, + 82, + 148, + 130, + 82, + 145, + 130, + 144, + 32, + 133, + 144, + 85, + 144, + 81, + 132, + 129, + 82, + 127, + 140, + 91, + 225, + 229, + 235, + 236, + 125, + 91, + 209, + 79, + 113, + 66, + 125, + 30, + 132, + 243, + 221, + 3, + 20, + 192, + 247, + 178, + 41, + 30, + 91, + 32, + 10, + 200, + 199, + 195, + 185, + 37, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 97, + 5, + 196, + 132, + 132, + 97, + 3, + 240, + 86, + 91, + 144, + 80, + 96, + 0, + 25, + 129, + 20, + 97, + 6, + 44, + 87, + 129, + 129, + 16, + 21, + 97, + 6, + 31, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 29, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 105, + 110, + 115, + 117, + 102, + 102, + 105, + 99, + 105, + 101, + 110, + 116, + 32, + 97, + 108, + 108, + 111, + 119, + 97, + 110, + 99, + 101, + 0, + 0, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 97, + 6, + 44, + 132, + 132, + 132, + 132, + 3, + 97, + 4, + 148, + 86, + 91, + 80, + 80, + 80, + 80, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 97, + 6, + 150, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 37, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 102, + 114, + 111, + 109, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 96, + 68, + 130, + 1, + 82, + 100, + 100, + 114, + 101, + 115, + 115, + 96, + 216, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 6, + 248, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 35, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 96, + 68, + 130, + 1, + 82, + 98, + 101, + 115, + 115, + 96, + 232, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 22, + 96, + 0, + 144, + 129, + 82, + 96, + 32, + 129, + 144, + 82, + 96, + 64, + 144, + 32, + 84, + 129, + 129, + 16, + 21, + 97, + 7, + 112, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 38, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 116, + 114, + 97, + 110, + 115, + 102, + 101, + 114, + 32, + 97, + 109, + 111, + 117, + 110, + 116, + 32, + 101, + 120, + 99, + 101, + 101, + 100, + 115, + 32, + 98, + 96, + 68, + 130, + 1, + 82, + 101, + 97, + 108, + 97, + 110, + 99, + 101, + 96, + 208, + 27, + 96, + 100, + 130, + 1, + 82, + 96, + 132, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 132, + 129, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 32, + 129, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 135, + 135, + 3, + 144, + 85, + 147, + 135, + 22, + 128, + 131, + 82, + 145, + 132, + 144, + 32, + 128, + 84, + 135, + 1, + 144, + 85, + 146, + 81, + 133, + 129, + 82, + 144, + 146, + 127, + 221, + 242, + 82, + 173, + 27, + 226, + 200, + 155, + 105, + 194, + 176, + 104, + 252, + 55, + 141, + 170, + 149, + 43, + 167, + 241, + 99, + 196, + 161, + 22, + 40, + 245, + 90, + 77, + 245, + 35, + 179, + 239, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 97, + 6, + 44, + 86, + 91, + 96, + 5, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 22, + 51, + 20, + 97, + 3, + 81, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 129, + 144, + 82, + 96, + 36, + 130, + 1, + 82, + 127, + 79, + 119, + 110, + 97, + 98, + 108, + 101, + 58, + 32, + 99, + 97, + 108, + 108, + 101, + 114, + 32, + 105, + 115, + 32, + 110, + 111, + 116, + 32, + 116, + 104, + 101, + 32, + 111, + 119, + 110, + 101, + 114, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 97, + 8, + 134, + 87, + 96, + 64, + 81, + 98, + 70, + 27, + 205, + 96, + 229, + 27, + 129, + 82, + 96, + 32, + 96, + 4, + 130, + 1, + 82, + 96, + 31, + 96, + 36, + 130, + 1, + 82, + 127, + 69, + 82, + 67, + 50, + 48, + 58, + 32, + 109, + 105, + 110, + 116, + 32, + 116, + 111, + 32, + 116, + 104, + 101, + 32, + 122, + 101, + 114, + 111, + 32, + 97, + 100, + 100, + 114, + 101, + 115, + 115, + 0, + 96, + 68, + 130, + 1, + 82, + 96, + 100, + 1, + 97, + 3, + 204, + 86, + 91, + 128, + 96, + 2, + 96, + 0, + 130, + 130, + 84, + 97, + 8, + 152, + 145, + 144, + 97, + 10, + 160, + 86, + 91, + 144, + 145, + 85, + 80, + 80, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 130, + 22, + 96, + 0, + 129, + 129, + 82, + 96, + 32, + 129, + 129, + 82, + 96, + 64, + 128, + 131, + 32, + 128, + 84, + 134, + 1, + 144, + 85, + 81, + 132, + 129, + 82, + 127, + 221, + 242, + 82, + 173, + 27, + 226, + 200, + 155, + 105, + 194, + 176, + 104, + 252, + 55, + 141, + 170, + 149, + 43, + 167, + 241, + 99, + 196, + 161, + 22, + 40, + 245, + 90, + 77, + 245, + 35, + 179, + 239, + 145, + 1, + 96, + 64, + 81, + 128, + 145, + 3, + 144, + 163, + 80, + 80, + 86, + 91, + 96, + 5, + 128, + 84, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 131, + 129, + 22, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 25, + 131, + 22, + 129, + 23, + 144, + 147, + 85, + 96, + 64, + 81, + 145, + 22, + 145, + 144, + 130, + 144, + 127, + 139, + 224, + 7, + 156, + 83, + 22, + 89, + 20, + 19, + 68, + 205, + 31, + 208, + 164, + 242, + 132, + 25, + 73, + 127, + 151, + 34, + 163, + 218, + 175, + 227, + 180, + 24, + 111, + 107, + 100, + 87, + 224, + 144, + 96, + 0, + 144, + 163, + 80, + 80, + 86, + 91, + 96, + 0, + 96, + 32, + 128, + 131, + 82, + 131, + 81, + 128, + 130, + 133, + 1, + 82, + 96, + 0, + 91, + 129, + 129, + 16, + 21, + 97, + 9, + 110, + 87, + 133, + 129, + 1, + 131, + 1, + 81, + 133, + 130, + 1, + 96, + 64, + 1, + 82, + 130, + 1, + 97, + 9, + 82, + 86, + 91, + 80, + 96, + 0, + 96, + 64, + 130, + 134, + 1, + 1, + 82, + 96, + 64, + 96, + 31, + 25, + 96, + 31, + 131, + 1, + 22, + 133, + 1, + 1, + 146, + 80, + 80, + 80, + 146, + 145, + 80, + 80, + 86, + 91, + 128, + 53, + 96, + 1, + 96, + 1, + 96, + 160, + 27, + 3, + 129, + 22, + 129, + 20, + 97, + 9, + 166, + 87, + 96, + 0, + 128, + 253, + 91, + 145, + 144, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 64, + 131, + 133, + 3, + 18, + 21, + 97, + 9, + 190, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 9, + 199, + 131, + 97, + 9, + 143, + 86, + 91, + 148, + 96, + 32, + 147, + 144, + 147, + 1, + 53, + 147, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 0, + 96, + 96, + 132, + 134, + 3, + 18, + 21, + 97, + 9, + 234, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 9, + 243, + 132, + 97, + 9, + 143, + 86, + 91, + 146, + 80, + 97, + 10, + 1, + 96, + 32, + 133, + 1, + 97, + 9, + 143, + 86, + 91, + 145, + 80, + 96, + 64, + 132, + 1, + 53, + 144, + 80, + 146, + 80, + 146, + 80, + 146, + 86, + 91, + 96, + 0, + 96, + 32, + 130, + 132, + 3, + 18, + 21, + 97, + 10, + 35, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 10, + 44, + 130, + 97, + 9, + 143, + 86, + 91, + 147, + 146, + 80, + 80, + 80, + 86, + 91, + 96, + 0, + 128, + 96, + 64, + 131, + 133, + 3, + 18, + 21, + 97, + 10, + 70, + 87, + 96, + 0, + 128, + 253, + 91, + 97, + 10, + 79, + 131, + 97, + 9, + 143, + 86, + 91, + 145, + 80, + 97, + 10, + 93, + 96, + 32, + 132, + 1, + 97, + 9, + 143, + 86, + 91, + 144, + 80, + 146, + 80, + 146, + 144, + 80, + 86, + 91, + 96, + 1, + 129, + 129, + 28, + 144, + 130, + 22, + 128, + 97, + 10, + 122, + 87, + 96, + 127, + 130, + 22, + 145, + 80, + 91, + 96, + 32, + 130, + 16, + 129, + 3, + 97, + 10, + 154, + 87, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 34, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 91, + 80, + 145, + 144, + 80, + 86, + 91, + 128, + 130, + 1, + 128, + 130, + 17, + 21, + 97, + 2, + 221, + 87, + 99, + 78, + 72, + 123, + 113, + 96, + 224, + 27, + 96, + 0, + 82, + 96, + 17, + 96, + 4, + 82, + 96, + 36, + 96, + 0, + 253, + 254, + 162, + 100, + 105, + 112, + 102, + 115, + 88, + 34, + 18, + 32, + 253, + 219, + 133, + 110, + 73, + 92, + 0, + 147, + 166, + 78, + 244, + 255, + 131, + 246, + 4, + 122, + 242, + 74, + 188, + 163, + 116, + 209, + 16, + 33, + 154, + 27, + 110, + 123, + 34, + 163, + 47, + 138, + 100, + 115, + 111, + 108, + 99, + 67, + 0, + 8, + 18, + 0, + 51, + ]; + ///The deployed bytecode of the contract. + pub static MOCKERC20_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static( + __DEPLOYED_BYTECODE, + ); + pub struct MockERC20(::ethers::contract::Contract); + impl ::core::clone::Clone for MockERC20 { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for MockERC20 { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for MockERC20 { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for MockERC20 { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(stringify!(MockERC20)).field(&self.address()).finish() + } + } + impl MockERC20 { + /// 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(), + MOCKERC20_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( + MOCKERC20_ABI.clone(), + MOCKERC20_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `allowance` (0xdd62ed3e) function + pub fn allowance( + &self, + owner: ::ethers::core::types::Address, + spender: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([221, 98, 237, 62], (owner, spender)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `approve` (0x095ea7b3) function + pub fn approve( + &self, + spender: ::ethers::core::types::Address, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([9, 94, 167, 179], (spender, amount)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `balanceOf` (0x70a08231) function + pub fn balance_of( + &self, + account: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([112, 160, 130, 49], account) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `decimals` (0x313ce567) function + pub fn decimals(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([49, 60, 229, 103], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `decreaseAllowance` (0xa457c2d7) function + pub fn decrease_allowance( + &self, + spender: ::ethers::core::types::Address, + subtracted_value: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([164, 87, 194, 215], (spender, subtracted_value)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `increaseAllowance` (0x39509351) function + pub fn increase_allowance( + &self, + spender: ::ethers::core::types::Address, + added_value: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([57, 80, 147, 81], (spender, added_value)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `mint` (0x40c10f19) function + pub fn mint( + &self, + to: ::ethers::core::types::Address, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([64, 193, 15, 25], (to, amount)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `name` (0x06fdde03) function + pub fn name( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([6, 253, 222, 3], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + ::ethers::core::types::Address, + > { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `renounceOwnership` (0x715018a6) function + pub fn renounce_ownership( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([113, 80, 24, 166], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `symbol` (0x95d89b41) function + pub fn symbol( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([149, 216, 155, 65], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `totalSupply` (0x18160ddd) function + pub fn total_supply( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([24, 22, 13, 221], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transfer` (0xa9059cbb) function + pub fn transfer( + &self, + to: ::ethers::core::types::Address, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([169, 5, 156, 187], (to, amount)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transferFrom` (0x23b872dd) function + pub fn transfer_from( + &self, + from: ::ethers::core::types::Address, + to: ::ethers::core::types::Address, + amount: ::ethers::core::types::U256, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([35, 184, 114, 221], (from, to, amount)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transferOwnership` (0xf2fde38b) function + pub fn transfer_ownership( + &self, + new_owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([242, 253, 227, 139], new_owner) + .expect("method not found (this should never happen)") + } + ///Gets the contract's `Approval` event + pub fn approval_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + ApprovalFilter, + > { + self.0.event() + } + ///Gets the contract's `OwnershipTransferred` event + pub fn ownership_transferred_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + OwnershipTransferredFilter, + > { + self.0.event() + } + ///Gets the contract's `Transfer` event + pub fn transfer_filter( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + TransferFilter, + > { + self.0.event() + } + /// Returns an `Event` builder for all the events of this contract. + pub fn events( + &self, + ) -> ::ethers::contract::builders::Event< + ::std::sync::Arc, + M, + MockERC20Events, + > { + self.0.event_with_filter(::core::default::Default::default()) + } + } + impl From<::ethers::contract::Contract> + for MockERC20 { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent(name = "Approval", abi = "Approval(address,address,uint256)")] + pub struct ApprovalFilter { + #[ethevent(indexed)] + pub owner: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub spender: ::ethers::core::types::Address, + pub value: ::ethers::core::types::U256, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent( + name = "OwnershipTransferred", + abi = "OwnershipTransferred(address,address)" + )] + pub struct OwnershipTransferredFilter { + #[ethevent(indexed)] + pub previous_owner: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub new_owner: ::ethers::core::types::Address, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethevent(name = "Transfer", abi = "Transfer(address,address,uint256)")] + pub struct TransferFilter { + #[ethevent(indexed)] + pub from: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub to: ::ethers::core::types::Address, + pub value: ::ethers::core::types::U256, + } + ///Container type for all of the contract's events + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum MockERC20Events { + ApprovalFilter(ApprovalFilter), + OwnershipTransferredFilter(OwnershipTransferredFilter), + TransferFilter(TransferFilter), + } + impl ::ethers::contract::EthLogDecode for MockERC20Events { + fn decode_log( + log: &::ethers::core::abi::RawLog, + ) -> ::core::result::Result { + if let Ok(decoded) = ApprovalFilter::decode_log(log) { + return Ok(MockERC20Events::ApprovalFilter(decoded)); + } + if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { + return Ok(MockERC20Events::OwnershipTransferredFilter(decoded)); + } + if let Ok(decoded) = TransferFilter::decode_log(log) { + return Ok(MockERC20Events::TransferFilter(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData) + } + } + impl ::core::fmt::Display for MockERC20Events { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::ApprovalFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::OwnershipTransferredFilter(element) => { + ::core::fmt::Display::fmt(element, f) + } + Self::TransferFilter(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for MockERC20Events { + fn from(value: ApprovalFilter) -> Self { + Self::ApprovalFilter(value) + } + } + impl ::core::convert::From for MockERC20Events { + fn from(value: OwnershipTransferredFilter) -> Self { + Self::OwnershipTransferredFilter(value) + } + } + impl ::core::convert::From for MockERC20Events { + fn from(value: TransferFilter) -> Self { + Self::TransferFilter(value) + } + } + ///Container type for all input parameters for the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "allowance", abi = "allowance(address,address)")] + pub struct AllowanceCall { + pub owner: ::ethers::core::types::Address, + pub spender: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "approve", abi = "approve(address,uint256)")] + pub struct ApproveCall { + pub spender: ::ethers::core::types::Address, + pub amount: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "balanceOf", abi = "balanceOf(address)")] + pub struct BalanceOfCall { + pub account: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `decimals` function with signature `decimals()` and selector `0x313ce567` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "decimals", abi = "decimals()")] + pub struct DecimalsCall; + ///Container type for all input parameters for the `decreaseAllowance` function with signature `decreaseAllowance(address,uint256)` and selector `0xa457c2d7` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "decreaseAllowance", abi = "decreaseAllowance(address,uint256)")] + pub struct DecreaseAllowanceCall { + pub spender: ::ethers::core::types::Address, + pub subtracted_value: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `increaseAllowance` function with signature `increaseAllowance(address,uint256)` and selector `0x39509351` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "increaseAllowance", abi = "increaseAllowance(address,uint256)")] + pub struct IncreaseAllowanceCall { + pub spender: ::ethers::core::types::Address, + pub added_value: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `mint` function with signature `mint(address,uint256)` and selector `0x40c10f19` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "mint", abi = "mint(address,uint256)")] + pub struct MintCall { + pub to: ::ethers::core::types::Address, + pub amount: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `name` function with signature `name()` and selector `0x06fdde03` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "name", abi = "name()")] + pub struct NameCall; + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] + pub struct RenounceOwnershipCall; + ///Container type for all input parameters for the `symbol` function with signature `symbol()` and selector `0x95d89b41` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "symbol", abi = "symbol()")] + pub struct SymbolCall; + ///Container type for all input parameters for the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "totalSupply", abi = "totalSupply()")] + pub struct TotalSupplyCall; + ///Container type for all input parameters for the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "transfer", abi = "transfer(address,uint256)")] + pub struct TransferCall { + pub to: ::ethers::core::types::Address, + pub amount: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "transferFrom", abi = "transferFrom(address,address,uint256)")] + pub struct TransferFromCall { + pub from: ::ethers::core::types::Address, + pub to: ::ethers::core::types::Address, + pub amount: ::ethers::core::types::U256, + } + ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] + pub struct TransferOwnershipCall { + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum MockERC20Calls { + Allowance(AllowanceCall), + Approve(ApproveCall), + BalanceOf(BalanceOfCall), + Decimals(DecimalsCall), + DecreaseAllowance(DecreaseAllowanceCall), + IncreaseAllowance(IncreaseAllowanceCall), + Mint(MintCall), + Name(NameCall), + Owner(OwnerCall), + RenounceOwnership(RenounceOwnershipCall), + Symbol(SymbolCall), + TotalSupply(TotalSupplyCall), + Transfer(TransferCall), + TransferFrom(TransferFromCall), + TransferOwnership(TransferOwnershipCall), + } + impl ::ethers::core::abi::AbiDecode for MockERC20Calls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Allowance(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Approve(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::BalanceOf(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Decimals(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::DecreaseAllowance(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::IncreaseAllowance(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Mint(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Name(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::RenounceOwnership(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Symbol(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::TotalSupply(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::Transfer(decoded)); + } + if let Ok(decoded) + = ::decode(data) { + return Ok(Self::TransferFrom(decoded)); + } + if let Ok(decoded) + = ::decode( + data, + ) { + return Ok(Self::TransferOwnership(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for MockERC20Calls { + fn encode(self) -> Vec { + match self { + Self::Allowance(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Approve(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::BalanceOf(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Decimals(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::DecreaseAllowance(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::IncreaseAllowance(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Mint(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Name(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RenounceOwnership(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Symbol(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TotalSupply(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Transfer(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::TransferFrom(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::TransferOwnership(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + } + } + } + impl ::core::fmt::Display for MockERC20Calls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::Allowance(element) => ::core::fmt::Display::fmt(element, f), + Self::Approve(element) => ::core::fmt::Display::fmt(element, f), + Self::BalanceOf(element) => ::core::fmt::Display::fmt(element, f), + Self::Decimals(element) => ::core::fmt::Display::fmt(element, f), + Self::DecreaseAllowance(element) => ::core::fmt::Display::fmt(element, f), + Self::IncreaseAllowance(element) => ::core::fmt::Display::fmt(element, f), + Self::Mint(element) => ::core::fmt::Display::fmt(element, f), + Self::Name(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::Symbol(element) => ::core::fmt::Display::fmt(element, f), + Self::TotalSupply(element) => ::core::fmt::Display::fmt(element, f), + Self::Transfer(element) => ::core::fmt::Display::fmt(element, f), + Self::TransferFrom(element) => ::core::fmt::Display::fmt(element, f), + Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: AllowanceCall) -> Self { + Self::Allowance(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: ApproveCall) -> Self { + Self::Approve(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: BalanceOfCall) -> Self { + Self::BalanceOf(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: DecimalsCall) -> Self { + Self::Decimals(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: DecreaseAllowanceCall) -> Self { + Self::DecreaseAllowance(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: IncreaseAllowanceCall) -> Self { + Self::IncreaseAllowance(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: MintCall) -> Self { + Self::Mint(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: NameCall) -> Self { + Self::Name(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: RenounceOwnershipCall) -> Self { + Self::RenounceOwnership(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: SymbolCall) -> Self { + Self::Symbol(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: TotalSupplyCall) -> Self { + Self::TotalSupply(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: TransferCall) -> Self { + Self::Transfer(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: TransferFromCall) -> Self { + Self::TransferFrom(value) + } + } + impl ::core::convert::From for MockERC20Calls { + fn from(value: TransferOwnershipCall) -> Self { + Self::TransferOwnership(value) + } + } + ///Container type for all return fields from the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct AllowanceReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct ApproveReturn(pub bool); + ///Container type for all return fields from the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct BalanceOfReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `decimals` function with signature `decimals()` and selector `0x313ce567` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct DecimalsReturn(pub u8); + ///Container type for all return fields from the `decreaseAllowance` function with signature `decreaseAllowance(address,uint256)` and selector `0xa457c2d7` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct DecreaseAllowanceReturn(pub bool); + ///Container type for all return fields from the `increaseAllowance` function with signature `increaseAllowance(address,uint256)` and selector `0x39509351` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct IncreaseAllowanceReturn(pub bool); + ///Container type for all return fields from the `name` function with signature `name()` and selector `0x06fdde03` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct NameReturn(pub ::std::string::String); + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///Container type for all return fields from the `symbol` function with signature `symbol()` and selector `0x95d89b41` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct SymbolReturn(pub ::std::string::String); + ///Container type for all return fields from the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct TotalSupplyReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct TransferReturn(pub bool); + ///Container type for all return fields from the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash + )] + pub struct TransferFromReturn(pub bool); +} diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mod.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mod.rs new file mode 100644 index 0000000..dbac9b7 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/mock/mod.rs @@ -0,0 +1 @@ +pub mod mock_erc20; diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/mod.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/mod.rs new file mode 100644 index 0000000..55333bf --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/mod.rs @@ -0,0 +1,3 @@ +pub mod generated; +pub mod mock; +pub mod signer; diff --git a/tools/polyexen/circuit/solvency/backend/src/contracts/signer.rs b/tools/polyexen/circuit/solvency/backend/src/contracts/signer.rs new file mode 100644 index 0000000..abab24e --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/contracts/signer.rs @@ -0,0 +1,133 @@ +use ethers::{ + prelude::SignerMiddleware, + providers::{Http, Middleware, Provider}, + signers::{LocalWallet, Signer}, + types::{Address, U256}, +}; +use serde_json::Value; +use std::{error::Error, fs::File, io::BufReader, path::Path, str::FromStr, sync::Arc}; +use tokio::sync::Mutex; + +use super::generated::summa_contract::{AddressOwnershipProof, Cryptocurrency}; +use crate::contracts::generated::summa_contract::Summa; + +pub enum AddressInput { + Address(Address), + Path(String), +} + +#[derive(Debug)] +pub struct SummaSigner { + nonce_lock: Mutex<()>, // To prevent running `submit` methods concurrently + summa_contract: Summa>, LocalWallet>>, +} + +impl SummaSigner { + /// Creates a new SummaSigner instance + /// # Arguments + /// * `signer_key` - The private key of wallet that will interact with the chain on behalf of the exchange + /// * `url` - The endpoint for connecting to the node + /// * `address` - The address of the Summa contract + pub async fn new( + signer_key: &str, + url: &str, + address_input: AddressInput, + ) -> Result> { + let wallet: LocalWallet = LocalWallet::from_str(signer_key).unwrap(); + + let provider = Arc::new(Provider::try_from(url)?); + let chain_id = provider.get_chainid().await?.as_u64(); + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(chain_id), + )); + + let address = match address_input { + AddressInput::Address(address) => address, + AddressInput::Path(path) => { + let address = Self::get_deployment_address(path, chain_id).unwrap(); + address + } + }; + + Ok(Self { + nonce_lock: Mutex::new(()), + summa_contract: Summa::new(address, client), + }) + } + + pub fn get_summa_address(&self) -> Address { + self.summa_contract.address() + } + + fn get_deployment_address>( + path: P, + chain_id: u64, + ) -> Result> { + // Open file in RO mode with buffer + let file = File::open(path)?; + let reader = BufReader::new(file); + + // Read the JSON contents of the file + let payload: Value = serde_json::from_reader(reader)?; + + // Retrieve the contract address from the deployments.json file + let deployment_address: &Value = &payload.as_object().unwrap() + [chain_id.to_string().as_str()] + .as_object() + .unwrap()["address"]; + + let summa_address: &str = deployment_address.as_str().unwrap(); + + let address: Address = summa_address.parse().unwrap(); + + Ok(address) + } + + pub async fn submit_proof_of_address_ownership( + &self, + address_ownership_proofs: Vec, + ) -> Result<(), Box> { + let lock_guard = self.nonce_lock.lock().await; + + let submit_proof_of_address_ownership = &self + .summa_contract + .submit_proof_of_address_ownership(address_ownership_proofs); + + // To prevent nonce collision, we lock the nonce before sending the transaction + let tx = submit_proof_of_address_ownership.send().await?; + + // Wait for the pending transaction to be mined + tx.await?; + + drop(lock_guard); + Ok(()) + } + + pub async fn submit_commitment( + &self, + mst_root: U256, + root_sums: Vec, + cryptocurrencies: Vec, + timestamp: U256, + ) -> Result<(), Box> { + let lock_guard = self.nonce_lock.lock().await; + + let submit_liability_commitment = &self.summa_contract.submit_commitment( + mst_root, + root_sums, + cryptocurrencies, + timestamp, + ); + + // To prevent nonce collision, we lock the nonce before sending the transaction + let tx = submit_liability_commitment.send().await?; + + // Wait for the pending transaction to be mined + tx.await?; + + drop(lock_guard); + + Ok(()) + } +} diff --git a/tools/polyexen/circuit/solvency/backend/src/lib.rs b/tools/polyexen/circuit/solvency/backend/src/lib.rs new file mode 100644 index 0000000..534b1b6 --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/lib.rs @@ -0,0 +1,5 @@ +#![feature(generic_const_exprs)] +pub mod apis; +pub mod contracts; +pub mod tests; +pub use summa_solvency::merkle_sum_tree; diff --git a/tools/polyexen/circuit/solvency/backend/src/tests.rs b/tools/polyexen/circuit/solvency/backend/src/tests.rs new file mode 100644 index 0000000..8373c7c --- /dev/null +++ b/tools/polyexen/circuit/solvency/backend/src/tests.rs @@ -0,0 +1,299 @@ +use std::{sync::Arc, time::Duration}; + +use ethers::{ + abi::Token, + prelude::SignerMiddleware, + providers::{Http, Middleware, Provider}, + signers::{LocalWallet, Signer}, + types::{H160, U256}, + utils::{Anvil, AnvilInstance}, +}; +use tokio::time; + +use crate::contracts::generated::{inclusion_verifier::InclusionVerifier, summa_contract::Summa}; + +// Setup test environment on the anvil instance +pub async fn initialize_test_env( + block_time: Option, +) -> ( + AnvilInstance, + H160, + H160, + Arc, LocalWallet>>, + Summa, LocalWallet>>, +) { + // Initiate anvil by following assign block time or instant mining + let anvil = match block_time { + Some(interval) => Anvil::new() + .mnemonic("test test test test test test test test test test test junk") + .block_time(interval) + .spawn(), + None => Anvil::new() + .mnemonic("test test test test test test test test test test test junk") + .spawn(), + }; + + // Extracting two exchange addresses from the Anvil instance + let cex_addr_1 = anvil.addresses()[1]; + let cex_addr_2 = anvil.addresses()[2]; + + // Setup wallet from the first key in the Anvil and an HTTP provider with a 10ms interval from the Anvil endpoint + let wallet: LocalWallet = anvil.keys()[0].clone().into(); + let provider = Provider::::try_from(anvil.endpoint()) + .unwrap() + .interval(Duration::from_millis(10u64)); + + // Creating a client by wrapping the provider with a signing middleware and the Anvil chainid + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(anvil.chain_id()), + )); + + // Send RPC requests with `anvil_setBalance` method via provider to set ETH balance of `cex_addr_1` and `cex_addr_2` + for addr in [cex_addr_1, cex_addr_2].iter().copied() { + let _res = client + .provider() + .request::<(H160, U256), ()>("anvil_setBalance", (addr, U256::from(278432))) + .await; + } + + if block_time.is_some() { + time::sleep(Duration::from_secs(block_time.unwrap())).await; + }; + + let inclusion_verifier_contract = InclusionVerifier::deploy(Arc::clone(&client), ()) + .unwrap() + .send() + .await + .unwrap(); + + if block_time.is_some() { + time::sleep(Duration::from_secs(block_time.unwrap())).await; + }; + + // The number of levels of the Merkle sum tree + let mst_levels = 4; + //The number of cryptocurrencies supported by the Merkle sum tree + let currencies_count = 2; + // The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree + let balance_byte_range = 8; + + let args: &[Token] = &[ + Token::Address(inclusion_verifier_contract.address()), + Token::Uint(mst_levels.into()), + Token::Uint(currencies_count.into()), + Token::Uint(balance_byte_range.into()), + ]; + // Deploy Summa contract + let summa_contract = Summa::deploy(Arc::clone(&client), args) + .unwrap() + .send() + .await + .unwrap(); + + time::sleep(Duration::from_secs(3)).await; + + (anvil, cex_addr_1, cex_addr_2, client, summa_contract) +} + +#[cfg(test)] +mod test { + use ethers::{ + abi::AbiEncode, + providers::{Http, Middleware, Provider}, + types::{U256, U64}, + utils::to_checksum, + }; + use std::{convert::TryFrom, error::Error}; + use summa_solvency::merkle_sum_tree::MerkleSumTree; + use tokio::{ + join, + time::{sleep, Duration}, + }; + + use crate::apis::{address_ownership::AddressOwnership, round::Round}; + use crate::contracts::{ + generated::summa_contract::{ + AddressOwnershipProof, AddressOwnershipProofSubmittedFilter, Cryptocurrency, + LiabilitiesCommitmentSubmittedFilter, + }, + signer::{AddressInput, SummaSigner}, + }; + use crate::tests::initialize_test_env; + + #[tokio::test] + async fn test_deployed_address() -> Result<(), Box> { + let (anvil, _, _, _, summa_contract) = initialize_test_env(None).await; + + // Hardhat development environment, usually updates the address of a deployed contract in the `artifacts` directory. + // However, in our custom deployment script, `contracts/scripts/deploy.ts`, + // the address gets updated in `backend/src/contracts/deployments.json`. + let contract_address = summa_contract.address(); + + let signer = SummaSigner::new( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + anvil.endpoint().as_str(), + AddressInput::Path("./src/contracts/deployments.json".into()), // the file contains the address of the deployed contract + ) + .await?; + + assert_eq!(contract_address, signer.get_summa_address()); + + Ok(()) + } + + #[tokio::test] + async fn test_concurrent_sumbit_commitments() -> Result<(), Box> { + let (anvil, _, _, _, summa_contract) = initialize_test_env(Some(1)).await; + + // This test ensures that two proofs, when dispatched concurrently, do not result in nonce collisions. + // It checks that both proofs are processed and mined within a reasonable timeframe, + // indicating that there's no interference or delay when the two are submitted simultaneously. + let signer = SummaSigner::new( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + anvil.endpoint().as_str(), + AddressInput::Address(summa_contract.address()), + ) + .await?; + + let params_path = "ptau/hermez-raw-11"; + let entry_csv = "../csv/entry_16.csv"; + let mst = MerkleSumTree::from_csv(entry_csv).unwrap(); + + let mut round_one = + Round::<4, 2, 8>::new(&signer, Box::new(mst.clone()), params_path, 1).unwrap(); + let mut round_two = Round::<4, 2, 8>::new(&signer, Box::new(mst), params_path, 2).unwrap(); + + // Checking block number before sending transaction of liability commitment + let outer_provider: Provider = Provider::try_from(anvil.endpoint().as_str())?; + let start_block_number = outer_provider.get_block_number().await?; + + // Send two commitments simultaneously + let (round_one_result, round_two_result) = join!( + round_one.dispatch_commitment(), + round_two.dispatch_commitment() + ); + + // Check two blocks has been mined + for _ in 0..5 { + sleep(Duration::from_millis(500)).await; + let updated_block_number = outer_provider.get_block_number().await?; + if (updated_block_number - start_block_number) > U64::from(2) { + break; + } + } + + // Check two rounds' result are both Ok + assert!(round_one_result.is_ok()); + assert!(round_two_result.is_ok()); + + Ok(()) + } + + #[tokio::test] + async fn test_round_features() -> Result<(), Box> { + let (anvil, cex_addr_1, cex_addr_2, _, summa_contract) = initialize_test_env(None).await; + + let signer = SummaSigner::new( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + anvil.endpoint().as_str(), + AddressInput::Address(summa_contract.address()), + ) + .await?; + + let mut address_ownership_client = + AddressOwnership::new(&signer, "../csv/signatures.csv").unwrap(); + + address_ownership_client + .dispatch_proof_of_address_ownership() + .await?; + + let ownership_proof_logs = summa_contract + .address_ownership_proof_submitted_filter() + .query() + .await?; + + assert_eq!(ownership_proof_logs.len(), 1); + assert_eq!( + ownership_proof_logs[0], + AddressOwnershipProofSubmittedFilter { + address_ownership_proofs: vec![AddressOwnershipProof { + chain: "ETH".to_string(), + cex_address: to_checksum(&cex_addr_1, None), + signature: + ("0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b").parse().unwrap(), + message: "Summa proof of solvency for CryptoExchange".encode().into(), + },AddressOwnershipProof { + chain: "ETH".to_string(), + cex_address:to_checksum(&cex_addr_2, None), + signature: + ("0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c").parse().unwrap(), + message: "Summa proof of solvency for CryptoExchange".encode().into(), + }, + ], + } + ); + + // Initialize round + let params_path = "ptau/hermez-raw-11"; + let entry_csv = "../csv/entry_16.csv"; + + let mst = MerkleSumTree::from_csv(entry_csv).unwrap(); + let mut round = Round::<4, 2, 8>::new(&signer, Box::new(mst), params_path, 1).unwrap(); + + let mut liability_commitment_logs = summa_contract + .liabilities_commitment_submitted_filter() + .query() + .await?; + + assert_eq!(liability_commitment_logs.len(), 0); + + // Send liability commitment transaction + round.dispatch_commitment().await?; + + // After sending transaction of liability commitment, logs should be updated + liability_commitment_logs = summa_contract + .liabilities_commitment_submitted_filter() + .query() + .await?; + + assert_eq!(liability_commitment_logs.len(), 1); + assert_eq!( + liability_commitment_logs[0], + LiabilitiesCommitmentSubmittedFilter { + timestamp: U256::from(1), + mst_root: "0x18d6ab953235a811edffa4cead74ea045e7cd2085771a2269d59dca054c955b1" + .parse() + .unwrap(), + root_balances: vec![U256::from(556862), U256::from(556862)], + cryptocurrencies: vec![ + Cryptocurrency { + name: "ETH".to_string(), + chain: "ETH".to_string(), + }, + Cryptocurrency { + name: "USDT".to_string(), + chain: "ETH".to_string(), + }, + ], + } + ); + + // Test inclusion proof + let inclusion_proof = round.get_proof_of_inclusion(0).unwrap(); + + // Verify inclusion proof with onchain function + let verified = summa_contract + .verify_inclusion_proof( + inclusion_proof.get_proof().clone(), + inclusion_proof.get_public_inputs().clone(), + U256::from(1), + ) + .await?; + + assert!(verified); + + drop(anvil); + Ok(()) + } +} diff --git a/tools/polyexen/circuit/solvency/backend/summa_verifier_interface.png b/tools/polyexen/circuit/solvency/backend/summa_verifier_interface.png new file mode 100644 index 0000000..3d54477 Binary files /dev/null and b/tools/polyexen/circuit/solvency/backend/summa_verifier_interface.png differ diff --git a/tools/polyexen/circuit/solvency/contracts/.gitignore b/tools/polyexen/circuit/solvency/contracts/.gitignore new file mode 100644 index 0000000..9b921b1 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/.gitignore @@ -0,0 +1,12 @@ +node_modules +.env +coverage +coverage.json +typechain +typechain-types +.DS_Store + +# Hardhat files +cache +artifacts + diff --git a/tools/polyexen/circuit/solvency/contracts/README.md b/tools/polyexen/circuit/solvency/contracts/README.md new file mode 100644 index 0000000..4de546f --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/README.md @@ -0,0 +1,56 @@ +# Summa Smart Contract + +The [Summa smart contract](src/Summa.sol) acts as a registrar for Centralized Exchanges (CEXs) to commit to their liabilities by submitting a Merkle sum tree (MST) root of all the CEX liabilities owed to its users. Users can then verify their inclusion into the liabilities commitment, and the public can compare the committed total sums with the assets owned by the CEX onchain. + +## Features + +- **Address Ownership Proofs**: CEXs should submit the proof of address ownership for all addresses that hold the assets included into the commitment by using `submitProofOfAddressOwnership` function. The proofs are accepted optimistically and subject to off-chain verification. + +- **Liabilities Commitments**: CEXs can submit commitments to its liabilities in the form of MST roots and the corresponding total sums that represent the snapshots of the liabilities at a given timestamp by using `submitCommitment` function. + +- **Inclusion Verification**: Users are able to verify the zero-knowledge proof of inclusion of their balances into the MST using `verifyInclusionProof` function. The function is calling the underlying smart contract [Verifier](src/InclusionVerifier.sol). The verifier is generated from the [zk_prover](./../zk_prover/) module (see module's [readme](./../zk_prover/README.md)). + +## Installation + +Ensure you have Node.js installed on your machine before proceeding. The smart contract is written in Solidity and uses the Hardhat environment for testing and deployment. + +To set up the project environment, install the necessary dependencies: + +```shell +npm install +``` + +## Testing + +```shell +REPORT_GAS=true npx hardhat test +``` + +### Test Coverage + +```shell +npx hardhat coverage +``` + +## Deploying + +The deployment script writes the latest deployment address for the chain to the [deployments](./../backend/src/contracts/deployments.json) file in the backend project. This data can later be used by the backend module to connect to the deployed contract. +The deployment script will copy the contract ABIs from the ./artifacts/src/ to the [backend](./../backend/src/contracts/abi/) module. The backend buildscript will then be able to generate the updated contract interfaces (see the backend [readme](./../backend/README.md)). + +When deploying locally, don't forget to run the node: + +```shell +npx hardhat node +``` + +The deployment script takes a `--network` argument. The networks can be configured in [hardhat.config.ts](hardhat.config.ts). The following is an example of a local deployment: + +```shell +npx hardhat run scripts/deploy.ts --network localhost +``` + +The following Summa contract parameters are passed to its constructor inside the deployment script: + +- verifier contract address (set automatically after the script deploys the verifier); +- the number of levels of the Merkle sum tree; +- the number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree. diff --git a/tools/polyexen/circuit/solvency/contracts/hardhat.config.ts b/tools/polyexen/circuit/solvency/contracts/hardhat.config.ts new file mode 100644 index 0000000..d4b61d9 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/hardhat.config.ts @@ -0,0 +1,47 @@ +import "@nomicfoundation/hardhat-toolbox"; +import "hardhat-gas-reporter"; +import "solidity-coverage"; +import * as dotenv from "dotenv"; + +dotenv.config(); +module.exports = { + defaultNetwork: "hardhat", + networks: { + localhost: { + chainId: 31337, + url: "http://127.0.0.1:8545", + }, + hardhat: {}, + // goerli: { + // chainId: 5, + // url: process.env.GOERLI_URL, + // accounts: [process.env.GOERLI_PRIVATE_KEY], + // }, + }, + gasReporter: { + currency: "USD", + gasPrice: 30, + }, + solidity: { + compilers: [ + { + version: "0.8.18", + settings: { + evmVersion: "istanbul", + optimizer: { + enabled: true, + runs: 200, + }, + viaIR: true, + }, + }, + ], + }, + paths: { + sources: "src", + tests: "test", + cache: "cache", + artifacts: "artifacts", + out: "build/out", + }, +}; diff --git a/tools/polyexen/circuit/solvency/contracts/package-lock.json b/tools/polyexen/circuit/solvency/contracts/package-lock.json new file mode 100644 index 0000000..bb3bcd4 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/package-lock.json @@ -0,0 +1,6977 @@ +{ + "name": "hardhat-project", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hardhat-project", + "dependencies": { + "@openzeppelin/contracts": "^4.9.2", + "dotenv": "^16.3.1", + "ethers": "^5.6.9" + }, + "devDependencies": { + "@nomicfoundation/hardhat-network-helpers": "^1.0.8", + "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "hardhat": "^2.19.2", + "hardhat-gas-reporter": "^1.0.9", + "prettier": "^2.8.8", + "prettier-plugin-solidity": "^1.1.3", + "solidity-coverage": "^0.8.5" + } + }, + "node_modules/@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", + "dev": true + }, + "node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", + "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", + "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-ethash": "3.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", + "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.2", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", + "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", + "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", + "dev": true, + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", + "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", + "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", + "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", + "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", + "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", + "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz", + "integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.0", + "chai": "^4.2.0", + "ethers": "^5.0.0", + "hardhat": "^2.9.4" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz", + "integrity": "sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==", + "dev": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz", + "integrity": "sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg==", + "dev": true, + "peerDependencies": { + "@ethersproject/abi": "^5.4.7", + "@ethersproject/providers": "^5.4.7", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@typechain/ethers-v5": "^10.1.0", + "@typechain/hardhat": "^6.1.2", + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "@types/node": ">=12.0.0", + "chai": "^4.2.0", + "ethers": "^5.4.7", + "hardhat": "^2.11.0", + "hardhat-gas-reporter": "^1.0.8", + "solidity-coverage": "^0.8.1", + "ts-node": ">=8.0.0", + "typechain": "^8.1.0", + "typescript": ">=4.5.0" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-ethers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz", + "integrity": "sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==", + "dev": true, + "peer": true, + "peerDependencies": { + "ethers": "^5.0.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@nomiclabs/hardhat-etherscan": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz", + "integrity": "sha512-v5F6IzQhrsjHh6kQz4uNrym49brK9K5bYCq2zQZ729RYRaifI9hHbtmK+KkIVevfhut7huQFEQ77JLRMAzWYjQ==", + "deprecated": "The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.11", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + }, + "peerDependencies": { + "hardhat": "^2.0.4" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.5.tgz", + "integrity": "sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==" + }, + "node_modules/@scure/base": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "peer": true + }, + "node_modules/@typechain/ethers-v5": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz", + "integrity": "sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.0.0", + "@ethersproject/providers": "^5.0.0", + "ethers": "^5.1.3", + "typechain": "^8.1.1", + "typescript": ">=4.3.0" + } + }, + "node_modules/@typechain/hardhat": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-6.1.6.tgz", + "integrity": "sha512-BiVnegSs+ZHVymyidtK472syodx1sXYlYJJixZfRstHVGYTi8V1O7QG4nsjyb0PC/LORcq7sfBUcHto1y6UgJA==", + "dev": true, + "peer": true, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.4.7", + "@ethersproject/providers": "^5.4.7", + "@typechain/ethers-v5": "^10.2.1", + "ethers": "^5.4.7", + "hardhat": "^2.9.9", + "typechain": "^8.1.1" + } + }, + "node_modules/@typechain/hardhat/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typechain/hardhat/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@typechain/hardhat/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "node_modules/@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "peer": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/bigint-crypto-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "peer": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "peer": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "peer": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "peer": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/classic-level": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "peer": true + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "peer": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hardhat": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.19.2.tgz", + "integrity": "sha512-CRU3+0Cc8Qh9UpxKd8cLADDPes7ZDtKj4dTK+ERtLBomEzhRPLWklJn4VKOwjre9/k8GNd/e9DYxpfuzcxbXPQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@nomicfoundation/ethereumjs-vm": "7.0.2", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", + "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "peer": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "peer": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "peer": true + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-gyp-build": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "peer": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.2.0.tgz", + "integrity": "sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.16.2", + "semver": "^7.5.4", + "solidity-comments-extractor": "^0.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/solidity-coverage": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", + "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.16.0", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "peer": true + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, + "node_modules/then-request/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-command-line-args/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-command-line-args/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/ts-command-line-args/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-command-line-args/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "dev": true, + "peer": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "peer": true + }, + "node_modules/web3-utils": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.3.tgz", + "integrity": "sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ==", + "dev": true, + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "peer": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tools/polyexen/circuit/solvency/contracts/package.json b/tools/polyexen/circuit/solvency/contracts/package.json new file mode 100644 index 0000000..2d43f64 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/package.json @@ -0,0 +1,17 @@ +{ + "name": "hardhat-project", + "dependencies": { + "@openzeppelin/contracts": "^4.9.2", + "dotenv": "^16.3.1", + "ethers": "^5.6.9" + }, + "devDependencies": { + "@nomicfoundation/hardhat-network-helpers": "^1.0.8", + "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "hardhat": "^2.19.2", + "hardhat-gas-reporter": "^1.0.9", + "prettier": "^2.8.8", + "prettier-plugin-solidity": "^1.1.3", + "solidity-coverage": "^0.8.5" + } +} diff --git a/tools/polyexen/circuit/solvency/contracts/scripts/deploy.ts b/tools/polyexen/circuit/solvency/contracts/scripts/deploy.ts new file mode 100644 index 0000000..56bfacf --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/scripts/deploy.ts @@ -0,0 +1,84 @@ +import { ethers } from "hardhat"; +import hre from "hardhat"; + +type Deployment = { + address: string; +}; + +type Deployments = { + [network: number]: Deployment; +}; + +async function main() { + const inclusionVerifier = await ethers.deployContract( + "src/InclusionVerifier.sol:Verifier" + ); + await inclusionVerifier.deployed(); + + // The number of levels of the Merkle sum tree + const mstLevels = 4; + //The number of cryptocurrencies supported by the Merkle sum tree + const currenciesCount = 2; + // The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree + const balanceByteRange = 8; + const summa = await ethers.deployContract("Summa", [ + inclusionVerifier.address, + mstLevels, + currenciesCount, + balanceByteRange, + ]); + + await summa.deployed(); + + console.log(`Summa deployed to ${summa.address}`); + + let deploymentsJson: Deployments = {}; + const fs = require("fs"); + try { + const deploymentsRaw = fs.readFileSync( + "../backend/src/contracts/deployments.json", + "utf8" + ); + deploymentsJson = JSON.parse(deploymentsRaw); + // Removing the previous deployment from the JSON file + if (deploymentsJson[hre.network.config.chainId ?? 0]) + delete deploymentsJson[hre.network.config.chainId ?? 0]; + } catch (error) { + console.log("No previous deployments found"); + } + // Adding the new deployment to the previous deployments, indexed by network ID + const newDeployment = { + // Getting the contract address + address: summa.address, + }; + const deployments = { + ...deploymentsJson, + [hre.network.config.chainId ?? 0]: newDeployment, + }; + const deploymentsStringified = JSON.stringify(deployments); + //Save the contract address to a JSON file in backend src directory + fs.writeFileSync( + "../backend/src/contracts/deployments.json", + deploymentsStringified + ); + + //Copy the ABIs from `artifacts/src/*` to `backend/src/contracts/*` + copyAbi(fs, "Summa", "Summa"); + copyAbi(fs, "InclusionVerifier", "Verifier"); +} + +// We recommend this pattern to be able to use async/await everywhere +// and properly handle errors. +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); + +function copyAbi(fs: any, filename: string, contractName: string) { + const abi = require(`../artifacts/src/${filename}.sol/${contractName}.json`); + const abiStringified = JSON.stringify(abi); + fs.writeFileSync( + `../backend/src/contracts/abi/${filename}.json`, + abiStringified + ); +} diff --git a/tools/polyexen/circuit/solvency/contracts/src/InclusionVerifier.sol b/tools/polyexen/circuit/solvency/contracts/src/InclusionVerifier.sol new file mode 100644 index 0000000..7016ec8 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/src/InclusionVerifier.sol @@ -0,0 +1,1412 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract Verifier { + uint256 internal constant PROOF_LEN_CPTR = 0x44; + uint256 internal constant PROOF_CPTR = 0x64; + uint256 internal constant NUM_INSTANCE_CPTR = 0x08c4; + uint256 internal constant INSTANCE_CPTR = 0x08e4; + + uint256 internal constant FIRST_QUOTIENT_X_CPTR = 0x02a4; + uint256 internal constant LAST_QUOTIENT_X_CPTR = 0x03a4; + + uint256 internal constant VK_MPTR = 0x06c0; + uint256 internal constant VK_DIGEST_MPTR = 0x06c0; + uint256 internal constant K_MPTR = 0x06e0; + uint256 internal constant N_INV_MPTR = 0x0700; + uint256 internal constant OMEGA_MPTR = 0x0720; + uint256 internal constant OMEGA_INV_MPTR = 0x0740; + uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x0760; + uint256 internal constant NUM_INSTANCES_MPTR = 0x0780; + uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x07a0; + uint256 internal constant ACC_OFFSET_MPTR = 0x07c0; + uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x07e0; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x0800; + uint256 internal constant G1_X_MPTR = 0x0820; + uint256 internal constant G1_Y_MPTR = 0x0840; + uint256 internal constant G2_X_1_MPTR = 0x0860; + uint256 internal constant G2_X_2_MPTR = 0x0880; + uint256 internal constant G2_Y_1_MPTR = 0x08a0; + uint256 internal constant G2_Y_2_MPTR = 0x08c0; + uint256 internal constant NEG_S_G2_X_1_MPTR = 0x08e0; + uint256 internal constant NEG_S_G2_X_2_MPTR = 0x0900; + uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x0920; + uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x0940; + + uint256 internal constant CHALLENGE_MPTR = 0x0da0; + + uint256 internal constant THETA_MPTR = 0x0da0; + uint256 internal constant BETA_MPTR = 0x0dc0; + uint256 internal constant GAMMA_MPTR = 0x0de0; + uint256 internal constant Y_MPTR = 0x0e00; + uint256 internal constant X_MPTR = 0x0e20; + uint256 internal constant ZETA_MPTR = 0x0e40; + uint256 internal constant NU_MPTR = 0x0e60; + uint256 internal constant MU_MPTR = 0x0e80; + + uint256 internal constant ACC_LHS_X_MPTR = 0x0ea0; + uint256 internal constant ACC_LHS_Y_MPTR = 0x0ec0; + uint256 internal constant ACC_RHS_X_MPTR = 0x0ee0; + uint256 internal constant ACC_RHS_Y_MPTR = 0x0f00; + uint256 internal constant X_N_MPTR = 0x0f20; + uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x0f40; + uint256 internal constant L_LAST_MPTR = 0x0f60; + uint256 internal constant L_BLIND_MPTR = 0x0f80; + uint256 internal constant L_0_MPTR = 0x0fa0; + uint256 internal constant INSTANCE_EVAL_MPTR = 0x0fc0; + uint256 internal constant QUOTIENT_EVAL_MPTR = 0x0fe0; + uint256 internal constant QUOTIENT_X_MPTR = 0x1000; + uint256 internal constant QUOTIENT_Y_MPTR = 0x1020; + uint256 internal constant R_EVAL_MPTR = 0x1040; + uint256 internal constant PAIRING_LHS_X_MPTR = 0x1060; + uint256 internal constant PAIRING_LHS_Y_MPTR = 0x1080; + uint256 internal constant PAIRING_RHS_X_MPTR = 0x10a0; + uint256 internal constant PAIRING_RHS_Y_MPTR = 0x10c0; + + function verifyProof( + bytes calldata proof, + uint256[] calldata instances + ) public view returns (bool) { + assembly { + // Read EC point (x, y) at (proof_cptr, proof_cptr + 0x20), + // and check if the point is on affine plane, + // and store them in (hash_mptr, hash_mptr + 0x20). + // Return updated (success, proof_cptr, hash_mptr). + function read_ec_point(success, proof_cptr, hash_mptr, q) -> ret0, ret1, ret2 { + let x := calldataload(proof_cptr) + let y := calldataload(add(proof_cptr, 0x20)) + ret0 := and(success, lt(x, q)) + ret0 := and(ret0, lt(y, q)) + ret0 := and(ret0, eq(mulmod(y, y, q), addmod(mulmod(x, mulmod(x, x, q), q), 3, q))) + mstore(hash_mptr, x) + mstore(add(hash_mptr, 0x20), y) + ret1 := add(proof_cptr, 0x40) + ret2 := add(hash_mptr, 0x40) + } + + // Squeeze challenge by keccak256(memory[0..hash_mptr]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr, hash_mptr). + function squeeze_challenge(challenge_mptr, hash_mptr, r) -> ret0, ret1 { + let hash := keccak256(0x00, hash_mptr) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret0 := add(challenge_mptr, 0x20) + ret1 := 0x20 + } + + // Squeeze challenge without absorbing new input from calldata, + // by putting an extra 0x01 in memory[0x20] and squeeze by keccak256(memory[0..21]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr). + function squeeze_challenge_cont(challenge_mptr, r) -> ret { + mstore8(0x20, 0x01) + let hash := keccak256(0x00, 0x21) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret := add(challenge_mptr, 0x20) + } + + // Batch invert values in memory[mptr_start..mptr_end] in place. + // Return updated (success). + function batch_invert(success, mptr_start, mptr_end, r) -> ret { + let gp_mptr := mptr_end + let gp := mload(mptr_start) + let mptr := add(mptr_start, 0x20) + for + {} + lt(mptr, sub(mptr_end, 0x20)) + {} + { + gp := mulmod(gp, mload(mptr), r) + mstore(gp_mptr, gp) + mptr := add(mptr, 0x20) + gp_mptr := add(gp_mptr, 0x20) + } + gp := mulmod(gp, mload(mptr), r) + + mstore(gp_mptr, 0x20) + mstore(add(gp_mptr, 0x20), 0x20) + mstore(add(gp_mptr, 0x40), 0x20) + mstore(add(gp_mptr, 0x60), gp) + mstore(add(gp_mptr, 0x80), sub(r, 2)) + mstore(add(gp_mptr, 0xa0), r) + ret := and(success, staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20)) + let all_inv := mload(gp_mptr) + + let first_mptr := mptr_start + let second_mptr := add(first_mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + for + {} + lt(second_mptr, mptr) + {} + { + let inv := mulmod(all_inv, mload(gp_mptr), r) + all_inv := mulmod(all_inv, mload(mptr), r) + mstore(mptr, inv) + mptr := sub(mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + } + let inv_first := mulmod(all_inv, mload(second_mptr), r) + let inv_second := mulmod(all_inv, mload(first_mptr), r) + mstore(first_mptr, inv_first) + mstore(second_mptr, inv_second) + } + + // Add (x, y) into point at (0x00, 0x20). + // Return updated (success). + function ec_add_acc(success, x, y) -> ret { + mstore(0x40, x) + mstore(0x60, y) + ret := and(success, staticcall(gas(), 0x06, 0x00, 0x80, 0x00, 0x40)) + } + + // Scale point at (0x00, 0x20) by scalar. + function ec_mul_acc(success, scalar) -> ret { + mstore(0x40, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40)) + } + + // Add (x, y) into point at (0x80, 0xa0). + // Return updated (success). + function ec_add_tmp(success, x, y) -> ret { + mstore(0xc0, x) + mstore(0xe0, y) + ret := and(success, staticcall(gas(), 0x06, 0x80, 0x80, 0x80, 0x40)) + } + + // Scale point at (0x80, 0xa0) by scalar. + // Return updated (success). + function ec_mul_tmp(success, scalar) -> ret { + mstore(0xc0, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x80, 0x60, 0x80, 0x40)) + } + + // Perform pairing check. + // Return updated (success). + function ec_pairing(success, lhs_x, lhs_y, rhs_x, rhs_y) -> ret { + mstore(0x00, lhs_x) + mstore(0x20, lhs_y) + mstore(0x40, mload(G2_X_1_MPTR)) + mstore(0x60, mload(G2_X_2_MPTR)) + mstore(0x80, mload(G2_Y_1_MPTR)) + mstore(0xa0, mload(G2_Y_2_MPTR)) + mstore(0xc0, rhs_x) + mstore(0xe0, rhs_y) + mstore(0x100, mload(NEG_S_G2_X_1_MPTR)) + mstore(0x120, mload(NEG_S_G2_X_2_MPTR)) + mstore(0x140, mload(NEG_S_G2_Y_1_MPTR)) + mstore(0x160, mload(NEG_S_G2_Y_2_MPTR)) + ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20)) + ret := and(ret, mload(0x00)) + } + + // Modulus + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // BN254 base field + let r := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // BN254 scalar field + + // Initialize success as true + let success := true + + { + // Load vk into memory + mstore(0x06c0, 0x10f28bc710a8bdd00dd701df2f5fc4f5ccdb260238eba6f819db692f79dc3dc9) // vk_digest + mstore(0x06e0, 0x000000000000000000000000000000000000000000000000000000000000000b) // k + mstore(0x0700, 0x305e41e912d579f5b3193badcab128321c8ee1cb70aa396331b979553d820001) // n_inv + mstore(0x0720, 0x14c60185e75885d674db4b3f7d4a5694fa6c01aa0f53557b060bc04a4172705f) // omega + mstore(0x0740, 0x2afd4e77273f1cb3434a4a667929058c156b21573c3f1efc882e708597d7161a) // omega_inv + mstore(0x0760, 0x22b55603586d5fc42c6c14c2fc27a028c207da8b2c71cb33d549fa4a2be5d302) // omega_inv_to_l + mstore(0x0780, 0x0000000000000000000000000000000000000000000000000000000000000004) // num_instances + mstore(0x07a0, 0x0000000000000000000000000000000000000000000000000000000000000000) // has_accumulator + mstore(0x07c0, 0x0000000000000000000000000000000000000000000000000000000000000000) // acc_offset + mstore(0x07e0, 0x0000000000000000000000000000000000000000000000000000000000000000) // num_acc_limbs + mstore(0x0800, 0x0000000000000000000000000000000000000000000000000000000000000000) // num_acc_limb_bits + mstore(0x0820, 0x0000000000000000000000000000000000000000000000000000000000000001) // g1_x + mstore(0x0840, 0x0000000000000000000000000000000000000000000000000000000000000002) // g1_y + mstore(0x0860, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // g2_x_1 + mstore(0x0880, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) // g2_x_2 + mstore(0x08a0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) // g2_y_1 + mstore(0x08c0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) // g2_y_2 + mstore(0x08e0, 0x26186a2d65ee4d2f9c9a5b91f86597d35f192cd120caf7e935d8443d1938e23d) // neg_s_g2_x_1 + mstore(0x0900, 0x30441fd1b5d3370482c42152a8899027716989a6996c2535bc9f7fee8aaef79e) // neg_s_g2_x_2 + mstore(0x0920, 0x16f363f103c80d7bbc8ad3c6867e0822bbc6000be91a4689755c7df40221c145) // neg_s_g2_y_1 + mstore(0x0940, 0x2b1cbb3e521edf5a622d82762a44a5e63f1e50b332d71154a4a7958d6011deff) // neg_s_g2_y_2 + mstore(0x0960, 0x010920a3471867216dc9dd6b478c16842fb5aca434fe6c9bf1622c4abd70381a) // fixed_comms[0].x + mstore(0x0980, 0x300e30930f1a05253b28b6b139f2c38025d99b7a54e641f1d6ff2797d113c118) // fixed_comms[0].y + mstore(0x09a0, 0x05e7899750f7abeae5d19c16666c47618fce810326b125d253dd41fb817dd65a) // fixed_comms[1].x + mstore(0x09c0, 0x1e0e399ce46f208ab3f43aad0222f4dd37b8327b9f7afffa9cf9ee214e2460dd) // fixed_comms[1].y + mstore(0x09e0, 0x22274e4efd4197dd6515994652d5beafcc7af94313d33e049cf5a1e464b52395) // fixed_comms[2].x + mstore(0x0a00, 0x0ebb470e19409fcd84c0358c04300dc38cba0240141ddeb899ad9cca90167a64) // fixed_comms[2].y + mstore(0x0a20, 0x162baf6245e2cec59bc93bc2302527d299cdb50e100f14895f170f316a2a2643) // fixed_comms[3].x + mstore(0x0a40, 0x172a6f183e2ddc0607d23fd3daf4b23110b81d8a9d0a4e8d3d07ba24a007e04b) // fixed_comms[3].y + mstore(0x0a60, 0x22e1cdbfffcfcf4f18cf4342edf1fb26c3b6e52ace3d5fadcf5cc2614333baa4) // fixed_comms[4].x + mstore(0x0a80, 0x0e28df72dcc69cc6442d72f693661997480a913ac353890efd63a873959727c0) // fixed_comms[4].y + mstore(0x0aa0, 0x01021a51384124c6844f2ba0e40e2545f26f280a79745c9164b0a56f1ee54d56) // fixed_comms[5].x + mstore(0x0ac0, 0x2533607ba6f153a0126a8450a3cf47946933c93eaf69c996236b45603179c914) // fixed_comms[5].y + mstore(0x0ae0, 0x1f59be81b3fd7d290930430d204c1a866937862306d75be70fedfe13e565ce0b) // fixed_comms[6].x + mstore(0x0b00, 0x05931c531cd08b4aa937245293af81c4532fc4c01387d5b539d29f6c4ae00031) // fixed_comms[6].y + mstore(0x0b20, 0x203b21a648fbfb96459640bbc5b41852dd1efc1209c89b635ba638dcb929da6b) // fixed_comms[7].x + mstore(0x0b40, 0x04e7002f06f2091a44afcd311e93c22f46dd9f3207b5bcc34f0ca7652098f097) // fixed_comms[7].y + mstore(0x0b60, 0x20ab7490b42f3f7b2b0bbe601a09d72ee93f924801d597f48cf2d443751d5f91) // fixed_comms[8].x + mstore(0x0b80, 0x2bca2f1762946a05fb1632550c6cb12c02d18d9bee5bdd4212ca7342888720fd) // fixed_comms[8].y + mstore(0x0ba0, 0x2aaba546cdd9969ef0aecc85b2aaa19b6e9639879962661415c8f0df426bac0c) // fixed_comms[9].x + mstore(0x0bc0, 0x12b15327bcfbe7d9e9de1bc648ba3bdf910087362179a0b403cf70bad1c093c8) // fixed_comms[9].y + mstore(0x0be0, 0x25909db723a8021ffe088c50525d6d260f9157be7a7c194b6f315386a46cdab8) // fixed_comms[10].x + mstore(0x0c00, 0x25cbeae8ec2a8a2f74844f5e3276ed94079907bed6d7b1b26ed695328fe7bcae) // fixed_comms[10].y + mstore(0x0c20, 0x26bffd26dd8f5f7679281f8d1a432690e07b15cbdf684fe456aa1277515e1730) // permutation_comms[0].x + mstore(0x0c40, 0x015a3f09c82a770a69d67583d7049d83d69b7b8e03d38484497215cdc5979556) // permutation_comms[0].y + mstore(0x0c60, 0x1ee4241e91ac391756b0b9893ac1e34ea95c6dd689e7dca12c62a6ce943960f1) // permutation_comms[1].x + mstore(0x0c80, 0x10ad75f199bf1fb9335b91c20db6cd8958dcb2fe11983bc77cdb4036e57e59ca) // permutation_comms[1].y + mstore(0x0ca0, 0x05eb5d19e589c11e0bb2200d66da829955545481885cfbc9099ec6a53e266ed2) // permutation_comms[2].x + mstore(0x0cc0, 0x25ac1d9849f9f448cecc7ead7d48670f66bbfe7df8e248bd818a954df6936c27) // permutation_comms[2].y + mstore(0x0ce0, 0x0743ea40f14084db2673217283aa053f986896ee7c181f52118442e99c452974) // permutation_comms[3].x + mstore(0x0d00, 0x0203e3493a2594ece57d22cc75dd081ac68271ec7c758153cfd2152bfb5c19e3) // permutation_comms[3].y + mstore(0x0d20, 0x1b95c5dc9bae0fb3f8208684042e57e0fcfbc3774af9ae0903ab9e9ddb4f89fd) // permutation_comms[4].x + mstore(0x0d40, 0x1e8564e01419713739871224ce15f4c4b51e6af161d6e07a178e6545879035bf) // permutation_comms[4].y + mstore(0x0d60, 0x1cefc889639cf98f94d831ea41c356929f9317778dda05ba0c5885401638db67) // permutation_comms[5].x + mstore(0x0d80, 0x1e0466deb22a86d9122bc7180b7d293e47288244abf1450a5cd63a3289a457ca) // permutation_comms[5].y + + // Check valid length of proof + success := and(success, eq(0x0860, calldataload(PROOF_LEN_CPTR))) + + // Check valid length of instances + let num_instances := mload(NUM_INSTANCES_MPTR) + success := and(success, eq(num_instances, calldataload(NUM_INSTANCE_CPTR))) + + // Absorb vk diegst + mstore(0x00, mload(VK_DIGEST_MPTR)) + + // Read instances and witness commitments and generate challenges + let hash_mptr := 0x20 + let instance_cptr := INSTANCE_CPTR + for + { let instance_cptr_end := add(instance_cptr, mul(0x20, num_instances)) } + lt(instance_cptr, instance_cptr_end) + {} + { + let instance := calldataload(instance_cptr) + success := and(success, lt(instance, r)) + mstore(hash_mptr, instance) + instance_cptr := add(instance_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + let proof_cptr := PROOF_CPTR + let challenge_mptr := CHALLENGE_MPTR + + // Phase 1 + for + { let proof_cptr_end := add(proof_cptr, 0xc0) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + + // Phase 2 + for + { let proof_cptr_end := add(proof_cptr, 0x80) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) + + // Phase 3 + for + { let proof_cptr_end := add(proof_cptr, 0x0100) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + + // Phase 4 + for + { let proof_cptr_end := add(proof_cptr, 0x0140) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + + // Read evaluations + for + { let proof_cptr_end := add(proof_cptr, 0x0460) } + lt(proof_cptr, proof_cptr_end) + {} + { + let eval := calldataload(proof_cptr) + success := and(success, lt(eval, r)) + mstore(hash_mptr, eval) + proof_cptr := add(proof_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + // Read batch opening proof and generate challenges + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // zeta + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) // nu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W' + + // Read accumulator from instances + if mload(HAS_ACCUMULATOR_MPTR) { + let num_limbs := mload(NUM_ACC_LIMBS_MPTR) + let num_limb_bits := mload(NUM_ACC_LIMB_BITS_MPTR) + + let cptr := add(INSTANCE_CPTR, mul(mload(ACC_OFFSET_MPTR), 0x20)) + let lhs_y_off := mul(num_limbs, 0x20) + let rhs_x_off := mul(lhs_y_off, 2) + let rhs_y_off := mul(lhs_y_off, 3) + let lhs_x := calldataload(cptr) + let lhs_y := calldataload(add(cptr, lhs_y_off)) + let rhs_x := calldataload(add(cptr, rhs_x_off)) + let rhs_y := calldataload(add(cptr, rhs_y_off)) + for + { + let cptr_end := add(cptr, mul(0x20, num_limbs)) + let shift := num_limb_bits + } + lt(cptr, cptr_end) + {} + { + cptr := add(cptr, 0x20) + lhs_x := add(lhs_x, shl(shift, calldataload(cptr))) + lhs_y := add(lhs_y, shl(shift, calldataload(add(cptr, lhs_y_off)))) + rhs_x := add(rhs_x, shl(shift, calldataload(add(cptr, rhs_x_off)))) + rhs_y := add(rhs_y, shl(shift, calldataload(add(cptr, rhs_y_off)))) + shift := add(shift, num_limb_bits) + } + + success := and(success, eq(mulmod(lhs_y, lhs_y, q), addmod(mulmod(lhs_x, mulmod(lhs_x, lhs_x, q), q), 3, q))) + success := and(success, eq(mulmod(rhs_y, rhs_y, q), addmod(mulmod(rhs_x, mulmod(rhs_x, rhs_x, q), q), 3, q))) + + mstore(ACC_LHS_X_MPTR, lhs_x) + mstore(ACC_LHS_Y_MPTR, lhs_y) + mstore(ACC_RHS_X_MPTR, rhs_x) + mstore(ACC_RHS_Y_MPTR, rhs_y) + } + + pop(q) + } + + // Revert earlier if anything from calldata is invalid + if iszero(success) { + revert(0, 0) + } + + // Compute lagrange evaluations and instance evaluation + { + let k := mload(K_MPTR) + let x := mload(X_MPTR) + let x_n := x + for + { let idx := 0 } + lt(idx, k) + { idx := add(idx, 1) } + { + x_n := mulmod(x_n, x_n, r) + } + + let omega := mload(OMEGA_MPTR) + + let mptr := X_N_MPTR + let mptr_end := add(mptr, mul(0x20, add(mload(NUM_INSTANCES_MPTR), 6))) + if iszero(mload(NUM_INSTANCES_MPTR)) { + mptr_end := add(mptr_end, 0x20) + } + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, addmod(x, sub(r, pow_of_omega), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) + success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), r) + + mptr := X_N_MPTR + let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + + let l_blind := mload(add(X_N_MPTR, 0x20)) + let l_i_cptr := add(X_N_MPTR, 0x40) + for + { let l_i_cptr_end := add(X_N_MPTR, 0xc0) } + lt(l_i_cptr, l_i_cptr_end) + { l_i_cptr := add(l_i_cptr, 0x20) } + { + l_blind := addmod(l_blind, mload(l_i_cptr), r) + } + + let instance_eval := 0 + for + { + let instance_cptr := INSTANCE_CPTR + let instance_cptr_end := add(instance_cptr, mul(0x20, mload(NUM_INSTANCES_MPTR))) + } + lt(instance_cptr, instance_cptr_end) + { + instance_cptr := add(instance_cptr, 0x20) + l_i_cptr := add(l_i_cptr, 0x20) + } + { + instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r) + } + + let x_n_minus_1_inv := mload(mptr_end) + let l_last := mload(X_N_MPTR) + let l_0 := mload(add(X_N_MPTR, 0xc0)) + + mstore(X_N_MPTR, x_n) + mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) + mstore(L_LAST_MPTR, l_last) + mstore(L_BLIND_MPTR, l_blind) + mstore(L_0_MPTR, l_0) + mstore(INSTANCE_EVAL_MPTR, instance_eval) + } + + // Compute quotient evavluation + { + let quotient_eval_numer + let delta := 4131629893567559867359510883348571134090853742863529169391034518566172092834 + let y := mload(Y_MPTR) + { + let f_7 := calldataload(0x05a4) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let var4 := mulmod(var3, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var5 := addmod(a_1, f_1, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var6, r) + let var8 := mulmod(var7, var5, r) + let var9 := mulmod(var8, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8, r) + let var10 := addmod(var4, var9, r) + let a_0_next_1 := calldataload(0x0424) + let var11 := sub(r, a_0_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(f_7, var12, r) + quotient_eval_numer := var13 + } + { + let f_7 := calldataload(0x05a4) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let var4 := mulmod(var3, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var5 := addmod(a_1, f_1, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var6, r) + let var8 := mulmod(var7, var5, r) + let var9 := mulmod(var8, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8, r) + let var10 := addmod(var4, var9, r) + let a_1_next_1 := calldataload(0x0444) + let var11 := sub(r, a_1_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(f_7, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_8 := calldataload(0x05c4) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let a_2 := calldataload(0x0464) + let var4 := sub(r, a_2) + let var5 := addmod(var3, var4, r) + let var6 := mulmod(f_8, var5, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var6, r) + } + { + let f_8 := calldataload(0x05c4) + let a_2 := calldataload(0x0464) + let var0 := mulmod(a_2, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var1 := addmod(a_1, f_1, r) + let var2 := mulmod(var1, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8, r) + let var3 := addmod(var0, var2, r) + let f_2 := calldataload(0x04c4) + let var4 := addmod(var3, f_2, r) + let var5 := mulmod(var4, var4, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var4, r) + let a_0_next_1 := calldataload(0x0424) + let var8 := mulmod(a_0_next_1, 0x13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66, r) + let a_1_next_1 := calldataload(0x0444) + let var9 := mulmod(a_1_next_1, 0x1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe, r) + let var10 := addmod(var8, var9, r) + let var11 := sub(r, var10) + let var12 := addmod(var7, var11, r) + let var13 := mulmod(f_8, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_8 := calldataload(0x05c4) + let a_2 := calldataload(0x0464) + let var0 := mulmod(a_2, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var1 := addmod(a_1, f_1, r) + let var2 := mulmod(var1, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8, r) + let var3 := addmod(var0, var2, r) + let f_3 := calldataload(0x04e4) + let var4 := addmod(var3, f_3, r) + let a_0_next_1 := calldataload(0x0424) + let var5 := mulmod(a_0_next_1, 0x0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02, r) + let a_1_next_1 := calldataload(0x0444) + let var6 := mulmod(a_1_next_1, 0x16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be, r) + let var7 := addmod(var5, var6, r) + let var8 := sub(r, var7) + let var9 := addmod(var4, var8, r) + let var10 := mulmod(f_8, var9, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var10, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x2 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_0_prev_1 := calldataload(0x04a4) + let a_0 := calldataload(0x03e4) + let var10 := addmod(a_0_prev_1, a_0, r) + let a_0_next_1 := calldataload(0x0424) + let var11 := sub(r, a_0_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(var9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x2 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_1_prev_1 := calldataload(0x0484) + let a_1_next_1 := calldataload(0x0444) + let var10 := sub(r, a_1_next_1) + let var11 := addmod(a_1_prev_1, var10, r) + let var12 := mulmod(var9, var11, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var12, r) + } + { + let f_9 := calldataload(0x05e4) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let var4 := mulmod(var3, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var5 := addmod(a_1, f_1, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var6, r) + let var8 := mulmod(var7, var5, r) + let var9 := mulmod(var8, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8, r) + let var10 := addmod(var4, var9, r) + let a_0_next_1 := calldataload(0x0424) + let var11 := sub(r, a_0_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(f_9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_9 := calldataload(0x05e4) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let var4 := mulmod(var3, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var5 := addmod(a_1, f_1, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var6, r) + let var8 := mulmod(var7, var5, r) + let var9 := mulmod(var8, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8, r) + let var10 := addmod(var4, var9, r) + let a_1_next_1 := calldataload(0x0444) + let var11 := sub(r, a_1_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(f_9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_10 := calldataload(0x0604) + let a_0 := calldataload(0x03e4) + let f_0 := calldataload(0x0504) + let var0 := addmod(a_0, f_0, r) + let var1 := mulmod(var0, var0, r) + let var2 := mulmod(var1, var1, r) + let var3 := mulmod(var2, var0, r) + let a_2 := calldataload(0x0464) + let var4 := sub(r, a_2) + let var5 := addmod(var3, var4, r) + let var6 := mulmod(f_10, var5, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var6, r) + } + { + let f_10 := calldataload(0x0604) + let a_2 := calldataload(0x0464) + let var0 := mulmod(a_2, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var1 := addmod(a_1, f_1, r) + let var2 := mulmod(var1, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8, r) + let var3 := addmod(var0, var2, r) + let f_2 := calldataload(0x04c4) + let var4 := addmod(var3, f_2, r) + let var5 := mulmod(var4, var4, r) + let var6 := mulmod(var5, var5, r) + let var7 := mulmod(var6, var4, r) + let a_0_next_1 := calldataload(0x0424) + let var8 := mulmod(a_0_next_1, 0x13abec390ada7f4370819ab1c7846f210554569d9b29d1ea8dbebd0fa8c53e66, r) + let a_1_next_1 := calldataload(0x0444) + let var9 := mulmod(a_1_next_1, 0x1eb9e1dc19a33a624c9862a1d97d1510bd521ead5dfe0345aaf6185b1a1e60fe, r) + let var10 := addmod(var8, var9, r) + let var11 := sub(r, var10) + let var12 := addmod(var7, var11, r) + let var13 := mulmod(f_10, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_10 := calldataload(0x0604) + let a_2 := calldataload(0x0464) + let var0 := mulmod(a_2, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9, r) + let a_1 := calldataload(0x0404) + let f_1 := calldataload(0x0524) + let var1 := addmod(a_1, f_1, r) + let var2 := mulmod(var1, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8, r) + let var3 := addmod(var0, var2, r) + let f_3 := calldataload(0x04e4) + let var4 := addmod(var3, f_3, r) + let a_0_next_1 := calldataload(0x0424) + let var5 := mulmod(a_0_next_1, 0x0fc1c9394db89bb2601abc49fdad4f038ce5169030a2ad69763f7875036bcb02, r) + let a_1_next_1 := calldataload(0x0444) + let var6 := mulmod(a_1_next_1, 0x16a9e98c493a902b9502054edc03e7b22b7eac34345961bc8abced6bd147c8be, r) + let var7 := addmod(var5, var6, r) + let var8 := sub(r, var7) + let var9 := addmod(var4, var8, r) + let var10 := mulmod(f_10, var9, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var10, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x2 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x3 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_0_prev_1 := calldataload(0x04a4) + let a_0 := calldataload(0x03e4) + let var10 := addmod(a_0_prev_1, a_0, r) + let a_0_next_1 := calldataload(0x0424) + let var11 := sub(r, a_0_next_1) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(var9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x2 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x3 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_1_prev_1 := calldataload(0x0484) + let a_1_next_1 := calldataload(0x0444) + let var10 := sub(r, a_1_next_1) + let var11 := addmod(a_1_prev_1, var10, r) + let var12 := mulmod(var9, var11, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var12, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x2 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x3 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_2 := calldataload(0x0464) + let var10 := mulmod(var9, a_2, r) + let var11 := 0x1 + let var12 := sub(r, a_2) + let var13 := addmod(var11, var12, r) + let var14 := mulmod(var10, var13, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var14, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x2 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x3 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_1 := calldataload(0x0404) + let a_0 := calldataload(0x03e4) + let var10 := sub(r, a_0) + let var11 := addmod(a_1, var10, r) + let a_2 := calldataload(0x0464) + let var12 := mulmod(var11, a_2, r) + let var13 := addmod(var12, a_0, r) + let a_0_next_1 := calldataload(0x0424) + let var14 := sub(r, a_0_next_1) + let var15 := addmod(var13, var14, r) + let var16 := mulmod(var9, var15, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var16, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x2 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x3 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_0 := calldataload(0x03e4) + let a_1 := calldataload(0x0404) + let var10 := sub(r, a_1) + let var11 := addmod(a_0, var10, r) + let a_2 := calldataload(0x0464) + let var12 := mulmod(var11, a_2, r) + let var13 := addmod(var12, a_1, r) + let a_1_next_1 := calldataload(0x0444) + let var14 := sub(r, a_1_next_1) + let var15 := addmod(var13, var14, r) + let var16 := mulmod(var9, var15, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var16, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x3 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_0 := calldataload(0x03e4) + let a_1 := calldataload(0x0404) + let var10 := addmod(a_0, a_1, r) + let a_2 := calldataload(0x0464) + let var11 := sub(r, a_2) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(var9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let f_6 := calldataload(0x0584) + let var0 := 0x1 + let var1 := sub(r, f_6) + let var2 := addmod(var0, var1, r) + let var3 := mulmod(f_6, var2, r) + let var4 := 0x3 + let var5 := addmod(var4, var1, r) + let var6 := mulmod(var3, var5, r) + let var7 := 0x4 + let var8 := addmod(var7, var1, r) + let var9 := mulmod(var6, var8, r) + let a_0 := calldataload(0x03e4) + let a_1 := calldataload(0x0404) + let var10 := addmod(a_0, a_1, r) + let a_2 := calldataload(0x0464) + let var11 := sub(r, a_2) + let var12 := addmod(var10, var11, r) + let var13 := mulmod(var9, var12, r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), var13, r) + } + { + let l_0 := mload(L_0_MPTR) + let eval := addmod(l_0, sub(r, mulmod(l_0, calldataload(0x0704), r)), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let perm_z_last := calldataload(0x0764) + let eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(perm_z_last, perm_z_last, r), sub(r, perm_z_last), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let eval := mulmod(mload(L_0_MPTR), addmod(calldataload(0x0764), sub(r, calldataload(0x0744)), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let gamma := mload(GAMMA_MPTR) + let beta := mload(BETA_MPTR) + let lhs := calldataload(0x0724) + let rhs := calldataload(0x0704) + lhs := mulmod(lhs, addmod(addmod(calldataload(0x04c4), mulmod(beta, calldataload(0x0644), r), r), gamma, r), r) + lhs := mulmod(lhs, addmod(addmod(calldataload(0x03e4), mulmod(beta, calldataload(0x0664), r), r), gamma, r), r) + lhs := mulmod(lhs, addmod(addmod(calldataload(0x0404), mulmod(beta, calldataload(0x0684), r), r), gamma, r), r) + lhs := mulmod(lhs, addmod(addmod(calldataload(0x04e4), mulmod(beta, calldataload(0x06a4), r), r), gamma, r), r) + mstore(0x00, mulmod(beta, mload(X_MPTR), r)) + rhs := mulmod(rhs, addmod(addmod(calldataload(0x04c4), mload(0x00), r), gamma, r), r) + mstore(0x00, mulmod(mload(0x00), delta, r)) + rhs := mulmod(rhs, addmod(addmod(calldataload(0x03e4), mload(0x00), r), gamma, r), r) + mstore(0x00, mulmod(mload(0x00), delta, r)) + rhs := mulmod(rhs, addmod(addmod(calldataload(0x0404), mload(0x00), r), gamma, r), r) + mstore(0x00, mulmod(mload(0x00), delta, r)) + rhs := mulmod(rhs, addmod(addmod(calldataload(0x04e4), mload(0x00), r), gamma, r), r) + mstore(0x00, mulmod(mload(0x00), delta, r)) + let left_sub_right := addmod(lhs, sub(r, rhs), r) + let eval := addmod(left_sub_right, sub(r, mulmod(left_sub_right, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r), r)), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let gamma := mload(GAMMA_MPTR) + let beta := mload(BETA_MPTR) + let lhs := calldataload(0x0784) + let rhs := calldataload(0x0764) + lhs := mulmod(lhs, addmod(addmod(calldataload(0x0464), mulmod(beta, calldataload(0x06c4), r), r), gamma, r), r) + lhs := mulmod(lhs, addmod(addmod(mload(INSTANCE_EVAL_MPTR), mulmod(beta, calldataload(0x06e4), r), r), gamma, r), r) + rhs := mulmod(rhs, addmod(addmod(calldataload(0x0464), mload(0x00), r), gamma, r), r) + mstore(0x00, mulmod(mload(0x00), delta, r)) + rhs := mulmod(rhs, addmod(addmod(mload(INSTANCE_EVAL_MPTR), mload(0x00), r), gamma, r), r) + let left_sub_right := addmod(lhs, sub(r, rhs), r) + let eval := addmod(left_sub_right, sub(r, mulmod(left_sub_right, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r), r)), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let l_0 := mload(L_0_MPTR) + let eval := addmod(l_0, mulmod(l_0, sub(r, calldataload(0x07a4)), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let l_last := mload(L_LAST_MPTR) + let eval := mulmod(l_last, addmod(mulmod(calldataload(0x07a4), calldataload(0x07a4), r), sub(r, calldataload(0x07a4)), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let theta := mload(THETA_MPTR) + let input + { + let f_5 := calldataload(0x0564) + let a_0 := calldataload(0x03e4) + let a_0_next_1 := calldataload(0x0424) + let var0 := 0x100 + let var1 := mulmod(a_0_next_1, var0, r) + let var2 := sub(r, var1) + let var3 := addmod(a_0, var2, r) + let var4 := mulmod(f_5, var3, r) + input := var4 + } + let table + { + let f_4 := calldataload(0x0544) + table := f_4 + } + let beta := mload(BETA_MPTR) + let gamma := mload(GAMMA_MPTR) + let lhs := mulmod(calldataload(0x07c4), mulmod(addmod(calldataload(0x07e4), beta, r), addmod(calldataload(0x0824), gamma, r), r), r) + let rhs := mulmod(calldataload(0x07a4), mulmod(addmod(input, beta, r), addmod(table, gamma, r), r), r) + let eval := mulmod(addmod(1, sub(r, addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)), r), addmod(lhs, sub(r, rhs), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let eval := mulmod(mload(L_0_MPTR), addmod(calldataload(0x07e4), sub(r, calldataload(0x0824)), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + { + let eval := mulmod(addmod(1, sub(r, addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)), r), mulmod(addmod(calldataload(0x07e4), sub(r, calldataload(0x0824)), r), addmod(calldataload(0x07e4), sub(r, calldataload(0x0804)), r), r), r) + quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r) + } + + pop(y) + pop(delta) + + let quotient_eval := mulmod(quotient_eval_numer, mload(X_N_MINUS_1_INV_MPTR), r) + mstore(QUOTIENT_EVAL_MPTR, quotient_eval) + } + + // Compute quotient commitment + { + mstore(0x00, calldataload(LAST_QUOTIENT_X_CPTR)) + mstore(0x20, calldataload(add(LAST_QUOTIENT_X_CPTR, 0x20))) + let x_n := mload(X_N_MPTR) + for + { + let cptr := sub(LAST_QUOTIENT_X_CPTR, 0x40) + let cptr_end := sub(FIRST_QUOTIENT_X_CPTR, 0x40) + } + lt(cptr_end, cptr) + {} + { + success := ec_mul_acc(success, x_n) + success := ec_add_acc(success, calldataload(cptr), calldataload(add(cptr, 0x20))) + cptr := sub(cptr, 0x40) + } + mstore(QUOTIENT_X_MPTR, mload(0x00)) + mstore(QUOTIENT_Y_MPTR, mload(0x20)) + } + + // Compute pairing lhs and rhs + { + { + let x := mload(X_MPTR) + let omega := mload(OMEGA_MPTR) + let omega_inv := mload(OMEGA_INV_MPTR) + let x_pow_of_omega := mulmod(x, omega, r) + mstore(0x0420, x_pow_of_omega) + mstore(0x0400, x) + x_pow_of_omega := mulmod(x, omega_inv, r) + mstore(0x03e0, x_pow_of_omega) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r) + mstore(0x03c0, x_pow_of_omega) + } + { + let mu := mload(MU_MPTR) + for + { + let mptr := 0x0440 + let mptr_end := 0x04c0 + let point_mptr := 0x03c0 + } + lt(mptr, mptr_end) + { + mptr := add(mptr, 0x20) + point_mptr := add(point_mptr, 0x20) + } + { + mstore(mptr, addmod(mu, sub(r, mload(point_mptr)), r)) + } + let s + s := mload(0x0460) + s := mulmod(s, mload(0x0480), r) + s := mulmod(s, mload(0x04a0), r) + mstore(0x04c0, s) + let diff + diff := mload(0x0440) + mstore(0x04e0, diff) + mstore(0x00, diff) + diff := mload(0x0440) + diff := mulmod(diff, mload(0x0460), r) + diff := mulmod(diff, mload(0x04a0), r) + mstore(0x0500, diff) + diff := mload(0x0460) + mstore(0x0520, diff) + diff := mload(0x0440) + diff := mulmod(diff, mload(0x0460), r) + mstore(0x0540, diff) + diff := mload(0x0440) + diff := mulmod(diff, mload(0x04a0), r) + mstore(0x0560, diff) + } + { + let point_1 := mload(0x03e0) + let point_2 := mload(0x0400) + let point_3 := mload(0x0420) + let coeff + coeff := addmod(point_1, sub(r, point_2), r) + coeff := mulmod(coeff, addmod(point_1, sub(r, point_3), r), r) + coeff := mulmod(coeff, mload(0x0460), r) + mstore(0x20, coeff) + coeff := addmod(point_2, sub(r, point_1), r) + coeff := mulmod(coeff, addmod(point_2, sub(r, point_3), r), r) + coeff := mulmod(coeff, mload(0x0480), r) + mstore(0x40, coeff) + coeff := addmod(point_3, sub(r, point_1), r) + coeff := mulmod(coeff, addmod(point_3, sub(r, point_2), r), r) + coeff := mulmod(coeff, mload(0x04a0), r) + mstore(0x60, coeff) + } + { + let point_2 := mload(0x0400) + let coeff + coeff := 1 + coeff := mulmod(coeff, mload(0x0480), r) + mstore(0x80, coeff) + } + { + let point_0 := mload(0x03c0) + let point_2 := mload(0x0400) + let point_3 := mload(0x0420) + let coeff + coeff := addmod(point_0, sub(r, point_2), r) + coeff := mulmod(coeff, addmod(point_0, sub(r, point_3), r), r) + coeff := mulmod(coeff, mload(0x0440), r) + mstore(0xa0, coeff) + coeff := addmod(point_2, sub(r, point_0), r) + coeff := mulmod(coeff, addmod(point_2, sub(r, point_3), r), r) + coeff := mulmod(coeff, mload(0x0480), r) + mstore(0xc0, coeff) + coeff := addmod(point_3, sub(r, point_0), r) + coeff := mulmod(coeff, addmod(point_3, sub(r, point_2), r), r) + coeff := mulmod(coeff, mload(0x04a0), r) + mstore(0xe0, coeff) + } + { + let point_2 := mload(0x0400) + let point_3 := mload(0x0420) + let coeff + coeff := addmod(point_2, sub(r, point_3), r) + coeff := mulmod(coeff, mload(0x0480), r) + mstore(0x0100, coeff) + coeff := addmod(point_3, sub(r, point_2), r) + coeff := mulmod(coeff, mload(0x04a0), r) + mstore(0x0120, coeff) + } + { + let point_1 := mload(0x03e0) + let point_2 := mload(0x0400) + let coeff + coeff := addmod(point_1, sub(r, point_2), r) + coeff := mulmod(coeff, mload(0x0460), r) + mstore(0x0140, coeff) + coeff := addmod(point_2, sub(r, point_1), r) + coeff := mulmod(coeff, mload(0x0480), r) + mstore(0x0160, coeff) + } + { + success := batch_invert(success, 0, 0x0180, r) + let diff_0_inv := mload(0x00) + mstore(0x04e0, diff_0_inv) + for + { + let mptr := 0x0500 + let mptr_end := 0x0580 + } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, mulmod(mload(mptr), diff_0_inv, r)) + } + } + { + let zeta := mload(ZETA_MPTR) + let r_eval := 0 + r_eval := addmod(r_eval, mulmod(mload(0x20), calldataload(0x0484), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x40), calldataload(0x0404), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x60), calldataload(0x0444), r), r) + r_eval := mulmod(r_eval, zeta, r) + r_eval := addmod(r_eval, mulmod(mload(0x20), calldataload(0x04a4), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x40), calldataload(0x03e4), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x60), calldataload(0x0424), r), r) + mstore(0x0580, r_eval) + } + { + let coeff := mload(0x80) + let zeta := mload(ZETA_MPTR) + let r_eval := 0 + r_eval := addmod(r_eval, mulmod(coeff, calldataload(0x0624), r), r) + r_eval := mulmod(r_eval, zeta, r) + r_eval := addmod(r_eval, mulmod(coeff, mload(QUOTIENT_EVAL_MPTR), r), r) + for + { + let mptr := 0x06e4 + let mptr_end := 0x0624 + } + lt(mptr_end, mptr) + { mptr := sub(mptr, 0x20) } + { + r_eval := addmod(mulmod(r_eval, zeta, r), mulmod(coeff, calldataload(mptr), r), r) + } + for + { + let mptr := 0x0604 + let mptr_end := 0x04a4 + } + lt(mptr_end, mptr) + { mptr := sub(mptr, 0x20) } + { + r_eval := addmod(mulmod(r_eval, zeta, r), mulmod(coeff, calldataload(mptr), r), r) + } + r_eval := mulmod(r_eval, zeta, r) + r_eval := addmod(r_eval, mulmod(coeff, calldataload(0x0824), r), r) + r_eval := mulmod(r_eval, zeta, r) + r_eval := addmod(r_eval, mulmod(coeff, calldataload(0x0464), r), r) + r_eval := mulmod(r_eval, mload(0x0500), r) + mstore(0x05a0, r_eval) + } + { + let zeta := mload(ZETA_MPTR) + let r_eval := 0 + r_eval := addmod(r_eval, mulmod(mload(0xa0), calldataload(0x0744), r), r) + r_eval := addmod(r_eval, mulmod(mload(0xc0), calldataload(0x0704), r), r) + r_eval := addmod(r_eval, mulmod(mload(0xe0), calldataload(0x0724), r), r) + r_eval := mulmod(r_eval, mload(0x0520), r) + mstore(0x05c0, r_eval) + } + { + let zeta := mload(ZETA_MPTR) + let r_eval := 0 + r_eval := addmod(r_eval, mulmod(mload(0x0100), calldataload(0x07a4), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x0120), calldataload(0x07c4), r), r) + r_eval := mulmod(r_eval, zeta, r) + r_eval := addmod(r_eval, mulmod(mload(0x0100), calldataload(0x0764), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x0120), calldataload(0x0784), r), r) + r_eval := mulmod(r_eval, mload(0x0540), r) + mstore(0x05e0, r_eval) + } + { + let zeta := mload(ZETA_MPTR) + let r_eval := 0 + r_eval := addmod(r_eval, mulmod(mload(0x0140), calldataload(0x0804), r), r) + r_eval := addmod(r_eval, mulmod(mload(0x0160), calldataload(0x07e4), r), r) + r_eval := mulmod(r_eval, mload(0x0560), r) + mstore(0x0600, r_eval) + } + { + let sum := mload(0x20) + sum := addmod(sum, mload(0x40), r) + sum := addmod(sum, mload(0x60), r) + mstore(0x0620, sum) + } + { + let sum := mload(0x80) + mstore(0x0640, sum) + } + { + let sum := mload(0xa0) + sum := addmod(sum, mload(0xc0), r) + sum := addmod(sum, mload(0xe0), r) + mstore(0x0660, sum) + } + { + let sum := mload(0x0100) + sum := addmod(sum, mload(0x0120), r) + mstore(0x0680, sum) + } + { + let sum := mload(0x0140) + sum := addmod(sum, mload(0x0160), r) + mstore(0x06a0, sum) + } + { + for + { + let mptr := 0x00 + let mptr_end := 0xa0 + let sum_mptr := 0x0620 + } + lt(mptr, mptr_end) + { + mptr := add(mptr, 0x20) + sum_mptr := add(sum_mptr, 0x20) + } + { + mstore(mptr, mload(sum_mptr)) + } + success := batch_invert(success, 0, 0xa0, r) + let r_eval := mulmod(mload(0x80), mload(0x0600), r) + for + { + let sum_inv_mptr := 0x60 + let sum_inv_mptr_end := 0xa0 + let r_eval_mptr := 0x05e0 + } + lt(sum_inv_mptr, sum_inv_mptr_end) + { + sum_inv_mptr := sub(sum_inv_mptr, 0x20) + r_eval_mptr := sub(r_eval_mptr, 0x20) + } + { + r_eval := mulmod(r_eval, mload(NU_MPTR), r) + r_eval := addmod(r_eval, mulmod(mload(sum_inv_mptr), mload(r_eval_mptr), r), r) + } + mstore(R_EVAL_MPTR, r_eval) + } + { + let nu := mload(NU_MPTR) + mstore(0x00, calldataload(0xa4)) + mstore(0x20, calldataload(0xc4)) + success := ec_mul_acc(success, mload(ZETA_MPTR)) + success := ec_add_acc(success, calldataload(0x64), calldataload(0x84)) + mstore(0x80, calldataload(0x0264)) + mstore(0xa0, calldataload(0x0284)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(QUOTIENT_X_MPTR), mload(QUOTIENT_Y_MPTR)) + for + { + let mptr := 0x0d60 + let mptr_end := 0x0a20 + } + lt(mptr_end, mptr) + { mptr := sub(mptr, 0x40) } + { + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(mptr), mload(add(mptr, 0x20))) + } + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(0x09a0), mload(0x09c0)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(0x0960), mload(0x0980)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(0x0a20), mload(0x0a40)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, mload(0x09e0), mload(0x0a00)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, calldataload(0x0164), calldataload(0x0184)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, calldataload(0xe4), calldataload(0x0104)) + success := ec_mul_tmp(success, mulmod(nu, mload(0x0500), r)) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + nu := mulmod(nu, mload(NU_MPTR), r) + mstore(0x80, calldataload(0x01a4)) + mstore(0xa0, calldataload(0x01c4)) + success := ec_mul_tmp(success, mulmod(nu, mload(0x0520), r)) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + nu := mulmod(nu, mload(NU_MPTR), r) + mstore(0x80, calldataload(0x0224)) + mstore(0xa0, calldataload(0x0244)) + success := ec_mul_tmp(success, mload(ZETA_MPTR)) + success := ec_add_tmp(success, calldataload(0x01e4), calldataload(0x0204)) + success := ec_mul_tmp(success, mulmod(nu, mload(0x0540), r)) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + nu := mulmod(nu, mload(NU_MPTR), r) + mstore(0x80, calldataload(0x0124)) + mstore(0xa0, calldataload(0x0144)) + success := ec_mul_tmp(success, mulmod(nu, mload(0x0560), r)) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + mstore(0x80, mload(G1_X_MPTR)) + mstore(0xa0, mload(G1_Y_MPTR)) + success := ec_mul_tmp(success, sub(r, mload(R_EVAL_MPTR))) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + mstore(0x80, calldataload(0x0844)) + mstore(0xa0, calldataload(0x0864)) + success := ec_mul_tmp(success, sub(r, mload(0x04c0))) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + mstore(0x80, calldataload(0x0884)) + mstore(0xa0, calldataload(0x08a4)) + success := ec_mul_tmp(success, mload(MU_MPTR)) + success := ec_add_acc(success, mload(0x80), mload(0xa0)) + mstore(PAIRING_LHS_X_MPTR, mload(0x00)) + mstore(PAIRING_LHS_Y_MPTR, mload(0x20)) + mstore(PAIRING_RHS_X_MPTR, calldataload(0x0884)) + mstore(PAIRING_RHS_Y_MPTR, calldataload(0x08a4)) + } + } + + // Random linear combine with accumulator + if mload(HAS_ACCUMULATOR_MPTR) { + mstore(0x00, mload(ACC_LHS_X_MPTR)) + mstore(0x20, mload(ACC_LHS_Y_MPTR)) + mstore(0x40, mload(ACC_RHS_X_MPTR)) + mstore(0x60, mload(ACC_RHS_Y_MPTR)) + mstore(0x80, mload(PAIRING_LHS_X_MPTR)) + mstore(0xa0, mload(PAIRING_LHS_Y_MPTR)) + mstore(0xc0, mload(PAIRING_RHS_X_MPTR)) + mstore(0xe0, mload(PAIRING_RHS_Y_MPTR)) + let challenge := mod(keccak256(0x00, 0x100), r) + + // [pairing_lhs] += challenge * [acc_lhs] + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_LHS_X_MPTR), mload(PAIRING_LHS_Y_MPTR)) + mstore(PAIRING_LHS_X_MPTR, mload(0x00)) + mstore(PAIRING_LHS_Y_MPTR, mload(0x20)) + + // [pairing_rhs] += challenge * [acc_rhs] + mstore(0x00, mload(ACC_RHS_X_MPTR)) + mstore(0x20, mload(ACC_RHS_Y_MPTR)) + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_RHS_X_MPTR), mload(PAIRING_RHS_Y_MPTR)) + mstore(PAIRING_RHS_X_MPTR, mload(0x00)) + mstore(PAIRING_RHS_Y_MPTR, mload(0x20)) + } + + // Perform pairing + success := ec_pairing( + success, + mload(PAIRING_LHS_X_MPTR), + mload(PAIRING_LHS_Y_MPTR), + mload(PAIRING_RHS_X_MPTR), + mload(PAIRING_RHS_Y_MPTR) + ) + + // Revert if anything fails + if iszero(success) { + revert(0x00, 0x00) + } + + // Return 1 as result if everything succeeds + mstore(0x00, 1) + return(0x00, 0x20) + } + } +} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/contracts/src/Summa.sol b/tools/polyexen/circuit/solvency/contracts/src/Summa.sol new file mode 100644 index 0000000..f7ca486 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/src/Summa.sol @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.18; + +// Uncomment this line to use console.log +//import "hardhat/console.sol"; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +import "./interfaces/IVerifier.sol"; + +contract Summa is Ownable { + /** + * @dev Struct representing the configuration of the Summa instance + * @param mstLevels The number of levels of the Merkle sum tree + * @param currenciesCount The number of cryptocurrencies supported by the Merkle sum tree + * @param balanceByteRange The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree + */ + struct SummaConfig { + uint16 mstLevels; + uint16 currenciesCount; + uint8 balanceByteRange; + } + /** + * @dev Struct representing an address ownership proof submitted by the CEX + * @param cexAddress The address owned by the CEX (submitted as a string, as it can be a non-EVM address) + * @param chain The name of the chain name where the address belongs (e.g., ETH, BTC) + * @param signature The signature of the message signed by the address public key + * @param message The message signed by the address public key + */ + struct AddressOwnershipProof { + string cexAddress; + string chain; + bytes signature; + bytes message; + } + + /** + * @dev Struct identifying a cryptocurrency traded on the CEX + * @param name The name of the cryptocurrency + * @param chain The name of the chain name where the cryptocurrency lives (e.g., ETH, BTC) + */ + struct Cryptocurrency { + string name; + string chain; + } + + /** + * @dev Struct representing a commitment submitted by the CEX. + * @param mstRoot Merkle sum tree root of the CEX's liabilities + * @param rootBalances The total sums of the liabilities included in the tree + * @param blockchainNames The names of the blockchains where the CEX holds the cryptocurrencies included into the tree + * @param cryptocurrencyNames The names of the cryptocurrencies included into the tree + */ + struct Commitment { + uint256 mstRoot; + uint256[] rootBalances; + string[] cryptocurrencyNames; + string[] blockchainNames; + } + + // Summa configuration + SummaConfig public config; + + // User inclusion proof verifier + IVerifier private immutable inclusionVerifier; + + // List of all address ownership proofs submitted by the CEX + AddressOwnershipProof[] public addressOwnershipProofs; + + function getAddressOwnershipProof( + bytes32 addressHash + ) public view returns (AddressOwnershipProof memory) { + require( + _ownershipProofByAddress[addressHash] > 0, + "Address not verified" + ); + // -1 comes from the fact that 0 is reserved to distinguish the case when the proof has not yet been submitted + return + addressOwnershipProofs[_ownershipProofByAddress[addressHash] - 1]; + } + + // Convenience mapping to check if an address has already been verified + mapping(bytes32 => uint256) private _ownershipProofByAddress; + + // Solvency commitments by timestamp submitted by the CEX + mapping(uint256 => Commitment) public commitments; + + event AddressOwnershipProofSubmitted( + AddressOwnershipProof[] addressOwnershipProofs + ); + event LiabilitiesCommitmentSubmitted( + uint256 indexed timestamp, + uint256 mstRoot, + uint256[] rootBalances, + Cryptocurrency[] cryptocurrencies + ); + + constructor( + IVerifier _inclusionVerifier, + uint16 mstLevels, + uint16 currenciesCount, + uint8 balanceByteRange + ) { + inclusionVerifier = _inclusionVerifier; + config = SummaConfig(mstLevels, currenciesCount, balanceByteRange); + } + + /** + * @dev Submit an optimistic proof of multiple address ownership for a CEX. The proof is subject to an off-chain verification as it's not feasible to verify the signatures of non-EVM chains in an Ethereum smart contract. + * @param _addressOwnershipProofs The list of address ownership proofs + */ + function submitProofOfAddressOwnership( + AddressOwnershipProof[] memory _addressOwnershipProofs + ) public onlyOwner { + for (uint i = 0; i < _addressOwnershipProofs.length; i++) { + bytes32 addressHash = keccak256( + abi.encodePacked(_addressOwnershipProofs[i].cexAddress) + ); + uint256 proofIndex = _ownershipProofByAddress[addressHash]; + require(proofIndex == 0, "Address already verified"); + + addressOwnershipProofs.push(_addressOwnershipProofs[i]); + _ownershipProofByAddress[addressHash] = addressOwnershipProofs + .length; + require( + bytes(_addressOwnershipProofs[i].cexAddress).length != 0 && + bytes(_addressOwnershipProofs[i].chain).length != 0 && + _addressOwnershipProofs[i].signature.length != 0 && + _addressOwnershipProofs[i].message.length != 0, + "Invalid proof of address ownership" + ); + } + + emit AddressOwnershipProofSubmitted(_addressOwnershipProofs); + } + + /** + * @dev Submit commitment for a CEX + * @param mstRoot Merkle sum tree root of the CEX's liabilities + * @param rootBalances The total sums of the liabilities included into the Merkle sum tree + * @param cryptocurrencies The cryptocurrencies included into the Merkle sum tree + * @param timestamp The timestamp at which the CEX took the snapshot of its assets and liabilities + */ + function submitCommitment( + uint256 mstRoot, + uint256[] memory rootBalances, + Cryptocurrency[] memory cryptocurrencies, + uint256 timestamp + ) public onlyOwner { + require(mstRoot != 0, "Invalid MST root"); + require( + rootBalances.length == cryptocurrencies.length, + "Root liabilities sums and liabilities number mismatch" + ); + string[] memory cryptocurrencyNames = new string[]( + cryptocurrencies.length + ); + string[] memory blockchainNames = new string[](cryptocurrencies.length); + for (uint i = 0; i < cryptocurrencies.length; i++) { + require( + bytes(cryptocurrencies[i].chain).length != 0 && + bytes(cryptocurrencies[i].name).length != 0, + "Invalid cryptocurrency" + ); + require( + rootBalances[i] != 0, + "All root sums should be greater than zero" + ); + cryptocurrencyNames[i] = cryptocurrencies[i].name; + blockchainNames[i] = cryptocurrencies[i].chain; + } + + commitments[timestamp] = Commitment( + mstRoot, + rootBalances, + cryptocurrencyNames, + blockchainNames + ); + + emit LiabilitiesCommitmentSubmitted( + timestamp, + mstRoot, + rootBalances, + cryptocurrencies + ); + } + + /** + * Verify the proof of user inclusion into the liabilities tree + * @param proof ZK proof + * @param publicInputs proof inputs + */ + function verifyInclusionProof( + bytes memory proof, + uint256[] memory publicInputs, + uint256 timestamp + ) public view returns (bool) { + require( + commitments[timestamp].mstRoot == publicInputs[1], + "Invalid MST root" + ); + for (uint i = 2; i < publicInputs.length; i++) { + require( + commitments[timestamp].rootBalances[i - 2] == publicInputs[i], + "Invalid root balance" + ); + } + + // "require" won't catch the exception thrown by the verifier, so we need to catch it manually + try inclusionVerifier.verifyProof(proof, publicInputs) returns ( + bool result + ) { + return result; + } catch (bytes memory /*lowLevelData*/) { + // force revert to return the error message + require(false, "Invalid inclusion proof"); + return false; + } + } +} diff --git a/tools/polyexen/circuit/solvency/contracts/src/interfaces/IVerifier.sol b/tools/polyexen/circuit/solvency/contracts/src/interfaces/IVerifier.sol new file mode 100644 index 0000000..b157e04 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/src/interfaces/IVerifier.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.18; + +/** + * @dev Zero-knowledge proof verifier + */ +interface IVerifier { + /** + * @dev Verify a proof + * @param proof The proof + * @param instances The public inputs to the proof + * @return true if the proof is valid, false otherwise + */ + function verifyProof( + bytes calldata proof, + uint256[] calldata instances + ) external view returns (bool); +} diff --git a/tools/polyexen/circuit/solvency/contracts/test/Summa.ts b/tools/polyexen/circuit/solvency/contracts/test/Summa.ts new file mode 100644 index 0000000..9f7f407 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/test/Summa.ts @@ -0,0 +1,528 @@ +import { expect } from "chai"; +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { ethers } from "hardhat"; +import { Summa } from "../typechain-types"; +import { BigNumber } from "ethers"; +import { defaultAbiCoder } from "ethers/lib/utils"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import * as fs from "fs"; +import * as path from "path"; + +describe("Summa Contract", () => { + function submitCommitment( + summa: Summa, + mstRoot: BigNumber, + rootBalances: BigNumber[], + cryptocurrencies = [ + { + chain: "ETH", + name: "ETH", + }, + { + chain: "BTC", + name: "BTC", + }, + ] + ): any { + return summa.submitCommitment( + mstRoot, + rootBalances, + cryptocurrencies, + BigNumber.from(1693559255) + ); + } + + function verifyInclusionProof( + summa: Summa, + inclusionProof: string, + leafHash: BigNumber, + mstRoot: BigNumber, + balance1: BigNumber, + balance2: BigNumber + ): any { + return summa.verifyInclusionProof( + inclusionProof, + [leafHash, mstRoot, balance1, balance2], + 1693559255 + ); + } + + async function deploySummaFixture() { + // Contracts are deployed using the first signer/account by default + const [owner, addr1, addr2, addr3]: SignerWithAddress[] = + await ethers.getSigners(); + + const inclusionVerifier = await ethers.deployContract( + "src/InclusionVerifier.sol:Verifier" + ); + await inclusionVerifier.deployed(); + + const summa = await ethers.deployContract("Summa", [ + inclusionVerifier.address, + 4, // The number of levels of the Merkle sum tree + 2, // The number of cryptocurrencies supported by the Merkle sum tree + 8, // The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree + ]); + await summa.deployed(); + + return { + summa: summa as Summa, + owner, + addr1, + addr2, + addr3, + }; + } + + describe("verify address ownership", () => { + let summa: Summa; + let account1: SignerWithAddress; + let account2: SignerWithAddress; + let account3: SignerWithAddress; + let ownedAddresses: Summa.AddressOwnershipProofStruct[]; + const message = ethers.utils.defaultAbiCoder.encode( + ["string"], + ["Summa proof of solvency for CryptoExchange"] + ); + + beforeEach(async () => { + const deploymentInfo = await loadFixture(deploySummaFixture); + summa = deploymentInfo.summa as Summa; + account1 = deploymentInfo.addr1; + account2 = deploymentInfo.addr2; + account3 = deploymentInfo.addr3; + + //Reference signing procedure for ETH: + // const message = ethers.utils.defaultAbiCoder.encode( + // ["string"], + // ["Summa proof of solvency for CryptoExchange"] + // ); + // const hashedMessage = ethers.utils.solidityKeccak256( + // ["bytes"], + // [message] + // ); + // const signature = await deploymentInfo.addr3.signMessage( + // ethers.utils.arrayify(hashedMessage) + // ); + // console.log("signature", signature); + + ownedAddresses = [ + { + chain: "ETH", + cexAddress: account1.address.toString(), + signature: + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b", + message: message, + }, + { + chain: "ETH", + cexAddress: account2.address.toString(), + signature: + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c", + message: message, + }, + ]; + }); + + it("should verify the address ownership and store the addresses", async () => { + await expect(summa.submitProofOfAddressOwnership(ownedAddresses)) + .to.emit(summa, "AddressOwnershipProofSubmitted") + .withArgs((ownedAddresses: any) => { + return ( + ownedAddresses[0].chain == "ETH" && + ownedAddresses[0].cexAddress == account1.address && + ownedAddresses[0].signature == + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b" && + ownedAddresses[0].message == message && + ownedAddresses[1].chain == "ETH" && + ownedAddresses[1].cexAddress == account2.address && + ownedAddresses[1].signature == + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c" && + ownedAddresses[1].message == message + ); + }); + + const addr1Hash = ethers.utils.solidityKeccak256( + ["string"], + [account1.address] + ); + let proofOfAddressOwnership1 = await summa.getAddressOwnershipProof( + addr1Hash + ); + expect(proofOfAddressOwnership1.chain).to.be.equal("ETH"); + expect(proofOfAddressOwnership1.cexAddress).to.be.equal(account1.address); + expect(proofOfAddressOwnership1.signature).to.be.equal( + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b" + ); + expect(proofOfAddressOwnership1.message).to.be.equal(message); + const addr2Hash = ethers.utils.solidityKeccak256( + ["string"], + [account2.address] + ); + let proofOfAddressOwnership2 = await summa.getAddressOwnershipProof( + addr2Hash + ); + expect(proofOfAddressOwnership2.chain).to.be.equal("ETH"); + expect(proofOfAddressOwnership2.cexAddress).to.be.equal(account2.address); + expect(proofOfAddressOwnership2.signature).to.be.equal( + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c" + ); + expect(proofOfAddressOwnership2.message).to.be.equal(message); + }); + + it("should revert if the caller is not the owner", async () => { + await expect( + summa.connect(account3).submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("should revert if the address ownership has already been verified", async () => { + await summa.submitProofOfAddressOwnership(ownedAddresses); + await expect( + summa.submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Address already verified"); + }); + + it("should revert if the proof of address ownership has invalid address", async () => { + ownedAddresses[0].cexAddress = ""; + await expect( + summa.submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Invalid proof of address ownership"); + }); + + it("should revert if the proof of address ownership has invalid chain type", async () => { + ownedAddresses[0].chain = ""; + await expect( + summa.submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Invalid proof of address ownership"); + }); + + it("should revert if the proof of address ownership has invalid signature", async () => { + ownedAddresses[0].signature = ethers.utils.toUtf8Bytes(""); + await expect( + summa.submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Invalid proof of address ownership"); + }); + + it("should revert if the proof of address ownership has invalid message", async () => { + ownedAddresses[0].message = ethers.utils.toUtf8Bytes(""); + await expect( + summa.submitProofOfAddressOwnership(ownedAddresses) + ).to.be.revertedWith("Invalid proof of address ownership"); + }); + + it("should revert if requesting proof for unverified address", async () => { + const addr1Hash = ethers.utils.solidityKeccak256( + ["string"], + [account1.address] + ); + await expect( + summa.getAddressOwnershipProof(addr1Hash) + ).to.be.revertedWith("Address not verified"); + }); + }); + + describe("submit commitment", () => { + let mstRoot: BigNumber; + let rootBalances: BigNumber[]; + let summa: Summa; + let account1: SignerWithAddress; + let account2: SignerWithAddress; + //let ethAccount3; + let ownedAddresses: Summa.AddressOwnershipProofStruct[]; + const message = ethers.utils.defaultAbiCoder.encode( + ["string"], + ["Summa proof of solvency for CryptoExchange"] + ); + + beforeEach(async () => { + const deploymentInfo = await loadFixture(deploySummaFixture); + summa = deploymentInfo.summa as Summa; + account1 = deploymentInfo.addr1; + account2 = deploymentInfo.addr2; + + ownedAddresses = [ + { + chain: "ETH", + cexAddress: account1.address.toString(), + signature: + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b", + message: message, + }, + { + chain: "ETH", + cexAddress: account2.address.toString(), + signature: + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c", + message: message, + }, + ]; + + const commitmentCalldataJson = fs.readFileSync( + path.resolve( + __dirname, + "../../zk_prover/examples/commitment_solidity_calldata.json" + ), + "utf-8" + ); + const commitmentCalldata: any = JSON.parse(commitmentCalldataJson); + + mstRoot = commitmentCalldata.root_hash; + rootBalances = commitmentCalldata.root_balances; + }); + + it("should submit commitment for the given public input", async () => { + await summa.submitProofOfAddressOwnership(ownedAddresses); + + await expect(submitCommitment(summa, mstRoot, rootBalances)) + .to.emit(summa, "LiabilitiesCommitmentSubmitted") + .withArgs( + BigNumber.from(1693559255), + mstRoot, + rootBalances, + (cryptocurrencies: [Summa.CryptocurrencyStruct]) => { + return ( + cryptocurrencies[0].chain == "ETH" && + cryptocurrencies[0].name == "ETH" + ); + } + ); + }); + + it("should revert if the caller is not the owner", async () => { + await expect( + summa.connect(account2).submitCommitment( + mstRoot, + [BigNumber.from(1000000000)], + [ + { + chain: "ETH", + name: "ETH", + }, + ], + BigNumber.from(1693559255) + ) + ).to.be.revertedWith("Ownable: caller is not the owner"); + }); + + it("should revert with invalid root sum", async () => { + rootBalances = [BigNumber.from(0), BigNumber.from(0)]; + + await summa.submitProofOfAddressOwnership(ownedAddresses); + + await expect( + submitCommitment(summa, mstRoot, rootBalances) + ).to.be.revertedWith("All root sums should be greater than zero"); + }); + + it("should revert with invalid cryptocurrencies", async () => { + await summa.submitProofOfAddressOwnership(ownedAddresses); + + await expect( + submitCommitment(summa, mstRoot, rootBalances, [ + { + chain: "BTC", + name: "BTC", + }, + { + chain: "", + name: "ETH", + }, + ]) + ).to.be.revertedWith("Invalid cryptocurrency"); + + await expect( + submitCommitment(summa, mstRoot, rootBalances, [ + { + chain: "ETH", + name: "ETH", + }, + { + chain: "BTC", + name: "", + }, + ]) + ).to.be.revertedWith("Invalid cryptocurrency"); + }); + + it("should not submit invalid root", async () => { + await expect( + submitCommitment(summa, BigNumber.from(0), rootBalances) + ).to.be.revertedWith("Invalid MST root"); + }); + + it("should revert if cryptocurrency and liability counts don't match", async () => { + rootBalances = [BigNumber.from(10000000)]; + await expect( + submitCommitment(summa, mstRoot, rootBalances) + ).to.be.revertedWith( + "Root liabilities sums and liabilities number mismatch" + ); + }); + }); + + describe("verify proof of inclusion", () => { + let commitmentMstRoot: BigNumber; + let rootBalances: BigNumber[]; + let inclusionMstRoot: BigNumber; + let leafHash: BigNumber; + let balance1: BigNumber; + let balance2: BigNumber; + let summa: Summa; + let account1: SignerWithAddress; + let account2: SignerWithAddress; + let inclusionProof: string; + let ownedAddresses: Summa.AddressOwnershipProofStruct[]; + const message = ethers.utils.defaultAbiCoder.encode( + ["string"], + ["Summa proof of solvency for CryptoExchange"] + ); + + beforeEach(async () => { + const deploymentInfo = await loadFixture(deploySummaFixture); + summa = deploymentInfo.summa as Summa; + account1 = deploymentInfo.addr1; + account2 = deploymentInfo.addr2; + + ownedAddresses = [ + { + chain: "ETH", + cexAddress: defaultAbiCoder.encode(["address"], [account1.address]), + signature: + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b", + message: message, + }, + { + chain: "ETH", + cexAddress: defaultAbiCoder.encode(["address"], [account2.address]), + signature: + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c", + message: message, + }, + ]; + + const inclusionJson = fs.readFileSync( + path.resolve( + __dirname, + "../../zk_prover/examples/inclusion_proof_solidity_calldata.json" + ), + "utf-8" + ); + const inclusionCalldata: any = JSON.parse(inclusionJson); + + inclusionProof = inclusionCalldata.proof; + leafHash = inclusionCalldata.public_inputs[0]; + inclusionMstRoot = inclusionCalldata.public_inputs[1]; + balance1 = inclusionCalldata.public_inputs[2]; + balance2 = inclusionCalldata.public_inputs[3]; + + const commitmentCalldataJson = fs.readFileSync( + path.resolve( + __dirname, + "../../zk_prover/examples/commitment_solidity_calldata.json" + ), + "utf-8" + ); + const commitmentCalldata: any = JSON.parse(commitmentCalldataJson); + + commitmentMstRoot = commitmentCalldata.root_hash; + rootBalances = commitmentCalldata.root_balances; + }); + + it("should verify the proof of inclusion for the given public input", async () => { + await summa.submitProofOfAddressOwnership(ownedAddresses); + await submitCommitment(summa, commitmentMstRoot, rootBalances); + expect( + await verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.equal(true); + }); + + it("should not verify with invalid MST root", async () => { + await summa.submitProofOfAddressOwnership(ownedAddresses); + await submitCommitment(summa, commitmentMstRoot, rootBalances); + inclusionMstRoot = BigNumber.from(0); + await expect( + verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.revertedWith("Invalid MST root"); + }); + + it("should not verify if the MST root lookup by timestamp returns an incorrect MST root", async () => { + // The lookup will return a zero MST root as no MST root has been stored yet + await expect( + verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.revertedWith("Invalid MST root"); + }); + + it("should not verify with invalid root balances", async () => { + balance1 = BigNumber.from(0); + + await summa.submitProofOfAddressOwnership(ownedAddresses); + await submitCommitment(summa, commitmentMstRoot, rootBalances); + await expect( + verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.revertedWith("Invalid root balance"); + }); + + it("should not verify with invalid leaf", async () => { + leafHash = BigNumber.from(0); + + await summa.submitProofOfAddressOwnership(ownedAddresses); + await submitCommitment(summa, commitmentMstRoot, rootBalances); + await expect( + verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.revertedWith("Invalid inclusion proof"); + }); + + it("should not verify with invalid proof", async () => { + inclusionProof = inclusionProof.replace("1", "2"); + + await summa.submitProofOfAddressOwnership(ownedAddresses); + await submitCommitment(summa, commitmentMstRoot, rootBalances); + await expect( + verifyInclusionProof( + summa, + inclusionProof, + leafHash, + inclusionMstRoot, + balance1, + balance2 + ) + ).to.be.revertedWith("Invalid inclusion proof"); + }); + }); +}); diff --git a/tools/polyexen/circuit/solvency/contracts/tsconfig.json b/tools/polyexen/circuit/solvency/contracts/tsconfig.json new file mode 100644 index 0000000..574e785 --- /dev/null +++ b/tools/polyexen/circuit/solvency/contracts/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } +} diff --git a/tools/polyexen/circuit/solvency/csv/entry_13.csv b/tools/polyexen/circuit/solvency/csv/entry_13.csv new file mode 100644 index 0000000..3294526 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_13.csv @@ -0,0 +1,14 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,11888,41163 +MBlfbBGI,67823,18651 +lAhWlEWZ,18651,2087 +nuZweYtO,22073,55683 +gbdSwiuY,34897,83296 +RZNneNuP,83296,16881 +YsscHXkp,31699,35479 +RkLzkDun,2087,79731 +HlQlnEYI,30605,11888 +RqkZOFYe,16881,14874 +NjCSRAfD,41163,67823 +pHniJMQY,14874,22073 +dOGIMzKR,10032,10032 \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/csv/entry_16.csv b/tools/polyexen/circuit/solvency/csv/entry_16.csv new file mode 100644 index 0000000..c0d4ebc --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_16.csv @@ -0,0 +1,17 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,11888,41163 +MBlfbBGI,67823,18651 +lAhWlEWZ,18651,2087 +nuZweYtO,22073,55683 +gbdSwiuY,34897,83296 +RZNneNuP,83296,16881 +YsscHXkp,31699,35479 +RkLzkDun,2087,79731 +HlQlnEYI,30605,11888 +RqkZOFYe,16881,14874 +NjCSRAfD,41163,67823 +pHniJMQY,14874,22073 +dOGIMzKR,10032,10032 +HfMDmNLp,55683,34897 +xPLKzCBl,79731,30605 +AtwIxZHo,35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/entry_16_bigints.csv b/tools/polyexen/circuit/solvency/csv/entry_16_bigints.csv new file mode 100644 index 0000000..04e2e24 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_16_bigints.csv @@ -0,0 +1,17 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,18446744073709551616,79731 +MBlfbBGI,67823,55683 +lAhWlEWZ,18651,22073 +nuZweYtO,22073,35479 +gbdSwiuY,34897,10032 +RZNneNuP,83296,2087 +YsscHXkp,31699,34897 +RkLzkDun,2087,67823 +HlQlnEYI,30605,31699 +RqkZOFYe,16881,16881 +NjCSRAfD,41163,14874 +pHniJMQY,14874,18651 +dOGIMzKR,10032,41163 +HfMDmNLp,55683,83296 +xPLKzCBl,79731,18446744073709551616 +AtwIxZHo,35479,30605 diff --git a/tools/polyexen/circuit/solvency/csv/entry_16_modified.csv b/tools/polyexen/circuit/solvency/csv/entry_16_modified.csv new file mode 100644 index 0000000..b5496bf --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_16_modified.csv @@ -0,0 +1,17 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,11888,41163 +MBlfbBGI,67823,18651 +lAhWlEWZ,18651,2087 +nuZweYtO,22073,55683 +gbdSwiuY,34897,83296 +RZNneNuP,83296,16881 +YsscHXkp,31699,35479 +RkLzkDun,2086,79732 +HlQlnEYI,30605,11888 +RqkZOFYe,16881,14874 +NjCSRAfD,41163,67823 +pHniJMQY,14874,22073 +dOGIMzKR,10032,10032 +HfMDmNLp,55683,34897 +xPLKzCBl,79731,30605 +AtwIxZHo,35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/entry_16_overflow.csv b/tools/polyexen/circuit/solvency/csv/entry_16_overflow.csv new file mode 100644 index 0000000..124d162 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_16_overflow.csv @@ -0,0 +1,17 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,5192296858534827628530496329220096,41163 +MBlfbBGI,67823,18651 +lAhWlEWZ,18651,2087 +nuZweYtO,22073,55683 +gbdSwiuY,34897,83296 +RZNneNuP,83296,16881 +YsscHXkp,31699,35479 +RkLzkDun,2087,79731 +HlQlnEYI,30605,11888 +RqkZOFYe,16881,14874 +NjCSRAfD,41163,67823 +pHniJMQY,14874,22073 +dOGIMzKR,10032,10032 +HfMDmNLp,55683,34897 +xPLKzCBl,79731,30605 +AtwIxZHo,35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/entry_16_switched_order.csv b/tools/polyexen/circuit/solvency/csv/entry_16_switched_order.csv new file mode 100644 index 0000000..a83d2b4 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_16_switched_order.csv @@ -0,0 +1,17 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,11888,79731 +MBlfbBGI,67823,22073 +lAhWlEWZ,18651,18651 +nuZweYtO,22073,35479 +gbdSwiuY,34897,83296 +RZNneNuP,83296,34897 +YsscHXkp,31699,55683 +RkLzkDun,2087,30605 +HlQlnEYI,30605,10032 +RqkZOFYe,16881,16881 +NjCSRAfD,41163,41163 +pHniJMQY,14874,31699 +dOGIMzKR,10032,11888 +HfMDmNLp,55683,14874 +AtwIxZHo,35479,67823 +xPLKzCBl,79731,2087 diff --git a/tools/polyexen/circuit/solvency/csv/entry_17.csv b/tools/polyexen/circuit/solvency/csv/entry_17.csv new file mode 100644 index 0000000..ea4bb7a --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/entry_17.csv @@ -0,0 +1,19 @@ +username,balance_ETH_ETH,balance_USDT_ETH +dxGaEAii,11888,41163 +MBlfbBGI,67823,18651 +lAhWlEWZ,18651,2087 +nuZweYtO,22073,55683 +gbdSwiuY,34897,83296 +RZNneNuP,83296,16881 +YsscHXkp,31699,35479 +RkLzkDun,2087,79731 +HlQlnEYI,30605,11888 +RqkZOFYe,16881,14874 +NjCSRAfD,41163,67823 +pHniJMQY,14874,22073 +dOGIMzKR,10032,10032 +HfMDmNLp,55683,34897 +xPLKzCBl,79731,30605 +AtwIxZHo,35479,31699 +HuIIxzHo,1,1 + diff --git a/tools/polyexen/circuit/solvency/csv/signatures.csv b/tools/polyexen/circuit/solvency/csv/signatures.csv new file mode 100644 index 0000000..89e4ba1 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/signatures.csv @@ -0,0 +1,3 @@ +chain;address;signature;message +ETH;0x70997970C51812dc3A010C7d01b50e0d17dc79C8;0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b;Summa proof of solvency for CryptoExchange +ETH;0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC;0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c;Summa proof of solvency for CryptoExchange diff --git a/tools/polyexen/circuit/solvency/csv/states/entry_16_1.csv b/tools/polyexen/circuit/solvency/csv/states/entry_16_1.csv new file mode 100644 index 0000000..11b3f4e --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/states/entry_16_1.csv @@ -0,0 +1,17 @@ +username;balances +dxGaEAii;11888,41163 +MBlfbBGI;67823,18651 +lAhWlEWZ;18651,2087 +nuZweYtO;22073,55683 +gbdSwiuY;34897,83296 +RZNneNuP;83296,16881 +YsscHXkp;31699,35479 +RkLzkDun;2087,79731 +HlQlnEYI;30605,11888 +RqkZOFYe;16881,14874 +NjCSRAfD;41163,67823 +pHniJMQY;14874,22073 +dOGIMzKR;10032,10032 +HfMDmNLp;55683,34897 +xPLKzCBl;79731,30605 +AtwIxZHo;35479,31699 \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/csv/states/entry_16_2.csv b/tools/polyexen/circuit/solvency/csv/states/entry_16_2.csv new file mode 100644 index 0000000..857a8a8 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/states/entry_16_2.csv @@ -0,0 +1,17 @@ +username;balances +dxGaEAii;10888,40163 +MBlfbBGI;68823,19651 +lAhWlEWZ;18651,2087 +nuZweYtO;22073,55683 +gbdSwiuY;34897,83296 +RZNneNuP;83296,16881 +YsscHXkp;31699,35479 +RkLzkDun;2087,79731 +HlQlnEYI;30605,11888 +RqkZOFYe;16881,14874 +NjCSRAfD;41163,67823 +pHniJMQY;14874,22073 +dOGIMzKR;10032,10032 +HfMDmNLp;55683,34897 +xPLKzCBl;79731,30605 +AtwIxZHo;35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/states/entry_16_3.csv b/tools/polyexen/circuit/solvency/csv/states/entry_16_3.csv new file mode 100644 index 0000000..557fd9e --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/states/entry_16_3.csv @@ -0,0 +1,17 @@ +username;balances +dxGaEAii;8888,40163 +MBlfbBGI;68823,19651 +lAhWlEWZ;20651,2087 +nuZweYtO;22073,55683 +gbdSwiuY;34897,83296 +RZNneNuP;83296,16881 +YsscHXkp;31699,35479 +RkLzkDun;2087,79731 +HlQlnEYI;30605,11888 +RqkZOFYe;16881,14874 +NjCSRAfD;41163,67823 +pHniJMQY;14874,22073 +dOGIMzKR;10032,10032 +HfMDmNLp;55683,34897 +xPLKzCBl;79731,30605 +AtwIxZHo;35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/states/entry_16_4.csv b/tools/polyexen/circuit/solvency/csv/states/entry_16_4.csv new file mode 100644 index 0000000..f2b1d8e --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/states/entry_16_4.csv @@ -0,0 +1,17 @@ +username;balances +dxGaEAii;10888,41163 +MBlfbBGI;68823,19651 +lAhWlEWZ;18651,2087 +nuZweYtO;22073,54683 +gbdSwiuY;34897,83296 +RZNneNuP;83296,16881 +YsscHXkp;31699,35479 +RkLzkDun;2087,79731 +HlQlnEYI;30605,11888 +RqkZOFYe;16881,14874 +NjCSRAfD;41163,67823 +pHniJMQY;14874,22073 +dOGIMzKR;10032,10032 +HfMDmNLp;55683,34897 +xPLKzCBl;79731,30605 +AtwIxZHo;35479,31699 diff --git a/tools/polyexen/circuit/solvency/csv/states/entry_16_5.csv b/tools/polyexen/circuit/solvency/csv/states/entry_16_5.csv new file mode 100644 index 0000000..55079c6 --- /dev/null +++ b/tools/polyexen/circuit/solvency/csv/states/entry_16_5.csv @@ -0,0 +1,17 @@ +username;balances +dxGaEAii;15888,41163 +MBlfbBGI;68823,19651 +lAhWlEWZ;18651,2087 +nuZweYtO;22073,54683 +gbdSwiuY;34897,83296 +RZNneNuP;83296,16881 +YsscHXkp;31699,35479 +RkLzkDun;2087,79731 +HlQlnEYI;30605,11888 +RqkZOFYe;16881,14874 +NjCSRAfD;41163,67823 +pHniJMQY;14874,22073 +dOGIMzKR;10032,10032 +HfMDmNLp;50683,34897 +xPLKzCBl;79731,30605 +AtwIxZHo;35479,31699 diff --git a/tools/polyexen/circuit/solvency/remappings.txt b/tools/polyexen/circuit/solvency/remappings.txt new file mode 100644 index 0000000..4047cd3 --- /dev/null +++ b/tools/polyexen/circuit/solvency/remappings.txt @@ -0,0 +1,2 @@ +@openzeppelin/=contracts/node_modules/@openzeppelin +hardhat/=contracts/node_modules/hardhat \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/.gitignore b/tools/polyexen/circuit/solvency/zk_prover/.gitignore new file mode 100644 index 0000000..8d79064 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target +/ptau +/benches/csv +circuit_parameters_gen/generate_parameters_grain.sage.py +circuit_parameters_gen/__pycache__ +node_modules diff --git a/tools/polyexen/circuit/solvency/zk_prover/Cargo.lock b/tools/polyexen/circuit/solvency/zk_prover/Cargo.lock new file mode 100644 index 0000000..7c2620c --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/Cargo.lock @@ -0,0 +1,5350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addchain" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +dependencies = [ + "num-bigint 0.3.3", + "num-integer", + "num-traits", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "alloy-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal 0.4.1", + "itoa", + "ruint", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +dependencies = [ + "alloy-rlp-derive", + "arrayvec 0.7.4", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.4", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.4", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "colored", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.48", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" +dependencies = [ + "serde", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bellperson" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93eaee4b4753554139ae52ecf0e8b8c128cbc561b32e1bfaa32f70cba8518c1f" +dependencies = [ + "bincode", + "blake2s_simd 1.0.2", + "blstrs", + "byteorder", + "crossbeam-channel", + "digest 0.10.7", + "ec-gpu", + "ec-gpu-gen", + "ff", + "group", + "log", + "memmap2", + "pairing", + "rand 0.8.5", + "rand_core 0.6.4", + "rayon", + "rustversion", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.48", + "which", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac926d808fb72fe09ebf471a091d6d72918876ccf0b4989766093d2d0d24a0ef" +dependencies = [ + "bindgen", + "blst", + "cc", + "glob", + "hex", + "libc", + "serde", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.21", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3 0.10.8", + "thiserror", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "const-cstr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" + +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling", + "derive_builder_core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + +[[package]] +name = "ec-gpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45" + +[[package]] +name = "ec-gpu-gen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "892df2aa20abec5b816e15d5d6383892ca142077708efa3067dd3ac44b75c664" +dependencies = [ + "bitvec", + "crossbeam-channel", + "ec-gpu", + "execute", + "ff", + "group", + "hex", + "log", + "num_cpus", + "once_cell", + "rayon", + "sha2", + "thiserror", + "yastl", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3 0.10.8", + "zeroize", +] + +[[package]] +name = "enumn" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3 0.10.8", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5344eea9b20effb5efeaad29418215c4d27017639fd1f908260f59cbbd226e" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf35eb7d2e2092ad41f584951e08ec7c077b142dba29c4f1b8f52d2efddc49c" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0111ead599d17a7bff6985fd5756f39ca7033edc79a31b23026a8d5d64fa95cd" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbdfb952aafd385b31d316ed80d7b76215ce09743c172966d840e96924427e0c" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.48", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7465c814a2ecd0de0442160da13584205d1cdc08f4717a6511cad455bd5d7dc4" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.48", +] + +[[package]] +name = "ethers-core" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.48", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "facabf8551b4d1a3c08cb935e7fca187804b6c2525cc0dafb8e5a6dd453a24de" +dependencies = [ + "chrono", + "ethers-core", + "ethers-solc", + "reqwest", + "semver 1.0.21", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681ece6eb1d10f7cf4f873059a77c04ff1de4f35c63dd7bccde8f438374fcb93" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d6c0c9455d93d4990c06e049abf9b30daf148cf461ee939c11d88907c60816" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1b714e227bbd2d8c53528adb580b203009728b17d0d0e4119353aa9bc5532" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver 1.0.21", + "serde", + "serde_json", + "solang-parser", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "execute" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a82608ee96ce76aeab659e9b8d3c2b787bffd223199af88c674923d861ada10" +dependencies = [ + "execute-command-macro", + "execute-command-tokens", + "generic-array 1.0.0", +] + +[[package]] +name = "execute-command-macro" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dec53d547564e911dc4ff3ecb726a64cf41a6fa01a2370ebc0d95175dd08bd" +dependencies = [ + "execute-command-macro-impl", +] + +[[package]] +name = "execute-command-macro-impl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b" +dependencies = [ + "execute-command-tokens", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "execute-command-tokens" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69dc321eb6be977f44674620ca3aa21703cb20ffbe560e1ae97da08401ffbcad" + +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "byteorder", + "ff_derive", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff_ce" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a682c12d0cc98a32ab7540401a5ea1ed21d11571eea11d5829cd721f85ff0" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", +] + +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ff_derive_ce" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b" +dependencies = [ + "num-bigint 0.2.6", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-ord" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "font-kit" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fe28504d371085fae9ac7a3450f0b289ab71e07c8e57baa3fb68b9e57d6ce5" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "core-foundation", + "core-graphics", + "core-text", + "dirs-next", + "dwrote", + "float-ord", + "freetype", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "freetype" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc8599a3078adf8edeb86c71e9f8fa7d88af5ca31e806a867756081f90f5d83" +dependencies = [ + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ee28c39a43d89fbed8b4798fb4ba56722cfd2b5af81f9326c27614ba88ecd5" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "halo2_gadgets" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "ff", + "group", + "halo2_proofs", + "halo2curves", + "lazy_static", + "rand 0.8.5", + "subtle", + "uint", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves", + "maybe-rayon", + "plotters", + "rand_chacha", + "rand_core 0.6.4", + "sha3 0.9.1", + "tabbycat", + "tracing", +] + +[[package]] +name = "halo2_solidity_verifier" +version = "0.1.0" +source = "git+https://github.com/summa-dev/halo2-solidity-verifier#d33972567f83f3218257b286b541ad97ba32928c" +dependencies = [ + "askama", + "blake2b_simd", + "halo2_proofs", + "hex", + "itertools 0.11.0", + "revm", + "ruint", + "sha3 0.10.8", +] + +[[package]] +name = "halo2curves" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint 0.4.4", + "num-traits", + "pasta_curves", + "paste", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "serde_arrays", + "static_assertions", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-traits", + "png", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi 0.3.4", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.7.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "neptune" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9a64337e6d214e2a48db5714ef18cf1e5a7bbff9043838fdf6e57ce5659335" +dependencies = [ + "bellperson", + "blake2s_simd 0.5.11", + "blstrs", + "byteorder", + "ff", + "generic-array 0.14.7", + "itertools 0.8.2", + "log", + "pasta_curves", + "serde", + "trait-set", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nova-scotia" +version = "0.5.0" +source = "git+https://github.com/nalinbhardwaj/Nova-Scotia#54f2bdbb78aad841d8714f7e2d0344bcc593a922" +dependencies = [ + "anyhow", + "bellperson", + "byteorder", + "ff", + "hex-literal 0.3.4", + "itertools 0.9.0", + "js-sys", + "nova-snark", + "num-bigint 0.4.4", + "num-traits", + "pasta_curves", + "rayon", + "serde", + "serde_json", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-rayon", +] + +[[package]] +name = "nova-snark" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e12911ac9672ad436acfc992f09e26a5960513bbe81d1572005cadd8c1be8f4" +dependencies = [ + "bellperson", + "bincode", + "bitvec", + "byteorder", + "digest 0.10.7", + "ff", + "flate2", + "generic-array 0.14.7", + "getrandom", + "halo2curves", + "itertools 0.11.0", + "neptune", + "num-bigint 0.4.4", + "num-integer", + "num-traits", + "pasta-msm", + "pasta_curves", + "rand_chacha", + "rand_core 0.6.4", + "rayon", + "serde", + "sha3 0.10.8", + "subtle", + "thiserror", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint 0.4.4", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.4", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.4", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pasta-msm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e85d75eba3e7e9ee3bd11342b669185e194dadda3557934bc1000d9b87159d3" +dependencies = [ + "cc", + "pasta_curves", + "semolina", + "sppark", + "which", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0444332826c70dc47be74a7c6a5fc44e23a7905ad6858d4162b658320455ef93" +dependencies = [ + "rustc_version 0.4.0", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "chrono", + "font-kit", + "image", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-bitmap" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cebbe1f70205299abc69e8b295035bb52a6a70ee35474ad10011f0a4efb8543" +dependencies = [ + "gif", + "image", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6c3c3e617595665b8ea2ff95a86066be38fb121ff920a9c0eb282abcd1da5a" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "poseidon-rs" +version = "0.0.10" +source = "git+https://github.com/arnaucube/poseidon-rs#f4ba1f7c32905cd2ae5a71e7568564bb150a9862" +dependencies = [ + "ff_ce", + "rand 0.4.6", + "serde_json", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", + "wasm_sync", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", + "wasm_sync", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[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_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "revm" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f4ca8ae0345104523b4af1a8a7ea97cfa1865cdb7a7c25d23c1a18d9b48598" +dependencies = [ + "auto_impl", + "revm-interpreter", + "revm-precompile", +] + +[[package]] +name = "revm-interpreter" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f959cafdf64a7f89b014fa73dc2325001cf654b3d9400260b212d19a2ebe3da0" +dependencies = [ + "revm-primitives", +] + +[[package]] +name = "revm-precompile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d360a88223d85709d2e95d4609eb1e19c649c47e28954bfabae5e92bb37e83e" +dependencies = [ + "c-kzg", + "k256", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51187b852d9e458816a2e19c81f1dd6c924077e1a8fccd16e4f044f865f299d7" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "auto_impl", + "bitflags 2.4.2", + "bitvec", + "c-kzg", + "enumn", + "hashbrown", + "hex", + "once_cell", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ruint" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint 0.4.4", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.21", +] + +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "semolina" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0111fd4fa831becb0606b9a2285ef3bee3c6a70d690209b8ae9514e9befe23" +dependencies = [ + "cc", + "glob", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sppark" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7a6d98937866ea8917015cd4a72d56d6e7feee8979dbccf83fc0c870053c46" +dependencies = [ + "cc", + "which", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "summa-solvency" +version = "0.1.0" +dependencies = [ + "ark-std 0.3.0", + "criterion", + "csv", + "ethers", + "ff_ce", + "halo2_gadgets", + "halo2_proofs", + "halo2_solidity_verifier", + "hex", + "itertools 0.11.0", + "nova-scotia", + "nova-snark", + "num-bigint 0.4.4", + "num-traits", + "num_cpus", + "plotters", + "poseidon-rs", + "rand 0.8.5", + "rayon", + "regex", + "serde", + "serde_json", + "tabbycat", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tabbycat" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c45590f0f859197b4545be1b17b2bc3cc7bb075f7d1cc0ea1dc6521c0bf256a3" +dependencies = [ + "anyhow", + "derive_builder", + "regex", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-rayon" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e02b7785fe15de188657b7d3a234ef042bfd8da10822016915e06d4e29cba7" +dependencies = [ + "crossbeam-channel", + "js-sys", + "rayon", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "wasm_sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff360cade7fec41ff0e9d2cda57fe58258c5f16def0e21302394659e6bbb0ea" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" +dependencies = [ + "const-cstr", + "dlib", + "once_cell", + "pkg-config", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] diff --git a/tools/polyexen/circuit/solvency/zk_prover/Cargo.toml b/tools/polyexen/circuit/solvency/zk_prover/Cargo.toml new file mode 100644 index 0000000..bba8596 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "summa-solvency" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +dev-graph = ["halo2_proofs/dev-graph", "plotters"] + + +[dependencies] +halo2_proofs = { git = "https://github.com/summa-dev/halo2"} +halo2_gadgets = { git = "https://github.com/summa-dev/halo2"} +plotters = { version = "0.3.4", optional = true } +rand = "0.8" +ark-std = { version = "0.3.0", features = ["print-trace"] } +tabbycat = { version = "0.1", features = ["attributes"], optional = true } +csv = "1.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +hex = "0.4.3" +num-bigint = "0.4" +num_cpus = "1.15" +halo2_solidity_verifier = {git = "https://github.com/summa-dev/halo2-solidity-verifier", features = ["evm"]} +itertools = "0.11.0" +ethers = { version = "2.0.7", default-features = false, features = ["ethers-solc"] } +regex-simple = { version = "1", package = "regex" } +nova-snark = "0.23.0" +nova-scotia = { git = "https://github.com/nalinbhardwaj/Nova-Scotia" } +poseidon-rs = { git = "https://github.com/arnaucube/poseidon-rs" } +ff = {package="ff_ce" , version="0.11", features = ["derive"]} +num-traits = "0.2.16" +rayon = "1.8.0" + +[dev-dependencies] +criterion= "0.3" + +[[bench]] +name = "full_solvency_flow" +harness = false diff --git a/tools/polyexen/circuit/solvency/zk_prover/README.md b/tools/polyexen/circuit/solvency/zk_prover/README.md new file mode 100644 index 0000000..28e4f5d --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/README.md @@ -0,0 +1,122 @@ +# ZK Prover + +This directory contains the Halo2 ZK circuit implementation for the Summa Proof of Solvency protocol. + +## Usage + +To build, test and print the circuits, execute + +``` +cargo build +cargo test --release --features dev-graph +``` + +## Documentation + +The documentation for the circuits can be generated by running + +``` +cargo doc --no-deps --open +``` + +## Powers of Tau Trusted Setup + +For testing purposes, it's not necessary to download the `ptau` file. The `generate_setup_artifacts` function can manage this by generating a new setup from a randomly generated value. This automated generation process is intended for testing and development convenience, and it should not be used in production. +For real-world situations, you must provide the path of a specific `ptau` file to the `generate_setup_artifacts`. The circuit will use the randomness from the given file. You can find an example that initializes a `Snapshot` instance [here](https://github.com/summa-dev/summa-solvency/blob/11d4fce5d18f6175804aa792fc9fc5ac27bf5c00/backend/src/apis/snapshot.rs#L115-L116) in the backend. + +## Build an Inclusion Verifier Contract + +A `gen_inclusion_verifier.rs` script is provided to generate a solidity contract that can be used to verify the proof of user inclusion into CEX liabilites. The script can be run as follows: + +``` +cargo run --release --example gen_inclusion_verifier +``` + +The script will generate a new `InclusionVerifier.sol` and `InclusionVerifier.yul` contracts in `contracts/src`. + +Note that the generic parameters of the circuits `LEVELS`, `N_CURRENCIES` and `N_BYTES` are set to `4`, `2` and `8`. This means that the circuit is tuned to verify the proof of inclusion for an exchange with a userbase of 4 levels (2^4 = 16 users), 2 currencies and a balances in a range of 8 bytes. These parameters can be changed in the script. + +The verifier are generated based on a trusted setup located at `backend/ptau/hermez-raw-11`. Note that setting different generic parameters may require a bigger trusted setup. More details on how to generate a trusted setup can be found [here](https://summa.gitbook.io/summa-book/backend/summa-solvency#3.-generate-verifier-contract). + +## Build a Commitment + +A `gen_commitment.rs` script is provided to generate a commitment out of a Merkle Sum Tree. In particular, the example takes a csv file located in "../csv/entry_16.csv", build a Merkle Sum Tree and extract a commitment out it. The commitment is made of the `root_hash` and the `root_balances`. + +The script will eventually generate a `commitment_solidity_calldata.json` file that contains some testing calldata to be used within `contracts` to test the publishing of the commitment to the Summa Smart Contract. + +The script can be run as follows: + +``` +cargo run --release --example gen_commitment +``` + +Note that the generic parameters of the Merkle Sum Tree `N_CURRENCIES` and `N_BYTES` are set to `2` and `8`. This means that this should go in pair with a Inclusion Verifier Circuit tuned to the same generic parameters. + +## Build an Inclusion Proof + +A `gen_inclusion_proof.rs` script is provided to a proof of inclusion that can verified by the Smart Contract. The script can be run as follows: + +``` +cargo run --release --example gen_inclusion_proof +``` + +This generated proof is saved in `inclusion_proof_solidity_calldata.json`. The file contains some testing calldata to be used within `contracts` to test the verifier. + +In the example, the proof is generated based on the `../csv/entry_16.csv` file for a specific `user_index`, which is set to 0 by default. The setup parameters are set to `LEVELS = 4`, `N_CURRENCIES = 2` and `N_BYTES = 8`. The ptau file is located at `backend/ptau/hermez-raw-11`. Note that these parameters should go in pair with the ones used to generate Inclusion Verifier Circuit and the Commtiment in order to generate a valid proof. + +## Incremental Nova Verifier + +The Incremental Nova Verifier is an experimental feature that allows a user to verify a sequence of proofs of inclusion in one shot. More details can be found in the [write up](https://hackmd.io/@summa/HkGMF4Ovn). + +We provide an example to test the Nova verifier. The build folder already contains the artifacts generated by the circuit compilation. If you want to recompile the circuit, you can run the following command: + +``` +$ cd src/circom +$ npm install +$ circom incremental_mst_inclusion.circom --r1cs --wasm -o ../../examples/build --prime bn128 +``` + +To run the Nova Incremental Verifier example run: + +``` +cargo run --release --example nova_incremental_verifier +``` + +## Benches + +The benchmarking included the following areas: + +- Merkle Sum Tree Generation +- Verification Key Gen for MstInclusion Circuit +- Proving Key Gen for MstInclusion Circuit +- ZK Proof Generation for MstInclusion Circuit +- ZK Proof Verification for MstInclusion Circuit + +In order to run the benchmarking, we provide a set of dummy `username, balances` entries formatted in csv files. The csv files can be downloaded as follows + +```bash +mkdir -p benches/csv +cd benches/csv +wget https://summa-solvency.s3.eu-central-1.amazonaws.com/1_entry_2_20.zip +unzip 1_entry_2_20.zip +``` + +The file naming convention, such as `1_entry_2_20.csv`, follows the pattern `[number of cryptocurrency]_entry_2_[power of 2]`. In this example, `1_entry` indicates a single currency, and the `2_20` part represents $2^{20}$ entries in the file. These entries, which are intended to populate the Merkle sum tree and feed the zk prover, correspond to the number of users on the exchange. + +To run the benches + +`cargo bench` + +You can set the following parameters to run the benches: + +- `LEVELS` -> the number of entries in the merkle sum tree. By default it is set to 20, which means that the benches will run for 2^20 entries. +- `SAMPLE_SIZE` -> the number of samples to run for each bench. By default it is set to 10, which is the minimum allowed by criterion.rs +- `N_CURRENCIES` -> the number of currencies to be used in the benchmarking. By default it is set to 1. + +Note that the `k` of the circuit may vary based on the LEVELS + +Furthermore the benchmarking function `verify_zk_proof_benchmark` will also print out the proof size in bytes. + +## Current Benches + +Benchmark results are available at [Summa Gitbook](https://summa.gitbook.io/summa-book/backend/summa-solvency/benchmarks) diff --git a/tools/polyexen/circuit/solvency/zk_prover/benches/full_solvency_flow.rs b/tools/polyexen/circuit/solvency/zk_prover/benches/full_solvency_flow.rs new file mode 100644 index 0000000..6d21b64 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/benches/full_solvency_flow.rs @@ -0,0 +1,161 @@ +#![feature(generic_const_exprs)] +use criterion::{criterion_group, criterion_main, Criterion}; +use halo2_proofs::plonk::{keygen_pk, keygen_vk}; +use summa_solvency::{ + circuits::merkle_sum_tree::MstInclusionCircuit, + circuits::{ + utils::{full_prover, full_verifier, generate_setup_artifacts}, + WithInstances, + }, + merkle_sum_tree::{MerkleSumTree, Tree}, +}; + +const SAMPLE_SIZE: usize = 10; +const LEVELS: usize = 20; +const N_CURRENCIES: usize = 1; +const N_BYTES: usize = 8; + +fn build_mstree(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let csv_file = format!("benches/csv/{}_entry_2_{}.csv", N_CURRENCIES, LEVELS); + + let bench_name = format!( + "build Merkle sum tree for 2 power of {} entries with {} currencies", + LEVELS, N_CURRENCIES + ); + + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + MerkleSumTree::::from_csv(&csv_file).unwrap(); + }) + }); +} + +fn build_sorted_mstree(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let csv_file = format!("benches/csv/{}_entry_2_{}.csv", N_CURRENCIES, LEVELS); + + let bench_name = format!( + "build sorted Merkle sum tree for 2 power of {} entries with {} currencies", + LEVELS, N_CURRENCIES + ); + + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + MerkleSumTree::::from_csv_sorted(&csv_file).unwrap(); + }) + }); +} + +fn verification_key_gen_mst_inclusion_circuit(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let empty_circuit = MstInclusionCircuit::::init_empty(); + + let (params, _, _) = generate_setup_artifacts(13, None, empty_circuit.clone()).unwrap(); + + let bench_name = format!( + "gen verification key for 2 power of {} entries with {} currencies mst inclusion circuit", + LEVELS, N_CURRENCIES + ); + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + keygen_vk(¶ms, &empty_circuit).expect("vk generation should not fail"); + }) + }); +} + +fn proving_key_gen_mst_inclusion_circuit(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let empty_circuit = MstInclusionCircuit::::init_empty(); + + let (params, _, vk) = generate_setup_artifacts(13, None, empty_circuit.clone()).unwrap(); + + let bench_name = format!( + "gen proving key for 2 power of {} entries with {} currencies mst inclusion circuit", + LEVELS, N_CURRENCIES + ); + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + keygen_pk(¶ms, vk.clone(), &empty_circuit).expect("pk generation should not fail"); + }) + }); +} + +fn generate_zk_proof_mst_inclusion_circuit(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let empty_circuit = MstInclusionCircuit::::init_empty(); + + let (params, pk, _) = generate_setup_artifacts(13, None, empty_circuit).unwrap(); + + let csv_file = format!("benches/csv/{}_entry_2_{}.csv", N_CURRENCIES, LEVELS); + + let merkle_sum_tree = MerkleSumTree::::from_csv(&csv_file).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let bench_name = format!( + "generate zk proof - tree of 2 power of {} entries with {} currencies mst inclusion circuit", + LEVELS, N_CURRENCIES + ); + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + full_prover(¶ms, &pk, circuit.clone(), circuit.instances()); + }) + }); +} + +fn verify_zk_proof_mst_inclusion_circuit(_c: &mut Criterion) { + let mut criterion = Criterion::default().sample_size(SAMPLE_SIZE); + + let empty_circuit = MstInclusionCircuit::::init_empty(); + + let (params, pk, vk) = generate_setup_artifacts(13, None, empty_circuit).unwrap(); + + let csv_file = format!("benches/csv/{}_entry_2_{}.csv", N_CURRENCIES, LEVELS); + + let merkle_sum_tree = MerkleSumTree::::from_csv(&csv_file).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let proof = full_prover(¶ms, &pk, circuit.clone(), circuit.instances()); + + println!("proof size in bytes: {}", proof.len()); + + let bench_name = format!( + "verify zk proof - tree of 2 power of {} entries with {} currencies mst inclusion circuit", + LEVELS, N_CURRENCIES + ); + criterion.bench_function(&bench_name, |b| { + b.iter(|| { + full_verifier(¶ms, &vk, proof.clone(), circuit.instances()); + }) + }); +} + +criterion_group!( + benches, + build_mstree, + build_sorted_mstree, + verification_key_gen_mst_inclusion_circuit, + proving_key_gen_mst_inclusion_circuit, + generate_zk_proof_mst_inclusion_circuit, + verify_zk_proof_mst_inclusion_circuit, +); +criterion_main!(benches); diff --git a/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/calc_round_numbers.py b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/calc_round_numbers.py new file mode 100644 index 0000000..a656c2c --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/calc_round_numbers.py @@ -0,0 +1,120 @@ +# Credit: https://github.com/daira/pasta-hadeshash/blob/master/code/calc_round_numbers.py +from math import * + + +def sat_inequiv_alpha(p, t, R_F, R_P, alpha, M): + n = ceil(log(p, 2)) + N = int(n * t) + if alpha > 0: + R_F_1 = ( + 6 if M <= ((floor(log(p, 2) - ((alpha - 1) / 2.0))) * (t + 1)) else 10 + ) # Statistical + R_F_2 = ( + 1 + ceil(log(2, alpha) * min(M, n)) + ceil(log(t, alpha)) - R_P + ) # Interpolation + # R_F_3 = ceil(min(n, M) / float(3*log(alpha, 2))) - R_P # Groebner 1 + # R_F_3 = ((log(2, alpha) / float(2)) * min(n, M)) - R_P # Groebner 1 + R_F_3 = ( + 1 + (log(2, alpha) * min(M / float(3), log(p, 2) / float(2))) - R_P + ) # Groebner 1 + R_F_4 = ( + t + - 1 + + min( + (log(2, alpha) * M) / float(t + 1), + ((log(2, alpha) * log(p, 2)) / float(2)), + ) + - R_P + ) # Groebner 2 + # R_F_5 = ((1.0/(2*log((alpha**alpha)/float((alpha-1)**(alpha-1)), 2))) * min(n, M) + t - 2 - R_P) / float(t - 1) # Groebner 3 + R_F_max = max(ceil(R_F_1), ceil(R_F_2), ceil(R_F_3), ceil(R_F_4)) + return R_F >= R_F_max + elif alpha == (-1): + R_F_1 = 6 if M <= ((floor(log(p, 2) - 2)) * (t + 1)) else 10 # Statistical + R_P_1 = ( + 1 + ceil(0.5 * min(M, n)) + ceil(log(t, 2)) - floor(R_F * log(t, 2)) + ) # Interpolation + R_P_2 = 1 + ceil(0.5 * min(M, n)) + ceil(log(t, 2)) - floor(R_F * log(t, 2)) + R_P_3 = ( + t + - 1 + + ceil(log(t, 2)) + + min(ceil(M / float(t + 1)), ceil(0.5 * log(p, 2))) + - floor(R_F * log(t, 2)) + ) # Groebner 2 + R_F_max = ceil(R_F_1) + R_P_max = max(ceil(R_P_1), ceil(R_P_2), ceil(R_P_3)) + return R_F >= R_F_max and R_P >= R_P_max + else: + print("Invalid value for alpha!") + exit(1) + + +def get_sbox_cost(R_F, R_P, N, t): + return int(t * R_F + R_P) + + +def get_size_cost(R_F, R_P, N, t): + n = ceil(float(N) / t) + return int((N * R_F) + (n * R_P)) + + +def get_depth_cost(R_F, R_P, N, t): + return int(R_F + R_P) + + +def find_FD_round_numbers(p, t, alpha, M, cost_function, security_margin): + n = ceil(log(p, 2)) + N = int(n * t) + + sat_inequiv = sat_inequiv_alpha + + R_P = 0 + R_F = 0 + min_cost = float("inf") + max_cost_rf = 0 + # Brute-force approach + for R_P_t in range(1, 500): + for R_F_t in range(4, 100): + if R_F_t % 2 == 0: + if sat_inequiv(p, t, R_F_t, R_P_t, alpha, M) == True: + if security_margin == True: + R_F_t += 2 + R_P_t = int(ceil(float(R_P_t) * 1.075)) + cost = cost_function(R_F_t, R_P_t, N, t) + if (cost < min_cost) or ( + (cost == min_cost) and (R_F_t < max_cost_rf) + ): + R_P = ceil(R_P_t) + R_F = ceil(R_F_t) + min_cost = cost + max_cost_rf = R_F + return (int(R_F), int(R_P)) + + +def calc_final_numbers_fixed(p, t, alpha, M, security_margin): + # [Min. S-boxes] Find best possible for t and N + n = ceil(log(p, 2)) + N = int(n * t) + cost_function = get_sbox_cost + ret_list = [] + (R_F, R_P) = find_FD_round_numbers(p, t, alpha, M, cost_function, security_margin) + min_sbox_cost = cost_function(R_F, R_P, N, t) + ret_list.append(R_F) + ret_list.append(R_P) + ret_list.append(min_sbox_cost) + + # [Min. Size] Find best possible for t and N + # Minimum number of S-boxes for fixed n results in minimum size also (round numbers are the same)! + min_size_cost = get_size_cost(R_F, R_P, N, t) + ret_list.append(min_size_cost) + + return ret_list # [R_F, R_P, min_sbox_cost, min_size_cost] + + +# Modify this function to return results instead of printing them +def get_parameters(prime, t, alpha, M, security_margin): + [R_F, R_P, min_sbox_cost, min_size_cost] = calc_final_numbers_fixed( + prime, t, alpha, M, security_margin + ) + return t, M, alpha, security_margin, R_F, R_P, min_sbox_cost, min_size_cost \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_parameters_grain.sage b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_parameters_grain.sage new file mode 100644 index 0000000..e6db456 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_parameters_grain.sage @@ -0,0 +1,407 @@ +# Credit: https://github.com/daira/pasta-hadeshash/blob/master/code/generate_parameters_grain.sage +#!/usr/bin/env sage + +# Remark: This script contains functionality for GF(2^n), but currently works only over GF(p)! A few small adaptations are needed for GF(2^n). +from sage.rings.polynomial.polynomial_gf2x import GF2X_BuildIrred_list + +# Note that R_P is increased to the closest multiple of t +# GF(p), alpha=3, N = 1536, n = 64, t = 24, R_F = 8, R_P = 42: sage generate_parameters_grain.sage 1 0 64 24 8 42 0xfffffffffffffeff +# GF(p), alpha=5, N = 1524, n = 254, t = 6, R_F = 8, R_P = 60: sage generate_parameters_grain.sage 1 0 254 6 8 60 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +# GF(p), x^(-1), N = 1518, n = 253, t = 6, R_F = 8, R_P = 60: sage generate_parameters_grain.sage 1 1 253 6 8 60 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + +# GF(p), alpha=5, N = 765, n = 255, t = 3, R_F = 8, R_P = 57: sage generate_parameters_grain.sage 1 0 255 3 8 57 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +# GF(p), alpha=5, N = 1275, n = 255, t = 5, R_F = 8, R_P = 60: sage generate_parameters_grain.sage 1 0 255 5 8 60 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +# GF(p), alpha=5, N = 762, n = 254, t = 3, R_F = 8, R_P = 57: sage generate_parameters_grain.sage 1 0 254 3 8 57 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +# GF(p), alpha=5, N = 1270, n = 254, t = 5, R_F = 8, R_P = 60: sage generate_parameters_grain.sage 1 0 254 5 8 60 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + +FIELD = None +SBOX = None +FIELD_SIZE = None +NUM_CELLS = None +R_F_FIXED = None +R_P_FIXED = None +PRIME_NUMBER = None +F = None +INIT_SEQUENCE = None + +def grain_sr_generator(): + bit_sequence = INIT_SEQUENCE + for _ in range(0, 160): + new_bit = bit_sequence[62] ^^ bit_sequence[51] ^^ bit_sequence[38] ^^ bit_sequence[23] ^^ bit_sequence[13] ^^ bit_sequence[0] + bit_sequence.pop(0) + bit_sequence.append(new_bit) + + while True: + new_bit = bit_sequence[62] ^^ bit_sequence[51] ^^ bit_sequence[38] ^^ bit_sequence[23] ^^ bit_sequence[13] ^^ bit_sequence[0] + bit_sequence.pop(0) + bit_sequence.append(new_bit) + while new_bit == 0: + new_bit = bit_sequence[62] ^^ bit_sequence[51] ^^ bit_sequence[38] ^^ bit_sequence[23] ^^ bit_sequence[13] ^^ bit_sequence[0] + bit_sequence.pop(0) + bit_sequence.append(new_bit) + new_bit = bit_sequence[62] ^^ bit_sequence[51] ^^ bit_sequence[38] ^^ bit_sequence[23] ^^ bit_sequence[13] ^^ bit_sequence[0] + bit_sequence.pop(0) + bit_sequence.append(new_bit) + new_bit = bit_sequence[62] ^^ bit_sequence[51] ^^ bit_sequence[38] ^^ bit_sequence[23] ^^ bit_sequence[13] ^^ bit_sequence[0] + bit_sequence.pop(0) + bit_sequence.append(new_bit) + yield new_bit +grain_gen = grain_sr_generator() + +def grain_random_bits(num_bits): + random_bits = [next(grain_gen) for i in range(0, num_bits)] + # random_bits.reverse() ## Remove comment to start from least significant bit + random_int = int("".join(str(i) for i in random_bits), 2) + return random_int + +def init_generator(field, sbox, n, t, R_F, R_P): + # Generate initial sequence based on parameters + bit_list_field = [_ for _ in (bin(FIELD)[2:].zfill(2))] + bit_list_sbox = [_ for _ in (bin(SBOX)[2:].zfill(4))] + bit_list_n = [_ for _ in (bin(FIELD_SIZE)[2:].zfill(12))] + bit_list_t = [_ for _ in (bin(NUM_CELLS)[2:].zfill(12))] + bit_list_R_F = [_ for _ in (bin(R_F)[2:].zfill(10))] + bit_list_R_P = [_ for _ in (bin(R_P)[2:].zfill(10))] + bit_list_1 = [1] * 30 + global INIT_SEQUENCE + INIT_SEQUENCE = bit_list_field + bit_list_sbox + bit_list_n + bit_list_t + bit_list_R_F + bit_list_R_P + bit_list_1 + INIT_SEQUENCE = [int(_) for _ in INIT_SEQUENCE] + +def generate_constants(field, n, t, R_F, R_P, prime_number): + round_constants = [] + num_constants = (R_F + R_P) * t + + if field == 0: + for i in range(0, num_constants): + random_int = grain_random_bits(n) + round_constants.append(random_int) + elif field == 1: + for i in range(0, num_constants): + random_int = grain_random_bits(n) + while random_int >= prime_number: + # print("[Info] Round constant is not in prime field! Taking next one.") + random_int = grain_random_bits(n) + round_constants.append(random_int) + return round_constants + +def print_hex(c, last, rust=False): + c = int(c) + hex_str = "" + if rust: + hex_str += " Fp::from_raw([\n" + for i in range(0, FIELD_SIZE, 64): + hex_str += " 0x%04x_%04x_%04x_%04x,\n" % tuple([(c >> j) & 0xFFFF for j in range(i+48, i-1, -16)]) + hex_str += " ]),\n" + else: + hex_length = (FIELD_SIZE + 3)//4 + 2 # +2 for "0x" + hex_str += "{0:#0{1}x}".format(c, hex_length) + ("" if last else ", ") + return hex_str + +def print_round_constants(round_constants, n, t, field, R_F, R_P, rust=False, file_name="./../src/chips/poseidon/poseidon_params.rs"): + num_round_constants = len(round_constants) + assert num_round_constants % t == 0 + rounds = num_round_constants // t # R_F + R_P + with open(file_name, 'w') as f: + f.write("//! This file was generated by running generate_params.py\n") + f.write("//! Number of round constants: {}\n".format(num_round_constants)) + + if field == 0: + f.write("//! Round constants for GF(2^n):\n") + elif field == 1: + f.write("//! Round constants for GF(p):\n") + if rust: + f.write("//! Parameters for using rate {} Poseidon with the BN256 field.\n".format(t - 1)) + f.write("//! Patterned after [halo2_gadgets::poseidon::primitives::fp]\n") + f.write("//! The parameters can be reproduced by running the following Sage script from\n") + f.write("//! [this repository](https://github.com/daira/pasta-hadeshash):\n") + f.write("//!\n//! ```text\n//! $ sage generate_parameters_grain.sage 1 0 254 {} {} {} 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 --rust\n//! ```\n//!\n".format(t, R_F, R_P)) + f.write("//! where 1 means 'prime field', 0 means 'non-negative sbox', 254 is the bitsize\n//! of the field, {} is the Poseidon width (rate + 1), {} is the number of full\n//! rounds, {} is the number of partial rounds.\n//! More info here => https://hackmd.io/@letargicus/SJOvx48Nn\n".format(t, R_F, R_P)) + f.write("use halo2_proofs::halo2curves::bn256::Fr as Fp;\n") + f.write("pub(crate) const ROUND_CONSTANTS: [[Fp; {}]; {}] = [\n".format(t, rounds)) + + for r in range(rounds): + f.write(" [\n" if rust else " [") + for (i, entry) in enumerate(round_constants[r*t : (r+1)*t]): + f.write(print_hex(entry, i == t-1, rust=rust)) + f.write(" ],\n" if rust else "],\n") + if rust: + f.write("];\n") + +def create_mds_p(n, t): + M = matrix(F, t, t) + + # Sample random distinct indices and assign to xs and ys + while True: + flag = True + rand_list = [F(grain_random_bits(n)) for _ in range(0, 2*t)] + while len(rand_list) != len(set(rand_list)): # Check for duplicates + rand_list = [F(grain_random_bits(n)) for _ in range(0, 2*t)] + xs = rand_list[:t] + ys = rand_list[t:] + # xs = [F(ele) for ele in range(0, t)] + # ys = [F(ele) for ele in range(t, 2*t)] + for i in range(0, t): + for j in range(0, t): + if (flag == False) or ((xs[i] + ys[j]) == 0): + flag = False + else: + entry = (xs[i] + ys[j])^(-1) + M[i, j] = entry + if flag == False: + continue + return M + +def generate_vectorspace(round_num, M, M_round, NUM_CELLS): + t = NUM_CELLS + s = 1 + V = VectorSpace(F, t) + if round_num == 0: + return V + elif round_num == 1: + return V.subspace(V.basis()[s:]) + else: + mat_temp = matrix(F) + for i in range(0, round_num-1): + add_rows = [] + for j in range(0, s): + add_rows.append(M_round[i].rows()[j][s:]) + mat_temp = matrix(mat_temp.rows() + add_rows) + r_k = mat_temp.right_kernel() + extended_basis_vectors = [] + for vec in r_k.basis(): + extended_basis_vectors.append(vector([0]*s + list(vec))) + S = V.subspace(extended_basis_vectors) + + return S + +def subspace_times_matrix(subspace, M, NUM_CELLS): + t = NUM_CELLS + V = VectorSpace(F, t) + subspace_basis = subspace.basis() + new_basis = [] + for vec in subspace_basis: + new_basis.append(M * vec) + new_subspace = V.subspace(new_basis) + return new_subspace + +# Returns True if the matrix is considered secure, False otherwise +def algorithm_1(M, NUM_CELLS): + t = NUM_CELLS + s = 1 + r = floor((t - s) / float(s)) + + # Generate round matrices + M_round = [] + for j in range(0, t+1): + M_round.append(M^(j+1)) + + for i in range(1, r+1): + mat_test = M^i + entry = mat_test[0, 0] + mat_target = matrix.circulant(vector([entry] + ([F(0)] * (t-1)))) + + if (mat_test - mat_target) == matrix.circulant(vector([F(0)] * (t))): + return [False, 1] + + S = generate_vectorspace(i, M, M_round, t) + V = VectorSpace(F, t) + + basis_vectors= [] + for eigenspace in mat_test.eigenspaces_right(format='galois'): + if (eigenspace[0] not in F): + continue + vector_subspace = eigenspace[1] + intersection = S.intersection(vector_subspace) + basis_vectors += intersection.basis() + IS = V.subspace(basis_vectors) + + if IS.dimension() >= 1 and IS != V: + return [False, 2] + for j in range(1, i+1): + S_mat_mul = subspace_times_matrix(S, M^j, t) + if S == S_mat_mul: + print("S.basis():\n", S.basis()) + return [False, 3] + + return [True, 0] + +# Returns True if the matrix is considered secure, False otherwise +def algorithm_2(M, NUM_CELLS): + t = NUM_CELLS + s = 1 + + V = VectorSpace(F, t) + trail = [None, None] + test_next = False + I = range(0, s) + I_powerset = list(sage.misc.misc.powerset(I))[1:] + for I_s in I_powerset: + test_next = False + new_basis = [] + for l in I_s: + new_basis.append(V.basis()[l]) + IS = V.subspace(new_basis) + for i in range(s, t): + new_basis.append(V.basis()[i]) + full_iota_space = V.subspace(new_basis) + for l in I_s: + v = V.basis()[l] + while True: + delta = IS.dimension() + v = M * v + IS = V.subspace(IS.basis() + [v]) + if IS.dimension() == t or IS.intersection(full_iota_space) != IS: + test_next = True + break + if IS.dimension() <= delta: + break + if test_next == True: + break + if test_next == True: + continue + return [False, [IS, I_s]] + + return [True, None] + +# Returns True if the matrix is considered secure, False otherwise +def algorithm_3(M, NUM_CELLS): + t = NUM_CELLS + s = 1 + + V = VectorSpace(F, t) + + l = 4*t + for r in range(2, l+1): + next_r = False + res_alg_2 = algorithm_2(M^r, t) + if res_alg_2[0] == False: + return [False, None] + + # if res_alg_2[1] == None: + # continue + # IS = res_alg_2[1][0] + # I_s = res_alg_2[1][1] + # for j in range(1, r): + # IS = subspace_times_matrix(IS, M, t) + # I_j = [] + # for i in range(0, s): + # new_basis = [] + # for k in range(0, t): + # if k != i: + # new_basis.append(V.basis()[k]) + # iota_space = V.subspace(new_basis) + # if IS.intersection(iota_space) != iota_space: + # single_iota_space = V.subspace([V.basis()[i]]) + # if IS.intersection(single_iota_space) == single_iota_space: + # I_j.append(i) + # else: + # next_r = True + # break + # if next_r == True: + # break + # if next_r == True: + # continue + # return [False, [IS, I_j, r]] + + return [True, None] + +def generate_matrix(FIELD, FIELD_SIZE, NUM_CELLS): + if FIELD == 0: + print("Matrix generation not implemented for GF(2^n).") + exit(1) + elif FIELD == 1: + mds_matrix = create_mds_p(FIELD_SIZE, NUM_CELLS) + result_1 = algorithm_1(mds_matrix, NUM_CELLS) + result_2 = algorithm_2(mds_matrix, NUM_CELLS) + result_3 = algorithm_3(mds_matrix, NUM_CELLS) + while result_1[0] == False or result_2[0] == False or result_3[0] == False: + mds_matrix = create_mds_p(FIELD_SIZE, NUM_CELLS) + result_1 = algorithm_1(mds_matrix, NUM_CELLS) + result_2 = algorithm_2(mds_matrix, NUM_CELLS) + result_3 = algorithm_3(mds_matrix, NUM_CELLS) + return mds_matrix + +def invert_matrix(M): + MS = MatrixSpace(F, NUM_CELLS, NUM_CELLS, sparse=False) + return MS.matrix(M).inverse() + +def print_matrix(M, t, rust=False, file_name="./../src/chips/poseidon/poseidon_params.rs"): + # 'a' for append mode + with open(file_name, 'a') as f: + for row in range(t): + f.write(" [\n" if rust else "") + for (i, entry) in enumerate(M[row]): + f.write(print_hex(entry, i == t-1, rust=rust)) + f.write(" ]," if rust else "],") + f.write("\n];\n") + +def print_linear_layer(M, n, t, rust=False, file_name="./../src/chips/poseidon/poseidon_params.rs"): + # 'a' for append mode + with open(file_name, 'a') as f: + f.write("// n: {}\n".format(n)) + f.write("// t: {}\n".format(t)) + f.write("// N: {}\n".format(n * t)) + f.write("// Result Algorithm 1:\n") + f.write("// {}\n".format(algorithm_1(M, NUM_CELLS))) + f.write("// Result Algorithm 2:\n") + f.write("// {}\n".format(algorithm_2(M, NUM_CELLS))) + f.write("// Result Algorithm 3:\n") + f.write("// {}\n".format(algorithm_3(M, NUM_CELLS))) + f.write("// Prime number: {}\n".format("0x" + hex(PRIME_NUMBER))) + + f.write("// MDS matrix:\n") + f.write("pub(crate) const MDS: [[Fp; {}]; {}] = [\n".format(t, t) if rust else "") + + print_matrix(M, t, rust=rust, file_name=file_name) + + with open(file_name, 'a') as f: + f.write("// Inverse MDS matrix:\n") + f.write("pub(crate) const MDS_INV: [[Fp; {}]; {}] = [\n".format(t, t) if rust else "") + + print_matrix(invert_matrix(M), t, rust=rust, file_name=file_name) + +def main(args): + if len(args) < 7: + print("Usage: sage generate_parameters_grain.sage () [--rust]") + print("field = 1 for GF(p)") + print("s_box = 0 for x^alpha, s_box = 1 for x^(-1)") + return + + # Parameters + global FIELD, SBOX, FIELD_SIZE, NUM_CELLS, R_F_FIXED, R_P_FIXED, PRIME_NUMBER, F + + FIELD = int(args[0]) # 0 .. GF(2^n), 1 .. GF(p) + SBOX = int(args[1]) # 0 .. x^alpha, 1 .. x^(-1) + FIELD_SIZE = int(args[2]) # n + NUM_CELLS = int(args[3]) # t + R_F_FIXED = int(args[4]) + R_P_FIXED = int(args[5]) + + PRIME_NUMBER = 0 + if FIELD == 0: + args = args[6:] + elif FIELD == 1 and len(args) < 7: + print("Please specify a prime number (in hex format)!") + return + elif FIELD == 1 and len(args) >= 7: + PRIME_NUMBER = int(args[6], 16) # e.g. 0xa7, 0xFFFFFFFFFFFFFEFF, 0xa1a42c3efd6dbfe08daa6041b36322ef + args = args[7:] + + F = GF(PRIME_NUMBER) + + file_name = args[0] + rust = '--rust' in args + + # Init + init_generator(FIELD, SBOX, FIELD_SIZE, NUM_CELLS, R_F_FIXED, R_P_FIXED) + + # Round constants + round_constants = generate_constants(FIELD, FIELD_SIZE, NUM_CELLS, R_F_FIXED, R_P_FIXED, PRIME_NUMBER) + print_round_constants(round_constants, FIELD_SIZE, NUM_CELLS, FIELD, R_F_FIXED, R_P_FIXED, rust=rust, file_name=file_name) + + # Matrix + linear_layer = generate_matrix(FIELD, FIELD_SIZE, NUM_CELLS) + print_linear_layer(linear_layer, FIELD_SIZE, NUM_CELLS, rust=rust, file_name=file_name) + +if __name__ == "__main__": + main(sys.argv[1:]) \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_params.py b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_params.py new file mode 100644 index 0000000..9b5eddd --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/circuit_parameters_gen/generate_params.py @@ -0,0 +1,95 @@ +import os +from calc_round_numbers import get_parameters + +# Parameters +p = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001 + +t = 2 # Poseidon hasher width +M = 128 + +# Call the function and get the parameters +t, M, alpha, security_margin, R_F, R_P, min_sbox_cost, min_size_cost = get_parameters( + p, t, 5, M, True +) + +# Round R_P up to the nearest multiple of t +R_P = ((R_P + t - 1) // t) * t + +# Add one more t if partial rounds number is not even +if R_P % 2 != 0: + R_P += t + +command = f"sage generate_parameters_grain.sage 1 0 254 {t} {R_F} {R_P} 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 './../src/chips/poseidon/poseidon_params.rs' --rust" +os.system(command) + + +def generate_spec(t, alpha, R_F, R_P, file_name): + with open(file_name, "w") as f: + f.write("//! This file was generated by running generate_params.py\n") + f.write( + "//! Specification for rate {} Poseidon using the BN256 curve.".format( + t - 1 + ) + ) + f.write("\n") + f.write( + "//! Patterned after [halo2_gadgets::poseidon::primitives::P128Pow5T3]\n" + ) + + f.write("use crate::chips::poseidon::poseidon_params;\n") + f.write("use halo2_gadgets::poseidon::primitives::*;\n") + f.write("use halo2_proofs::arithmetic::Field;\n") + f.write("use halo2_proofs::halo2curves::bn256::Fr as Fp;\n") + f.write("\n") + f.write("#[derive(Debug, Clone, Copy)]\n") + f.write("pub struct PoseidonSpec;\n") + f.write("\n") + f.write("pub(crate) type Mds = [[Fp; T]; T];\n") + f.write("\n") + f.write("impl Spec for PoseidonSpec {{\n".format(t, t - 1)) + f.write(" fn full_rounds() -> usize {\n") + f.write(" {}\n".format(R_F)) + f.write(" }\n") + f.write("\n") + f.write(" fn partial_rounds() -> usize {\n") + f.write(" {}\n".format(R_P)) + f.write(" }\n") + f.write("\n") + f.write(" fn sbox(val: Fp) -> Fp {\n") + f.write(" val.pow_vartime([{}])\n".format(alpha)) + f.write(" }\n") + f.write("\n") + f.write(" fn secure_mds() -> usize {\n") + f.write(" unimplemented!()\n") + f.write(" }\n") + f.write("\n") + f.write( + " fn constants() -> (Vec<[Fp; {}]>, Mds, Mds) {{\n".format( + t, t, t + ) + ) + f.write(" (\n") + f.write(" poseidon_params::ROUND_CONSTANTS[..].to_vec(),\n") + f.write(" poseidon_params::MDS,\n") + f.write(" poseidon_params::MDS_INV,\n") + f.write(" )\n") + f.write(" }\n") + f.write("}\n") + + +file_name = "./../src/chips/poseidon/poseidon_spec.rs" +generate_spec(t, alpha, R_F, R_P, file_name) + +# Print the results +def print_results(t, M, alpha, security_margin, R_F, R_P, min_sbox_cost, min_size_cost): + print(f"t = {t}") + print(f"M = {M}") + print(f"alpha = {alpha}") + print(f"security_margin = {security_margin}") + print(f"R_F = {R_F}") + print(f"R_P = {R_P}") + print(f"min_sbox_cost = {min_sbox_cost}") + print(f"min_size_cost = {min_size_cost}") + + +print_results(t, M, alpha, security_margin, R_F, R_P, min_sbox_cost, min_size_cost) diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion.r1cs b/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion.r1cs new file mode 100644 index 0000000..d7258e5 Binary files /dev/null and b/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion.r1cs differ diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion_js/incremental_mst_inclusion.wasm b/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion_js/incremental_mst_inclusion.wasm new file mode 100644 index 0000000..7878c72 Binary files /dev/null and b/tools/polyexen/circuit/solvency/zk_prover/examples/build/incremental_mst_inclusion_js/incremental_mst_inclusion.wasm differ diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/commitment_solidity_calldata.json b/tools/polyexen/circuit/solvency/zk_prover/examples/commitment_solidity_calldata.json new file mode 100644 index 0000000..90faf8a --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/commitment_solidity_calldata.json @@ -0,0 +1,7 @@ +{ + "root_hash": "0x18d6ab953235a811edffa4cead74ea045e7cd2085771a2269d59dca054c955b1", + "root_balances": [ + "0x87f3e", + "0x87f3e" + ] +} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/gen_commitment.rs b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_commitment.rs new file mode 100644 index 0000000..7c841e1 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_commitment.rs @@ -0,0 +1,41 @@ +#![feature(generic_const_exprs)] + +use serde_json::to_string_pretty; +use std::{fs::File, io::Write}; +use summa_solvency::{ + circuits::types::CommitmentSolidityCallData, + circuits::utils::field_element_to_solidity_calldata, + merkle_sum_tree::{MerkleSumTree, Tree}, +}; + +const N_CURRENCIES: usize = 2; +const N_BYTES: usize = 8; + +fn main() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let root = merkle_sum_tree.root(); + + // The commitment to be published on-chain is made of (root_hash, root_balances) + let root_hash_hex_string = field_element_to_solidity_calldata(root.hash); + let root_balances_hex_strings: Vec = root + .balances + .iter() + .map(|balance| field_element_to_solidity_calldata(*balance)) + .collect(); + + let commitment = CommitmentSolidityCallData { + root_hash: root_hash_hex_string, + root_balances: root_balances_hex_strings, + }; + + // Serialize to a JSON string + let serialized_data = to_string_pretty(&commitment).expect("Failed to serialize data"); + + // Save the serialized data to a JSON file + let mut file = File::create("./examples/commitment_solidity_calldata.json") + .expect("Unable to create file"); + file.write_all(serialized_data.as_bytes()) + .expect("Unable to write data to file"); +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_proof.rs b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_proof.rs new file mode 100644 index 0000000..1069fb2 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_proof.rs @@ -0,0 +1,93 @@ +#![feature(generic_const_exprs)] + +use ethers::abi::parse_abi; +use ethers::abi::Token::{Array, Bytes, Uint}; +use halo2_solidity_verifier::{compile_solidity, BatchOpenScheme::Bdfg21, Evm, SolidityGenerator}; +use serde_json::to_string_pretty; +use std::{fs::File, io::Write}; +use summa_solvency::{ + circuits::{ + merkle_sum_tree::MstInclusionCircuit, + types::ProofSolidityCallData, + utils::{gen_proof_solidity_calldata, generate_setup_artifacts}, + WithInstances, + }, + merkle_sum_tree::{MerkleSumTree, Tree}, +}; + +const LEVELS: usize = 4; +const N_CURRENCIES: usize = 2; +const N_BYTES: usize = 8; + +fn main() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + // In order to generate a proof for testing purpose we create the circuit using the init() method + // which takes as input the merkle sum tree and the index of the leaf we are generating the proof for. + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Generate the circuit with the actual inputs + let circuit = MstInclusionCircuit::::init(merkle_proof); + + // generate a universal trusted setup for testing, along with the verification key (vk) and the proving key (pk). + let (params, pk, _) = + generate_setup_artifacts(11, Some("../backend/ptau/hermez-raw-11"), circuit.clone()) + .unwrap(); + + let num_instances = circuit.num_instances(); + + let generator: SolidityGenerator<'_> = + SolidityGenerator::new(¶ms, pk.get_vk(), Bdfg21, num_instances); + let verifier_solidity = generator + .render() + .unwrap() + .replace("Halo2Verifier", "Verifier"); + let deployment_code = compile_solidity(&verifier_solidity); + + let proof_solidity_calldata = gen_proof_solidity_calldata(¶ms, &pk, circuit.clone()); + + let proof_hex_string = format!("0x{}", hex::encode(&proof_solidity_calldata.clone().0 .0)); + + let calldata_instances = proof_solidity_calldata.1.clone(); + + let data = ProofSolidityCallData { + proof: proof_hex_string, + public_inputs: proof_solidity_calldata.1, + }; + + // Serialize the data to a JSON string + let serialized_data = to_string_pretty(&data).expect("Failed to serialize data"); + + // Save the serialized data to a JSON file + let mut file = File::create("./examples/inclusion_proof_solidity_calldata.json") + .expect("Unable to create file"); + file.write_all(serialized_data.as_bytes()) + .expect("Unable to write data to file"); + + let abi = parse_abi(&[ + "function verifyProof(bytes calldata proof, uint256[] calldata instances) public returns (bool)", + ]).expect("Invalid ABI"); + + let function = abi.function("verifyProof").unwrap(); + let calldata_encoded = function + .encode_input(&[ + Bytes(proof_solidity_calldata.0.to_vec()), + Array( + calldata_instances + .iter() + .map(|&instance| Uint(instance)) + .collect(), + ), + ]) + .unwrap(); + + let mut evm = Evm::default(); + let verifier_address = evm.create(deployment_code); + + let (gas_cost, output) = evm.call(verifier_address, calldata_encoded); + assert_eq!(output, [vec![0; 31], vec![1]].concat()); + println!("gas_cost: {:?}", gas_cost); +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_verifier.rs b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_verifier.rs new file mode 100644 index 0000000..ca1b1dc --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/gen_inclusion_verifier.rs @@ -0,0 +1,94 @@ +#![feature(generic_const_exprs)] + +use halo2_proofs::halo2curves::{bn256::Fr as Fp, ff::PrimeField}; +use num_bigint::BigInt; +use num_traits::Num; +use prelude::*; + +use halo2_solidity_verifier::{compile_solidity, BatchOpenScheme::Bdfg21, SolidityGenerator}; +use summa_solvency::circuits::utils::generate_setup_artifacts; +use summa_solvency::circuits::{merkle_sum_tree::MstInclusionCircuit, WithInstances}; + +const LEVELS: usize = 4; +const N_CURRENCIES: usize = 2; +const N_BYTES: usize = 8; + +fn main() { + // Assert that there is no risk of overflow in the Merkle Root given the combination of `N_BYTES` and `LEVELS` + assert!(!is_there_risk_of_overflow(N_BYTES, LEVELS), "There is a risk of balance overflow in the Merkle Root, given the combination of `N_BYTES` and `LEVELS`"); + + // In order to generate the verifier we create the circuit using the init_empty() method, which means that the circuit is not initialized with any data. + let circuit = MstInclusionCircuit::::init_empty(); + + // generate a universal trusted setup for testing, along with the verification key (vk) and the proving key (pk). + let (params, pk, _) = + generate_setup_artifacts(11, Some("../backend/ptau/hermez-raw-11"), circuit.clone()) + .unwrap(); + + let num_instances = circuit.num_instances(); + + let generator: SolidityGenerator<'_> = + SolidityGenerator::new(¶ms, pk.get_vk(), Bdfg21, num_instances); + let verifier_solidity = generator + .render() + .unwrap() + .replace("Halo2Verifier", "Verifier") + .replace(") public returns (bool)", ") public view returns (bool)"); + save_solidity("InclusionVerifier.sol", &verifier_solidity); + let deployment_code = compile_solidity(&verifier_solidity); + let verifier_creation_code_size = deployment_code.len(); + println!("Verifier creation code size: {verifier_creation_code_size}"); +} + +fn save_solidity(name: impl AsRef, solidity: &str) { + const DIR_GENERATED: &str = "../contracts/src"; + + create_dir_all(DIR_GENERATED).unwrap(); + let path = format!("{DIR_GENERATED}/{}", name.as_ref()); + File::create(&path) + .unwrap() + .write_all(solidity.as_bytes()) + .unwrap(); + println!("Saved {path}"); +} + +// Calculate the maximum value that the Merkle Root can have, given N_BYTES and LEVELS +fn calculate_max_root_balance(n_bytes: usize, n_levels: usize) -> BigInt { + // The max value that can be stored in a leaf node or a sibling node, according to the constraint set in the circuit + let max_leaf_value = BigInt::from(2).pow(n_bytes as u32 * 8) - 1; + max_leaf_value * (n_levels + 1) +} + +// Given a combination of `N_BYTES` and `LEVELS`, check if there is a risk of overflow in the Merkle Root +fn is_there_risk_of_overflow(n_bytes: usize, n_levels: usize) -> bool { + // Calculate the max root balance value + let max_root_balance = calculate_max_root_balance(n_bytes, n_levels); + + // The modulus of the BN256 curve + let modulus = BigInt::from_str_radix(&Fp::MODULUS[2..], 16).unwrap(); + + // Check if the max balance value is greater than the prime + max_root_balance > modulus +} + +mod prelude { + pub use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::{ + bn256::{Bn256, Fr, G1Affine}, + ff::PrimeField, + }, + plonk::*, + poly::{commitment::Params, kzg::commitment::ParamsKZG, Rotation}, + }; + pub use rand::{ + rngs::{OsRng, StdRng}, + RngCore, SeedableRng, + }; + pub use std::{ + collections::HashMap, + fs::{create_dir_all, File}, + io::Write, + ops::Range, + }; +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/inclusion_proof_solidity_calldata.json b/tools/polyexen/circuit/solvency/zk_prover/examples/inclusion_proof_solidity_calldata.json new file mode 100644 index 0000000..1d91831 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/inclusion_proof_solidity_calldata.json @@ -0,0 +1,9 @@ +{ + "proof": "0x099b655a72ad66888e1964305886c4c7993003b17ede68bc0546df28b077383701a9ff5f760f73c77ca2f768f10dfaced92fa87024be1d601470a35e1793f899012d48bcd264318f9739ded71a1177157ad18f37539b2dba5941aee67c955a9410f8f04a49c0ad9033fd8f96512abf2800ab36c333a73012b8da2ec5244923650b80abae3df7952513e169ce514bf7103062adf5c514b1889990a1f64f0e0981239bebd5877800a3a03b79832f426290cdb4da8aac2144139102bad984f4b94a159ccbadd7cfe525f5d6f48af294e4a8c1ebe342119273aafe1e986dbbaef6ea28f6d5db9a2e79ee2dcdff182b46b87457233de006ef08a1e2c2e168dad8d6bf305e4b48cbe8b3a793f80f9c1562c7abce178ea8672a45c0446d2c228e22464f2a28a38007d658d42426e790b193c38216c6df6494ee7c159b5e1ea006770f6424e48b02b4989c61743c8fe3d82e84581022f5100dbccdeed3257f24c6a1d47910a94b83a006c3b30d63933aee5176f5543761c7752175f82844e731324713560e4853fd3805e5765c719a73fb95f73a3a86eb597b41bb59a0798ae3a4061a212b85163e0c310af30d02a575a98ac81e4900ce5f4b899536301d8e75288f6748266b81397f57a9af767ba06f567336897f1395a3a8301e56604ffc04f7e762260616e31fb24b6caf2a581a5729921f6099996ef398c3f65fe59b50c3474d2cb30712a7500f4aeb7944268209de779ee3549bc088665c8d37e8ef0205123454ff2980dd7a99e4f8b665ca7d1e5199ddef3f1dda49e7d5bf5d4a0e1b3e43ab88952a88d12a96d037e5b7adab8991fc91abd56dafbd481fc9b1515f5cfeb06d922b03a6c89deda321893ab7414258d7424ed06d95e3c5ba140c3450e9605315dbaa041cfbf78d5a531fb20ed973b10a078fd9c0fa61cfdfc44275a4de2488fe2aa11fd6df19d45b2fb315d11c4635b16b09937d7a64c9980f0b80442fa163f5d13f0135c4ea16e5b160ed0ace73e9304702fe2c89230e194eeb17f15ad34218cf920ef036144cbc71a1d5af606f69a0199b3c95aaa3f7b76d4acc43930f23855fe3080110255a5f74dbc664f90550f0e2cba1c7abee1cedee6c957335ac529837f1281f96debb692df148c384c3601a62316cf660efc3aaa9aeda7541a6f9e1780d008c006cabd4c71f88f586bbe3dcaaff491a4d64e711720826de1e917ecc843b160e76eb81806c35439a995562e8c98bd29d23d2ccbfbb576ea3a068626886da1f0f6af74d39cd467882f75cd14aeb9dbaf6c04fb386019f69f9d052d9073ee72f65c01f4e37ef15eccd33ef3f374775be266c5a2ea9185ada549c88fdbb2e0e2d70a0d1a6f6477556d7bf092b85820409c9f9812b14b53d000aba9be503791106a8f2a5808ccecca9334e0df14dedf6c504e0e36fa3f55e616afd6f2fbf67382efefcf5369e6ec9b3e00a37d1f124a147628722f473157a51b1f4133e2238bd015b1508d310e271cdd0b7ab682472188d81dbdcbd264effe5b4aeebd6656b8108d1ce33d75443c58930c7425f2ffa70babf419324fadba2085f1fe5345382231eb87a3c22d4144b4a2137f2cc9968ddbbe084b42fbed844dfbb8ca04a0f84c62fd3d65fd20fcb93e63b8fa1db8c35fabd21dc360fec5ca772f307d8a3498586278bc26ceb63026c98e5a57b9e6216ac1946f2d018778120818f7b42501b05432f0c6b21e6f63b9e9000becb7a037c7412e676d422104f9ff9433a4233a2755114b9c50057a56a70007dc7db332d79f8e5b4f2ea45d62463506e604c78b9454a2a2a7837fe4312126f1688b7a5cf827fc154edc6fe930af78610989c855dacb510554f398e173ed85ede46c81cdb7e6ce57df43ad2541bd13963ea4a9184193922b185af0c568067002240986a58a3da91afe735b6aa6ce129d867bcce89ef0802d592d61d4cb0ba6255c3505e1f63db8e74510100566050b29f7cc66c460e9317cffb65833fc7c9b415ca470dde83008f77ec06768fa743637eca387ce7b87a09c5f2c0d1e2bf04811348d2a2d2a7f790f3d1e3fb957e58946828074acc61441ea08a3328c7254f9ac4dd788c7cc481fd23c9224ace6c0527c5878bb4ede7eb0c2f456f511b00f4bc99fc16085608d91b6bd596f83066a481aac412ac12446423fa9fb974f4adf0ab3ca154eab827b58a5dcb2a0532bc209acc2f0f315d0b141cb14eb278a8d44aca7e782fb57a29fe3a57e53a3e036d33201c7e9d443b46410491bb8fbe0783fb9850ca0944adee63f5cec918cd2eb1d9af5e04a337151edb24297a314c4e0d44f53e2f1039c4ffb2ccac9982e18d499570884e612bdb72fa275575c9d407c23a13052f364109d9513e32bc814df584c7dcd1b749749693240f5926f172bcfa64969b5120b70396c3888d6181e5d07d6e3acf1cbde2676ea922822d7abb9e832becb2f0e454e785bab709dc0e1628a7db40dfa2eec66805fb1abf5190c075be19afb87bcc0ad8e721ba4e0214c2c2bdfd88c00b5761842d090b2b8742864c7e5ef173f39786a6fbda94e129c40969efffaa979c32b7e915752b9bf1d5137b5028383dccadf48a7403b1d97d4d3832ab5a6abadf1d9bae36db2d30bcf77f36804a9e9c70e81eb5922fa813fd0fe831b7370846c2ee2a56d4f12e29f6e5935b7917b5e18bbfbf299da681fc9e75582a067624633a8ce3dc7f4608589fdb8e608e84ddba2d8a23d68aa2373563bb01f890c6af1a035ba954e5e90813ffc1bdf750ccd8eecdc2d968569185813698decf2e6d7271c7a038aeffe92b94951a8944e8e1385aac2bb16a6045ac341ec4ba78f52d28ba441645046c8b08a2e9fdc9b7fe53d5ef98bc24057709b7f04d4b34def8946d2a9dc32ae6cdcd0d72cee5d4b6c6e5b8780a96fd81250d950640450eb102a785a67808566725d626e5ff264c0ec0a72c072067b7034b2520e1d8f69ff3c60f02aac6c4ed42721b05f053b92ee64e7d7b942ab86e0abaf207f472255424ca1119493daa2c2e2601", + "public_inputs": [ + "0xe113acd03b98f0bab0ef6f577245d5d008cbcc19ef2dab3608aa4f37f72a407", + "0x18d6ab953235a811edffa4cead74ea045e7cd2085771a2269d59dca054c955b1", + "0x87f3e", + "0x87f3e" + ] +} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/examples/nova_incremental_verifier.rs b/tools/polyexen/circuit/solvency/zk_prover/examples/nova_incremental_verifier.rs new file mode 100644 index 0000000..a93e183 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/examples/nova_incremental_verifier.rs @@ -0,0 +1,448 @@ +use std::{ + collections::HashMap, + env::current_dir, + fs::File, + io::{BufRead, BufReader}, + time::Instant, +}; + +use ff::{Field, PrimeField}; +use nova_scotia::{ + circom::reader::load_r1cs, create_public_params, create_recursive_circuit, FileLocation, F, S, +}; +use nova_snark::{provider, CompressedSNARK, PublicParams}; +use num_bigint::BigUint; +use serde_json::json; +use summa_solvency::merkle_sum_tree::utils::big_intify_username; + +const N_CURRENCIES: usize = 2; + +/// In this scenario the Exchange is generating an incremental inclusion proof for a user after 3 rounds. +/// It means that starting from this proof, the user can verify their correct inclusion in the Liabilities Tree for each round up to round 3 in a single proof. +/// +fn run_test(circuit_filepath: String, witness_gen_filepath: String) { + // Liabilities State represents the state of the Liabilities Tree at each step. H(prev_state, root) = liabiltiies_state. It starts at 0 + // The Liabilties State is submitted to the smart contract at each step as part of the Proof of Solvency (not included in this example) + let liabilities_state_0 = Fr::from_str("0").unwrap(); + + // Merkle Proof represents the inclusion proof for the user 0 for each state + let merkle_proof_1 = build_merkle_proof("../csv/states/entry_16_1.csv".to_string(), 0).unwrap(); + let liabilities_state_1 = + build_liabilities_state_cur(liabilities_state_0, merkle_proof_1.root.hash); + + let merkle_proof_2 = build_merkle_proof("../csv/states/entry_16_2.csv".to_string(), 0).unwrap(); + let liabilities_state_2 = + build_liabilities_state_cur(liabilities_state_1, merkle_proof_2.root.hash); + + let merkle_proof_3 = build_merkle_proof("../csv/states/entry_16_3.csv".to_string(), 0).unwrap(); + let liabilities_state_3 = + build_liabilities_state_cur(liabilities_state_2, merkle_proof_3.root.hash); + + // At state 3, the user is requesting an incremental inclusion proof for the first time. The CEX generates it. + type G1 = provider::bn256_grumpkin::bn256::Point; + type G2 = provider::bn256_grumpkin::grumpkin::Point; + + println!( + "Running test with witness generator: {} and group: {}", + witness_gen_filepath, + std::any::type_name::() + ); + + let iteration_count = 3; + let root = current_dir().unwrap(); + + let circuit_file = root.join(circuit_filepath); + let r1cs = load_r1cs::(&FileLocation::PathBuf(circuit_file)); + let witness_generator_file = root.join(witness_gen_filepath); + + let pp: PublicParams = create_public_params(r1cs.clone()); + + println!( + "Number of constraints per step (primary circuit): {}", + pp.num_constraints().0 + ); + println!( + "Number of constraints per step (secondary circuit): {}", + pp.num_constraints().1 + ); + + println!( + "Number of variables per step (primary circuit): {}", + pp.num_variables().0 + ); + println!( + "Number of variables per step (secondary circuit): {}", + pp.num_variables().1 + ); + + // Build the private inputs for each step circuit + let merkle_proofs = vec![ + merkle_proof_1.clone(), + merkle_proof_2.clone(), + merkle_proof_3.clone(), + ]; + + let usernames = merkle_proofs + .iter() + .map(|proof| proof.username.clone()) + .collect::>(); + + let user_balances = merkle_proofs + .iter() + .map(|proof| proof.user_balances.clone()) + .collect::>>(); + + let path_element_hashes = merkle_proofs + .iter() + .map(|proof| proof.path_element_hashes.clone()) + .collect::>>(); + + let path_element_balances = merkle_proofs + .iter() + .map(|proof| proof.path_element_balances.clone()) + .collect::>>>(); + + let path_indices = merkle_proofs + .iter() + .map(|proof| proof.path_indices.clone()) + .collect::>>(); + + let mut private_inputs = Vec::new(); + for i in 0..iteration_count { + let mut private_input = HashMap::new(); + private_input.insert("username".to_string(), json!(usernames[i])); + private_input.insert("user_balances".to_string(), json!(user_balances[i])); + private_input.insert( + "path_element_hashes".to_string(), + json!(path_element_hashes[i]), + ); + private_input.insert( + "path_element_balances".to_string(), + json!(path_element_balances[i]), + ); + private_input.insert("path_indices".to_string(), json!(path_indices[i])); + private_inputs.push(private_input); + } + + // The start public input is [user_state_cur, liabilities_state_cur] which are both 0 at state 0 + let start_public_input = [F::::from(0), F::::from(0)]; + + println!("Creating a RecursiveSNARK..."); + let start = Instant::now(); + let recursive_snark = create_recursive_circuit( + FileLocation::PathBuf(witness_generator_file.clone()), + r1cs.clone(), + private_inputs, + start_public_input.to_vec(), + &pp, + ) + .unwrap(); + println!("RecursiveSNARK creation took {:?}", start.elapsed()); + + // TODO: empty? + let z0_secondary = [F::::from(0)]; + + // verify the recursive SNARK + println!("Verifying a RecursiveSNARK..."); + let start = Instant::now(); + let res = recursive_snark.verify(&pp, iteration_count, &start_public_input, &z0_secondary); + println!( + "RecursiveSNARK::verify: {:?}, took {:?}", + res, + start.elapsed() + ); + assert!(res.is_ok()); + + let z_last = res.unwrap().0; + + // The user has to check the correctness of the liabilities after state 3 according to the Incremental Proof + // The user checks that this is equal to the liabilities state committed by the CEX at state 3 + println!( + "liabilities_state_cur at state 3 as output of the Incremental Proof {:?}", + z_last[1] + ); + println!( + "liabilities state committed by the CEX at state 3 {:?}", + liabilities_state_3 + ); + + // The user also has to check the correctness of the user state after state 3 according to the Incremental Proof + // The user checks that this is equal to the locally computed user_state_cur + let user_state_0 = Fr::from_str("0").unwrap(); + + let user_state_1 = build_user_state_cur( + user_state_0, + merkle_proof_1.username, + merkle_proof_1.user_balances, + ); + let user_state_2 = build_user_state_cur( + user_state_1, + merkle_proof_2.username, + merkle_proof_2.user_balances, + ); + let user_state_3 = build_user_state_cur( + user_state_2, + merkle_proof_3.username, + merkle_proof_3.user_balances, + ); + + println!( + "user_state_cur at state 3 as output of the Incremental Proof {:?}", + z_last[0] + ); + println!( + "user state computed locally by the user starting from their logs {:?}", + user_state_3 + ); + + // produce a compressed SNARK + println!("Generating a CompressedSNARK using Spartan with IPA-PC..."); + let start = Instant::now(); + let (pk, vk) = CompressedSNARK::<_, _, _, _, S, S>::setup(&pp).unwrap(); + let res = CompressedSNARK::<_, _, _, _, S, S>::prove(&pp, &pk, &recursive_snark); + println!( + "CompressedSNARK::prove: {:?}, took {:?}", + res.is_ok(), + start.elapsed() + ); + assert!(res.is_ok()); + let compressed_snark = res.unwrap(); + + // verify the compressed SNARK + println!("Verifying a CompressedSNARK..."); + let start = Instant::now(); + let res = compressed_snark.verify( + &vk, + iteration_count, + start_public_input.to_vec(), + z0_secondary.to_vec(), + ); + println!( + "CompressedSNARK::verify: {:?}, took {:?}", + res.is_ok(), + start.elapsed() + ); + assert!(res.is_ok()); +} + +fn main() { + let circuit_filepath = "examples/build/incremental_mst_inclusion.r1cs".to_string(); + let witness_gen_filepath = + "examples/build/incremental_mst_inclusion_js/incremental_mst_inclusion.wasm".to_string(); + run_test(circuit_filepath.clone(), witness_gen_filepath); +} + +use num_traits::Num; +use poseidon_rs::{Fr, Poseidon}; + +// Note that we cannot reuse the MerkleSumTree implementation from zk_prover because it is not compatible with circom's Poseidon Hasher +#[derive(Clone, Debug)] +struct Node { + hash: Fr, + balance: [Fr; N_CURRENCIES], +} + +#[derive(Clone, Debug)] +struct MerkleProof { + username: String, + user_balances: Vec, + path_element_hashes: Vec, + path_element_balances: Vec>, + path_indices: Vec, + root: Node, +} + +impl Node { + /// Constructs a new Node given left and right child hashes. + fn new( + left: &Node, + right: &Node, + hasher: &Poseidon, + ) -> Node { + let mut input = vec![left.hash]; + input.extend(left.balance); + input.push(right.hash); + input.extend(right.balance); + + let mut balance = vec![]; + + // iterate over N_CURRENCIES + for i in 0..N_CURRENCIES { + let mut sum = Fr::from_str("0").unwrap(); + sum.add_assign(&left.balance[i]); + sum.add_assign(&right.balance[i]); + + balance.push(sum); + } + + Node { + hash: hasher.hash(input).unwrap(), + balance: balance.try_into().unwrap(), + } + } +} + +/// Generates a Merkle proof of inclusion for a leaf at a given index +fn build_merkle_proof( + csv_filepath: String, + user_index: usize, +) -> Option> { + let file = File::open(csv_filepath).expect("Unable to open file"); + let reader = BufReader::new(file); + + let mut leaves = vec![]; + + let hasher = Poseidon::new(); + + let mut captured_username = String::new(); + let mut captured_user_balances = vec![]; + + for (idx, line) in reader.lines().skip(1).enumerate() { + // skipping header + let line = line.expect("Unable to read line"); + let data: Vec<&str> = line.split(';').collect(); + + if data.len() != 2 { + continue; // Invalid line format + } + + let username = big_intify_username(data[0]).to_string(); + + // convert balances to Fr + let balances: Vec = data[1] + .split(',') + .map(|balance_str| Fr::from_str(balance_str).unwrap()) + .collect(); + + assert_eq!(balances.len(), N_CURRENCIES); + + // capture user's data if the index matches + if idx == user_index { + captured_username = username.to_string(); + captured_user_balances = data[1].split(',').map(|s| s.to_string()).collect(); + } + + let username = Fr::from_str(&username).unwrap(); + + // create a vector input that takes the username and the balances + let mut input = vec![username]; + input.extend(balances.clone()); + + let hash = hasher.hash(input).unwrap(); + + leaves.push(Node { + hash, + balance: balances.try_into().unwrap(), + }); + } + + let mut current_level = leaves.clone(); + + let mut path_element_hashes = vec![]; + let mut path_element_balances = vec![]; + let mut path_indices = vec![]; + + while current_level.len() > 1 { + let mut next_level = vec![]; + + for i in (0..current_level.len()).step_by(2) { + let left = ¤t_level[i]; + let right = if i + 1 < current_level.len() { + ¤t_level[i + 1] + } else { + ¤t_level[i] + }; + + if user_index == i { + path_element_hashes.push(fr_to_string(right.hash).unwrap()); + path_element_balances.push( + right + .balance + .iter() + .map(|fr| fr_to_string(*fr).unwrap()) + .collect(), + ); + path_indices.push("0".to_string()); // 0 means that the right element is the path element + } else if user_index == i + 1 { + path_element_hashes.push(fr_to_string(left.hash).unwrap()); + path_element_balances.push( + left.balance + .iter() + .map(|fr| fr_to_string(*fr).unwrap()) + .collect(), // 1 means that the left element is the path element + ); + path_indices.push("1".to_string()); + } + + let parent = Node::new(left, right, &hasher); + next_level.push(parent); + } + + current_level = next_level; + } + + // fetch the root + let root = current_level[0].clone(); + + Some(MerkleProof { + username: captured_username, + user_balances: captured_user_balances, + path_element_hashes, + path_element_balances, + path_indices, + root, + }) +} + +/// The current liabilities state is obtained by hashing the previous liabilities state and the root hash of the current liabilities tree +fn build_liabilities_state_cur(liabilities_state_prev: Fr, root_hash: Fr) -> Fr { + let hasher = Poseidon::new(); + + let mut input = vec![liabilities_state_prev]; + input.push(root_hash); + + hasher.hash(input).unwrap() +} + +/// The current user state is obtained by hashing the previous user state and the user leaf hash of the current liabilities tree +fn build_user_state_cur(user_state_prev: Fr, username: String, user_balances: Vec) -> Fr { + let hasher = Poseidon::new(); + + let leaf_hash = { + let mut input = vec![Fr::from_str(&username).unwrap()]; + input.extend( + user_balances + .iter() + .map(|balance_str| Fr::from_str(balance_str).unwrap()), + ); + + hasher.hash(input).unwrap() + }; + + let mut input = vec![user_state_prev]; + input.push(leaf_hash); + + hasher.hash(input).unwrap() +} + +/// Converts a Fr to a its decimal string representation +fn fr_to_string(v: Fr) -> Option { + // Convert v to string + let s = v.to_string(); + + // Extract the hexadecimal portion from the string. + // The pattern "Fr(" and ")" should surround the hexadecimal. + if let Some(hex_start) = s.find("Fr(0x") { + let hex_end = s.rfind(')')?; + let hex_str = &s[hex_start + 5..hex_end]; + + // Convert the hexadecimal to a decimal string. + let decimal_str = BigUint::from_str_radix(hex_str, 16) + .ok() + .map(|bigint| bigint.to_str_radix(10)) + .unwrap(); + + return Some(decimal_str); + } + None +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/prints/mst-inclusion-layout.png b/tools/polyexen/circuit/solvency/zk_prover/prints/mst-inclusion-layout.png new file mode 100644 index 0000000..61d9394 Binary files /dev/null and b/tools/polyexen/circuit/solvency/zk_prover/prints/mst-inclusion-layout.png differ diff --git a/tools/polyexen/circuit/solvency/zk_prover/prints/range-check-layout.png b/tools/polyexen/circuit/solvency/zk_prover/prints/range-check-layout.png new file mode 100644 index 0000000..cc706e8 Binary files /dev/null and b/tools/polyexen/circuit/solvency/zk_prover/prints/range-check-layout.png differ diff --git a/tools/polyexen/circuit/solvency/zk_prover/rust-toolchain b/tools/polyexen/circuit/solvency/zk_prover/rust-toolchain new file mode 100644 index 0000000..4524b7c --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/rust-toolchain @@ -0,0 +1 @@ +nightly-2023-07-11 \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/merkle_sum_tree.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/merkle_sum_tree.rs new file mode 100644 index 0000000..349e107 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/merkle_sum_tree.rs @@ -0,0 +1,228 @@ +use halo2_proofs::circuit::{AssignedCell, Layouter}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use halo2_proofs::plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}; +use halo2_proofs::poly::Rotation; + +/// Configuration for the Merkle Sum Tree Chip +/// +/// # Fields +/// +/// * `advice`: advice columns to fit the witness values. +/// * `bool_and_swap_selector`: Selector to enable the bool and swap constraints. +/// * `sum_selector`: Selector to enable the sum constraints. +#[derive(Debug, Clone)] +pub struct MerkleSumTreeConfig { + advice: [Column; 3], + bool_and_swap_selector: Selector, + sum_selector: Selector, +} + +/// Chip that performs various constraints related to a Merkle Sum Tree data structure such as: +/// +/// * `s * swap_bit * (1 - swap_bit) = 0` (if `bool_and_swap_selector` is toggled). It basically enforces that swap_bit is either a 0 or 1. +/// * `s * (element_r_cur - element_l_cur) * swap_bit + element_l_cur - element_l_next = 0` (if `bool_and_swap_selector` is toggled). +/// * `s * (element_l_cur - element_r_cur) * swap_bit + element_r_cur - element_r_next = 0` (if `bool_and_swap_selector` is toggled). +/// These 2 constraints enforce that if the swap_bit is equal to 1, the values will be swapped on the next row. If the swap_bit is equal to 0, the values will not be swapped on the next row. +/// * `s * (left_balance + right_balance - computed_sum)`. It constraints the computed sum to be equal to the sum of the left and right balances (if `sum_selector` is toggled). + +#[derive(Debug, Clone)] +pub struct MerkleSumTreeChip { + config: MerkleSumTreeConfig, +} + +impl MerkleSumTreeChip { + pub fn construct(config: MerkleSumTreeConfig) -> Self { + Self { config } + } + + pub fn configure( + meta: &mut ConstraintSystem, + advice: [Column; 3], + selectors: [Selector; 2], + ) -> MerkleSumTreeConfig { + let col_a: Column = advice[0]; + let col_b: Column = advice[1]; + let col_c: Column = advice[2]; + + let bool_and_swap_selector = selectors[0]; + let sum_selector = selectors[1]; + + meta.create_gate("bool constraint", |meta| { + let s = meta.query_selector(bool_and_swap_selector); + let swap_bit = meta.query_advice(col_c, Rotation::cur()); + vec![s * swap_bit.clone() * (Expression::Constant(Fp::from(1)) - swap_bit)] + }); + + meta.create_gate("swap constraint", |meta| { + let s = meta.query_selector(bool_and_swap_selector); + let swap_bit = meta.query_advice(col_c, Rotation::cur()); + let element_l_cur = meta.query_advice(col_a, Rotation::cur()); + let element_r_cur = meta.query_advice(col_b, Rotation::cur()); + let element_l_next = meta.query_advice(col_a, Rotation::next()); + let element_r_next = meta.query_advice(col_b, Rotation::next()); + + // element_l_next = (element_r_cur - element_l_cur)*s + element_l_cur + let swap_constraint_1 = s.clone() + * ((element_r_cur.clone() - element_l_cur.clone()) * swap_bit.clone() + + element_l_cur.clone() + - element_l_next); + + // element_r_next = (element_l_cur - element_r_cur)*s + element_r_cur + let swap_constraint_2 = s + * ((element_l_cur - element_r_cur.clone()) * swap_bit + element_r_cur + - element_r_next); + + vec![swap_constraint_1, swap_constraint_2] + }); + + meta.create_gate("sum constraint", |meta| { + (0..N_CURRENCIES) + .map(|_| { + let left_balance = meta.query_advice(col_a, Rotation::cur()); + let right_balance = meta.query_advice(col_b, Rotation::cur()); + let computed_sum = meta.query_advice(col_c, Rotation::cur()); + let s = meta.query_selector(sum_selector); + s * (left_balance + right_balance - computed_sum) + }) + .collect::>() + }); + + MerkleSumTreeConfig { + advice, + bool_and_swap_selector, + sum_selector, + } + } + + /// Swap the values of two cells in a region following this layout on 3 advice columns: + /// + /// | a | b | c | + /// | ------------ | ------------- | ---------- | + /// | `current_hash` | `sibling_hash` | `1` | + /// | `sibling_hash` | `current_hash` | - | + /// + /// At row 0 bool_and_swap_selector is enabled + /// If swap_bit is 0, the values will remain the same on the next row + /// If swap_bit is 1, the values will be swapped on the next row + pub fn swap_hashes_per_level( + &self, + mut layouter: impl Layouter, + current_hash: &AssignedCell, + sibling_hash: &AssignedCell, + swap_bit_assigned: &AssignedCell, + ) -> Result<(AssignedCell, AssignedCell), Error> { + layouter.assign_region( + || "assign nodes hashes per merkle tree level", + |mut region| { + // enable the bool_and_swap_selector at row 0 + self.config.bool_and_swap_selector.enable(&mut region, 0)?; + + // copy the current_hash to the column self.config.advice[0] at offset 0 + let l1 = current_hash.copy_advice( + || "copy current hash from previous level", + &mut region, + self.config.advice[0], + 0, + )?; + + // assign the element hash to the column self.config.advice[1] at offset 0 + let r1 = sibling_hash.copy_advice( + || "copy element hash from assigned value", + &mut region, + self.config.advice[1], + 0, + )?; + + // assign the swap_bit to the column self.config.advice[2] at offset 0 + let swap_bit = swap_bit_assigned.copy_advice( + || "swap bit", + &mut region, + self.config.advice[2], + 0, + )?; + + // Extract the value from the cell + let mut l1_val = l1.value().copied(); + let mut r1_val = r1.value().copied(); + + // perform the swap according to the swap bit + // if swap_bit is 0 return (l1, r1) else return (r1, l1) + swap_bit.value().copied().map(|x| { + (l1_val, r1_val) = if x == Fp::zero() { + (l1_val, r1_val) + } else { + (r1_val, l1_val) + }; + }); + + // Perform the assignment according to the swap at offset 1 + let left_hash = region.assign_advice( + || "assign left hash after swap", + self.config.advice[0], + 1, + || l1_val, + )?; + + let right_hash = region.assign_advice( + || "assign right hash after swap", + self.config.advice[1], + 1, + || r1_val, + )?; + + Ok((left_hash, right_hash)) + }, + ) + } + + /// Assign the nodes balance for a single currency in a region following this layout on 3 advice columns: + /// + /// | a | b | c | + /// | ------------ | ------------- | ---------- | + /// | `current_balance` | `element_balance` | `sum` | + /// + /// At row 0 sum_selector is enabled. + pub fn sum_balances_per_level( + &self, + mut layouter: impl Layouter, + current_balance: &AssignedCell, + element_balance: &AssignedCell, + ) -> Result, Error> { + layouter.assign_region( + || "sum nodes balances per currency", + |mut region| { + // enable the sum_selector at row 0 + self.config.sum_selector.enable(&mut region, 0)?; + + // copy the current_balances to the column self.config.advice[0] at offset 0 + let current_balance = current_balance.copy_advice( + || "copy current balance from prev level", + &mut region, + self.config.advice[0], + 0, + )?; + + // assign the element_balance to the column self.config.advice[1] at offset 0 + let element_balance = element_balance.copy_advice( + || "element balance", + &mut region, + self.config.advice[1], + 0, + )?; + + // Extract the values from the cell + let current_balance_val = current_balance.value().copied(); + let element_balance_val = element_balance.value().copied(); + + // compute the sum of the two balances and assign it to the column self.config.advice[2] at offset 0 + let sum = current_balance_val + .zip(element_balance_val) + .map(|(a, b)| a + b); + let sum_cell = + region.assign_advice(|| "sum of balances", self.config.advice[2], 0, || sum)?; + + Ok(sum_cell) + }, + ) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/mod.rs new file mode 100644 index 0000000..97a1ea8 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/mod.rs @@ -0,0 +1,3 @@ +pub mod merkle_sum_tree; +pub mod poseidon; +pub mod range; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/hash.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/hash.rs new file mode 100644 index 0000000..21fdafe --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/hash.rs @@ -0,0 +1,88 @@ +//! An easy-to-use implementation of the Poseidon Hash in the form of a Halo2 Chip. While the Poseidon Hash function +//! is already implemented in halo2_gadgets, there is no wrapper chip that makes it easy to use in other circuits. +use halo2_gadgets::poseidon::{primitives::*, Hash, Pow5Chip, Pow5Config}; +use halo2_proofs::{ + circuit::{AssignedCell, Layouter}, + halo2curves::bn256::Fr as Fp, + plonk::{Advice, Column, ConstraintSystem, Error, Fixed}, +}; +use std::marker::PhantomData; + +#[derive(Debug, Clone)] + +/// Wrapper structure around Pow5Config which is the Poseidon Hash Configuration from halo2_gadgets. +/// +/// Poseidon is a zk-friendly hash function. +/// +/// # Type Parameters +/// +/// * `WIDTH`: The width of the Poseidon permutation, +/// * `RATE`: The rate of the Poseidon permutation, typically WIDTH - 1. +/// * `L`: The length of the input array to the Poseidon hash function. +/// +/// # Fields +/// +/// * `pow5_config`: The configuration for the inner [halo2_gadgets::poseidon::Pow5Config] +pub struct PoseidonConfig { + pow5_config: Pow5Config, +} + +#[derive(Debug, Clone)] + +/// Chip that performs the Poseidon Hash +/// +/// # Type Parameters +/// +/// * `S`: The specification for the Poseidon hash function, +/// * `WIDTH`: The width of the Poseidon permutation, +/// * `RATE`: The rate of the Poseidon permutation, typically WIDTH - 1. +/// * `L`: The length of the input array to the Poseidon hash function. +pub struct PoseidonChip< + S: Spec, + const WIDTH: usize, + const RATE: usize, + const L: usize, +> { + config: PoseidonConfig, + _marker: PhantomData, +} + +impl, const WIDTH: usize, const RATE: usize, const L: usize> + PoseidonChip +{ + /// Constructs a new Poseidon Chip given a PoseidonConfig + pub fn construct(config: PoseidonConfig) -> Self { + Self { + config, + _marker: PhantomData, + } + } + + /// Configures the Poseidon Chip + pub fn configure( + meta: &mut ConstraintSystem, + state: [Column; WIDTH], + partial_sbox: Column, + rc_a: [Column; WIDTH], + rc_b: [Column; WIDTH], + ) -> PoseidonConfig { + let pow5_config = Pow5Chip::configure::(meta, state, partial_sbox, rc_a, rc_b); + + PoseidonConfig { pow5_config } + } + + /// Performs poseidon hash on the given input cells. Returns the output cell. + pub fn hash( + &self, + mut layouter: impl Layouter, + input_cells: [AssignedCell; L], + ) -> Result, Error> { + let pow5_chip = Pow5Chip::construct(self.config.pow5_config.clone()); + + let hasher = Hash::<_, _, S, ConstantLength, WIDTH, RATE>::init( + pow5_chip, + layouter.namespace(|| "hasher"), + )?; + hasher.hash(layouter.namespace(|| "hash"), input_cells) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/mod.rs new file mode 100644 index 0000000..fd69810 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/mod.rs @@ -0,0 +1,3 @@ +pub mod hash; +mod poseidon_params; +pub mod poseidon_spec; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_params.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_params.rs new file mode 100644 index 0000000..045f169 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_params.rs @@ -0,0 +1,987 @@ +//! This file was generated by running generate_params.py +//! Number of round constants: 128 +//! Round constants for GF(p): +//! Parameters for using rate 1 Poseidon with the BN256 field. +//! Patterned after [halo2_gadgets::poseidon::primitives::fp] +//! The parameters can be reproduced by running the following Sage script from +//! [this repository](https://github.com/daira/pasta-hadeshash): +//! +//! ```text +//! $ sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 --rust +//! ``` +//! +//! where 1 means 'prime field', 0 means 'non-negative sbox', 254 is the bitsize +//! of the field, 2 is the Poseidon width (rate + 1), 8 is the number of full +//! rounds, 56 is the number of partial rounds. +//! More info here => https://hackmd.io/@letargicus/SJOvx48Nn +use halo2_proofs::halo2curves::bn256::Fr as Fp; +pub(crate) const ROUND_CONSTANTS: [[Fp; 2]; 64] = [ + [ + Fp::from_raw([ + 0x6c7d_c0db_d0ab_d7a7, + 0xa71a_a177_534c_dd1b, + 0xfe1f_aaba_294c_ba38, + 0x09c4_6e9e_c68e_9bd4, + ]), + Fp::from_raw([ + 0x3c1d_83ff_a604_cb81, + 0xc514_2b3a_e405_b834, + 0x2a97_ed93_7f31_35cf, + 0x0c03_5653_0896_eec4, + ]), + ], + [ + Fp::from_raw([ + 0x317e_a977_cc15_4a30, + 0xa00e_a5aa_bd62_68bd, + 0x142e_5118_2bb5_4cf4, + 0x1e28_a1d9_3569_8ad1, + ]), + Fp::from_raw([ + 0x4cf9_e2b1_2b91_251f, + 0x0e57_57c3_e008_db96, + 0x0809_65db_30e2_98e4, + 0x27af_2d83_1a9d_2748, + ]), + ], + [ + Fp::from_raw([ + 0x79aa_f435_45b7_4e03, + 0x4129_1462_f214_cd08, + 0x3a6a_3cfe_16ae_175a, + 0x1e6f_11ce_60fc_8f51, + ]), + Fp::from_raw([ + 0xf719_2062_68d1_42d3, + 0x0446_2ed1_4c36_13d8, + 0x8541_819c_b681_f0be, + 0x2a67_384d_3bbd_5e43, + ]), + ], + [ + Fp::from_raw([ + 0x3640_8f5d_5c9f_45d0, + 0xb985_e381_f025_1889, + 0x1609_f8e1_2fbf_ecf0, + 0x0b66_fdf3_5609_3a61, + ]), + Fp::from_raw([ + 0xdaa6_852d_bdb0_9e21, + 0x0b26_c83c_c5ce_beed, + 0x830c_6109_3c2a_de37, + 0x012e_e3ec_1e78_d470, + ]), + ], + [ + Fp::from_raw([ + 0x2d10_8e7b_445b_b1b9, + 0x6cd1_c431_b099_b6bb, + 0xfd88_f67f_8175_e3fd, + 0x0252_ba5f_6760_bfbd, + ]), + Fp::from_raw([ + 0xef5a_eaad_7ca9_32f1, + 0x5439_1a89_35ff_71d6, + 0x6c6b_ec3c_ef54_2963, + 0x1794_74cc_eca5_ff67, + ]), + ], + [ + Fp::from_raw([ + 0x7e1a_2589_bbed_2b91, + 0x9c1f_974a_2649_69b3, + 0x9228_ff4a_503f_d4ed, + 0x2c24_2613_79a5_1bfa, + ]), + Fp::from_raw([ + 0x53e6_6c05_5180_1b05, + 0xc2f6_3f50_01fc_0fc5, + 0xac2f_288b_d069_5b43, + 0x1cc1_d7b6_2692_e63e, + ]), + ], + [ + Fp::from_raw([ + 0x5d9e_ff5f_d9c9_1b56, + 0x0078_4dbf_17fb_acd0, + 0xb2ed_55f8_5297_9e96, + 0x2550_5930_1aad_a98b, + ]), + Fp::from_raw([ + 0xb11c_29ce_7e59_efd9, + 0xaea2_4234_970a_8193, + 0x79e1_f5c0_eccd_32b3, + 0x2843_7be3_ac1c_b2e4, + ]), + ], + [ + Fp::from_raw([ + 0x3387_62c3_7f5f_2043, + 0x1854_8da8_fb4f_78d4, + 0x1ca4_fa6b_5376_6eb1, + 0x2821_6a44_2f2e_1f71, + ]), + Fp::from_raw([ + 0x131f_2377_3234_82c9, + 0xeee1_efce_0309_4581, + 0x1f39_f4e7_056d_d03f, + 0x2c1f_47cd_17fa_5adf, + ]), + ], + [ + Fp::from_raw([ + 0x646b_8566_a621_afc9, + 0xd9da_fca2_7663_8a63, + 0x8632_bcc9_356c_eb7d, + 0x07ab_ad02_b7a5_ebc4, + ]), + Fp::from_raw([ + 0x37da_0c4d_15f9_6c3c, + 0x9429_f908_80a6_9cd1, + 0x275b_33ff_aab5_1dfe, + 0x0230_2646_01ff_df29, + ]), + ], + [ + Fp::from_raw([ + 0x717e_5d66_899a_a0a9, + 0xa864_4145_57ee_289e, + 0xa0f1_6865_6497_ca40, + 0x1bc9_7305_4e51_d905, + ]), + Fp::from_raw([ + 0x2a6b_2228_8f0a_67fc, + 0xd249_aff5_c2d8_421f, + 0x206c_3157_e863_41ed, + 0x2e1c_22f9_6443_5008, + ]), + ], + [ + Fp::from_raw([ + 0xa704_52bc_2bba_86b8, + 0x9e8e_a159_8e46_c9f7, + 0x121c_1d5f_461b_bc50, + 0x1224_f38d_f67c_5378, + ]), + Fp::from_raw([ + 0x69d2_9891_86cd_e20e, + 0xd7bf_e8cd_9dfe_da19, + 0x9280_b4bd_9ed0_068f, + 0x02e4_e69d_8ba5_9e51, + ]), + ], + [ + Fp::from_raw([ + 0x6d47_e973_5d98_018e, + 0x4f19_ee36_4e65_3f07, + 0x7f5d_f81f_c04f_f3ee, + 0x1f1e_ccc3_4aab_a013, + ]), + Fp::from_raw([ + 0xeacb_8a4d_4284_f582, + 0x1424_4480_32cd_1819, + 0x7426_6c30_39a9_a731, + 0x1672_ad3d_709a_3539, + ]), + ], + [ + Fp::from_raw([ + 0x1d2e_d602_df8c_8fc7, + 0xcda6_961f_284d_2499, + 0x56f4_4af5_192b_4ae9, + 0x283e_3fdc_2c6e_420c, + ]), + Fp::from_raw([ + 0x614f_bd69_ff39_4bcc, + 0x6837_51f8_fdff_59d6, + 0xd0db_0957_170f_a013, + 0x1c2a_3d12_0c55_0ecf, + ]), + ], + [ + Fp::from_raw([ + 0x96cb_6b81_7765_3fbd, + 0x143a_9a43_773e_a6f2, + 0xf789_7a73_2345_6efe, + 0x216f_8487_7aac_6172, + ]), + Fp::from_raw([ + 0x11a1_f515_52f9_4788, + 0xceaa_47ea_61ca_59a4, + 0x64ba_7e8e_3e28_d12b, + 0x2c0d_272b_ecf2_a757, + ]), + ], + [ + Fp::from_raw([ + 0xcb4a_6c3d_8954_6f43, + 0x170a_5480_abe0_508f, + 0x484e_e7a7_4c45_4e9f, + 0x16e3_4299_865c_0e28, + ]), + Fp::from_raw([ + 0x48cd_9397_5548_8fc5, + 0x7720_4776_5802_290f, + 0x375a_232a_6fb9_cc71, + 0x175c_eba5_99e9_6f5b, + ]), + ], + [ + Fp::from_raw([ + 0xd8c5_ffbb_44a1_ee32, + 0x6aa4_10bf_bc35_4f54, + 0xfead_9e17_58b0_2806, + 0x0c75_9444_0dc4_8c16, + ]), + Fp::from_raw([ + 0x9247_9882_d919_fd8d, + 0x760e_2001_3ccf_912c, + 0xc466_db7d_7eb6_fd8f, + 0x1a3c_29bc_39f2_1bb5, + ]), + ], + [ + Fp::from_raw([ + 0x95c8_eeab_cd22_e68f, + 0x0855_d349_074f_5a66, + 0xc098_6ea0_49b2_5340, + 0x0ccf_dd90_6f34_26e5, + ]), + Fp::from_raw([ + 0xe0e6_99b6_7dd9_e796, + 0x66a7_a8a3_fd06_5b3c, + 0x2bdb_475c_e6c9_4118, + 0x14f6_bc81_d9f1_86f6, + ]), + ], + [ + Fp::from_raw([ + 0x88ed_eb73_86b9_7052, + 0xcc09_9810_c9c4_95c8, + 0x9702_ca70_b2f6_c5aa, + 0x0962_b827_89fb_3d12, + ]), + Fp::from_raw([ + 0xafef_0c8f_6a31_a86d, + 0x1328_4ab0_1ef0_2575, + 0xbf20_c79d_e251_27bc, + 0x1a88_0af7_074d_18b3, + ]), + ], + [ + Fp::from_raw([ + 0x4c30_12bb_7ae9_311b, + 0x20af_2924_fc20_ff3f, + 0xcd5e_77f0_211c_154b, + 0x10cb_a184_19a6_a332, + ]), + Fp::from_raw([ + 0x756a_2849_f302_f10d, + 0xfa27_b731_9cae_3406, + 0xbdc7_6ba6_3a9e_aca8, + 0x057e_62a9_a8f8_9b3e, + ]), + ], + [ + Fp::from_raw([ + 0xafa0_413b_4428_0cee, + 0xb961_303b_bf65_cff5, + 0xd44a_df53_84b4_988c, + 0x287c_971d_e91d_c0ab, + ]), + Fp::from_raw([ + 0x6f7f_7960_e306_891d, + 0x1e56_2bc4_6d4a_ba4e, + 0xb3bc_a9da_0cca_908f, + 0x21df_3388_af16_87bb, + ]), + ], + [ + Fp::from_raw([ + 0x3eff_8b56_0e16_82b3, + 0x789d_f8f7_0b49_8fd8, + 0x3e25_cc97_4d09_34cd, + 0x1be5_c887_d25b_ce70, + ]), + Fp::from_raw([ + 0x48d5_9c27_06a0_d5c1, + 0xd2cb_5d42_fda5_acea, + 0x6811_7175_cea2_cd0d, + 0x268d_a36f_76e5_68fb, + ]), + ], + [ + Fp::from_raw([ + 0xbd06_460c_c26a_5ed6, + 0xc5d8_bb74_135e_bd05, + 0xc609_beaf_5510_ecec, + 0x0e17_ab09_1f6e_ae50, + ]), + Fp::from_raw([ + 0x040f_5caa_1f62_af40, + 0x91ef_62d8_cf83_d270, + 0x7aee_535a_b074_a430, + 0x04d7_27e7_28ff_a0a6, + ]), + ], + [ + Fp::from_raw([ + 0x2b15_417d_7e39_ca6e, + 0x3370_2ac1_0f1b_fd86, + 0x81b5_4976_2bc0_22ed, + 0x0ddb_d7bf_9c29_3415, + ]), + Fp::from_raw([ + 0x8a29_c49c_8789_654b, + 0x34f5_b0d1_d3af_9b58, + 0x7681_62e8_2989_c6c2, + 0x2790_eb33_5162_1752, + ]), + ], + [ + Fp::from_raw([ + 0x84b7_6420_6142_f9e9, + 0x395f_3d9a_b8b2_fd09, + 0x4471_9501_93d8_a570, + 0x1e45_7c60_1a63_b73e, + ]), + Fp::from_raw([ + 0xc4c6_86fc_46e0_91b0, + 0xfa90_ecd0_c43f_f91f, + 0x638d_6ab2_bbe7_135f, + 0x21ae_6430_1dca_9625, + ]), + ], + [ + Fp::from_raw([ + 0x5858_534e_ed8d_350b, + 0x854b_e9e3_432e_0955, + 0x4da2_9316_6f49_4928, + 0x0379_f63c_8ce3_468d, + ]), + Fp::from_raw([ + 0x8c9f_58a3_24c3_5049, + 0xca0e_4921_a466_86ac, + 0x6a74_4a08_0809_e054, + 0x002d_5642_0359_d026, + ]), + ], + [ + Fp::from_raw([ + 0x0fc2_c5af_9635_15a6, + 0xda8d_6245_9e21_f409, + 0x1d68_b3cd_32e1_0bbe, + 0x1231_58e5_965b_5d9b, + ]), + Fp::from_raw([ + 0x60c8_0eb4_9cad_9ec1, + 0x0fbb_2b6f_5283_6d4e, + 0x661d_14bb_f6cb_e042, + 0x0be2_9fc4_0847_a941, + ]), + ], + [ + Fp::from_raw([ + 0x2338_02f2_4fdf_4c1a, + 0x36db_9d85_9cad_5f9a, + 0x5771_6142_015a_453c, + 0x1ac9_6991_dec2_bb05, + ]), + Fp::from_raw([ + 0x51ca_3355_bcb0_627e, + 0x5e12_c9fa_97f1_8a92, + 0x5f49_64fc_61d2_3b3e, + 0x1596_443f_763d_bcc2, + ]), + ], + [ + Fp::from_raw([ + 0xd6d0_49ea_e3ba_3212, + 0xf185_7d9f_17e7_15ae, + 0x6b28_61d4_ec3a_eae0, + 0x12e0_bcd3_654b_dfa7, + ]), + Fp::from_raw([ + 0x04e6_c76c_7cf9_64ba, + 0xceab_ac7f_3715_4b19, + 0x9ea7_3d4a_f9af_2a50, + 0x0fc9_2b4f_1bbe_a82b, + ]), + ], + [ + Fp::from_raw([ + 0x9c7e_9652_3387_2762, + 0xb14f_7c77_2223_6f4f, + 0xd6f2_e592_a801_3f40, + 0x1f9c_0b16_1044_6442, + ]), + Fp::from_raw([ + 0x8d15_9f64_3dbb_f4d3, + 0x050d_914d_a38b_4c05, + 0xf8cd_e061_57a7_82f4, + 0x0ebd_7424_4ae7_2675, + ]), + ], + [ + Fp::from_raw([ + 0x7a83_9839_dccf_c6d1, + 0x3b06_71e9_7346_ee39, + 0x69a9_fafd_4ab9_51c0, + 0x2cb7_f0ed_39e1_6e9f, + ]), + Fp::from_raw([ + 0x90c7_2bca_7352_d9bf, + 0xce76_1d05_14ce_5266, + 0x5605_443e_e41b_ab20, + 0x1a9d_6e2e_cff0_22cc, + ]), + ], + [ + Fp::from_raw([ + 0x87da_182d_648e_c72f, + 0xd0c1_3326_a9a7_ba30, + 0x5ea8_3c3b_c44a_9331, + 0x2a11_5439_607f_335a, + ]), + Fp::from_raw([ + 0x9535_c115_c5a4_c060, + 0xe738_b563_05cd_44f2, + 0x15b8_fa7a_ee3e_3410, + 0x23f9_b652_9b5d_040d, + ]), + ], + [ + Fp::from_raw([ + 0x260e_b939_f0e6_e8a7, + 0xa3ce_97c1_6d58_b68b, + 0x249a_c6ba_484b_b9c3, + 0x0587_2c16_db0f_72a2, + ]), + Fp::from_raw([ + 0x2b62_4a7c_dedd_f6a7, + 0x0219_b615_1d55_b5c5, + 0xca20_fb80_1180_75f4, + 0x1300_bdee_08bb_7824, + ]), + ], + [ + Fp::from_raw([ + 0x072e_4e7b_7d52_b376, + 0x8d7a_d299_16d9_8cb1, + 0xe638_1786_3a8f_6c28, + 0x19b9_b63d_2f10_8e17, + ]), + Fp::from_raw([ + 0x24a2_0128_481b_4f7f, + 0x13d1_c887_26b5_ec42, + 0xb5bd_a237_6685_22f6, + 0x015b_ee13_57e3_c015, + ]), + ], + [ + Fp::from_raw([ + 0xea92_c785_b128_ffd1, + 0xfe1e_1ce4_bab2_18cb, + 0x1b97_07a4_f161_5e4e, + 0x2953_736e_94bb_6b9f, + ]), + Fp::from_raw([ + 0x4ce7_266e_d660_8dfc, + 0x851b_98d3_72b4_5f54, + 0x862f_8061_80c0_385f, + 0x0b06_9353_ba09_1618, + ]), + ], + [ + Fp::from_raw([ + 0x4f58_8ac9_7d81_f429, + 0x55ae_b7eb_9306_b64e, + 0x15e4_e0bc_fb93_817e, + 0x304f_74d4_61cc_c131, + ]), + Fp::from_raw([ + 0xb8ee_5415_cde9_13fc, + 0xaad2_a164_a461_7a4c, + 0xe8a3_3f5e_77df_e4f5, + 0x15bb_f146_ce9b_ca09, + ]), + ], + [ + Fp::from_raw([ + 0xa9ff_2385_9572_c8c6, + 0x9b8f_4b85_0405_c10c, + 0x4490_1031_4879_64ed, + 0x0ab4_dfe0_c274_2cde, + ]), + Fp::from_raw([ + 0x251d_e39f_9639_779a, + 0xef5e_edfe_a546_dea9, + 0x97f4_5f76_49a1_9675, + 0x0e32_db32_0a04_4e31, + ]), + ], + [ + Fp::from_raw([ + 0xa307_8efa_516d_a016, + 0x6797_733a_8277_4896, + 0xb276_35a7_8b68_88e6, + 0x0a17_56aa_1f37_8ca4, + ]), + Fp::from_raw([ + 0x4254_d6a2_a25d_93ef, + 0x95e6_1d32_8f85_efa9, + 0x47fd_1717_7f95_2ef8, + 0x044c_4a33_b10f_6934, + ]), + ], + [ + Fp::from_raw([ + 0xd37b_07b5_466c_4b8b, + 0xfe08_79d7_9a49_6891, + 0xbe65_5b53_7f66_f700, + 0x2ed3_611b_725b_8a70, + ]), + Fp::from_raw([ + 0xd833_9ea7_1208_58aa, + 0xadfd_eb9c_fdd3_47b5, + 0xc8ec_c3d7_22aa_2e0e, + 0x1f9b_a4e8_bab7_ce42, + ]), + ], + [ + Fp::from_raw([ + 0xb740_56f8_65c5_d3da, + 0xa38e_82ac_4502_066d, + 0x8f7e_e907_a84e_518a, + 0x1b23_3043_052e_8c28, + ]), + Fp::from_raw([ + 0xca2f_97b0_2087_5954, + 0x9020_53bf_c0f1_4db0, + 0x7403_1ab7_2bd5_5b4c, + 0x2431_e1cc_164b_b8d0, + ]), + ], + [ + Fp::from_raw([ + 0xa791_f273_9658_01fd, + 0xa13e_3220_9758_3319, + 0x30cd_6953_a0a7_db45, + 0x082f_934c_91f5_aac3, + ]), + Fp::from_raw([ + 0x9ad6_bb93_0c48_997c, + 0xc772_45e2_ae7c_be99, + 0xa34b_e074_3155_42a3, + 0x2b9a_0a22_3e75_38b0, + ]), + ], + [ + Fp::from_raw([ + 0xb0b5_89cc_7021_4e7d, + 0x8164_163e_75a8_a00e, + 0xceb8_5483_b887_a9be, + 0x0e1c_d91e_dd2c_fa2c, + ]), + Fp::from_raw([ + 0x88d3_2460_1ceb_e2f9, + 0x9977_4f19_854d_00f5, + 0xc951_f614_77e3_6989, + 0x2e1e_ac0f_2bfd_fd63, + ]), + ], + [ + Fp::from_raw([ + 0x23d7_4811_5b50_0b83, + 0x7345_784d_8efd_b33c, + 0x0c76_158e_769d_6d15, + 0x0cbf_a95f_37fb_7406, + ]), + Fp::from_raw([ + 0x980c_232d_fa4a_4f84, + 0x76d9_91e3_a775_13d9, + 0xd65a_d49d_8a61_e9a6, + 0x08f0_5b3b_e923_ed44, + ]), + ], + [ + Fp::from_raw([ + 0x25a2_dd51_0c04_7ef6, + 0xe728_4925_dc07_58a3, + 0x52bf_8e21_984d_0443, + 0x2271_9e2a_070b_cd08, + ]), + Fp::from_raw([ + 0xf41f_62b2_f268_30c0, + 0x7bdb_f036_1199_82c0, + 0xc060_f7fc_c3a1_ab4c, + 0x041f_596a_9ee1_cb2b, + ]), + ], + [ + Fp::from_raw([ + 0x19fc_dd09_86b1_0f89, + 0x021b_e1c2_d0dc_464a, + 0x8762_8eb0_6f6b_1d4c, + 0x233f_d35d_e1be_520a, + ]), + Fp::from_raw([ + 0xefcb_453c_61c9_c267, + 0xd31e_078a_a1b4_707e, + 0x4325_e0a4_23eb_c810, + 0x0524_b46d_1aa8_7a5e, + ]), + ], + [ + Fp::from_raw([ + 0xcc44_8623_7c51_5211, + 0x4227_bb95_4b0f_3199, + 0xce47_fcac_894b_8582, + 0x2c34_f424_c81e_5716, + ]), + Fp::from_raw([ + 0xf330_1032_7de4_915e, + 0x2dd2_025b_5457_cc97, + 0x207e_ffc2_b554_1fb7, + 0x0b5f_2a4b_6338_7819, + ]), + ], + [ + Fp::from_raw([ + 0xaefa_c41f_e05c_659f, + 0xc174_35d2_f57a_f6ce, + 0xc5b7_2fe4_39d2_cfd6, + 0x2220_7856_082c_cc54, + ]), + Fp::from_raw([ + 0x2785_4048_ce2c_8171, + 0xcdfb_2101_94ca_f79f, + 0x4e24_159b_7f89_50b5, + 0x24d5_7a8b_f5da_63fe, + ]), + ], + [ + Fp::from_raw([ + 0x7391_9bb2_3b79_396e, + 0x374a_d709_7bb0_1a85, + 0x3b37_1d75_bd69_3f98, + 0x0afa_b181_fdd5_e058, + ]), + Fp::from_raw([ + 0xf162_90d6_2b11_28ee, + 0x76c0_0571_94c1_6c0b, + 0x998a_52ef_ac7c_bd56, + 0x2dba_9b10_8f20_8772, + ]), + ], + [ + Fp::from_raw([ + 0x5aff_13e6_bce4_20b3, + 0xcbb8_3de0_bd59_2b25, + 0x56f8_81c7_88f5_3f83, + 0x2634_9b66_edb8_b16f, + ]), + Fp::from_raw([ + 0x2352_88a3_e6f1_37db, + 0xd81a_56d2_8ecc_193b, + 0x685e_95f9_2339_753a, + 0x25af_7ce0_e5e1_0357, + ]), + ], + [ + Fp::from_raw([ + 0x1f7c_0187_fe35_011f, + 0x70ee_d7aa_e88b_2bff, + 0xc094_d6a5_5edd_68b9, + 0x25b4_ce7b_d229_4390, + ]), + Fp::from_raw([ + 0x8cb9_d54c_1e02_b631, + 0xde9c_ef28_ebdf_30b1, + 0x387e_53f1_908a_88e5, + 0x22c5_43f1_0f6c_89ec, + ]), + ], + [ + Fp::from_raw([ + 0xdf66_8e74_882f_87a9, + 0x425e_906a_919d_7a34, + 0x4fc7_908a_9f19_1e1e, + 0x0236_f93e_7789_c472, + ]), + Fp::from_raw([ + 0x9cb4_97af_980c_4b52, + 0x652b_dae1_14eb_0165, + 0x0e7d_27e3_7d05_da99, + 0x2935_0b40_1166_ca01, + ]), + ], + [ + Fp::from_raw([ + 0xee12_6091_6652_363f, + 0x65ed_b75d_844e_bb89, + 0x6bd3_1bba_b547_f75a, + 0x0eed_787d_6582_0d3f, + ]), + Fp::from_raw([ + 0x1906_f656_f4de_6fad, + 0xfdcd_0e99_bd94_297d, + 0x036a_753f_520b_3291, + 0x07cc_1170_f13b_46f2, + ]), + ], + [ + Fp::from_raw([ + 0x2059_4356_89e8_acea, + 0x9087_86d7_f9f5_d10c, + 0xf49b_cf61_3a3d_30b1, + 0x22b9_3923_3b1d_7205, + ]), + Fp::from_raw([ + 0xadd6_50ac_e60a_e5a6, + 0x740f_083a_5aa8_5438, + 0x8aad_1dc8_bc33_e870, + 0x0145_1762_a0aa_b81c, + ]), + ], + [ + Fp::from_raw([ + 0xe704_fec0_892f_ce89, + 0xe32e_aa61_dec7_da57, + 0x61fa_bf10_25d4_6d1f, + 0x2350_6bb5_d872_7d44, + ]), + Fp::from_raw([ + 0x7f8b_d689_0735_5522, + 0x2a37_0953_1e1e_fea9, + 0xbac0_6ae3_f71b_dd09, + 0x2e48_4c44_e838_aea0, + ]), + ], + [ + Fp::from_raw([ + 0x4541_8da2_6835_b54c, + 0xaf4a_5945_45ce_dc25, + 0x379e_78c5_0bd2_e42b, + 0x0f4b_c7d0_7eba_fd64, + ]), + Fp::from_raw([ + 0xe620_996d_50d8_e74e, + 0x5158_2388_725d_f460, + 0xfa76_6378_62fa_aee8, + 0x1f4d_3c8f_6583_e9e5, + ]), + ], + [ + Fp::from_raw([ + 0x53eb_9bcb_48fe_7389, + 0xfae0_2abc_7b68_1d91, + 0x2660_d07b_e0e4_a988, + 0x0935_14e0_c707_11f8, + ]), + Fp::from_raw([ + 0x4a58_e0a3_47e1_53d8, + 0x43ee_83ec_e472_28f2, + 0x4669_9a2b_5f3b_c036, + 0x1ada_b0c8_e2b3_bad3, + ]), + ], + [ + Fp::from_raw([ + 0x1a22_dbef_9e80_dad2, + 0x378c_1b94_b807_2bac, + 0xd147_09eb_b474_641a, + 0x1672_b172_6057_d99d, + ]), + Fp::from_raw([ + 0x30d4_7b23_9b47_9c14, + 0xc5d8_e2fa_e0ac_c4ee, + 0x8f44_f53f_dcab_468c, + 0x1dfd_53d4_576a_f2e3, + ]), + ], + [ + Fp::from_raw([ + 0xbc7f_2077_5320_5c60, + 0xe6d7_7d64_0f6f_c3de, + 0xa70a_3626_3a37_e17f, + 0x0c68_88a1_0b75_b0f3, + ]), + Fp::from_raw([ + 0x8509_1ecc_a9d1_e508, + 0x611a_61e0_0ee6_848b, + 0x92b3_4a7e_77d1_2fe8, + 0x1add_b933_a65b_e770, + ]), + ], + [ + Fp::from_raw([ + 0x7935_628e_299d_1791, + 0xf638_ff54_25f0_afff, + 0x5c10_ae18_d1de_933c, + 0x00d7_540d_cd26_8a84, + ]), + Fp::from_raw([ + 0xd316_939d_20b8_2c0e, + 0x26fe_dde4_acd9_9db1, + 0x01b2_827a_5664_ca9c, + 0x140c_0e42_687e_9ead, + ]), + ], + [ + Fp::from_raw([ + 0xc091_e2ae_5656_5984, + 0xc20a_0f9b_24f8_c5ed, + 0x91ba_89b8_d13d_1806, + 0x2f0c_3a11_5d43_17d1, + ]), + Fp::from_raw([ + 0xd8c5_38a1_dc95_8c61, + 0x08a0_cff6_70b2_2b82, + 0x3006_ed22_0cf9_c810, + 0x0c4e_e778_ff7c_1455, + ]), + ], + [ + Fp::from_raw([ + 0x27c3_d748_5de7_4c69, + 0x9424_ed26_c0ac_c662, + 0x3693_f004_40cc_c360, + 0x1704_f276_6d46_f82c, + ]), + Fp::from_raw([ + 0x39b6_6fe9_009c_3cfa, + 0xf076_9c9f_8544_e402, + 0xa7a0_2c1b_51d2_44ab, + 0x2f2d_19cc_3ea5_d78e, + ]), + ], + [ + Fp::from_raw([ + 0xd6c7_66a8_06fc_6629, + 0xdd7e_e6cb_9cfe_d9c7, + 0x5053_f112_e2a8_e8dc, + 0x1ae0_3853_b75f_caba, + ]), + Fp::from_raw([ + 0x4e41_a86d_daf0_56d5, + 0x3556_921b_2d6f_014e, + 0x51d1_31d0_fa61_aa5f, + 0x0971_aabf_7952_41df, + ]), + ], + [ + Fp::from_raw([ + 0x5f5c_29f7_bfe2_f646, + 0xda62_4f83_80df_1c87, + 0x91d4_cf6b_6e0d_e73e, + 0x1408_c316_e601_4e1a, + ]), + Fp::from_raw([ + 0x4169_1f39_822e_f5bd, + 0x6c89_f1f7_73ef_2853, + 0x248a_be42_b543_093b, + 0x1667_f3fe_2edb_e850, + ]), + ], + [ + Fp::from_raw([ + 0x424c_6957_6500_fe37, + 0x5b81_7184_09e5_c133, + 0xa48b_0a03_557c_df91, + 0x13bf_7c5d_0d2c_4376, + ]), + Fp::from_raw([ + 0x19bc_0ba7_43a6_2c2c, + 0x024b_9534_7856_b797, + 0x3016_adf3_d353_3c24, + 0x0762_0a6d_fb0b_6cec, + ]), + ], + [ + Fp::from_raw([ + 0x1675_de3e_1982_b4d0, + 0x75d2_959e_2f32_2b73, + 0x36a8_ca08_bdbd_d8b0, + 0x1574_c7ef_0c43_545f, + ]), + Fp::from_raw([ + 0xc06e_03a7_ff83_78f0, + 0x5bd4_1845_71c2_54fd, + 0xfd56_7970_a717_ceec, + 0x269e_4b5b_7a2e_b21a, + ]), + ], +]; +// n: 254 +// t: 2 +// N: 508 +// Result Algorithm 1: +// [True, 0] +// Result Algorithm 2: +// [True, None] +// Result Algorithm 3: +// [True, None] +// Prime number: 0x0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// MDS matrix: +pub(crate) const MDS: [[Fp; 2]; 2] = [ + [ + Fp::from_raw([ + 0xbcec_a70b_d2af_7ad5, + 0xaf07_f38a_f8c9_52a7, + 0xec10_3453_51a2_3a3a, + 0x066f_6f85_d6f6_8a85, + ]), + Fp::from_raw([ + 0x0546_2b9f_8125_b1e8, + 0x20a7_c02b_bd8b_ea73, + 0x7782_e150_9b1d_0fdb, + 0x2b9d_4b41_10c9_ae99, + ]), + ], + [ + Fp::from_raw([ + 0xf573_f431_221f_8ff9, + 0xb6c0_9d55_7013_fff1, + 0x2bf6_7a44_93cc_262f, + 0x0cc5_7cdb_b085_07d6, + ]), + Fp::from_raw([ + 0x21bc_d147_9432_03c8, + 0xade8_57e8_6eb5_c3a1, + 0xa31a_6ed6_9724_e1ad, + 0x1274_e649_a32e_d355, + ]), + ], +]; +// Inverse MDS matrix: +pub(crate) const MDS_INV: [[Fp; 2]; 2] = [ + [ + Fp::from_raw([ + 0x8dbe_bd0f_a8c5_3e66, + 0x0554_569d_9b29_d1ea, + 0x7081_9ab1_c784_6f21, + 0x13ab_ec39_0ada_7f43, + ]), + Fp::from_raw([ + 0xaaf6_185b_1a1e_60fe, + 0xbd52_1ead_5dfe_0345, + 0x4c98_62a1_d97d_1510, + 0x1eb9_e1dc_19a3_3a62, + ]), + ], + [ + Fp::from_raw([ + 0x763f_7875_036b_cb02, + 0x8ce5_1690_30a2_ad69, + 0x601a_bc49_fdad_4f03, + 0x0fc1_c939_4db8_9bb2, + ]), + Fp::from_raw([ + 0x8abc_ed6b_d147_c8be, + 0x2b7e_ac34_3459_61bc, + 0x9502_054e_dc03_e7b2, + 0x16a9_e98c_493a_902b, + ]), + ], +]; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_spec.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_spec.rs new file mode 100644 index 0000000..ed8d409 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/poseidon/poseidon_spec.rs @@ -0,0 +1,38 @@ +//! This file was generated by running generate_params.py +//! Specification for rate 1 Poseidon using the BN256 curve. +//! Patterned after [halo2_gadgets::poseidon::primitives::P128Pow5T3] +use crate::chips::poseidon::poseidon_params; +use halo2_gadgets::poseidon::primitives::*; +use halo2_proofs::arithmetic::Field; +use halo2_proofs::halo2curves::bn256::Fr as Fp; + +#[derive(Debug, Clone, Copy)] +pub struct PoseidonSpec; + +pub(crate) type Mds = [[Fp; T]; T]; + +impl Spec for PoseidonSpec { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + 56 + } + + fn sbox(val: Fp) -> Fp { + val.pow_vartime([5]) + } + + fn secure_mds() -> usize { + unimplemented!() + } + + fn constants() -> (Vec<[Fp; 2]>, Mds, Mds) { + ( + poseidon_params::ROUND_CONSTANTS[..].to_vec(), + poseidon_params::MDS, + poseidon_params::MDS_INV, + ) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/mod.rs new file mode 100644 index 0000000..0f763cb --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/mod.rs @@ -0,0 +1,3 @@ +pub mod range_check; +mod tests; +pub mod utils; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/range_check.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/range_check.rs new file mode 100644 index 0000000..c27f568 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/range_check.rs @@ -0,0 +1,154 @@ +use halo2_proofs::arithmetic::Field; +use halo2_proofs::circuit::{AssignedCell, Layouter, Value}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use halo2_proofs::plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector}; +use halo2_proofs::poly::Rotation; + +use std::fmt::Debug; + +use super::utils::decompose_fp_to_bytes; + +/// Configuration for the Range Check Chip +/// +/// # Type Parameters +/// +/// * `N_BYTES`: Number of bytes in which the value to be checked should lie +/// +/// # Fields +/// +/// * `z`: Advice column for the value to be checked and its running sum. +/// * `lookup_enable_selector`: Selector to enable the lookup check. +/// +/// Patterned after [halo2_gadgets](https://github.com/privacy-scaling-explorations/halo2/blob/main/halo2_gadgets/src/utilities/decompose_running_sum.rs) +#[derive(Debug, Copy, Clone)] +pub struct RangeCheckConfig { + z: Column, + lookup_enable_selector: Selector, +} + +/// Helper chip that verifies that the value witnessed in a given cell lies within a given range defined by N_BYTES. +/// For example, Let's say we want to constraint 0x1f2f3f4f to be within the range N_BYTES=4. +/// +/// * `z(0) = 0x1f2f3f4f` +/// * `z(1) = (0x1f2f3f4f - 0x4f) / 2^8 = 0x1f2f3f` +/// * `z(2) = (0x1f2f3f - 0x3f) / 2^8 = 0x1f2f` +/// * `z(3) = (0x1f2f - 0x2f) / 2^8 = 0x1f` +/// * `z(4) = (0x1f - 0x1f) / 2^8 = 0x00` +/// +/// | | `z` | +/// | ------------ | -------------| +/// | 0 | `0x1f2f3f4f` | +/// | 1 | `0x1f2f3f` | +/// | 2 | `0x1f2f` | +/// | 3 | `0x1f` | +/// | 4 | `0x00` | +/// +/// The column z contains the witnessed value to be checked at offset 0 +/// At offset i, the column z contains the value `z(i+1) = (z(i) - k(i)) / 2^8` (shift right by 8 bits) where k(i) is the i-th decomposition big-endian of `value` +/// The constraints that are enforced are: +/// * `z(i) - 2^8⋅z(i+1) ∈ lookup_u8_table` (enabled by lookup_enable_selector at offset [0, N_BYTES - 1]) +/// * `z(N_BYTES) == 0` +#[derive(Debug, Clone)] +pub struct RangeCheckChip { + config: RangeCheckConfig, +} + +impl RangeCheckChip { + pub fn construct(config: RangeCheckConfig) -> Self { + Self { config } + } + + /// Configures the Range Chip + /// Note: the lookup table should be loaded with values from `0` to `2^8 - 1` otherwise the range check will fail. + pub fn configure( + meta: &mut ConstraintSystem, + z: Column, + lookup_u8_table: Column, + lookup_enable_selector: Selector, + ) -> RangeCheckConfig { + meta.annotate_lookup_any_column(lookup_u8_table, || "LOOKUP_MAXBITS_RANGE"); + + meta.lookup_any( + "range u8 check for difference between each interstitial running sum output", + |meta| { + let z_cur = meta.query_advice(z, Rotation::cur()); + let z_next = meta.query_advice(z, Rotation::next()); + + let lookup_enable_selector = meta.query_selector(lookup_enable_selector); + let u8_range = meta.query_fixed(lookup_u8_table, Rotation::cur()); + + let diff = z_cur - z_next * Expression::Constant(Fp::from(1 << 8)); + + vec![(lookup_enable_selector * diff, u8_range)] + }, + ); + + RangeCheckConfig { + z, + lookup_enable_selector, + } + } + + /// Assign the running sum to the chip starting from the value within an assigned cell. + pub fn assign( + &self, + mut layouter: impl Layouter, + value: &AssignedCell, + ) -> Result<(), Error> { + layouter.assign_region( + || "assign value to perform range check", + |mut region| { + // enable the lookup at offset [0, N_BYTES - 1] + for i in 0..N_BYTES { + self.config.lookup_enable_selector.enable(&mut region, i)?; + } + + // copy `value` to `z_0` at offset 0 + let z_0 = value.copy_advice( + || "assign value to be range checked", + &mut region, + self.config.z, + 0, + )?; + + // Decompose the value in #N_BYTES bytes + let bytes = value + .value() + .copied() + .map(|x| decompose_fp_to_bytes(x, N_BYTES)) + .transpose_vec(N_BYTES); + + // Initialize empty vector to store running sum values [z_0, ..., z_W]. + let mut zs: Vec> = vec![z_0.clone()]; + let mut z = z_0; + + // Assign running sum `z_{i+1}` = (z_i - k_i) / (2^8) for i = 0..=N_BYTES - 1. + let two_pow_k_inv = Value::known(Fp::from(1 << 8).invert().unwrap()); + + for (i, byte) in bytes.iter().enumerate() { + // z_next = (z_cur - byte) / (2^K) + let z_next = { + let z_cur_val = z.value().copied(); + let byte = byte.map(|byte| Fp::from(byte as u64)); + let z_next_val = (z_cur_val - byte) * two_pow_k_inv; + region.assign_advice( + || format!("z_{:?}", i + 1), + self.config.z, + i + 1, + || z_next_val, + )? + }; + + // Update `z`. + z = z_next; + zs.push(z.clone()); + } + + // Constrain the final running sum output to be zero. + region.constrain_constant(zs[N_BYTES].cell(), Fp::from(0))?; + + Ok(()) + }, + ) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/tests.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/tests.rs new file mode 100644 index 0000000..99a4cb9 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/tests.rs @@ -0,0 +1,296 @@ +use crate::{ + chips::range::range_check::{RangeCheckChip, RangeCheckConfig}, + circuits::traits::CircuitBase, +}; +use halo2_proofs::{ + circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}, + halo2curves::bn256::Fr as Fp, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Selector}, + poly::Rotation, +}; + +#[derive(Debug, Clone)] +pub struct AddConfig { + pub col_a: Column, // stores the value of a + pub col_b: Column, // stores the value of b + pub col_c: Column, // stores the value of c = a + b + pub selector: Selector, +} + +#[derive(Debug, Clone)] +pub struct AddChip { + pub config: AddConfig, +} + +impl AddChip { + pub fn construct(config: AddConfig) -> Self { + Self { config } + } + + pub fn configure( + meta: &mut ConstraintSystem, + col_a: Column, + col_b: Column, + col_c: Column, + add_selector: Selector, + ) -> AddConfig { + meta.create_gate("add", |meta| { + let s = meta.query_selector(add_selector); + let a = meta.query_advice(col_a, Rotation::cur()); + let b = meta.query_advice(col_b, Rotation::cur()); + let c = meta.query_advice(col_c, Rotation::cur()); + vec![s * (a + b - c)] + }); + + AddConfig { + col_a, + col_b, + col_c, + selector: add_selector, + } + } + + pub fn assign( + &self, + a: Fp, + b: Fp, + mut layouter: impl Layouter, + ) -> Result< + ( + AssignedCell, + AssignedCell, + AssignedCell, + ), + Error, + > { + layouter.assign_region( + || "initialize value and sum", + |mut region| { + self.config.selector.enable(&mut region, 0)?; + + let a_cell = + region.assign_advice(|| "a", self.config.col_a, 0, || Value::known(a))?; + + let b_cell = + region.assign_advice(|| "b", self.config.col_b, 0, || Value::known(b))?; + + let c_cell = region.assign_advice( + || "a + b", + self.config.col_c, + 0, + || a_cell.value().copied() + b_cell.value(), + )?; + + Ok((a_cell, b_cell, c_cell)) + }, + ) + } +} + +#[derive(Debug, Clone)] +pub struct TestConfig { + pub addchip_config: AddConfig, + pub range_check_config: RangeCheckConfig, + pub lookup_u8_table: Column, +} + +// The test circuit takes two inputs a and b. +// It adds them together by using the add chip to produce c = a + b. +// Performs a range check on a, b and c. Each value should lie in N_BYTES. +#[derive(Default, Clone, Debug)] +struct TestCircuit { + pub a: Fp, + pub b: Fp, +} + +/// Inherit the `CircuitBase` trait for the `TestCircuit` struct. +impl CircuitBase for TestCircuit {} + +impl Circuit for TestCircuit { + type Config = TestConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let z = meta.advice_column(); + let lookup_u8_table = meta.fixed_column(); + + let a = meta.advice_column(); + let b = meta.advice_column(); + let c = meta.advice_column(); + + meta.enable_equality(z); + meta.enable_equality(a); + meta.enable_equality(b); + meta.enable_equality(c); + + let constants = meta.fixed_column(); + meta.enable_constant(constants); + + let add_selector = meta.selector(); + let lookup_enable_selector = meta.complex_selector(); + + let range_check_config = + RangeCheckChip::::configure(meta, z, lookup_u8_table, lookup_enable_selector); + + let addchip_config = AddChip::configure(meta, a, b, c, add_selector); + + { + TestConfig { + addchip_config, + range_check_config, + lookup_u8_table, + } + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Initiate the add chip + let addchip = AddChip::construct(config.addchip_config); + let (a_cell, b_cell, c_cell) = + addchip.assign(self.a, self.b, layouter.namespace(|| "add chip"))?; + + // Load the lookup table + self.load(&mut layouter, config.lookup_u8_table)?; + + // Initiate the range check chip + let range_chip = RangeCheckChip::construct(config.range_check_config); + + // check range on a, b and c + range_chip.assign( + layouter.namespace(|| "checking value a is in range"), + &a_cell, + )?; + range_chip.assign( + layouter.namespace(|| "checking value b is in range"), + &b_cell, + )?; + range_chip.assign( + layouter.namespace(|| "checking value c is in range"), + &c_cell, + )?; + + Ok(()) + } +} + +#[cfg(test)] +mod testing { + use super::TestCircuit; + use halo2_proofs::{ + dev::{FailureLocation, MockProver, VerifyFailure}, + halo2curves::bn256::Fr as Fp, + plonk::Any, + }; + + // a = (1 << 16) - 2 = 0xfffe + // b = 1 + // c = a + b = 0xffff + // All the values are within 2 bytes range. + #[test] + fn test_none_overflow_16bits() { + let k = 9; + + // a: new value + let a = Fp::from((1 << 16) - 2); + let b = Fp::from(1); + + let circuit = TestCircuit::<2> { a, b }; + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied(); + } + + // a = (1 << 16) - 2 = 0xfffe + // b = 2 + // c = a + b = 0x10000 + // a and b are within 2 bytes range. + // c overflows 2 bytes so the circuit should fail. + #[test] + fn test_overflow_16bits() { + let k = 9; + + let a = Fp::from((1 << 16) - 2); + let b = Fp::from(2); + + let circuit = TestCircuit::<2> { a, b }; + let invalid_prover = MockProver::run(k, &circuit, vec![]).unwrap(); + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (4, "assign value to perform range check").into(), + offset: 2 + } + }, + VerifyFailure::Permutation { + column: (Any::Fixed, 1).into(), + location: FailureLocation::OutsideRegion { row: 2 } + }, + ]) + ); + } + + // a is the max value within the range (32 bits / 4 bytes) + // a = 0x-ff-ff-ff-ff + // b = 1 + // a and b are within 4 bytes range. + // c overflows 4 bytes so the circuit should fail. + #[test] + fn test_overflow_32bits() { + let k = 9; + + let a = Fp::from(0xffffffff); + let b = Fp::from(1); + + let circuit = TestCircuit::<4> { a, b }; + let invalid_prover = MockProver::run(k, &circuit, vec![]).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (4, "assign value to perform range check").into(), + offset: 4 + } + }, + VerifyFailure::Permutation { + column: (Any::Fixed, 1).into(), + location: FailureLocation::OutsideRegion { row: 2 } + }, + ]) + ); + } + + #[cfg(feature = "dev-graph")] + #[test] + fn print_range_check_test() { + use plotters::prelude::*; + + let root = + BitMapBackend::new("prints/range-check-layout.png", (1024, 3096)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root + .titled("Range Check Layout", ("sans-serif", 60)) + .unwrap(); + + let circuit = TestCircuit::<4> { + a: Fp::from(0x1f2f3f4f), + b: Fp::from(1), + }; + halo2_proofs::dev::CircuitLayout::default() + .render(9, &circuit, &root) + .unwrap(); + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/utils.rs b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/utils.rs new file mode 100644 index 0000000..c246816 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/chips/range/utils.rs @@ -0,0 +1,89 @@ +use crate::merkle_sum_tree::utils::{big_uint_to_fp, fp_to_big_uint}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use num_bigint::BigUint; + +/// Converts value Fp to n bytes of bytes in little endian order. +/// If value is decomposed in #bytes which are less than n, then the returned bytes are padded with 0s at the most significant bytes. +/// Example: +/// decompose_fp_to_bytes(0x1f2f3f, 4) -> [0x3f, 0x2f, 0x1f, 0x00] +/// If value is decomposed in #bytes which are greater than n, then the most significant bytes are truncated. A warning is printed. +/// Example: +/// decompose_fp_to_bytes(0x1f2f3f, 2) -> [0x3f, 0x2f] +pub fn decompose_fp_to_bytes(value: Fp, n: usize) -> Vec { + let value_biguint = fp_to_big_uint(value); + + let mut bytes = value_biguint.to_bytes_le(); + + // Pad with 0s at the most significant bytes if bytes length is less than n. + while bytes.len() < n { + bytes.push(0); + } + + // If the bytes length exceeds n, print a warning and truncate the byte array at the most significant bytes. + if bytes.len() > n { + println!("Warning: `decompose_fp_to_bytes` value is decomposed in #bytes which are greater than n. Truncating the output to fit the specified length."); + bytes.truncate(n); + } + + bytes +} + +pub fn pow_of_two(by: usize) -> Fp { + let res = BigUint::from(1u8) << by; + big_uint_to_fp(&res) +} + +#[cfg(test)] +mod testing { + + use super::*; + use num_bigint::BigUint; + + #[test] + fn test_fp_to_big_uint() { + let f = Fp::from(5); + let big_uint = fp_to_big_uint(f); + assert_eq!(big_uint, BigUint::from(5u8)); + } + + // convert a 32 bit number in 4 bytes. Should correctly convert to 4 bytes + #[test] + fn test_decompose_fp_to_bytes_no_padding() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_bytes(f, 4); + assert_eq!(bytes, vec![0x4f, 0x3f, 0x2f, 0x1f]); + } + + // convert a 32 bit number in 6 bytes. Should correctly convert to 6 bytes in which the first 2 bytes are 0 padded. + #[test] + fn test_decompose_fp_to_bytes_padding() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_bytes(f, 6); + assert_eq!(bytes, vec![0x4f, 0x3f, 0x2f, 0x1f, 0x00, 0x00]); + } + + // convert a 32 bit number in 2 bytes. Should convert to 2 bytes and truncate the most significant bytes and emit a warning + #[test] + fn test_decompose_fp_to_bytes_overflow() { + let f = Fp::from(0x1f2f3f4f); + let bytes = decompose_fp_to_bytes(f, 2); + assert_eq!(bytes, vec![0x4f, 0x3f]); + } + + // convert a 40 bit number in 2 bytes. Should convert to 2 most significant bytes and truncate the least significant byte + #[test] + fn test_decompose_fp_to_bytes_overflow_2() { + let f = Fp::from(0xf1f2f3f); + let bytes = decompose_fp_to_bytes(f, 2); + assert_eq!(bytes, vec![0x3f, 0x2f]); + } + + #[test] + fn test_pow_2() { + let pow = pow_of_two(8); + assert_eq!(pow, Fp::from(0x100)); + let pow = pow_of_two(72); + let big_uint = BigUint::from(0x1000000000000000000u128); + assert_eq!(pow, big_uint_to_fp(&big_uint)); + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circom/incremental_mst_inclusion.circom b/tools/polyexen/circuit/solvency/zk_prover/src/circom/incremental_mst_inclusion.circom new file mode 100644 index 0000000..3dd14bd --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circom/incremental_mst_inclusion.circom @@ -0,0 +1,77 @@ +pragma circom 2.0.3; + +include "./node_modules/circomlib/circuits/poseidon.circom"; +include "./merkle_sum_tree.circom"; + +/* +Inputs: +--------- +- step_in[2] : `user_state_prev` and `liabilities_state_prev` from the previous step of the IVC +- username: username of the user whose inclusion in the merkle sum tree we want to prove +- user_balances[N_CURRENCIES]: balances of the user whose inclusion in the merkle sum tree we want to prove +- path_element_hashes[LEVELS]: hashes of elements of the merkle path +- path_element_balances[LEVELS][N_CURRENCIES]: balances of the elements of the merkle path +- path_indices[LEVELS]: binary selector that indicates whether given path_element is on the left or right side of merkle path + +Outputs: +--------- +- step_out[2] : `user_state_cur` and `liabilities_state_cur`, namely the resulting states after the IVC step. + - `user_state_cur` is equal to H(`user_state_prev`, `leaf_hash`) + - `liabilities_state_cur` is equal to H(`liabilities_state_prev`, `root_hash`) + +Parameters: +------------ +- LEVELS: number of levels in the merkle sum tree +- N_CURRENCIES: number of currencies for each user +- N_BYTES: range of the balances of the users + +Functionality: +-------------- +1. Starting from the username and balances of the user, compute the `leaf_hash` +2. Starting from `user_state_prev` and `leaf_hash`, compute `user_state_cur` as H(`user_state_prev`, `leaf_hash`) +3. Starting from the `leaf_hash` and the Merkle Proof, compute the `root_hash` of the resulting Merkle Sum Tree +4. Starting from `liabilities_state_prev` and `root_hash`, compute `liabilities_state_cur` as H(`liabilities_state_prev`, `root_hash`) +*/ +template IncrementalMstInclusion (LEVELS, N_CURRENCIES, N_BYTES) { + signal input step_in[2]; + + signal input username; + signal input user_balances[N_CURRENCIES]; + signal input path_element_hashes[LEVELS]; + signal input path_element_balances[LEVELS][N_CURRENCIES]; + signal input path_indices[LEVELS]; + + signal output step_out[2]; + + // 1. + component build_leaf_hash = Poseidon(1 + N_CURRENCIES); + build_leaf_hash.inputs[0] <== username; + for (var i = 0; i < N_CURRENCIES; i++) { + build_leaf_hash.inputs[i + 1] <== user_balances[i]; + } + + // 2. + component build_user_state_cur = Poseidon(2); + build_user_state_cur.inputs[0] <== step_in[0]; + build_user_state_cur.inputs[1] <== build_leaf_hash.out; + + // 3. + component check_inclusion = MerkleSumTreeInclusion(LEVELS, N_CURRENCIES, N_BYTES); + + check_inclusion.leaf_hash <== build_leaf_hash.out; + check_inclusion.leaf_balances <== user_balances; + check_inclusion.path_element_hashes <== path_element_hashes; + check_inclusion.path_element_balances <== path_element_balances; + check_inclusion.path_indices <== path_indices; + + // 4. + component build_liabilities_state_cur = Poseidon(2); + build_liabilities_state_cur.inputs[0] <== step_in[1]; + build_liabilities_state_cur.inputs[1] <== check_inclusion.root_hash; + + step_out[0] <== build_user_state_cur.out; + step_out[1] <== build_liabilities_state_cur.out; +} + +component main { public [step_in] } = IncrementalMstInclusion(4, 2, 14); + diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circom/merkle_sum_tree.circom b/tools/polyexen/circuit/solvency/zk_prover/src/circom/merkle_sum_tree.circom new file mode 100644 index 0000000..94cb83c --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circom/merkle_sum_tree.circom @@ -0,0 +1,254 @@ +pragma circom 2.0.3; + +include "./node_modules/circomlib/circuits/poseidon.circom"; +include "./node_modules/circomlib/circuits/bitify.circom"; +include "./node_modules/circomlib/circuits/mux1.circom"; + +/* +Inputs: +--------- +- left_balances[N_CURRENCIES] : Balances of the left node +- right_balances[N_CURRENCIES] : Balances of the right node + +Outputs: +--------- +- out_balances[N_CURRENCIES] : Each element of `out_balances` is the sum of the corresponding elements in left_balances and right_balances. +Ex. out_balances[0] = left_balances[0] + right_balances[0] + +Functionality: +-------------- +1. Constraint each input balance to be within the range [0, N_BYTES] +2. Perform the summation of two balances + +Notes: +------ +- The range check is performed only on the input of the summation. The range check on the output of the summation will be performed in the next level of the tree. +When the output will be used as an input to another summation. When the next level is the root, the range check is performed outside of the Summer template + +*/ + +template Summer(N_CURRENCIES, N_BYTES) { + signal input left_balances[N_CURRENCIES]; + signal input right_balances[N_CURRENCIES]; + signal output out_balances[N_CURRENCIES]; + + component left_in_range[N_CURRENCIES]; + component right_in_range[N_CURRENCIES]; + + for (var i = 0; i < N_CURRENCIES; i++) { + left_in_range[i] = Num2Bits(8*N_BYTES); + right_in_range[i] = Num2Bits(8*N_BYTES); + + left_in_range[i].in <== left_balances[i]; + right_in_range[i].in <== right_balances[i]; + + out_balances[i] <== left_balances[i] + right_balances[i]; + } +} + +/* +Inputs: +--------- +- left_hash: Hash of the left node +- left_balances[N_CURRENCIES] : Balances of the left node +- right_hash: Hash of the right node +- right_balances[N_CURRENCIES] : Balances of the right node +- s: binary selector + +Outputs: +--------- +- swapped_left_hash: left_hash if s = 0, right_hash if s = 1 +- swapped_left_balances[N_CURRENCIES]: left_balances if s = 0, right_balances if s = 1 +- swapped_right_hash: right_hash if s = 0, left_hash if s = 1 +- swapped_right_balances[N_CURRENCIES]: right_balances if s = 0, left_balances if s = 1 + +Parameters: +------------ +- N_CURRENCIES: number of currencies for each user + +Functionality: +-------------- +1. Perform the swapping of two nodes belonging to a level of the merkle sum tree according to the binary selector s +2. Constraint that s is either 0 or 1 +*/ + +template Swapper(N_CURRENCIES) { + signal input left_hash; + signal input left_balances[N_CURRENCIES]; + signal input right_hash; + signal input right_balances[N_CURRENCIES]; + signal input s; + signal output swapped_left_hash; + signal output swapped_left_balances[N_CURRENCIES]; + signal output swapped_right_hash; + signal output swapped_right_balances[N_CURRENCIES]; + + s * (1 - s) === 0; + + component mux = MultiMux1(2 + 2*N_CURRENCIES); + + mux.c[0][0] <== left_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + mux.c[1 + i][0] <== left_balances[i]; + } + + mux.c[1 + N_CURRENCIES][0] <== right_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + mux.c[2 + N_CURRENCIES + i][0] <== right_balances[i]; + } + + mux.c[0][1] <== right_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + mux.c[1 + i][1] <== right_balances[i]; + } + + mux.c[1 + N_CURRENCIES][1] <== left_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + mux.c[2 + N_CURRENCIES + i][1] <== left_balances[i]; + } + + mux.s <== s; + + swapped_left_hash <== mux.out[0]; + + for (var i = 0; i < N_CURRENCIES; i++) { + swapped_left_balances[i] <== mux.out[1 + i]; + } + + swapped_right_hash <== mux.out[1 + N_CURRENCIES]; + + for (var i = 0; i < N_CURRENCIES; i++) { + swapped_right_balances[i] <== mux.out[2 + N_CURRENCIES + i]; + } +} + +/* +Inputs: +--------- +- left_hash: Hash of the left node +- left_balances[N_CURRENCIES] : Balances of the left node +- right_hash: Hash of the right node +- right_balances[N_CURRENCIES] : Balances of the right node + +Outputs: +--------- +- hash: poseidon hash of (left_hash, left_balances[0], ..., left_balances[N_CURRENCIES - 1], right_hash, right_balances[0], ..., right_balances[N_CURRENCIES - 1]) + +Parameters: +------------ +- N_CURRENCIES: number of currencies for each user + +Functionality: +-------------- +1. Perform the hashing of two nodes belonging to a level of the merkle sum tree +*/ + +template Hasher(N_CURRENCIES) { + signal input left_hash; + signal input left_balances[N_CURRENCIES]; + signal input right_hash; + signal input right_balances[N_CURRENCIES]; + signal output hash; + + // 1. + component hasher = Poseidon(2 + 2*N_CURRENCIES); + + hasher.inputs[0] <== left_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + hasher.inputs[1 + i] <== left_balances[i]; + } + + hasher.inputs[1 + N_CURRENCIES] <== right_hash; + + for (var i = 0; i < N_CURRENCIES; i++) { + hasher.inputs[2 + N_CURRENCIES + i] <== right_balances[i]; + } + + hash <== hasher.out; +} + + +/* +Inputs: +--------- +- leaf_hash: hash of the leaf node that we want to prove inclusion for +- leaf_balances[N_CURRENCIES]: balances of the leaf node that we want to prove inclusion for +- path_element_hashes[LEVELS]: hashes of elements of the merkle path +- path_element_balances[LEVELS][N_CURRENCIES]: balances of the elements of the merkle path +- path_indices[LEVELS]: binary selector that indicates whether given path_element is on the left or right side of merkle path + +Outputs: +--------- +- root_hash: root hash of the resulting merkle sum tree + +Parameters: +------------ +- LEVELS: number of levels in the merkle sum tree +- N_CURRENCIES: number of currencies for each user +- N_BYTES: range of the balances of the users + +Functionality: +-------------- +1. For each level of the tree, perform the summation between the balances of the two nodes +2. For each level of the tree, perform the swapping of the nodes according to the binary selector +3. For each level of the tree, perform the hashing of the two swapped nodes +4. At the latest level, perform the range check on the root balances + +Notes: +------ +- The summer is performed before the swapper because the swap doesn't influence the summation. +*/ +template MerkleSumTreeInclusion(LEVELS, N_CURRENCIES, N_BYTES) { + signal input leaf_hash; + signal input leaf_balances[N_CURRENCIES]; + signal input path_element_hashes[LEVELS]; + signal input path_element_balances[LEVELS][N_CURRENCIES]; + signal input path_indices[LEVELS]; + + signal output root_hash; + + component summers[LEVELS]; + component swappers[LEVELS]; + component hashers[LEVELS]; + + for (var i = 0; i < LEVELS; i++) { + // 1. + summers[i] = Summer(N_CURRENCIES, N_BYTES); + + summers[i].left_balances <== i == 0 ? leaf_balances : summers[i - 1].out_balances; + summers[i].right_balances <== path_element_balances[i]; + + // 2. + swappers[i] = Swapper(N_CURRENCIES); + + swappers[i].left_hash <== i == 0 ? leaf_hash : hashers[i - 1].hash; + swappers[i].left_balances <== i == 0 ? leaf_balances : summers[i - 1].out_balances; + swappers[i].right_hash <== path_element_hashes[i]; + swappers[i].right_balances <== path_element_balances[i]; + swappers[i].s <== path_indices[i]; + + // 3. + hashers[i] = Hasher(N_CURRENCIES); + + hashers[i].left_hash <== swappers[i].swapped_left_hash; + hashers[i].left_balances <== swappers[i].swapped_left_balances; + hashers[i].right_hash <== swappers[i].swapped_right_hash; + hashers[i].right_balances <== swappers[i].swapped_right_balances; + + } + + // 4. + component root_balance_in_range[N_CURRENCIES]; + + for (var i = 0; i < N_CURRENCIES; i++) { + root_balance_in_range[i] = Num2Bits(8*N_BYTES); + root_balance_in_range[i].in <== summers[LEVELS - 1].out_balances[i]; + } + + root_hash <== hashers[LEVELS - 1].hash; +} \ No newline at end of file diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circom/package-lock.json b/tools/polyexen/circuit/solvency/zk_prover/src/circom/package-lock.json new file mode 100644 index 0000000..123c855 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circom/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "circom", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "circom", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "circomlib": "^2.0.5" + } + }, + "node_modules/circomlib": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/circomlib/-/circomlib-2.0.5.tgz", + "integrity": "sha512-O7NQ8OS+J4eshBuoy36z/TwQU0YHw8W3zxZcs4hVwpEll3e4hDm3mgkIPqItN8FDeLEKZFK3YeT/+k8TiLF3/A==" + } + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circom/package.json b/tools/polyexen/circuit/solvency/zk_prover/src/circom/package.json new file mode 100644 index 0000000..7117d38 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circom/package.json @@ -0,0 +1,9 @@ +{ + "name": "circom", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "circomlib": "^2.0.5" + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/merkle_sum_tree.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/merkle_sum_tree.rs new file mode 100644 index 0000000..819a165 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/merkle_sum_tree.rs @@ -0,0 +1,522 @@ +use crate::chips::merkle_sum_tree::{MerkleSumTreeChip, MerkleSumTreeConfig}; +use crate::chips::poseidon::hash::{PoseidonChip, PoseidonConfig}; +use crate::chips::poseidon::poseidon_spec::PoseidonSpec; +use crate::chips::range::range_check::{RangeCheckChip, RangeCheckConfig}; +use crate::circuits::traits::CircuitBase; +use crate::circuits::WithInstances; +use crate::merkle_sum_tree::utils::big_uint_to_fp; +use crate::merkle_sum_tree::{Entry, MerkleProof, Node}; +use halo2_proofs::circuit::{AssignedCell, Layouter, SimpleFloorPlanner}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use halo2_proofs::plonk::{ + Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector, +}; + +/// Circuit for verifying inclusion of an entry (username, balances) inside a merkle sum tree with a given root. +/// +/// # Type Parameters +/// +/// * `LEVELS`: The number of levels of the merkle sum tree. In particular, it indicates the number of hashing operations that are performed from the leaf to the root. For example a tree with 16 entries has 4 levels. +/// * `N_CURRENCIES`: The number of currencies for which the solvency is verified. +/// * `N_BYTES`: The number of bytes in which the balances should lie +/// +/// # Fields +/// +/// * `entry`: The entry to be verified inclusion of. +/// * `path_indices`: The boolean indices of the path elements from the leaf to the root. 0 indicates that the element is on the right to the path, 1 indicates that the element is on the left to the path. The length of this vector is LEVELS +/// * `sibling_leaf_node_hash_preimage`: The preimage of the hash that corresponds to the Sibling Leaf Node (part of the Merkle Proof). +/// * `sibling_middle_node_hash_preimages`: The preimages of the hashes that corresponds to the Sibling Middle Nodes (part of the Merkle Proof). +/// * `root`: The root of the Merkle Sum Tree +#[derive(Clone)] +pub struct MstInclusionCircuit +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub entry: Entry, + pub path_indices: Vec, + pub sibling_leaf_node_hash_preimage: [Fp; N_CURRENCIES + 1], + pub sibling_middle_node_hash_preimages: Vec<[Fp; N_CURRENCIES + 2]>, + pub root: Node, +} + +impl WithInstances + for MstInclusionCircuit +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + /// Returns the number of public inputs of the circuit. It is {2 + N_CURRENCIES}, namely the leaf hash to be verified inclusion of, the root hash of the merkle sum tree and the root balances of the merkle sum tree. + fn num_instances(&self) -> usize { + 2 + N_CURRENCIES + } + /// Returns the values of the public inputs of the circuit. Namely the leaf hash to be verified inclusion of and the root hash of the merkle sum tree. + fn instances(&self) -> Vec> { + let mut instance = vec![self.entry.compute_leaf().hash, self.root.hash]; + instance.extend_from_slice(&self.root.balances); + vec![instance] + } +} + +impl CircuitBase + for MstInclusionCircuit +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ +} + +impl + MstInclusionCircuit +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub fn init_empty() -> Self { + Self { + entry: Entry::zero_entry(), + path_indices: vec![Fp::zero(); LEVELS], + sibling_leaf_node_hash_preimage: [Fp::zero(); N_CURRENCIES + 1], + sibling_middle_node_hash_preimages: vec![[Fp::zero(); N_CURRENCIES + 2]; LEVELS], + root: Node::init_empty(), + } + } + + /// Initializes the circuit with the merkle proof and the entry of the user of which the inclusion is to be verified. + pub fn init(merkle_proof: MerkleProof) -> Self + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + assert_eq!(merkle_proof.path_indices.len(), LEVELS); + assert_eq!( + merkle_proof.sibling_middle_node_hash_preimages.len(), + LEVELS - 1 + ); + Self { + entry: merkle_proof.entry, + path_indices: merkle_proof.path_indices, + sibling_leaf_node_hash_preimage: merkle_proof.sibling_leaf_node_hash_preimage, + sibling_middle_node_hash_preimages: merkle_proof.sibling_middle_node_hash_preimages, + root: merkle_proof.root, + } + } +} + +/// Configuration for the Mst Inclusion circuit +/// # Type Parameters +/// +/// * `N_CURRENCIES`: The number of currencies for which the solvency is verified. +/// * `N_BYTES`: The number of bytes in which the balances should lie +/// +/// # Fields +/// +/// * `merkle_sum_tree_config`: Configuration for the merkle sum tree +/// * `poseidon_entry_config`: Configuration for the poseidon hash function with WIDTH = 2 and RATE = 1 and input length of N_CURRENCIES + 1. Needed to perform the hashing from the entry to the leaf. +/// * `poseidon_middle_config`: Configuration for the poseidon hash function with WIDTH = 2 and RATE = 1 and input length of N_CURRENCIES + 2. Needed to perform hashings from the leaf to the root. +/// * `range_check_config`: Configuration for the range check chip +/// * `instance`: Instance column used to store the public inputs +/// * `advices`: Advice columns used to store the private inputs + +#[derive(Debug, Clone)] +pub struct MstInclusionConfig +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + merkle_sum_tree_config: MerkleSumTreeConfig, + poseidon_entry_config: PoseidonConfig<2, 1, { N_CURRENCIES + 1 }>, + poseidon_middle_config: PoseidonConfig<2, 1, { N_CURRENCIES + 2 }>, + range_check_config: RangeCheckConfig, + instance: Column, + advices: [Column; 3], + fixed_columns: [Column; 5], +} + +impl MstInclusionConfig +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub fn configure(meta: &mut ConstraintSystem) -> Self { + // the max number of advices columns needed is WIDTH + 1 given requirement of the poseidon config + let advices: [Column; 3] = std::array::from_fn(|_| meta.advice_column()); + + // we need 2 * WIDTH fixed columns for poseidon config + 1 for the range check chip + let fixed_columns: [Column; 5] = std::array::from_fn(|_| meta.fixed_column()); + + // we also need 2 selectors for the MerkleSumTreeChip + let selectors: [Selector; 2] = std::array::from_fn(|_| meta.selector()); + + // we need 1 complex selector for the lookup check in the range check chip + let enable_lookup_selector = meta.complex_selector(); + + // enable constant for the fixed_column[2], this is required for the poseidon chip and the range check chip + meta.enable_constant(fixed_columns[2]); + + let poseidon_entry_config = + PoseidonChip::::configure( + meta, + advices[0..2].try_into().unwrap(), + advices[2], + fixed_columns[0..2].try_into().unwrap(), + fixed_columns[2..4].try_into().unwrap(), + ); + + // in fact, the poseidon config requires #WIDTH advice columns for state and 1 for partial_sbox, #WIDTH fixed columns for rc_a and #WIDTH for rc_b + let poseidon_middle_config = + PoseidonChip::::configure( + meta, + advices[0..2].try_into().unwrap(), + advices[2], + fixed_columns[0..2].try_into().unwrap(), + fixed_columns[2..4].try_into().unwrap(), + ); + + // enable permutation for all the advice columns + for col in &advices { + meta.enable_equality(*col); + } + + // the configuration of merkle_sum_tree will always require 3 advices, no matter the number of currencies + let merkle_sum_tree_config = MerkleSumTreeChip::::configure( + meta, + advices[0..3].try_into().unwrap(), + selectors[0..2].try_into().unwrap(), + ); + + let range_check_config = RangeCheckChip::::configure( + meta, + advices[0], + fixed_columns[4], + enable_lookup_selector, + ); + + let instance = meta.instance_column(); + meta.enable_equality(instance); + + Self { + merkle_sum_tree_config, + poseidon_entry_config, + poseidon_middle_config, + range_check_config, + instance, + advices, + fixed_columns, + } + } +} + +impl Circuit + for MstInclusionCircuit +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + type Config = MstInclusionConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self::init_empty() + } + + /// Configures the circuit + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + MstInclusionConfig::::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // build auxiliary chips + let merkle_sum_tree_chip = + MerkleSumTreeChip::::construct(config.merkle_sum_tree_config); + + let poseidon_entry_chip = + PoseidonChip::::construct( + config.poseidon_entry_config, + ); + + let poseidon_middle_chip = + PoseidonChip::::construct( + config.poseidon_middle_config, + ); + + let range_check_chip = RangeCheckChip::::construct(config.range_check_config); + + // Assign the entry username to the witness + let username = self.assign_value_to_witness( + layouter.namespace(|| "assign entry username"), + big_uint_to_fp(self.entry.username_as_big_uint()), + "entry username", + config.advices[0], + )?; + + // Assign the entry balances to the witness + let mut current_balances = vec![]; + + for i in 0..N_CURRENCIES { + let balance = self.assign_value_to_witness( + layouter.namespace(|| format!("assign entry balance {}", i)), + big_uint_to_fp(&self.entry.balances()[i]), + "entry balance", + config.advices[1], + )?; + current_balances.push(balance); + } + + // Perform the hashing to username and balances to obtain the leaf hash + // create an hash_input array of length N_CURRENCIES + 1 that contains the entry username and the entry balances + let entry_hasher_input_vec: Vec> = [username] + .iter() + .chain(current_balances.iter()) + .map(|x| x.to_owned()) + .collect(); + + let entry_hasher_input: [AssignedCell; N_CURRENCIES + 1] = + match entry_hasher_input_vec.try_into() { + Ok(arr) => arr, + Err(_) => panic!("Failed to convert Vec to Array"), + }; + + // compute the entry hash + let mut current_hash = poseidon_entry_chip.hash( + layouter.namespace(|| "perform poseidon entry hash"), + entry_hasher_input, + )?; + + // expose the first current hash, namely the leaf hash, as public input + self.expose_public( + layouter.namespace(|| "public leaf hash"), + ¤t_hash, + 0, + config.instance, + )?; + + // load lookup table for range check + self.load(&mut layouter, config.fixed_columns[4])?; + + for level in 0..LEVELS { + let namespace_prefix = format!("level {}", level); + + let sibling_hash: AssignedCell; // hash of the sibling node + let mut sibling_balances: Vec> = vec![]; // balances of the sibling node + + // Perform the hashing of sibling leaf hash preimage to obtain the sibling leaf hash + if level == 0 { + // Assign username from sibling leaf node hash preimage to the circuit + let sibling_leaf_node_username = self.assign_value_to_witness( + layouter.namespace(|| format!("sibling leaf node username")), + self.sibling_leaf_node_hash_preimage[0], + "sibling leaf node username", + config.advices[0], + )?; + + // Assign balances from sibling leaf node hash preimage to the circuit + for currency in 0..N_CURRENCIES { + let leaf_node_sibling_balance = self.assign_value_to_witness( + layouter.namespace(|| format!("sibling leaf node balance {}", currency)), + self.sibling_leaf_node_hash_preimage[currency + 1], + "sibling leaf balance", + config.advices[1], + )?; + sibling_balances.push(leaf_node_sibling_balance); + } + + // create an hash_input array of length N_CURRENCIES + 1 that contains the sibling_leaf_node_username and the sibling_balances (the sibling leaf node hash preimage) + let sibling_hasher_input_vec: Vec> = + [sibling_leaf_node_username] + .iter() + .chain(sibling_balances.iter()) + .map(|x| x.to_owned()) + .collect(); + + let sibling_hasher_input: [AssignedCell; N_CURRENCIES + 1] = + match sibling_hasher_input_vec.try_into() { + Ok(arr) => arr, + Err(_) => panic!("Failed to convert Vec to Array"), + }; + + // compute the sibling hash + let computed_sibling_hash = poseidon_entry_chip.hash( + layouter.namespace(|| format!("{}: perform poseidon hash", namespace_prefix)), + sibling_hasher_input, + )?; + + // For level 0, perform range check on the leaf node balances and on the sibling node balances + for currency in 0..N_CURRENCIES { + // Each balance cell is constrained to be within the range defined by N_BYTES + range_check_chip.assign( + layouter.namespace(|| { + format!( + "{}: currency {}: range check leaf balance", + namespace_prefix, currency + ) + }), + ¤t_balances[currency], + )?; + range_check_chip.assign( + layouter.namespace(|| { + format!( + "{}: currency {}: range check sibling balance", + namespace_prefix, currency + ) + }), + &sibling_balances[currency], + )?; + } + + sibling_hash = computed_sibling_hash; + } + // Other levels + // Assign sibling node hash preimage to the circuit (split it in balances, left child hash and right child hash) + // Perform the hashing of sibling node hash preimage to obtain the sibling node hash + else { + // Assign balances from sibling middle node hash preimage to the circuit + for currency in 0..N_CURRENCIES { + let middle_node_sibling_balance = self.assign_value_to_witness( + layouter.namespace(|| format!("sibling node balance {}", currency)), + self.sibling_middle_node_hash_preimages[level - 1][currency], + "sibling node balance", + config.advices[1], + )?; + sibling_balances.push(middle_node_sibling_balance); + } + + // Assign middle_node_sibling_child_left_hash from middle node hash preimage to the circuit + let middle_node_sibling_child_left_hash = self.assign_value_to_witness( + layouter.namespace(|| format!("sibling left hash")), + self.sibling_middle_node_hash_preimages[level - 1][N_CURRENCIES], + "sibling left hash", + config.advices[2], + )?; + + // Assign middle_node_sibling_child_right_hash from middle node hash preimage to the circuit + let middle_node_sibling_child_right_hash = self.assign_value_to_witness( + layouter.namespace(|| format!("sibling right hash")), + self.sibling_middle_node_hash_preimages[level - 1][N_CURRENCIES + 1], + "sibling right hash", + config.advices[2], + )?; + + // create an hash_input array of length 2 + N_CURRENCIES that contains the sibling balances, the middle_node_sibling_child_left_hash and the middle_node_sibling_child_right_hash + let sibling_hasher_input_vec: Vec> = sibling_balances + .iter() + .chain([middle_node_sibling_child_left_hash].iter()) + .chain([middle_node_sibling_child_right_hash].iter()) + .map(|x| x.to_owned()) + .collect(); + + let sibling_hasher_input: [AssignedCell; N_CURRENCIES + 2] = + match sibling_hasher_input_vec.try_into() { + Ok(arr) => arr, + Err(_) => panic!("Failed to convert Vec to Array"), + }; + + // compute the sibling hash + let computed_sibling_hash = poseidon_middle_chip.hash( + layouter.namespace(|| format!("{}: perform poseidon hash", namespace_prefix)), + sibling_hasher_input, + )?; + + // For other levels, only perform range on the sibling node balances. Any risk of overflow of the `current_balances` will be checked during verification + for (currency, sibling_balance) in + sibling_balances.iter().enumerate().take(N_CURRENCIES) + { + // Each balance cell is constrained to be within the range defined by N_BYTES + range_check_chip.assign( + layouter.namespace(|| { + format!( + "{}: currency {}: range check sibling balance", + namespace_prefix, currency + ) + }), + sibling_balance, + )?; + } + + sibling_hash = computed_sibling_hash; + }; + + // For each level assign the swap bit to the circuit + let swap_bit_level = self.assign_value_to_witness( + layouter.namespace(|| format!("{}: assign swap bit", namespace_prefix)), + self.path_indices[level], + "swap bit", + config.advices[0], + )?; + + // For every level, perform the swap of the hashes (between `current_hash` and `sibling_hash`) according to the swap bit + let (hash_left_current, hash_right_current) = merkle_sum_tree_chip + .swap_hashes_per_level( + layouter.namespace(|| format!("{}: swap hashes", namespace_prefix)), + ¤t_hash, + &sibling_hash, + &swap_bit_level, + )?; + + let mut next_balances = vec![]; + + // For every level, perform sum the balances `current_balances` and `sibling_balances` + for currency in 0..N_CURRENCIES { + let next_balance = merkle_sum_tree_chip.sum_balances_per_level( + layouter.namespace(|| { + format!( + "{}: currency {}: perform balance sum", + namespace_prefix, currency + ) + }), + ¤t_balances[currency], + &sibling_balances[currency], + )?; + + next_balances.push(next_balance); + } + + // create an hash_input array of length N_CURRENCIES + 2 that contains the next balances, the left hash and the right hash + let middle_hasher_input_vec: Vec> = next_balances + .iter() + .chain([hash_left_current].iter()) + .chain([hash_right_current].iter()) + .map(|x| x.to_owned()) + .collect(); + + let middle_hasher_input: [AssignedCell; N_CURRENCIES + 2] = + match middle_hasher_input_vec.try_into() { + Ok(arr) => arr, + Err(_) => panic!("Failed to convert Vec to Array"), + }; + + // compute the next hash + let computed_hash = poseidon_middle_chip.hash( + layouter.namespace(|| format!("{}: perform poseidon hash", namespace_prefix)), + middle_hasher_input, + )?; + + current_balances = next_balances; + current_hash = computed_hash; + } + + // expose the last current hash, namely the root hash, as public input + self.expose_public( + layouter.namespace(|| "public root hash"), + ¤t_hash, + 1, + config.instance, + )?; + + // expose the last current balances, namely the root balances, as public input + for (i, balance) in current_balances.iter().enumerate() { + self.expose_public( + layouter.namespace(|| format!("public root balance {}", i)), + balance, + 2 + i, + config.instance, + )?; + } + Ok(()) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/mod.rs new file mode 100644 index 0000000..0563766 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/mod.rs @@ -0,0 +1,12 @@ +pub mod merkle_sum_tree; +mod tests; +pub mod traits; +pub mod types; +pub mod utils; + +use halo2_proofs::halo2curves::bn256::Fr as Fp; + +pub trait WithInstances { + fn num_instances(&self) -> usize; + fn instances(&self) -> Vec>; +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/tests.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/tests.rs new file mode 100644 index 0000000..cab5e15 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/tests.rs @@ -0,0 +1,461 @@ +#[cfg(test)] +mod test { + + use crate::circuits::WithInstances; + use crate::merkle_sum_tree::{MerkleSumTree, Tree}; + use crate::{ + circuits::{ + merkle_sum_tree::MstInclusionCircuit, + utils::{full_prover, full_verifier, generate_setup_artifacts}, + }, + merkle_sum_tree::Entry, + }; + use halo2_proofs::{ + dev::{FailureLocation, MockProver, VerifyFailure}, + halo2curves::bn256::Fr as Fp, + plonk::Any, + }; + use num_bigint::ToBigUint; + + const N_CURRENCIES: usize = 2; + const LEVELS: usize = 4; + const N_BYTES: usize = 8; + const K: u32 = 11; + + #[test] + fn test_valid_merkle_sum_tree() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + for user_index in 0..16 { + // get proof for entry ˆuser_indexˆ + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let valid_prover = MockProver::run(K, &circuit, circuit.instances()).unwrap(); + + assert_eq!(circuit.instances()[0].len(), circuit.num_instances()); + assert_eq!(circuit.instances()[0].len(), 2 + N_CURRENCIES); + + valid_prover.assert_satisfied(); + } + } + + #[test] + fn test_valid_merkle_sum_tree_with_full_prover() { + let circuit = MstInclusionCircuit::::init_empty(); + + // Generate a universal trusted setup for testing purposes. + // + // The verification key (vk) and the proving key (pk) are then generated. + // An empty circuit is used here to emphasize that the circuit inputs are not relevant when generating the keys. + // Important: The dimensions of the circuit used to generate the keys must match those of the circuit used to generate the proof. + // In this case, the dimensions are represented by the height of the Merkle tree. + let (params, pk, vk) = generate_setup_artifacts(K, None, circuit).unwrap(); + + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + let user_entry = merkle_sum_tree.get_entry(user_index); + + // Only now we can instantiate the circuit with the actual inputs + let circuit = MstInclusionCircuit::::init(merkle_proof); + + // Generate the proof + let proof = full_prover(¶ms, &pk, circuit.clone(), circuit.instances()); + + // verify the proof to be true + assert!(full_verifier(¶ms, &vk, proof, circuit.instances())); + + // the user should perform the check on the public inputs + // public input #0 is the leaf hash + let expected_leaf_hash = user_entry.compute_leaf().hash; + assert_eq!(circuit.instances()[0][0], expected_leaf_hash); + + // public input #1 is the root hash + let expected_root_hash = merkle_sum_tree.root().hash; + assert_eq!(circuit.instances()[0][1], expected_root_hash); + + // public inputs [2, 2+N_CURRENCIES - 1] are the root balances + let expected_root_balances = merkle_sum_tree.root().balances; + for i in 0..N_CURRENCIES { + assert_eq!(circuit.instances()[0][2 + i], expected_root_balances[i]); + } + } + + // Passing an invalid root hash in the instance column should fail the permutation check between the computed root hash and the instance column root hash + #[test] + fn test_invalid_root_hash() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let mut instances = circuit.instances(); + let invalid_root_hash = Fp::from(1000u64); + instances[0][1] = invalid_root_hash; + + let invalid_prover = MockProver::run(K, &circuit, instances).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (121, "permute state").into(), + offset: 36 + } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 1 } + }, + ]) + ); + } + + #[test] + fn test_invalid_root_hash_as_instance_with_full_prover() { + let circuit = MstInclusionCircuit::::init_empty(); + + // generate a universal trusted setup for testing, along with the verification key (vk) and the proving key (pk). + let (params, pk, vk) = generate_setup_artifacts(K, None, circuit).unwrap(); + + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let invalid_root_hash = Fp::from(1000u64); + + let mut instances = circuit.instances(); + instances[0][1] = invalid_root_hash; + + // Generate the proof + let proof = full_prover(¶ms, &pk, circuit, instances.clone()); + + // verify the proof to be false + assert!(!full_verifier(¶ms, &vk, proof, instances)); + } + + // Passing an invalid entry balance as input for the witness generation should fail: + // - the permutation check between the leaf hash and the instance column leaf hash + // - the permutation check between the computed root hash and the instance column root hash + // - the permutations checks between the computed root balances and the instance column root balances + #[test] + fn test_invalid_entry_balance_as_witness() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let mut circuit = MstInclusionCircuit::::init(merkle_proof); + + let instances = circuit.instances(); + + let invalid_leaf_balances = [1000.to_biguint().unwrap(), 1000.to_biguint().unwrap()]; + + // invalidate user entry + let invalid_entry = + Entry::new(circuit.entry.username().to_string(), invalid_leaf_balances).unwrap(); + + circuit.entry = invalid_entry; + + let invalid_prover = MockProver::run(K, &circuit, instances).unwrap(); + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (26, "assign nodes hashes per merkle tree level").into(), + offset: 0 + } + }, + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (121, "permute state").into(), + offset: 36 + } + }, + VerifyFailure::Permutation { + column: (Any::advice(), 2).into(), + location: FailureLocation::InRegion { + region: (111, "sum nodes balances per currency").into(), + offset: 0 + } + }, + VerifyFailure::Permutation { + column: (Any::advice(), 2).into(), + location: FailureLocation::InRegion { + region: (112, "sum nodes balances per currency").into(), + offset: 0 + } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 0 } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 1 } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 2 } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 3 } + }, + ]) + ); + } + + // Passing an invalid leaf hash in the instance column should fail the permutation check between the (valid) leaf hash added as part of the witness and the instance column leaf hash + #[test] + fn test_invalid_leaf_hash_as_instance() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let mut instances = circuit.instances(); + let invalid_leaf_hash = Fp::from(1000u64); + instances[0][0] = invalid_leaf_hash; + + let invalid_prover = MockProver::run(K, &circuit, instances).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (26, "assign nodes hashes per merkle tree level").into(), + offset: 0 + } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 0 } + }, + ]) + ); + } + + // Building a proof using as input a csv file with an entry that is not in range [0, 2^N_BYTES*8 - 1] should fail the range check constraint on the leaf balance + #[test] + fn test_balance_not_in_range() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16_overflow.csv") + .unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let invalid_prover = MockProver::run(K, &circuit, circuit.instances()).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::Fixed, 2).into(), + location: FailureLocation::OutsideRegion { row: 246 } + }, + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (21, "assign value to perform range check").into(), + offset: 8 + } + }, + ]) + ); + } + + // Passing a non binary index should fail the bool constraint inside "assign nodes hashes per merkle tree level" and "assign nodes balances per currency" region and the permutation check between the computed root hash and the instance column root hash + #[test] + fn test_non_binary_index() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let mut circuit = MstInclusionCircuit::::init(merkle_proof); + + let instances = circuit.instances(); + + // invalidate path index inside the circuit + circuit.path_indices[0] = Fp::from(2); + + let invalid_prover = MockProver::run(K, &circuit, instances).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::ConstraintNotSatisfied { + constraint: ((6, "bool constraint").into(), 0, "").into(), + location: FailureLocation::InRegion { + region: (26, "assign nodes hashes per merkle tree level").into(), + offset: 0 + }, + cell_values: vec![(((Any::advice(), 2).into(), 0).into(), "0x2".to_string()),] + }, + VerifyFailure::ConstraintNotSatisfied { + constraint: ((7, "swap constraint").into(), 0, "").into(), + location: FailureLocation::InRegion { + region: (26, "assign nodes hashes per merkle tree level").into(), + offset: 0 + }, + cell_values: vec![ + ( + ((Any::advice(), 0).into(), 0).into(), + "0xe113acd03b98f0bab0ef6f577245d5d008cbcc19ef2dab3608aa4f37f72a407" + .to_string() + ), + ( + ((Any::advice(), 0).into(), 1).into(), + "0x17ef9d8ee0e2c8470814651413b71009a607a020214f749687384a7b7a7eb67a" + .to_string() + ), + ( + ((Any::advice(), 1).into(), 0).into(), + "0x17ef9d8ee0e2c8470814651413b71009a607a020214f749687384a7b7a7eb67a" + .to_string() + ), + (((Any::advice(), 2).into(), 0).into(), "0x2".to_string()), + ] + }, + VerifyFailure::ConstraintNotSatisfied { + constraint: ((7, "swap constraint").into(), 1, "").into(), + location: FailureLocation::InRegion { + region: (26, "assign nodes hashes per merkle tree level").into(), + offset: 0 + }, + cell_values: vec![ + ( + ((Any::advice(), 0).into(), 0).into(), + "0xe113acd03b98f0bab0ef6f577245d5d008cbcc19ef2dab3608aa4f37f72a407" + .to_string() + ), + ( + ((Any::advice(), 1).into(), 0).into(), + "0x17ef9d8ee0e2c8470814651413b71009a607a020214f749687384a7b7a7eb67a" + .to_string() + ), + ( + ((Any::advice(), 1).into(), 1).into(), + "0xe113acd03b98f0bab0ef6f577245d5d008cbcc19ef2dab3608aa4f37f72a407" + .to_string() + ), + (((Any::advice(), 2).into(), 0).into(), "0x2".to_string()), + ] + }, + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (121, "permute state").into(), + offset: 36 + } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 1 } + }, + ]) + ); + } + + // Swapping the indices should fail the permutation check between the computed root hash and the instance column root hash + #[test] + fn test_swapping_index() { + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + // Only now we can instantiate the circuit with the actual inputs + let mut circuit = MstInclusionCircuit::::init(merkle_proof); + + let instances = circuit.instances(); + + // swap indices + circuit.path_indices[0] = Fp::from(1); + + let invalid_prover = MockProver::run(K, &circuit, instances).unwrap(); + + assert_eq!( + invalid_prover.verify(), + Err(vec![ + VerifyFailure::Permutation { + column: (Any::advice(), 0).into(), + location: FailureLocation::InRegion { + region: (121, "permute state").into(), + offset: 36 + } + }, + VerifyFailure::Permutation { + column: (Any::Instance, 0).into(), + location: FailureLocation::OutsideRegion { row: 1 } + }, + ]) + ); + } + + #[cfg(feature = "dev-graph")] + #[test] + fn print_mst_inclusion() { + use plotters::prelude::*; + + let merkle_sum_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let user_index = 0; + + let merkle_proof = merkle_sum_tree.generate_proof(user_index).unwrap(); + + let circuit = MstInclusionCircuit::::init(merkle_proof); + + let root = BitMapBackend::new("prints/mst-inclusion-layout.png", (2048, 32768)) + .into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root + .titled("Merkle Sum Tree Inclusion Layout", ("sans-serif", 60)) + .unwrap(); + + halo2_proofs::dev::CircuitLayout::default() + .render(K, &circuit, &root) + .unwrap(); + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/traits.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/traits.rs new file mode 100644 index 0000000..359b3f5 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/traits.rs @@ -0,0 +1,53 @@ +use halo2_proofs::circuit::{Layouter, Value}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use halo2_proofs::plonk::{Advice, Column, Error, Fixed}; +use halo2_proofs::{circuit::AssignedCell, plonk::Instance}; + +/// Trait containing common methods for all circuits +pub trait CircuitBase { + /// Enforce copy constraint check between input cell and instance column at row passed as input + fn expose_public( + &self, + mut layouter: impl Layouter, + cell: &AssignedCell, + row: usize, + instance: Column, + ) -> Result<(), Error> { + layouter.constrain_instance(cell.cell(), instance, row) + } + + /// Generic method to assign `value` to a cell in the witness table to advice column `advice_col`. `object_to_assign` is label to identify the object being assigned. It is useful for debugging. + /// Returns the assigned cell. + fn assign_value_to_witness( + &self, + mut layouter: impl Layouter, + value: Fp, + object_to_assign: &'static str, + advice_col: Column, + ) -> Result, Error> { + layouter.assign_region( + || format!("assign {}", object_to_assign), + |mut region| region.assign_advice(|| "value", advice_col, 0, || Value::known(value)), + ) + } + + /// Loads the lookup table with values from `0` to `2^8 - 1` + fn load(&self, layouter: &mut impl Layouter, column: Column) -> Result<(), Error> { + let range = 1 << 8; + + layouter.assign_region( + || format!("load range check table of {} bits", 8), + |mut region| { + for i in 0..range { + region.assign_fixed( + || "assign cell in fixed column", + column, + i, + || Value::known(Fp::from(i as u64)), + )?; + } + Ok(()) + }, + ) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/types.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/types.rs new file mode 100644 index 0000000..4a54666 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/types.rs @@ -0,0 +1,14 @@ +use ethers::types::U256; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProofSolidityCallData { + pub proof: String, + pub public_inputs: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct CommitmentSolidityCallData { + pub root_hash: U256, + pub root_balances: Vec, +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/circuits/utils.rs b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/utils.rs new file mode 100644 index 0000000..662d41f --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/circuits/utils.rs @@ -0,0 +1,203 @@ +use std::fs::File; + +use ark_std::{end_timer, start_timer}; +use ethers::{ + abi::parse_abi, + contract::BaseContract, + types::{Bytes, U256}, +}; +use halo2_proofs::{ + halo2curves::{ + bn256::{Bn256, Fr as Fp, G1Affine}, + ff::PrimeField, + }, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, + poly::{ + commitment::{Params, ParamsProver}, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, +}; +use halo2_solidity_verifier::{encode_calldata, Keccak256Transcript}; +use rand::{rngs::OsRng, RngCore}; + +use crate::circuits::WithInstances; + +/// Generate setup artifacts for a circuit of size `k`, where 2^k represents the number of rows in the circuit. +/// +/// If the trusted setup parameters are not found, the function performs an unsafe trusted setup to generate the necessary parameters +/// If the provided `k` value is larger than the `k` value of the loaded parameters, an error is returned, as the provided `k` is too large. +/// Otherwise, if the `k` value is smaller than the `k` value of the loaded parameters, the parameters are downsized to fit the requested `k`. +pub fn generate_setup_artifacts>( + k: u32, + params_path: Option<&str>, + circuit: C, +) -> Result< + ( + ParamsKZG, + ProvingKey, + VerifyingKey, + ), + &'static str, +> { + let mut params: ParamsKZG; + + match params_path { + Some(path) => { + let timer = start_timer!(|| "Creating params"); + let mut params_fs = File::open(path).expect("couldn't load params"); + params = ParamsKZG::::read(&mut params_fs).expect("Failed to read params"); + end_timer!(timer); + + if params.k() < k { + return Err("k is too large for the given params"); + } + + if params.k() > k { + let timer = start_timer!(|| "Downsizing params"); + params.downsize(k); + end_timer!(timer); + } + } + None => { + let timer = start_timer!(|| "None Creating params"); + params = ParamsKZG::::setup(k, OsRng); + end_timer!(timer); + } + } + + let vk = keygen_vk(¶ms, &circuit).expect("vk generation should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("pk generation should not fail"); + + Ok((params, pk, vk)) +} + +/// Generates a proof given the public setup, the proving key, the initiated circuit and its public inputs. +pub fn full_prover>( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: C, + public_inputs: Vec>, +) -> Vec { + let pf_time = start_timer!(|| "Creating proof"); + + let instance: Vec<&[Fp]> = public_inputs.iter().map(|input| &input[..]).collect(); + let instances = &[&instance[..]]; + + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + let result = create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + _, + Blake2bWrite, G1Affine, Challenge255>, + _, + >(params, pk, &[circuit], instances, OsRng, &mut transcript) + .expect("prover should not fail"); + assert!(result.0.is_ok()); + let proof = transcript.finalize(); + end_timer!(pf_time); + proof +} + +/// Verifies a proof given the public setup, the verification key, the proof and the public inputs of the circuit. +pub fn full_verifier( + params: &ParamsKZG, + vk: &VerifyingKey, + proof: Vec, + public_inputs: Vec>, +) -> bool { + let verifier_params = params.verifier_params(); + let strategy = SingleStrategy::new(params); + let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); + + let instance: Vec<&[Fp]> = public_inputs.iter().map(|input| &input[..]).collect(); + let instances = &[&instance[..]]; + + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >(verifier_params, vk, strategy, instances, &mut transcript) + .is_ok() +} + +/// Generate the proof Solidity calldata for a circuit +pub fn gen_proof_solidity_calldata + WithInstances>( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: C, +) -> (Bytes, Vec) { + let instances_clone = circuit.instances().clone(); + let pf_time = start_timer!(|| "Creating proof"); + let proof = create_proof_checked(params, pk, circuit, &instances_clone[0], OsRng); + end_timer!(pf_time); + + let calldata = encode_calldata(None, &proof, &instances_clone[0]); + + let abi = parse_abi(&[ + "function verifyProof(bytes calldata proof, uint256[] calldata instances) public returns (bool)", + ]).expect("Invalid ABI"); + + let base_contract = BaseContract::from(abi); + + type VerifyProofInput = (Bytes, Vec); + + // Decode the function input + let decoded: VerifyProofInput = base_contract + .decode_input(calldata) + .expect("Failed to decode data"); + + (decoded.0, decoded.1) +} + +fn create_proof_checked( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: impl Circuit, + instances: &[Fp], + mut rng: impl RngCore, +) -> Vec { + let proof = { + let mut transcript = Keccak256Transcript::new(Vec::new()); + let proof_creation_result = create_proof::<_, ProverSHPLONK<_>, _, _, _, _>( + params, + pk, + &[circuit], + &[&[instances]], + &mut rng, + &mut transcript, + ); + assert!(proof_creation_result.is_ok()); + transcript.finalize() + }; + + let result = { + let mut transcript = Keccak256Transcript::new(proof.as_slice()); + verify_proof::<_, VerifierSHPLONK<_>, _, _, SingleStrategy<_>>( + params, + pk.get_vk(), + SingleStrategy::new(params), + &[&[instances]], + &mut transcript, + ) + }; + assert!(result.is_ok()); + + proof +} + +/// Converts a field element to a Solidity calldata +pub fn field_element_to_solidity_calldata(field_element: Fp) -> U256 { + let bytes = field_element.to_repr(); + let u = U256::from_little_endian(bytes.as_slice()); + u +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/lib.rs b/tools/polyexen/circuit/solvency/zk_prover/src/lib.rs new file mode 100644 index 0000000..40b1e26 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/lib.rs @@ -0,0 +1,12 @@ +//! This crate contains the cryptogarphic primitives for implementing proof of solvency protocol. +//! The tooling being used to generate the zkSNARKs is [Halo2 PSE Fork](https://github.com/privacy-scaling-explorations/halo2). + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +/// Zk circuit subcomponents aka chips. +pub mod chips; +/// Zk circuits with a full prover and verifier. A circuit can be viewed as an assembly of chips. +pub mod circuits; +/// Utilities to build the merkle sum tree data structure. No zk proof in here. +pub mod merkle_sum_tree; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/entry.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/entry.rs new file mode 100644 index 0000000..e77de9f --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/entry.rs @@ -0,0 +1,66 @@ +use crate::merkle_sum_tree::utils::big_intify_username; +use crate::merkle_sum_tree::Node; +use num_bigint::BigUint; + +/// An entry in the Merkle Sum Tree from the database of the CEX. +/// It contains the username and the balances of the user. +#[derive(Clone, Debug, std::cmp::PartialEq)] +pub struct Entry { + username_as_big_uint: BigUint, + balances: [BigUint; N_CURRENCIES], + username: String, +} + +impl Entry { + pub fn new(username: String, balances: [BigUint; N_CURRENCIES]) -> Result { + Ok(Entry { + username_as_big_uint: big_intify_username(&username), + balances, + username, + }) + } + + /// Returns a zero entry where the username is 0 and the balances are all 0 + pub fn zero_entry() -> Self { + let empty_balances: [BigUint; N_CURRENCIES] = std::array::from_fn(|_| BigUint::from(0u32)); + + Entry { + username_as_big_uint: BigUint::from(0u32), + balances: empty_balances, + username: "0".to_string(), + } + } + + pub fn compute_leaf(&self) -> Node + where + [usize; N_CURRENCIES + 1]: Sized, + { + Node::leaf(&self.username_as_big_uint, &self.balances) + } + + /// Stores the new balance values + /// + /// Returns the updated node + pub fn recompute_leaf( + &mut self, + updated_balances: &[BigUint; N_CURRENCIES], + ) -> Node + where + [usize; N_CURRENCIES + 1]: Sized, + { + self.balances = updated_balances.clone(); + Node::leaf(&self.username_as_big_uint, updated_balances) + } + + pub fn balances(&self) -> &[BigUint; N_CURRENCIES] { + &self.balances + } + + pub fn username_as_big_uint(&self) -> &BigUint { + &self.username_as_big_uint + } + + pub fn username(&self) -> &str { + &self.username + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mod.rs new file mode 100644 index 0000000..02bb452 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mod.rs @@ -0,0 +1,33 @@ +mod entry; +mod mst; +mod node; +mod tests; +mod tree; +pub mod utils; +use halo2_proofs::halo2curves::bn256::Fr as Fp; + +/// A struct representing a Merkle Proof. +/// +/// Fields: +/// * `entry`: The entry for which the proof is generated +/// * `root`: The root of the Merkle Sum Tree +/// * `sibling_leaf_node_hash_preimage`: The hash preimage of the sibling leaf node. The hash preimage is equal to `[sibling_username, sibling.balance[0], sibling.balance[1], ... sibling.balance[N_CURRENCIES - 1]]` +/// * `sibling_middle_node_hash_preimages`: The hash preimages of the sibling middle nodes. The hash preimage is equal to `[sibling_left_child.balance[0] + sibling_right_child.balance[0], sibling_left_child.balance[1] + sibling_right_child.balance[1], ..., sibling_left_child.balance[N_CURRENCIES - 1] + sibling_right_child.balance[N_CURRENCIES - 1], sibling_left_child.hash, sibling_right_child.hash]` +#[derive(Clone, Debug)] +pub struct MerkleProof +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + pub entry: Entry, + pub root: Node, + pub sibling_leaf_node_hash_preimage: [Fp; N_CURRENCIES + 1], + pub sibling_middle_node_hash_preimages: Vec<[Fp; N_CURRENCIES + 2]>, + pub path_indices: Vec, +} + +pub use entry::Entry; +pub use mst::Cryptocurrency; +pub use mst::MerkleSumTree; +pub use node::Node; +pub use tree::Tree; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mst.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mst.rs new file mode 100644 index 0000000..f141357 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/mst.rs @@ -0,0 +1,227 @@ +use crate::merkle_sum_tree::utils::{ + build_leaves_from_entries, build_merkle_tree_from_leaves, parse_csv_to_entries, +}; +use crate::merkle_sum_tree::{Entry, Node, Tree}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use num_bigint::BigUint; + +/// Merkle Sum Tree Data Structure. +/// +/// A Merkle Sum Tree is a binary Merkle Tree with the following properties: +/// * Each Entry of a Merkle Sum Tree is a pair of a username and #N_CURRENCIES balances. +/// * Each Leaf Node contains a hash and #N_CURRENCIES balances. The hash is equal to `H(username, balance[0], balance[1], ... balance[N_CURRENCIES - 1])`. The balances are equal to the balances associated to the entry +/// * Each Middle Node contains a hash and #N_CURRENCIES balances. The hash is equal to `H(LeftChild.balance[0] + RightChild.balance[0], LeftChild.balance[1] + RightChild.balance[1], ..., LeftChild.balance[N_CURRENCIES - 1] + RightChild.balance[N_CURRENCIES - 1], LeftChild.hash, RightChild.hash)`. The balances are equal to the sum of the balances of the child nodes per each cryptocurrency. +/// * The Root Node represents the committed state of the Tree and contains the sum of all the entries' balances per each cryptocurrency. +/// +/// # Type Parameters +/// +/// * `N_CURRENCIES`: The number of cryptocurrencies for each user account +/// * `N_BYTES`: Range in which each node balance should lie +#[derive(Debug, Clone)] +pub struct MerkleSumTree { + root: Node, + nodes: Vec>>, + depth: usize, + entries: Vec>, + cryptocurrencies: Vec, + is_sorted: bool, +} + +impl Tree + for MerkleSumTree +{ + fn root(&self) -> &Node { + &self.root + } + + fn depth(&self) -> &usize { + &self.depth + } + + fn nodes(&self) -> &[Vec>] { + &self.nodes + } + + fn get_entry(&self, index: usize) -> &Entry { + &self.entries[index] + } + + fn cryptocurrencies(&self) -> &[Cryptocurrency] { + &self.cryptocurrencies + } +} + +#[derive(Debug, Clone)] +pub struct Cryptocurrency { + pub name: String, + pub chain: String, +} + +impl MerkleSumTree { + /// Returns the leaves of the tree + pub fn leaves(&self) -> &[Node] { + &self.nodes[0] + } + /// Returns the entries of the tree + pub fn entries(&self) -> &[Entry] { + &self.entries + } + /// Builds a Merkle Sum Tree from a CSV file stored at `path`. The CSV file must be formatted as follows: + /// + /// `username,balance__,balance__,...` + /// + /// `dxGaEAii,11888,41163` + pub fn from_csv(path: &str) -> Result> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let (cryptocurrencies, entries) = + parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path)?; + Self::from_entries(entries, cryptocurrencies, false) + } + + /// Builds a Merkle Sum Tree from a CSV file stored at `path`. The MST leaves are sorted by the username byte values. The CSV file must be formatted as follows: + /// + /// `username,balance__,balance__,...` + /// + /// `dxGaEAii,11888,41163` + pub fn from_csv_sorted(path: &str) -> Result> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let (cryptocurrencies, mut entries) = + parse_csv_to_entries::<&str, N_CURRENCIES, N_BYTES>(path)?; + + entries.sort_by(|a, b| a.username().cmp(b.username())); + + Self::from_entries(entries, cryptocurrencies, true) + } + + /// Builds a Merkle Sum Tree from a vector of entries + pub fn from_entries( + mut entries: Vec>, + cryptocurrencies: Vec, + is_sorted: bool, + ) -> Result, Box> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let depth = (entries.len() as f64).log2().ceil() as usize; + + let mut nodes = vec![]; + + // Pad the entries with empty entries to make the number of entries equal to 2^depth + if entries.len() < 2usize.pow(depth as u32) { + entries.extend(vec![ + Entry::zero_entry(); + 2usize.pow(depth as u32) - entries.len() + ]); + } + + let leaves = build_leaves_from_entries(&entries); + + let root = build_merkle_tree_from_leaves(&leaves, depth, &mut nodes)?; + + Ok(MerkleSumTree { + root, + nodes, + depth, + entries, + cryptocurrencies, + is_sorted, + }) + } + + /// Builds a Merkle Sum Tree from a root node, a vector of nodes, a depth, a vector of entries, a vector of cryptocurrencies and a boolean indicating whether the leaves are sorted by the username byte values. + pub fn from_params( + root: Node, + nodes: Vec>>, + depth: usize, + entries: Vec>, + cryptocurrencies: Vec, + is_sorted: bool, + ) -> Result> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + Ok(MerkleSumTree:: { + root, + nodes, + depth, + entries, + cryptocurrencies, + is_sorted, + }) + } + + /// Updates the balances of the entry with the given username and returns the new root of the tree. + /// + /// # Arguments + /// + /// * `username`: The username of the entry to update + /// * `new_balances`: The new balances of the entry + /// + /// # Returns + /// + /// The new root of the tree + pub fn update_leaf( + &mut self, + username: &str, + new_balances: &[BigUint; N_CURRENCIES], + ) -> Result, Box> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let index = self.index_of_username(username)?; + + // Update the leaf node. + let updated_leaf = self.entries[index].recompute_leaf(new_balances); + self.nodes[0][index] = updated_leaf; + + // Recompute the hashes and balances up the tree. + let mut current_index = index; + for depth in 1..=self.depth { + let parent_index = current_index / 2; + let left_child = &self.nodes[depth - 1][2 * parent_index]; + let right_child = &self.nodes[depth - 1][2 * parent_index + 1]; + + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 2]; + for (i, balance) in hash_preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = left_child.balances[i] + right_child.balances[i]; + } + hash_preimage[N_CURRENCIES] = left_child.hash; + hash_preimage[N_CURRENCIES + 1] = right_child.hash; + + self.nodes[depth][parent_index] = Node::middle_node_from_preimage(&hash_preimage); + current_index = parent_index; + } + + let root = self.nodes[self.depth][0].clone(); + + Ok(root) + } + + /// Returns the index of the leaf with the matching username + pub fn index_of_username(&self, username: &str) -> Result> + where + [usize; N_CURRENCIES + 1]: Sized, + { + if !self.is_sorted { + self.entries + .iter() + .enumerate() + .find(|(_, entry)| entry.username() == username) + .map(|(index, _)| index) + .ok_or_else(|| Box::from("Username not found")) + } else { + self.entries + .binary_search_by_key(&username, |entry| entry.username()) + .map_err(|_| Box::from("Username not found")) + } + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/node.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/node.rs new file mode 100644 index 0000000..963ac6e --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/node.rs @@ -0,0 +1,114 @@ +use crate::chips::poseidon::poseidon_spec::PoseidonSpec; +use crate::merkle_sum_tree::utils::big_uint_to_fp; +use halo2_gadgets::poseidon::primitives::{self as poseidon, ConstantLength}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use num_bigint::BigUint; + +#[derive(Clone, Debug, PartialEq)] +pub struct Node { + pub hash: Fp, + pub balances: [Fp; N_CURRENCIES], +} +impl Node { + /// Builds a leaf-level node of the MST + /// The leaf node hash is equal to `H(username, balance[0], balance[1], ... balance[N_CURRENCIES - 1])` + /// The balances are equal to `balance[0], balance[1], ... balance[N_CURRENCIES - 1]` + pub fn leaf(username: &BigUint, balances: &[BigUint; N_CURRENCIES]) -> Node + where + [usize; N_CURRENCIES + 1]: Sized, + { + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 1]; + hash_preimage[0] = big_uint_to_fp(username); + for (i, balance) in hash_preimage.iter_mut().enumerate().skip(1) { + *balance = big_uint_to_fp(&balances[i - 1]); + } + + Node::leaf_node_from_preimage(&hash_preimage) + } + + /// Builds a "middle" (non-leaf-level) node of the MST + /// The middle node hash is equal to `H(LeftChild.balance[0] + RightChild.balance[0], LeftChild.balance[1] + RightChild.balance[1], ..., LeftChild.balance[N_CURRENCIES - 1] + RightChild.balance[N_CURRENCIES - 1], LeftChild.hash, RightChild.hash)` + /// The balances are equal to `LeftChild.balance[0] + RightChild.balance[0], LeftChild.balance[1] + RightChild.balance[1], ..., LeftChild.balance[N_CURRENCIES - 1] + RightChild.balance[N_CURRENCIES - 1]` + pub fn middle(child_l: &Node, child_r: &Node) -> Node + where + [(); N_CURRENCIES + 2]: Sized, + { + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 2]; + for (i, balance) in hash_preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = child_l.balances[i] + child_r.balances[i]; + } + hash_preimage[N_CURRENCIES] = child_l.hash; + hash_preimage[N_CURRENCIES + 1] = child_r.hash; + + Node::middle_node_from_preimage(&hash_preimage) + } + + /// Returns an empty node where the hash is 0 and the balances are all 0 + pub fn init_empty() -> Node + where + [usize; N_CURRENCIES + 1]: Sized, + { + Node { + hash: Fp::zero(), + balances: [Fp::zero(); N_CURRENCIES], + } + } + + pub fn leaf_node_from_preimage(preimage: &[Fp; N_CURRENCIES + 1]) -> Node + where + [usize; N_CURRENCIES + 1]: Sized, + { + Node { + hash: Self::poseidon_hash_leaf(preimage[0], preimage[1..].try_into().unwrap()), + balances: preimage[1..].try_into().unwrap(), + } + } + + /// Builds a middle-level node of the MST + /// The hash preimage must be equal to `LeftChild.balance[0] + RightChild.balance[0], LeftChild.balance[1] + RightChild.balance[1], ..., LeftChild.balance[N_CURRENCIES - 1] + RightChild.balance[N_CURRENCIES - 1], LeftChild.hash, RightChild.hash` + /// The balances are equal to `LeftChild.balance[0] + RightChild.balance[0], LeftChild.balance[1] + RightChild.balance[1], ..., LeftChild.balance[N_CURRENCIES - 1] + RightChild.balance[N_CURRENCIES - 1]` + pub fn middle_node_from_preimage(preimage: &[Fp; N_CURRENCIES + 2]) -> Node + where + [usize; N_CURRENCIES + 2]: Sized, + { + Node { + hash: Self::poseidon_hash_middle( + preimage[0..N_CURRENCIES].try_into().unwrap(), + preimage[N_CURRENCIES], + preimage[N_CURRENCIES + 1], + ), + balances: preimage[0..N_CURRENCIES].try_into().unwrap(), + } + } + + fn poseidon_hash_middle( + balances_sum: [Fp; N_CURRENCIES], + hash_child_left: Fp, + hash_child_right: Fp, + ) -> Fp + where + [usize; N_CURRENCIES + 2]: Sized, + { + let mut hash_inputs: [Fp; N_CURRENCIES + 2] = [Fp::zero(); N_CURRENCIES + 2]; + + hash_inputs[0..N_CURRENCIES].copy_from_slice(&balances_sum); + hash_inputs[N_CURRENCIES] = hash_child_left; + hash_inputs[N_CURRENCIES + 1] = hash_child_right; + + poseidon::Hash::, 2, 1>::init() + .hash(hash_inputs) + } + + fn poseidon_hash_leaf(username: Fp, balances: [Fp; N_CURRENCIES]) -> Fp + where + [usize; N_CURRENCIES + 1]: Sized, + { + let mut hash_inputs: [Fp; N_CURRENCIES + 1] = [Fp::zero(); N_CURRENCIES + 1]; + + hash_inputs[0] = username; + hash_inputs[1..N_CURRENCIES + 1].copy_from_slice(&balances); + + poseidon::Hash::, 2, 1>::init() + .hash(hash_inputs) + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tests.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tests.rs new file mode 100644 index 0000000..b79fb22 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tests.rs @@ -0,0 +1,265 @@ +#[cfg(test)] +mod test { + + use crate::merkle_sum_tree::utils::big_uint_to_fp; + use crate::merkle_sum_tree::{Entry, MerkleSumTree, Node, Tree}; + use num_bigint::{BigUint, ToBigUint}; + use rand::Rng as _; + + const N_CURRENCIES: usize = 2; + const N_BYTES: usize = 8; + + #[test] + fn test_mst() { + // create new merkle tree + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + // get root + let root = merkle_tree.root(); + + // expect root hash to be different than 0 + assert!(root.hash != 0.into()); + // expect balance to match the sum of all entries + assert!(root.balances == [556862.into(), 556862.into()]); + // expect depth to be 4 + assert!(*merkle_tree.depth() == 4_usize); + + // get proof for entry 0 + let proof = merkle_tree.generate_proof(0).unwrap(); + + // verify proof + assert!(merkle_tree.verify_proof(&proof)); + + // Should generate different root hashes when changing the entry order + let merkle_tree_2 = + MerkleSumTree::::from_csv("../csv/entry_16_switched_order.csv") + .unwrap(); + assert_ne!(root.hash, merkle_tree_2.root().hash); + + // the balance total should be the same + assert_eq!(root.balances, merkle_tree_2.root().balances); + + // should create valid proof for each entry in the tree and verify it + for i in 0..=15 { + let proof = merkle_tree.generate_proof(i).unwrap(); + assert!(merkle_tree.verify_proof(&proof)); + } + + // shouldn't create a proof for an entry that doesn't exist in the tree + assert!(merkle_tree.generate_proof(16).is_err()); + + // shouldn't verify a proof with a wrong leaf + let invalid_entry = Entry::new( + "AtwIxZHo".to_string(), + [35479.to_biguint().unwrap(), 35479.to_biguint().unwrap()], + ) + .unwrap(); + let invalid_entry = invalid_entry; + let mut proof_invalid_1 = proof.clone(); + proof_invalid_1.entry = invalid_entry; + assert!(!merkle_tree.verify_proof(&proof_invalid_1)); + + // shouldn't verify a proof with a wrong root hash + let mut proof_invalid_2 = proof.clone(); + proof_invalid_2.root.hash = 0.into(); + assert!(!merkle_tree.verify_proof(&proof_invalid_2)); + } + + #[test] + fn test_update_mst_leaf() { + let merkle_tree_1 = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let root_hash_1 = merkle_tree_1.root().hash; + + //Create the second tree with the 7th entry different from the the first tree + let mut merkle_tree_2 = + MerkleSumTree::::from_csv("../csv/entry_16_modified.csv") + .unwrap(); + + let root_hash_2 = merkle_tree_2.root().hash; + assert!(root_hash_1 != root_hash_2); + + //Update the 7th leaf of the second tree so all the entries now match the first tree + let new_root = merkle_tree_2 + .update_leaf( + "RkLzkDun", + &[2087.to_biguint().unwrap(), 79731.to_biguint().unwrap()], + ) + .unwrap(); + //The roots should match + assert!(root_hash_1 == new_root.hash); + } + + #[test] + fn test_update_invalid_mst_leaf() { + let mut merkle_tree = + MerkleSumTree::::from_csv_sorted("../csv/entry_16.csv").unwrap(); + + let new_root = merkle_tree.update_leaf( + "non_existing_user", //This username is not present in the tree + &[11888.to_biguint().unwrap(), 41163.to_biguint().unwrap()], + ); + + if let Err(e) = new_root { + assert_eq!(e.to_string(), "Username not found"); + } + } + + #[test] + fn test_sorted_mst() { + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let old_root_balances = merkle_tree.root().balances; + let old_root_hash = merkle_tree.root().hash; + + let sorted_merkle_tree = + MerkleSumTree::::from_csv_sorted("../csv/entry_16.csv").unwrap(); + + let new_root_balances = sorted_merkle_tree.root().balances; + let new_root_hash = sorted_merkle_tree.root().hash; + + // The root balances should be the same for sorted and unsorted MST + assert!(old_root_balances == new_root_balances); + // The root hash should not be the same for sorted and unsorted MST + assert!(old_root_hash != new_root_hash); + } + + #[test] + fn test_big_uint_conversion() { + let big_uint = 3.to_biguint().unwrap(); + let fp = big_uint_to_fp(&big_uint); + + assert_eq!(fp, 3.into()); + + let big_int_over_64 = (18446744073709551616_i128).to_biguint().unwrap(); + let fp_2 = big_uint_to_fp(&big_int_over_64); + + let big_int_to_bytes = { + let mut bytes = BigUint::to_bytes_le(&big_int_over_64); + bytes.resize(32, 0); + bytes + }; + + assert_eq!(fp_2.to_bytes().to_vec(), big_int_to_bytes); + + let fp_3 = fp_2 - fp; + assert_eq!(fp_3, 18446744073709551613.into()); + } + + #[test] + fn get_middle_node_hash_preimage() { + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + let depth = *merkle_tree.depth(); + + // The tree has 16 leaves, so the levels are 0, 1, 2, 3, 4. Where level 0 is the leaves and level 4 is the root + // Fetch a random level from 1 to depth + let mut rng = rand::thread_rng(); + let level = rng.gen_range(1..depth); + + // Fetch a random index inside the level. For example level 1 has 8 nodes, so the index can be 0, 1, 2, 3, 4, 5, 6, 7 + let index = rng.gen_range(0..merkle_tree.nodes()[level].len()); + + // Fetch middle node with index from level + let middle_node = merkle_tree.nodes()[level][index].clone(); + + // Fetch the hash preimage of the middle node + let hash_preimage = merkle_tree + .get_middle_node_hash_preimage(level, index) + .unwrap(); + + let computed_middle_node = Node::::middle_node_from_preimage(&hash_preimage); + + // The hash of the middle node should match the hash computed from the hash preimage + assert_eq!(middle_node.hash, computed_middle_node.hash); + } + + #[test] + fn get_leaf_node_hash_preimage() { + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_16.csv").unwrap(); + + // Generate a random number between 0 and 15 + let mut rng = rand::thread_rng(); + let index = rng.gen_range(0..16); + + // Fetch leaf with index + let leaf = merkle_tree.leaves()[index].clone(); + + // Fetch the hash preimage of the leaf + let hash_preimage = merkle_tree.get_leaf_node_hash_preimage(index).unwrap(); + + let computed_leaf = Node::::leaf_node_from_preimage(&hash_preimage); + + // The hash of the leaf should match the hash computed from the hash preimage + assert_eq!(leaf.hash, computed_leaf.hash); + } + + #[test] + fn test_tree_with_zero_element_1() { + // create new merkle tree + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_13.csv").unwrap(); + + // get root + let root = merkle_tree.root(); + + // The last 3 entries of the merkle tree should be zero entries + for i in 13..16 { + let entry = merkle_tree.entries()[i].clone(); + assert_eq!(entry, Entry::::zero_entry()); + } + + // expect root hash to be different than 0 + assert!(root.hash != 0.into()); + // expect balance to match the sum of all entries + assert!(root.balances == [385969.into(), 459661.into()]); + // expect depth to be 4 + assert!(*merkle_tree.depth() == 4_usize); + + // should create valid proof for each entry in the tree and verify it + for i in 0..=15 { + let proof = merkle_tree.generate_proof(i).unwrap(); + assert!(merkle_tree.verify_proof(&proof)); + } + + // shouldn't create a proof for an entry that doesn't exist in the tree + assert!(merkle_tree.generate_proof(16).is_err()); + } + + #[test] + fn test_tree_with_zero_element_2() { + // create new merkle tree + let merkle_tree = + MerkleSumTree::::from_csv("../csv/entry_17.csv").unwrap(); + + // get root + let root = merkle_tree.root(); + + // The last 15 entries of the merkle tree should be zero entries + for i in 17..32 { + let entry = merkle_tree.entries()[i].clone(); + assert_eq!(entry, Entry::::zero_entry()); + } + + // expect root hash to be different than 0 + assert!(root.hash != 0.into()); + // expect balance to match the sum of all entries + assert!(root.balances == [556863.into(), 556863.into()]); + // expect depth to be 5 + assert!(*merkle_tree.depth() == 5_usize); + + // should create valid proof for each entry in the tree and verify it + for i in 0..=31 { + let proof = merkle_tree.generate_proof(i).unwrap(); + assert!(merkle_tree.verify_proof(&proof)); + } + + // shouldn't create a proof for an entry that doesn't exist in the tree + assert!(merkle_tree.generate_proof(32).is_err()); + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tree.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tree.rs new file mode 100644 index 0000000..b19019b --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/tree.rs @@ -0,0 +1,185 @@ +use crate::merkle_sum_tree::utils::big_uint_to_fp; +use crate::merkle_sum_tree::Cryptocurrency; +use crate::merkle_sum_tree::{Entry, MerkleProof, Node}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; + +/// A trait representing the basic operations for a Merkle-Sum-like Tree. +pub trait Tree { + /// Returns a reference to the root node. + fn root(&self) -> &Node; + + /// Returns the depth of the tree. + fn depth(&self) -> &usize; + + /// Returns a slice of the nodes. + fn nodes(&self) -> &[Vec>]; + + /// Returns the cryptocurrencies whose balances are in the tree. The order of cryptocurrencies and balances is supposed to agree for all the entries. + fn cryptocurrencies(&self) -> &[Cryptocurrency]; + + fn get_entry(&self, index: usize) -> &Entry; + + /// Returns the hash preimage of a middle node. + fn get_middle_node_hash_preimage( + &self, + level: usize, + index: usize, + ) -> Result<[Fp; N_CURRENCIES + 2], Box> + where + [usize; N_CURRENCIES + 2]: Sized, + { + if level == 0 || level > *self.depth() { + return Err(Box::from("Invalid depth")); + } + + self.nodes() + .get(level) + .and_then(|layer| layer.get(index)) + .ok_or_else(|| Box::::from("Node not found"))?; + + // Assuming the left and right children are stored in order + let left_child = &self.nodes()[level - 1][2 * index]; + let right_child = &self.nodes()[level - 1][2 * index + 1]; + + // Constructing preimage + let mut preimage = [Fp::zero(); N_CURRENCIES + 2]; + + // for each balance in the left and right child, add them together and store in preimage + for (i, balance) in preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = left_child.balances[i] + right_child.balances[i]; + } + + // Add left and right child hashes to preimage + preimage[N_CURRENCIES] = left_child.hash; + preimage[N_CURRENCIES + 1] = right_child.hash; + + Ok(preimage) + } + + /// Returns the hash preimage of a leaf node. + fn get_leaf_node_hash_preimage( + &self, + index: usize, + ) -> Result<[Fp; N_CURRENCIES + 1], Box> + where + [usize; N_CURRENCIES + 1]: Sized, + { + // Fetch entry corresponding to index + let entry = self.get_entry(index); + + // Constructing preimage + let mut preimage = [Fp::zero(); N_CURRENCIES + 1]; + + // Add username to preimage + preimage[0] = big_uint_to_fp(entry.username_as_big_uint()); + + // Add balances to preimage + for (i, balance) in preimage.iter_mut().enumerate().skip(1).take(N_CURRENCIES) { + *balance = big_uint_to_fp(&entry.balances()[i - 1]); + } + + Ok(preimage) + } + + /// Generates a MerkleProof for the user with the given index. + fn generate_proof( + &self, + index: usize, + ) -> Result, Box> + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let nodes = self.nodes(); + let depth = *self.depth(); + let root = self.root(); + + if index >= nodes[0].len() { + return Err(Box::from("Index out of bounds")); + } + + let mut sibling_middle_node_hash_preimages = Vec::with_capacity(depth - 1); + + let sibling_leaf_index = if index % 2 == 0 { index + 1 } else { index - 1 }; + + let sibling_leaf_node_hash_preimage: [Fp; N_CURRENCIES + 1] = + self.get_leaf_node_hash_preimage(sibling_leaf_index)?; + let mut path_indices = vec![Fp::zero(); depth]; + let mut current_index = index; + + for level in 0..depth { + let position = current_index % 2; + let sibling_index = current_index - position + (1 - position); + + if sibling_index < nodes[level].len() && level != 0 { + // Fetch hash preimage for sibling middle nodes + let sibling_node_preimage = + self.get_middle_node_hash_preimage(level, sibling_index)?; + sibling_middle_node_hash_preimages.push(sibling_node_preimage); + } + + path_indices[level] = Fp::from(position as u64); + current_index /= 2; + } + + let entry = self.get_entry(index).clone(); + + Ok(MerkleProof { + entry, + root: root.clone(), + sibling_leaf_node_hash_preimage, + sibling_middle_node_hash_preimages, + path_indices, + }) + } + + /// Verifies a MerkleProof. + fn verify_proof(&self, proof: &MerkleProof) -> bool + where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, + { + let mut node = proof.entry.compute_leaf(); + + let sibling_leaf_node = + Node::::leaf_node_from_preimage(&proof.sibling_leaf_node_hash_preimage); + + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 2]; + for (i, balance) in hash_preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = node.balances[i] + sibling_leaf_node.balances[i]; + } + + if proof.path_indices[0] == 0.into() { + hash_preimage[N_CURRENCIES] = node.hash; + hash_preimage[N_CURRENCIES + 1] = sibling_leaf_node.hash; + node = Node::middle_node_from_preimage(&hash_preimage); + } else { + hash_preimage[N_CURRENCIES] = sibling_leaf_node.hash; + hash_preimage[N_CURRENCIES + 1] = node.hash; + node = Node::middle_node_from_preimage(&hash_preimage); + } + + for i in 1..proof.path_indices.len() { + let sibling_node = Node::::middle_node_from_preimage( + &proof.sibling_middle_node_hash_preimages[i - 1], + ); + + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 2]; + for (i, balance) in hash_preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = node.balances[i] + sibling_node.balances[i]; + } + + if proof.path_indices[i] == 0.into() { + hash_preimage[N_CURRENCIES] = node.hash; + hash_preimage[N_CURRENCIES + 1] = sibling_node.hash; + node = Node::middle_node_from_preimage(&hash_preimage); + } else { + hash_preimage[N_CURRENCIES] = sibling_node.hash; + hash_preimage[N_CURRENCIES + 1] = node.hash; + node = Node::middle_node_from_preimage(&hash_preimage); + } + } + + proof.root.hash == node.hash && proof.root.balances == node.balances + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/build_tree.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/build_tree.rs new file mode 100644 index 0000000..813b491 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/build_tree.rs @@ -0,0 +1,101 @@ +use crate::merkle_sum_tree::{Entry, Node}; +use halo2_proofs::halo2curves::bn256::Fr as Fp; +use rayon::prelude::*; + +pub fn build_merkle_tree_from_leaves( + leaves: &[Node], + depth: usize, + nodes: &mut Vec>>, +) -> Result, Box> +where + [usize; N_CURRENCIES + 1]: Sized, + [usize; N_CURRENCIES + 2]: Sized, +{ + let n = leaves.len(); + + let mut tree: Vec>> = Vec::with_capacity(depth + 1); + + tree.push(vec![ + Node { + hash: Fp::from(0), + balances: [Fp::from(0); N_CURRENCIES] + }; + n + ]); + + for _ in 1..=depth { + let previous_level = tree.last().unwrap(); + let nodes_in_level = (previous_level.len() + 1) / 2; + + tree.push(vec![ + Node { + hash: Fp::from(0), + balances: [Fp::from(0); N_CURRENCIES] + }; + nodes_in_level + ]); + } + + for (index, leaf) in leaves.iter().enumerate() { + tree[0][index] = leaf.clone(); + } + + for level in 1..=depth { + build_middle_level(level, &mut tree) + } + + let root = tree[depth][0].clone(); + *nodes = tree; + Ok(root) +} + +pub fn build_leaves_from_entries( + entries: &[Entry], +) -> Vec> +where + [usize; N_CURRENCIES + 1]: Sized, +{ + // Precompute the zero leaf (this will only be used if we encounter a zero entry) + let zero_leaf = Entry::::zero_entry().compute_leaf(); + + let leaves = entries + .par_iter() + .map(|entry| { + // If the entry is the zero entry then we return the precomputed zero leaf + // Otherwise, we compute the leaf as usual + if entry == &Entry::::zero_entry() { + zero_leaf.clone() + } else { + entry.compute_leaf() + } + }) + .collect::>(); + + leaves +} + +fn build_middle_level(level: usize, tree: &mut [Vec>]) +where + [usize; N_CURRENCIES + 2]: Sized, +{ + let results: Vec> = (0..tree[level - 1].len()) + .into_par_iter() + .step_by(2) + .map(|index| { + let mut hash_preimage = [Fp::zero(); N_CURRENCIES + 2]; + + for (i, balance) in hash_preimage.iter_mut().enumerate().take(N_CURRENCIES) { + *balance = + tree[level - 1][index].balances[i] + tree[level - 1][index + 1].balances[i]; + } + + hash_preimage[N_CURRENCIES] = tree[level - 1][index].hash; + hash_preimage[N_CURRENCIES + 1] = tree[level - 1][index + 1].hash; + Node::middle_node_from_preimage(&hash_preimage) + }) + .collect(); + + for (index, new_node) in results.into_iter().enumerate() { + tree[level][index] = new_node; + } +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/csv_parser.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/csv_parser.rs new file mode 100644 index 0000000..5df9c44 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/csv_parser.rs @@ -0,0 +1,65 @@ +use crate::merkle_sum_tree::{Cryptocurrency, Entry}; +use num_bigint::BigUint; +use std::collections::HashMap; +use std::error::Error; +use std::fs::File; +use std::path::Path; + +pub fn parse_csv_to_entries, const N_CURRENCIES: usize, const N_BYTES: usize>( + path: P, +) -> Result<(Vec, Vec>), Box> { + let file = File::open(path)?; + let mut rdr = csv::ReaderBuilder::new().from_reader(file); + + let headers = rdr.headers()?.clone(); + let mut cryptocurrencies: Vec = Vec::with_capacity(N_CURRENCIES); + + // Extracting cryptocurrency names from column names + for header in headers.iter().skip(1) { + // Skipping 'username' column + let parts: Vec<&str> = header.split('_').collect(); + if parts.len() == 3 && parts[0] == "balance" { + cryptocurrencies.push(Cryptocurrency { + name: parts[1].to_owned(), + chain: parts[2].to_owned(), + }); + } else { + // Throw an error if the header is malformed + return Err(format!("Invalid header: {}", header).into()); + } + } + + let mut entries = Vec::new(); + let mut balances_acc: Vec = vec![BigUint::from(0_usize); N_CURRENCIES]; + + for result in rdr.deserialize() { + let record: HashMap = result?; + let username = record.get("username").ok_or("Username not found")?.clone(); + + let mut balances_big_int = Vec::new(); + for cryptocurrency in &cryptocurrencies { + let balance_str = record + .get(format!("balance_{}_{}", cryptocurrency.name, cryptocurrency.chain).as_str()) + .ok_or(format!( + "Balance for {} on {} not found", + cryptocurrency.name, cryptocurrency.chain + ))?; + let balance = BigUint::parse_bytes(balance_str.as_bytes(), 10).ok_or(format!( + "Invalid balance for {} on {}", + cryptocurrency.name, cryptocurrency.chain + ))?; + balances_big_int.push(balance); + } + + balances_acc = balances_acc + .iter() + .zip(balances_big_int.iter()) + .map(|(x, y)| x + y) + .collect(); + + let entry = Entry::new(username, balances_big_int.try_into().unwrap())?; + entries.push(entry); + } + + Ok((cryptocurrencies, entries)) +} diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/mod.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/mod.rs new file mode 100644 index 0000000..c4f0a33 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/mod.rs @@ -0,0 +1,7 @@ +mod build_tree; +mod csv_parser; +mod operation_helpers; + +pub use build_tree::{build_leaves_from_entries, build_merkle_tree_from_leaves}; +pub use csv_parser::parse_csv_to_entries; +pub use operation_helpers::*; diff --git a/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/operation_helpers.rs b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/operation_helpers.rs new file mode 100644 index 0000000..81704c6 --- /dev/null +++ b/tools/polyexen/circuit/solvency/zk_prover/src/merkle_sum_tree/utils/operation_helpers.rs @@ -0,0 +1,17 @@ +use halo2_proofs::halo2curves::{bn256::Fr as Fp, group::ff::PrimeField}; +use num_bigint::BigUint; + +/// Return a BigUint representation of the username +pub fn big_intify_username(username: &str) -> BigUint { + let utf8_bytes = username.as_bytes(); + BigUint::from_bytes_be(utf8_bytes) +} +/// Converts a BigUint to a Field Element +pub fn big_uint_to_fp(big_uint: &BigUint) -> Fp { + Fp::from_str_vartime(&big_uint.to_str_radix(10)[..]).unwrap() +} + +/// Converts a Field element to a BigUint +pub fn fp_to_big_uint(f: Fp) -> BigUint { + BigUint::from_bytes_le(f.to_bytes().as_slice()) +} diff --git a/tools/polyexen/deps/polyexen/.gitignore b/tools/polyexen/deps/polyexen/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/tools/polyexen/deps/polyexen/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tools/polyexen/deps/polyexen/Cargo.lock b/tools/polyexen/deps/polyexen/Cargo.lock new file mode 100644 index 0000000..aa55466 --- /dev/null +++ b/tools/polyexen/deps/polyexen/Cargo.lock @@ -0,0 +1,658 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/summa-dev/halo2#8386d6e64fc33baccf626869123185890b8284dc" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves", + "maybe-rayon", + "rand_chacha", + "rand_core", + "sha3", + "tracing", +] + +[[package]] +name = "halo2curves" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "paste", + "rand", + "rand_core", + "static_assertions", + "subtle", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pest" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "polyexen" +version = "0.1.0" +dependencies = [ + "halo2_proofs", + "lazy_static", + "log", + "nom", + "num-bigint", + "num-integer", + "num-traits", + "pest", + "pest_derive", + "rand", + "rand_chacha", + "static_assertions", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/tools/polyexen/deps/polyexen/Cargo.toml b/tools/polyexen/deps/polyexen/Cargo.toml new file mode 100644 index 0000000..b82a648 --- /dev/null +++ b/tools/polyexen/deps/polyexen/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "polyexen" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# crypto-bigint = "0.4.8" +num-bigint = { version = "0.4", features = [ "rand" ] } +num-traits = "0.2" +num-integer = "0.1" +rand = "0.8.5" +rand_chacha = "0.3.1" +nom = "7" +pest = "2.5" +pest_derive = "2.4" +lazy_static = "1.4" +# Uncomment with the next release +# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", features = ["circuit-params"], tag = "v2023_04_20" } +# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", features = ["circuit-params"], rev = "d3746109d7d38be53afc8ddae8fdfaf1f02ad1d7" } +# branch kilic:shuffle +# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", features = ["circuit-params"], tag = "v0.3.0" } +halo2_proofs = { git = "https://github.com/summa-dev/halo2", commit= "8386d6e", features = ["circuit-params"] } +log = "0.4.14" +static_assertions = "1.1.0" diff --git a/tools/polyexen/deps/polyexen/NOTES.md b/tools/polyexen/deps/polyexen/NOTES.md new file mode 100644 index 0000000..74170ba --- /dev/null +++ b/tools/polyexen/deps/polyexen/NOTES.md @@ -0,0 +1,336 @@ +# Types + + +bool: [0, 1]. +- 0: False +- 1: True + +booly: [0, q] +- 0: False +- 1-q: True + +range(a, b): [a, b] + +u8, byte: range(0, 0xff) + +u16: range(0, 0xffff) + + +# Rules + +BOOLY(e: expr) -> booly +- if e(x) == 0 then False else True + +IF (b: booly) THEN e: expr +- if b(x) is truthy then BOOLY(e(x)) is false +> e * p + +IF (e: bool) THEN e1: expr ELSE e2: expr +- if e(x) is true then e1(x) == 0, else e2(x) == 0 +> e * e1 +> (1 - e) * e2 + +e1: booly AND e2:booly -> booly +> e1 * e2 + +e1: bool AND e2:bool -> bool +> e1 * e2 + +e1: bool OR e2:bool -> bool +> e1 + e2 - e1 * e2 +> [alt] 1 - ((1 - e1) * (1 - e2)) = 1 - (1 - e2 - e1 + e1 * e2) = e1 + e2 - e1 * e2 # DeMorgan + +e1: expr == q: const -> bool +> (1 - (e1 - q) * w) +% (e1 - q) * (1 - (e1 - q) * w) +$ w := inv(e1 - q) if (e1 - q) != 0 +$ w := 0 if (e1 - q) == 0 + +not(e: expr in S) -> booly + for S = {s1, s2, ..., sn} + +(e - s1) * (e - s2) * ... * (e - sn) + +CONSTRAIN(not(e: booly)) +- e(x) == false +> e == 0 + +# Polynomail constraint analysis + + + +# DSL design notes + +This is a list of features that the DSL should optimize for +- Constraint definition and witness assignment should be done together +- Should not expose rotations, only variables (advices, constants?) and expressions. +- Should add gadget selectors implicitly +- Should allow modeling state machines gadgets +- Should make it easy to add negative tests +- A constraint checker should report the line and trace (in case of nested + gadgets) of a failing constraint along with the values used in that + constraint +- Advice and Expressions can be typed, and a checker will verify that the types + are correct. + +This is a list of nice to have features +- Witness assignment should be done automatically when possible + +Open questions: +- How is composition modeled? +- How are dynamic lookups modeled? What about composition via dynamic lookups? +- How does it work with the challenge API? + +# Embeddable scripting languages for Rust + +- https://github.com/pistondevelopers/dyon +- https://github.com/gluon-lang/gluon +- https://github.com/rune-rs/rune +- https://github.com/rhaiscript/rhai +- https://github.com/RustPython/RustPython + +# Gadgets + +Aux + +``` +let from_bytes_le = |bytes| bytes.zip(0..bytes.len()).map(|(b, i)| b * 2.pow(8 * i)).sum(); + +fn from_bytes_le(bytes: &[T]) -> T { + let mut res = 0; + for i in 0..bytes.len() { + res += b * 2.pow(8 * i) + } + res +} +``` + + +## IsZero + +inputs: +- `value: any` + +outputs: +- `is_zero: bool` + + +``` +gadget iz_zero(value: expr) -> bool expr { + let value_inv: witness; + witness { + value_inv = if value != 0 { + value.invert(); + } else { + 0 + }; + } + let is_zero_expression: bool expr = 1 - value * value_inv; + @ value * value_inv = 0; + return is_zero_expression; +} +``` + +## LowerThan + +inputs: +- `lhs: range(0, 2.pow(8*N))` +- `rhs: range(0, 2.pow(8*N))` + +outputs: +- `lt: bool` + +``` +gadget lt(N: usize, lhs: T2P8 expr, rhs: T2P8 expr) -> bool witness + where T2P8 is range(0, 2.pow(8*N)) { + let lt: bool witness; + witness { + lt = lhs < rhs; + } + let diff_bytes: [u8 witness; N]; + witness { + let diff: field = (lhs - rhs) + if lt { 2.pow(8*N) } else { 0 }; + for i in 0..N { + diff_bytes[i] = (diff >> 8*i) & 0xff; + } + } + let diff: T2P8 expr = from_bytes_le(diff_bytes); + @ lhs - rhs = diff - lt * 2.pow(8*N); + return lt; +} +``` + +## Add256 + +inputs: +- `a: [u8 expr; 32]` +- `b: [u8 expr; 32]` + +``` +alias u128 = range(0, 2.pow(128)); +gadget add256(a_le: [u8 expr; 32], b_le: [u8 expr; 32]) -> ([u8 witness; 32], bool witness) { + let res_le: [u8 witness; 32]; + let carry_lo: range(0, 1) witness; + let carry_hi: range(0, 1) witness; + witness { + let mut carry = 0; + for i in 0..32 { + let tmp = a_le[i] + b_le[i]; + res_le[i] = tmp & 0xff + carry; + carry = tmp >> 8; + if i == 15 { + carry_lo = carry; + } + } + carry_hi = carry; + } + + let a_lo: u128 expr = from_bytes_le(a_le[..16]); + let b_lo: u128 expr = from_bytes_le(b_le[..16]); + let a_hi: u128 expr = from_bytes_le(a_le[16..]); + let b_hi: u128 expr = from_bytes_le(b_le[16..]); + let res_lo: u128 expr = from_bytes_le(res_le[..16]); + let res_hi: u128 expr = from_bytes_le(res_le[16..]); + @ a_lo + b_lo = res_lo + carry_lo * 2.pow(128); + @ a_hi + b_hi + carry_lo = res_hi + carry_hi * 2.pow(128); + return res_le; +} +``` + +## Bytecode circuit + +An example of a state machine + lookupable table circuit + +https://hackmd.io/Cv5Pmh8fRyuuuwCFcCZdzg + +Types: +- Tag: enum{ Length, Byte } +- Word: [u128, u128] + +BytecodeLookup: +- codeHash: Word +- tag: Tag +- index: u16 +- value: u8 + +State: +- tag: Tag +- length: u16 +- index: u16 +- value: u8 +- is_code: bool +- push_data_size: u16 +- push_data_left: u16 +- hash: Word +- values_rlc: field +- is_first: bool fixed +- is_last: bool fixed + +Witness: list of State structs with the following values defined: +- tag +- if tag == Length + - length + - hash +- if tag == Byte + - value + +``` +circuit bytecode(curr: State, next: State) { + // Length state validation + if curr.tag == Length { + @ curr.index = 0; + @ curr.value = curr.length; + if curr.length == 0 { + @ curr.hash = EMPTY_HASH; + } + } + // Byte state validation + if curr.tag == Byte { + @ curr.push_data_size = push_data_size_table[curr.value]; + @ curr.is_code = (curr.push_data_left == 0); + if curr.is_code { + @ next.push_data_left = curr.push_data_size; + } else { + @ next.push_data_left = curr.push_data_left - 1; + } + } + + // Start state + if curr.is_first { + @ curr.tag = Tag.Length; + } + // End state + if curr.is_last { + @ curr.tag = Tag.Length; + } + + // State transition validation + if !curr.is_last { + // Length -> Byte + if curr.tag == Length and next.tag == Byte { + @ next.length = curr.length; + @ next.index = 0; + @ next.is_code = 1; + @ next.hash = curr.hash; + @ next.values_rlc = next.value; + @ next.value = any; + @ next.push_data_left = any; + } + + // Length -> Length + if curr.tag == Length and next.tag == Length { + @ curr.length = 0; + @ curr.hash = EMPTY_HASH; + @ next.length = any; + @ next.index = any; + @ next.value = any; + @ next.is_code = any; + @ next.push_data_left = any; + @ next.hash = any; + @ next.values_rlc = any; + } + + // Byte -> Byte + if curr.tag == Byte and next.tag == Byte { + @ next.length = curr.length; + @ next.index = curr.index + 1; + @ next.hash = curr.hash; + @ next.values_rlc = curr.values_rlc * randomness + curr.value; + @ next.value = any; + } + + // Byte -> Length + if curr.tag == Byte and next.tag == Length { + @ curr.index = curr.length - 1; + @ curr.hash = keccak256[curr.values_rlc, curr.length]; + @ next.length = any; + @ next.index = any; + @ next.value = any; + @ next.hash = any; + @ next.values_rlc = any; + } + } +} +``` + +Exercice: write a function that given a list of byte vectors, generates the list of Bytecode +circuit states. + +``` +fn gen(inputs: &[Vec]) -> Vec { + let mut states = Vec::new(); + for input in inputs { + states.push(State{ + tag: Lenght, + value: input.len(), + hash: rlc(r, hash(input)), + }); + for byte in input { + states.push(State{ + tag: Byte, + value: byte, + }); + } + } +} +``` diff --git a/tools/polyexen/deps/polyexen/format.md b/tools/polyexen/deps/polyexen/format.md new file mode 100644 index 0000000..9b7253d --- /dev/null +++ b/tools/polyexen/deps/polyexen/format.md @@ -0,0 +1,65 @@ +# plaf: Plonkish Arithmetization Format + +Original notes for Plaf. The current implementation is slightly different. + +``` +[info] +name = "Circuit Foo" +size = 4096 # k = 12 + +[columns.witness] +w0 = {} +w1 = {} +w2 = { phase = 2 } # dictionary allows adding extra properties to witness columns + +[columns.fixed] +q0 = {} +q1 = {} +q2 = {} +q3 = {} + +[constraints.poly] +"gate 1" = "q0 * ((w0 - 0) * (w0 - 1))" +"gate 2" = "q1 * (w0 - w1)" +"gate 3" = "q2 * w0 * w1 * w2" +"gate 4" = "q3 * (w1[1] = w0[0])" + +[constraints.lookup] +"lookup 1" = [["w0", "w1"], ["w2[0]", "w2[1]"]] +"lookup 2" = [["w0", "w0 + w1"], ["w2 + w2", "q0 * w2"]] + +[[constraints.copy]] +columns = ["w0", "w1"] +offsets = [[0, 10], [1, 11], [2, 12]] + +[[constraints.copy]] +columns = ["w0", "w2"] +offsets = [[0, 1], [2, 3], [4, 5]] +``` + +# cova: Column Values + +## covab: Column Values in Binary + +## covat: Column Values in Text + +It's just CSV, where values can be in decimal (with "-" to negate), hex (with "0x" prefix) +The first line contains the column names, the rest are values. which can be skipped to mean +unassigned (0). + +Why CSV? Because it's the simplest text format to encode table values, and it can be easily +imported into sqlite to explore big tables. + +``` +w0,w1,w2 +12,0x4,-1 +,,33 +12345,88,0x124 +``` + +``` +q0,q1,q2,q3 +,,,1 +1,1, +1,,, +``` diff --git a/tools/polyexen/deps/polyexen/plaf.md b/tools/polyexen/deps/polyexen/plaf.md new file mode 100644 index 0000000..0d03ee6 --- /dev/null +++ b/tools/polyexen/deps/polyexen/plaf.md @@ -0,0 +1,38 @@ +# plaf: Plonkish Arithmetization Format + +**Disclaimer**: This is a work in process and some parts of the implementation may be incomplete. + +Plaf is an attempt to create a standard format for plonkish circuits so that it can be reused in components that work with plonkish arithmetization. + +Plaf supports the following "plonkish arithmetization" features: +- Listing of columns (or commitment polynomials) with names (aliases) +- Listing of polynomail expressions constraints that use the columns at any level of rotation +- Listing of lookup constraints as list of expression pairs +- Listing of copy constraints as list of column pairs with list of offset pairs +- Partial support for the Challange API: https://github.com/privacy-scaling-explorations/halo2/pull/97 +- Fixed column values + +## Serialization & Deserialization + +Plaf is currently implemented as a Rust struct but it can also be serialized. + +The current implementation supports the serialization of a Plaf circuit into 2 parts: +- A csv file with the fixed column values +- The rest of the circuit definition in a toml file + +Currently the deserialization is not implemented + +## Motivation and goals + +The first motivation is to have a standard format that can be reused among various plonkish systems so that frontends and backend become independent and can be made interchangeable. The definition of frontend and backend used here is this: +- frontend: module that generates the plonkish circuit (encoded as a Plaf circuit), and also is able to generate the witness values +- backend: module that has the following functionalities: + - receive a Plaf circuit and generate the corresponding verifying and proving keys. + - receive a Plaf circuit, a proving key and the witness values and generate a proof. + - receive a Plaf circuit, a verifying key and a proof and verify it. + +The current implemnentation supports the halo2 frontend (the halo2 Rust API) and the halo2 backend (the halo2 provig system implementation). Using halo2 as backend requires a small change in halo2 because the original version only supports circuits defined at compile time. The approach I've followed to support runtime circuit definitions is to add `&self` to `Circuit::configure`: https://github.com/ed255/halo2/commit/63e969673de83a410f21553fabec8f4b35bda1a5 + +A second goal is to have a standard format that supports pretty serialization to help reviewing/auditing circuits. + +A third goal is to have a standard format which circuit analysis tools can target so that they can be reused for circuits targeting different proving systems. diff --git a/tools/polyexen/deps/polyexen/rustfmt.toml b/tools/polyexen/deps/polyexen/rustfmt.toml new file mode 100644 index 0000000..c3c8c37 --- /dev/null +++ b/tools/polyexen/deps/polyexen/rustfmt.toml @@ -0,0 +1 @@ +imports_granularity = "Crate" diff --git a/tools/polyexen/deps/polyexen/src/analyze.rs b/tools/polyexen/deps/polyexen/src/analyze.rs new file mode 100644 index 0000000..0cbf16c --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/analyze.rs @@ -0,0 +1,536 @@ +use crate::expr::{modinv, mul, neg, Expr, Var}; +use std::fmt::{self, Display}; + +use num_bigint::{BigInt, BigUint, Sign}; +use num_traits::{cast::ToPrimitive, One, Zero}; +use std::collections::{hash_map::RandomState, HashMap, HashSet}; + +#[derive(Debug, Clone, PartialEq)] +pub enum Bound { + Range(BigUint, BigUint), // x in [start..end] + Set(Vec), // non contiguous set, always sorted +} + +impl Display for Bound { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Bound::Range(start, end) => write!(f, "[{}:{}]", start, end), + // Bound::Set(xs) => write!(f, "{:?}", xs), + Bound::Set(xs) => { + let mut s = format!("{:?}", xs); + s.truncate(10); + write!(f, "{}", s) + } + } + } +} + +impl Bound { + pub fn new>(iter: I) -> Self { + let one = BigUint::from(1u64); + let mut set: Vec = iter.into_iter().collect(); + set.sort(); + set.dedup(); + if set.len() == 0 { + return Self::Set(vec![]); + } else if set.len() == 1 { + return Self::Set(vec![set[0].clone()]); + } + let mut inc = set[0].clone(); + for v in &set { + if *v != inc { + return Self::Set(set); + } + inc += &one; + } + Self::Range(set[0].clone(), set[set.len() - 1].clone()) + } + pub fn new_unique(f: BigUint) -> Self { + Self::Set(vec![f]) + } + pub fn empty() -> Self { + Self::Set(vec![]) + } + pub fn new_bool() -> Self { + Self::Range(BigUint::from(0u64), BigUint::from(1u64)) + } + pub fn new_u8() -> Self { + Self::Range(BigUint::from(0u64), BigUint::from(0xffu64)) + } + pub fn new_u16() -> Self { + Self::Range(BigUint::from(0u64), BigUint::from(0xff_ffu64)) + } + pub fn new_range(min: BigUint, max: BigUint) -> Self { + Self::Range(min, max) + } + + pub fn overlap(&self, other: &Self) -> bool { + use Bound::*; + if let (Some(a), Some(b)) = (self.unique(), other.unique()) { + return a == b; + } + match (&self, other) { + (Range(a, b), Range(c, d)) => { + let a: &BigUint = a; + let b: &BigUint = b; + let min = a.max(c); + let max = b.min(d); + if min <= max { + true + } else { + false + } + } + (Set(a), Set(b)) => { + let a: HashSet<&BigUint, RandomState> = HashSet::from_iter(a.iter()); + let b: HashSet<&BigUint, RandomState> = HashSet::from_iter(b.iter()); + let intersection = a.intersection(&b); + intersection.count() != 0 + } + (Range(min, max), Set(s)) | (Set(s), Range(min, max)) => { + s.iter().filter(|v| &min <= v && v <= &max).count() != 0 + } + } + } + + /// Returns true if self changes. + pub fn intersection(&mut self, other: &Self) -> bool { + use Bound::*; + let self_old = self.clone(); + match (&self, other) { + (Range(a, b), Range(c, d)) => { + let a: &BigUint = a; + let b: &BigUint = b; + let min = a.max(c); + let max = b.min(d); + if min <= max { + *self = Range(min.clone(), max.clone()); + } else { + *self = Set(vec![]); + } + } + (Set(a), Set(b)) => { + let a: HashSet<&BigUint, RandomState> = HashSet::from_iter(a.iter()); + let b: HashSet<&BigUint, RandomState> = HashSet::from_iter(b.iter()); + let intersection = a.intersection(&b); + *self = Set(intersection.map(|v| (*v).clone()).collect()); + } + (Range(min, max), Set(s)) | (Set(s), Range(min, max)) => { + *self = Self::new(s.iter().filter(|v| &min <= v && v <= &max).cloned()); + } + } + let changed = self_old != *self; + // if changed { + // println!("DBG {} -> {}", self_old, self); + // } + changed + } + + pub fn range_u64(&self) -> Option<(u64, u64)> { + if let Self::Range(start, end) = self { + if let (Some(start), Some(end)) = (start.to_u64(), end.to_u64()) { + Some((start, end)) + } else { + None + } + } else { + None + } + } + pub fn range_bits(&self) -> Option { + if let Self::Range(start, end) = self { + if start.is_zero() && end.count_ones() == end.bits() { + Some(end.bits()) + } else { + None + } + } else { + None + } + } + pub fn is_bool(&self) -> bool { + if let Some((0, 1)) = self.range_u64() { + true + } else { + false + } + } + pub fn is_u8(&self) -> bool { + if let Some((0, 0xff)) = self.range_u64() { + true + } else { + false + } + } + pub fn is_u16(&self) -> bool { + if let Some((0, 0xff_ff)) = self.range_u64() { + true + } else { + false + } + } + pub fn unique(&self) -> Option<&BigUint> { + match self { + Bound::Set(xs) => { + if xs.len() == 1 { + Some(&xs[0]) + } else { + None + } + } + _ => None, + } + } +} + +#[derive(Debug)] +pub struct Attrs { + pub bound: Bound, +} + +#[derive(Debug)] +pub struct Analysis { + pub vars_attrs: HashMap, +} + +impl Analysis { + pub fn new() -> Self { + Self { + vars_attrs: HashMap::new(), + } + } + + pub fn bound_exp(&self, e: &Expr) -> Option { + use Expr::*; + match e { + Var(cell) => self.vars_attrs.get(cell).map(|attrs| attrs.bound.clone()), + Const(f) => Some(Bound::new([f.clone()])), + _ => { + // TODO: Implement + None + } + } + } +} + +fn to_biguint(c: BigInt, p: &BigUint) -> BigUint { + let (sign, c) = c.into_parts(); + if sign == Sign::Minus { + p - c + } else { + c + } +} + +pub fn bound_base(p: &BigUint) -> Bound { + Bound::new_range(BigUint::zero(), p.clone() - BigUint::one()) +} + +/// Try to find solutions on variables in the expression that follow a linear combination with bit-ranged variables. Returns the list of variables with updated bounds. +/// This works by fiding the pattern `0xabc - (x + B * y + B^2 * z + ...)` where `x,y,z` are ranged +/// from 0 to B-1. +pub fn solve_ranged_linear_comb( + e: &Expr, + p: &BigUint, + analysis: &mut Analysis, +) -> Vec { + use Expr::*; + let empty = Vec::new(); + let xs = if let Sum(xs) = e { + xs + } else { + return empty; + }; + if xs.len() != 2 { + return empty; + } + let mut value = if let Const(f) = &xs[0] { + f.clone() + } else { + return empty; + }; + let exp = if let Neg(e) = &xs[1] { + e + } else { + return empty; + }; + let (base, elems) = if let Some((base, elems)) = exp.get_linear_comb(p) { + (base, elems) + } else { + return empty; + }; + let base = if let Const(f) = base { + f + } else { + return empty; + }; + let base_bits = if base.count_ones() == 1 { + base.bits() - 1 + } else { + return empty; + }; + let vars: Vec<&V> = elems + .iter() + .filter_map(|elem| if let Var(v) = elem { Some(v) } else { None }) + .collect(); + if vars.len() != elems.len() { + return empty; + } + for v in &vars { + if let Some(attrs) = analysis.vars_attrs.get(&v) { + if let Some(range_bits) = attrs.bound.range_bits() { + if range_bits > base_bits { + return empty; + } + } else { + return empty; + } + } else { + return empty; + } + } + let mask = base - BigUint::one(); + for v in &vars { + analysis.vars_attrs.insert( + (*v).clone(), + Attrs { + bound: Bound::new_unique(value.clone() & mask.clone()), + }, + ); + value = value >> base_bits; + } + assert!(value.is_zero()); + vars.iter().cloned().cloned().collect() +} + +/// Try to find bounds on variables in the expression by finding values that will not satisfy the +/// polynomial identity. Returns the list of variables with updated bounds. +pub fn find_bounds_poly(e: &Expr, p: &BigUint, analysis: &mut Analysis) -> Vec { + let (exhaustive, solutions_list) = find_solutions(e, p); + let mut solutions = HashMap::new(); + if exhaustive { + for (var, value) in &solutions_list { + solutions + .entry(var) + .and_modify(|values: &mut Vec| values.push(value.clone())) + .or_insert(vec![value.clone()]); + } + } + // If there are several exhaustive solutions but they involve different variables, we can't + // bound any variable. + if solutions.keys().count() > 1 { + solutions = HashMap::new(); + } + let bound_base = bound_base(p); + let mut update = Vec::new(); + // if analysis.vars_attrs.len() == 0 { + // println!("DBG1"); + // } + for var in e.vars().iter() { + let bound = match solutions.get(var) { + Some(values) => Bound::new(values.into_iter().map(|c| to_biguint(c.clone(), p))), + None => bound_base.clone(), + }; + analysis + .vars_attrs + .entry(var.clone()) + .and_modify(|attrs| { + let changed = attrs.bound.intersection(&bound); + if changed { + update.push(var.clone()); + } + }) + .or_insert_with(|| { + update.push(var.clone()); + Attrs { bound } + }); + } + update +} + +fn find_solutions_base(e: &Expr) -> (bool, Vec<(V, BigInt)>) { + use Expr::*; + match e { + Const(_) => (true, Vec::new()), + Var(v) => (true, vec![(v.clone(), BigInt::zero())]), + Neg(e) => find_solutions_base(e), + Sum(es) => { + // println!("DBG1"); + // for e in es { + // println!(" {}", e); + // } + let mut var: Option = None; + let mut con: Option = None; + let mut neg = false; + for e in es { + match (e, &var, &con) { + (Const(c), _, None) => { + neg ^= true; + con = Some(c.clone().into()); + } + (Var(v), None, _) => { + var = Some(v.clone()); + } + (Neg(e), _, _) => match (&**e, &var, &con) { + (Const(c), _, None) => { + con = Some(c.clone().into()); + } + (Var(v), None, _) => { + neg ^= true; + var = Some(v.clone()); + } + _ => return (false, Vec::new()), + }, + _ => return (false, Vec::new()), + } + } + if neg { + con = Some(-con.unwrap()); + } + (true, vec![(var.unwrap(), con.unwrap())]) + } + _ => (false, Vec::new()), + } +} + +fn solve_1(a: &BigUint, b: &BigUint, p: &BigUint) -> BigUint { + // a + b*x = 0 + // x = -a * inv(b) + mul(neg(a.clone(), p), &modinv(b.clone(), p), p) +} + +pub fn find_solution_1(e: &Expr, p: &BigUint) -> Option<(V, BigInt)> { + use Expr::*; + match e { + Mul(xs) => { + if xs.len() != 2 { + return None; + } + if let (Const(b), Var(v)) = (&xs[0], &xs[1]) { + let res = solve_1(&BigUint::zero(), &b, p); + return Some((v.clone(), BigInt::from(res))); + } + return None; + } + Sum(xs) => { + if xs.len() != 2 { + return None; + } + if let (Const(a), Mul(ys)) = (&xs[0], &xs[1]) { + if ys.len() != 2 { + return None; + } + if let (Const(b), Var(v)) = (&ys[0], &ys[1]) { + let res = solve_1(&a, &b, p); + return Some((v.clone(), BigInt::from(res))); + } + } + return None; + } + _ => None, + } +} + +// Attempt to find solutions to `e(X) == 0` by matching on the pattern `(x - A)(y - B)...`. +// Returns true when the solutions returned are exhaustive. +pub fn find_solutions(e: &Expr, p: &BigUint) -> (bool, Vec<(V, BigInt)>) { + use Expr::*; + if let Some(solution) = find_solution_1(e, p) { + return (true, vec![solution]); + } + match e { + Mul(es) => { + let mut exhaustive = true; + let mut solutions = Vec::new(); + for e in es { + let (e_exhaustive, e_solutions) = find_solutions_base(e); + exhaustive &= e_exhaustive; + solutions.extend_from_slice(&e_solutions); + } + (exhaustive, solutions) + } + _ => find_solutions_base(e), + } +} + +#[cfg(test)] +mod tests_with_parser { + use super::*; + use crate::parser::parse_expr; + + // Return a prime for testing + fn prime() -> BigUint { + BigUint::parse_bytes(b"100000000000000000000000000000000", 16).unwrap() + - BigUint::from(159u64) + } + + #[test] + fn test_find_solutions00() { + let p = prime(); + for (e_str, sol_str, expected_exhaustive) in [ + ("(a - 5) * (b + 8)", vec![("a", "5"), ("b", "-8")], true), + ("(a - 5) * (a - 7)", vec![("a", "5"), ("a", "7")], true), + ("(-a + 5) * (-a - 7)", vec![("a", "5"), ("a", "-7")], true), + ("(a - 3) * -(a - 4)", vec![("a", "3"), ("a", "4")], true), + ("(a - 3) * (a + b - 4)", vec![("a", "3")], false), + ( + "(a - 0) * (a - 1) * (a - 2) * (a - 3)", + vec![("a", "0"), ("a", "1"), ("a", "2"), ("a", "3")], + true, + ), + ] { + let e = parse_expr(e_str).unwrap(); + let mut expected_solutions = Vec::new(); + for s in sol_str { + let v = s.0.to_string(); + let c = BigInt::parse_bytes(s.1.as_bytes(), 10).unwrap(); + expected_solutions.push((v, c)); + } + expected_solutions.sort(); + + let (exhaustive, mut solutions) = find_solutions(&e, &p); + solutions.sort(); + assert_eq!(exhaustive, expected_exhaustive, "{}", e_str); + assert_eq!(solutions, expected_solutions, "{}", e_str); + } + } + + #[test] + fn test_find_bounds_poly00() { + let p = prime(); + + let poly1 = parse_expr("(a - 0) * (a - 1)").unwrap(); + let mut analysis = Analysis::new(); + find_bounds_poly(&poly1, &p, &mut analysis); + assert_eq!( + analysis.vars_attrs.get("a").unwrap().bound.range_u64(), + Some((0, 1)) + ); + + let poly2 = parse_expr("(a - 0) * (a - 1) * (a - 2) * (a - 3)").unwrap(); + let mut analysis = Analysis::new(); + find_bounds_poly(&poly2, &p, &mut analysis); + assert_eq!( + analysis.vars_attrs.get("a").unwrap().bound.range_u64(), + Some((0, 3)) + ); + } + + #[test] + fn test_carlos() { + let p = prime(); + let poly1 = parse_expr("(x - 4) * (x - 1) * x * (x - 2) * (x - 3)").unwrap(); + let mut analysis = Analysis::new(); + find_bounds_poly(&poly1, &p, &mut analysis); + println!("{:?}", &analysis); + } + + #[test] + fn test_find_bounds_poly01() { + let p = prime(); + let poly1 = parse_expr("5*(1 - tag[1])").unwrap(); + let mut analysis = Analysis::new(); + find_bounds_poly(&poly1, &p, &mut analysis); + println!("{:?}", &analysis); + } +} diff --git a/tools/polyexen/deps/polyexen/src/expr.rs b/tools/polyexen/deps/polyexen/src/expr.rs new file mode 100644 index 0000000..4efa471 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/expr.rs @@ -0,0 +1,1283 @@ +use halo2_proofs::{ + halo2curves::group::ff::{Field, PrimeField}, + plonk::Expression, +}; +use num_bigint::{BigInt, BigUint, RandBigInt, Sign}; +use num_integer::Integer; +use num_traits::{One, ToPrimitive, Zero}; +use rand::Rng; +use std::{ + cmp::{Eq, Ord, Ordering, PartialEq}, + collections::{HashMap, HashSet}, + fmt::{self, Debug, Display, Write}, + hash::Hash, + mem, + ops::{Add, Mul, Neg, Sub}, +}; + +// trait Field: Add + Sub + Mul + Neg + Clone + Sized + Debug { +// fn q() -> Self; +// fn zero() -> Self; +// fn one() -> Self; +// fn from(v: u64) -> Self; +// fn is_zero(&self) -> bool; +// fn is_one(&self) -> bool; +// } + +pub trait Var: Clone + Debug + PartialEq + Eq + Hash + Ord + Display {} + +impl Var for &'static str {} +impl Var for String {} + +#[derive(Debug, Clone, PartialEq)] +pub enum Expr { + Const(BigUint), + Var(V), + Sum(Vec>), + Mul(Vec>), + Neg(Box>), + Pow(Box>, u32), +} + +pub type Ex = Expr; + +pub fn get_field_p>() -> BigUint { + let p_1 = F::ZERO - F::ONE; + let p_1 = BigUint::from_bytes_le(&p_1.to_repr()[..]); + p_1 + 1u64 +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ColumnKind { + Witness, + Public, + Fixed, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Column { + pub kind: ColumnKind, + pub index: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ColumnQuery { + pub column: Column, + pub rotation: i32, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum PlonkVar { + Query(ColumnQuery), + Challenge { index: usize, phase: usize }, +} + +impl Var for PlonkVar {} + +impl Display for PlonkVar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ColumnKind::*; + use PlonkVar::*; + match self { + Query(ColumnQuery { + column: Column { kind, index }, + rotation, + }) => { + write!( + f, + "{}{:02}", + match kind { + Witness => "w", + Public => "p", + Fixed => "f", + }, + index + )?; + if *rotation != 0 { + write!(f, "[{}]", rotation)?; + } + } + Challenge { index, phase } => write!(f, "ch{}_{}", index, phase)?, + } + Ok(()) + } +} + +impl> From<&Expression> for Expr { + fn from(e: &Expression) -> Self { + use Expression::*; + match e { + Constant(c) => Expr::Const(BigUint::from_bytes_le(&c.to_repr()[..])), + Selector(_) => unreachable!("selector exoression is unsupported"), + Fixed(query) => Expr::Var(PlonkVar::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Fixed, + index: query.column_index(), + }, + rotation: query.rotation().0, + })), + Advice(query) => Expr::Var(PlonkVar::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Witness, + index: query.column_index(), + }, + rotation: query.rotation().0, + })), + Instance(query) => Expr::Var(PlonkVar::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Public, + index: query.column_index(), + }, + rotation: query.rotation().0, + })), + Challenge(challenge) => Expr::Var(PlonkVar::Challenge { + index: challenge.index(), + phase: challenge.phase() as usize, + }), + Negated(e) => -Self::from(&**e), + Sum(e1, e2) => Self::from(&**e1) + Self::from(&**e2), + Product(e1, e2) => Self::from(&**e1) * Self::from(&**e2), + Scaled(e, c) => { + Expr::Const(BigUint::from_bytes_le(&c.to_repr()[..])) * Self::from(&**e) + } + } + } +} + +fn rand(rng: &mut R, p: &BigUint) -> BigUint { + rng.gen_biguint_below(p) +} + +const VARS: &str = "abcdefghijklmnopqrstuvwxyz"; + +impl Expr<&'static str> { + pub fn rand_depth(rng: &mut R, p: &BigUint, depth: usize) -> Self { + use Expr::*; + const MAX_ELEMS: usize = 8; + let case_max = if depth > 0 { 4 } else { 1 }; + let case: u8 = rng.gen_range(0..=case_max); + match case { + 0 => Const(rand(rng, p)), + 1 => { + let i = rng.gen_range(0..26); + Var(&VARS[i..i + 1]) + } + 2 => { + let mut v = Vec::new(); + for _ in 0..rng.gen_range(2..MAX_ELEMS) { + v.push(Expr::rand_depth(rng, p, depth - 1)); + } + Sum(v) + } + 3 => { + let mut v = Vec::new(); + for _ in 0..rng.gen_range(2..MAX_ELEMS) { + v.push(Expr::rand_depth(rng, p, depth - 1)); + } + Mul(v) + } + 4 => Neg(Box::new(Expr::rand_depth(rng, p, depth - 1))), + _ => unreachable!(), + } + } + pub fn rand(rng: &mut R, p: &BigUint) -> Self { + Expr::rand_depth(rng, p, 4) + } +} + +impl Add for Expr { + type Output = Self; + fn add(self, rhs: Self) -> Self { + use Expr::*; + match self { + Sum(mut xs) => { + xs.push(rhs); + Sum(xs) + } + e => Sum(vec![e, rhs]), + } + } +} + +impl Sub for Expr { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + use Expr::*; + match self { + Sum(mut xs) => { + xs.push(rhs.neg()); + Sum(xs) + } + e => Sum(vec![e, rhs.neg()]), + } + } +} + +impl Mul for Expr { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + use Expr::*; + match self { + Mul(mut xs) => { + xs.push(rhs); + Mul(xs) + } + e => Mul(vec![e, rhs]), + } + } +} + +impl Neg for Expr { + type Output = Self; + fn neg(self) -> Self { + Expr::Neg(Box::new(self)) + } +} + +impl Ord for Expr { + fn cmp(&self, other: &Self) -> Ordering { + use Expr::*; + use Ordering::*; + // Ordering: Const, Var, Sum, Mul + match (self, other) { + (Const(_), Const(_)) => Equal, + (Const(_), Var(_)) => Less, + (Const(_), Sum(_)) => Less, + (Const(_), Mul(_)) => Less, + (Const(_), Neg(e)) => self.cmp(e), + (Var(_), Const(_)) => Greater, + (Var(_), Var(_)) => Equal, // TODO + (Var(_), Sum(_)) => Less, + (Var(_), Mul(_)) => Less, + (Var(_), Neg(e)) => self.cmp(e), + (Sum(_), Const(_)) => Greater, + (Sum(_), Var(_)) => Greater, + (Sum(a), Sum(b)) => a.len().cmp(&b.len()), + (Sum(_), Mul(_)) => Less, + (Sum(_), Neg(e)) => self.cmp(e), + (Mul(_), Const(_)) => Greater, + (Mul(_), Var(_)) => Greater, + (Mul(_), Sum(_)) => Greater, + (Mul(a), Mul(b)) => a.len().cmp(&b.len()), + (Mul(_), Neg(e)) => self.cmp(e), + (Neg(e), Const(_)) => (**e).cmp(other), + (Neg(e), Var(_)) => (**e).cmp(other), + (Neg(e), Sum(_)) => (**e).cmp(other), + (Neg(e), Mul(_)) => (**e).cmp(other), + (Neg(e1), Neg(e2)) => (**e1).cmp(e2), + _ => Equal, + } + } +} + +impl PartialOrd for Expr { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// impl PartialEq for Expr { +// fn eq(&self, _other: &Self) -> bool { +// true +// } +// } + +impl Eq for Expr {} + +// Keep n between -(p-1) and (p-1) after an addition or subtraction operation. +fn norm(n: BigInt, p: &BigInt) -> BigInt { + if &n >= p { + n - p + } else if n <= -p { + n + p + } else { + n + } +} + +fn iadd(lhs: BigInt, rhs: BigUint, p: &BigInt) -> BigInt { + let r = lhs + BigInt::from(rhs); + norm(r, p) +} + +fn isub(lhs: BigInt, rhs: BigUint, p: &BigInt) -> BigInt { + let r = lhs - BigInt::from(rhs); + norm(r, p) +} + +fn add(lhs: BigUint, rhs: BigUint, p: &BigUint) -> BigUint { + let r = lhs + rhs; + if &r >= p { + r - p + } else { + r + } +} + +pub(crate) fn neg(n: BigUint, p: &BigUint) -> BigUint { + p - n +} + +pub(crate) fn mul(lhs: BigUint, rhs: &BigUint, p: &BigUint) -> BigUint { + (lhs * rhs).mod_floor(p) +} + +pub(crate) fn pow(base: &BigUint, exponent: u32, p: &BigUint) -> BigUint { + let mut exponent = exponent; + let mut res = BigUint::one(); + let mut acc = base.clone(); + while exponent != 0 { + if (exponent & 1) != 0 { + res = mul(res, &acc, p); + } + acc = mul(acc.clone(), &acc, p); + exponent = exponent >> 1; + } + res +} + +pub(crate) fn modinv(n: BigUint, p: &BigUint) -> BigUint { + if p.is_one() { + return BigUint::one(); + } + + let n = BigInt::from(n); + let p = BigInt::from(p.clone()); + + let (mut a, mut m, mut x, mut inv) = (n.clone(), p.clone(), BigInt::zero(), BigInt::one()); + + let one = BigInt::one(); + while a > one { + let (div, rem) = a.div_rem(&m); + inv -= div * &x; + a = rem; + std::mem::swap(&mut a, &mut m); + std::mem::swap(&mut x, &mut inv); + } + + if inv < BigInt::zero() { + inv += p + } + + let (sign, res) = inv.into_parts(); + assert_eq!(sign, Sign::Plus); + res +} + +impl Expr { + // p is the base field + pub fn eval(&self, p: &BigUint, vars: &HashMap) -> BigUint { + use Expr::*; + match self { + Neg(e) => neg((*e).eval(p, vars), p), + Const(f) => f.clone(), + Var(v) => vars.get(v).unwrap().clone(), + Sum(es) => { + let mut res = BigUint::zero(); + for e in es.iter().map(|e| e.eval(p, vars)) { + res = add(res, e, p); + } + res + } + Mul(es) => { + let mut res = BigUint::one(); + for e in es.iter().map(|e| e.eval(p, vars)) { + res = mul(res, &e, p); + } + res + } + Pow(e, f) => { + let b = e.eval(p, vars); + let mut res = BigUint::one(); + let exp: u32 = f.to_u32().expect("exponent too big"); + // TODO: Implement efficient expmod + for _ in 0..exp { + res = mul(res, &b, p); + } + res + } + } + } + + fn _simplify(self, p: &BigUint, ip: &BigInt) -> Self { + use Expr::*; + // p-1 == -1 + // let p_1 = p.clone() - BigUint::one(); + match self { + Pow(e, f) => match *e { + Const(e) => Const(pow(&e, f, p)), + _ => { + let e = e._simplify(p, ip); + Pow(Box::new(e), f) + } + }, + Neg(e) => { + let e = e._simplify(p, ip); + match e { + Neg(ne) => *ne, // double negate concels itself + e => Neg(Box::new(e)), + } + } + Const(f) => match (f.count_ones(), f.trailing_zeros()) { + // Express values greater-equal than 2^8 as 2^n + (1, Some(n)) if n >= 8 => Pow(Box::new(Const(BigUint::from(2u32))), n as u32), + _ => Const(f), + }, + Var(v) => Var(v), + Sum(es) => { + let mut xs: Vec> = Vec::new(); + for x in es.into_iter().map(|x| x._simplify(p, ip)) { + match x { + Sum(es) => xs.extend(es.into_iter()), + e => xs.push(e), + } + } + xs.sort(); + let mut c = BigInt::zero(); + let mut tail = Vec::new(); + for x in xs { + match x { + Neg(e) => match *e { + Const(a) => c = isub(c, a, ip), + a => tail.push(Neg(Box::new(a))), + }, + Const(a) => c = iadd(c, a, ip), + a => tail.push(a), + } + } + let mut r = if c.is_zero() { + vec![] + } else { + let (sign, c) = c.into_parts(); + if sign == Sign::Minus { + vec![Neg(Box::new(Const(c)))] + } else { + vec![Const(c)] + } + }; + r.extend(tail.into_iter()); + match r.len() { + 0 => Const(BigUint::zero()), + 1 => r.swap_remove(0), + _ => Sum(r), + } + } + Mul(es) => { + // TODO: get Pow's out of Mul elements + let mut xs: Vec> = Vec::new(); + let mut neg = false; + for x in es.into_iter().map(|x| x._simplify(p, ip)) { + match x { + Neg(e) => { + neg ^= true; + match *e { + Mul(es) => xs.extend(es.into_iter()), + ne => xs.push(ne), + } + } + Mul(es) => xs.extend(es.into_iter()), + e => xs.push(e), + } + } + xs.sort(); + let mut c = BigUint::one(); + let mut tail = Vec::new(); + for x in xs { + match x { + Const(a) => c = mul(c, &a, p), + a => tail.push(a), + } + } + let mut r = if c.is_zero() { + return Const(BigUint::zero()); + } else if c.is_one() { + vec![] + } else { + vec![Const(c)] + }; + r.extend(tail.into_iter()); + let m = if r.len() == 1 { + r.swap_remove(0) + } else if r.len() == 0 { + Const(BigUint::one()) + } else { + Mul(r) + }; + if neg { + Neg(Box::new(m)) + } else { + m + } + } + } + } + + fn is_recursive_linear_comb(e: &Self, base: &mut Option, elems: &mut Vec) -> bool { + use Expr::*; + // match pattern "sum_lhs + sum_rhs" + // where "sum_rhs = mul_lhs * mul_rhs" + // in summary "sum_lhs + mul_lhs * mul_rhs" + match e { + Sum(xs) => { + if xs.len() != 2 { + return false; + } + let sum_lhs = &xs[0]; + let sum_rhs = &xs[1]; + match sum_rhs { + Mul(ys) => { + if ys.len() < 2 { + return false; + } + let mul_lhs = &ys[0]; + if base.is_none() { + *base = Some(mul_lhs.clone()); + } + // When elem is 0, this "r * (0 + r * (10 ..))" becomes this + // "r * r * (10 ..)" + let mut zeros = 0; + for v in &ys[1..ys.len() - 1] { + if Some(v) == base.as_ref() { + zeros += 1; + continue; + } + return false; + } + let mul_rhs = &ys[ys.len() - 1]; + // sort (mul_lhs, mul_rhs) so that base into mul_lhs (if it exists) + let (mul_lhs, mul_rhs) = if Some(mul_lhs) == base.as_ref() { + (mul_lhs, mul_rhs) + } else if Some(mul_rhs) == base.as_ref() { + (mul_rhs, mul_lhs) + } else { + (mul_lhs, mul_rhs) + }; + if Some(mul_lhs) == base.as_ref() { + elems.push(sum_lhs.clone()); + (0..zeros).for_each(|_| elems.push(Const(BigUint::zero()))); + if mul_rhs.is_terminal() { + elems.push(mul_rhs.clone()); + return true; + } + return Self::is_recursive_linear_comb(&mul_rhs, base, elems); + } + return false; + } + _ => return false, + } + } + _ => return false, + } + } + + fn get_recursive_linear_comb(&self) -> Option<(Self, Vec)> { + let mut base = None; + let mut elems = Vec::new(); + let result = Self::is_recursive_linear_comb(self, &mut base, &mut elems); + if result { + Some((base.expect("base found"), elems)) + } else { + None + } + } + + /// Try to match a linear combination pattern heuristically and return the base and elements + /// from it. + pub fn get_linear_comb(&self, p: &BigUint) -> Option<(Self, Vec)> { + use Expr::*; + let xs = if let Sum(xs) = self { + xs + } else { + return None; + }; + if xs.len() < 2 { + return None; + } + let mut xs = xs.iter(); + let mut elems = Vec::new(); + elems.push(xs.next().unwrap().clone()); + let second = xs.next().unwrap(); + let base = if let Mul(pair) = second { + if pair.len() != 2 { + return None; + } + if let Const(b) = &pair[0] { + elems.push(pair[1].clone()); + b + } else { + return None; + } + } else { + return None; + }; + let mut power = base.clone(); + for x in xs { + if let Mul(pair) = x { + if pair.len() != 2 { + return None; + } + if let Const(b) = &pair[0] { + power = mul(power, base, p); + if b != &power { + return None; + } + elems.push(pair[1].clone()); + } else { + return None; + } + } else { + return None; + }; + } + Some((Const(base.clone()), elems)) + } + + // Find linear combinations expressed in recursive form "a + r * (b + r * (c + r * (...)))" + // and replace them by "a + b*r + c*r^2 + ..." + fn normalize_linear_comb(self) -> Self { + use Expr::*; + match self { + Neg(e) => Neg(Box::new(e.normalize_linear_comb())), + Sum(xs) => { + let e = Sum(xs); + if let Some((base, elems)) = e.get_recursive_linear_comb() { + if elems.len() >= 3 { + let mut xs = Vec::with_capacity(elems.len()); + for (i, elem) in elems.into_iter().enumerate() { + // let e = if i == 0 { + // elem + // } else { + // Mul(vec![elem, Pow(Box::new(base.clone()), BigUint::from(i))]) + // }; + let e = Mul(vec![elem, Pow(Box::new(base.clone()), i as u32)]); + xs.push(e); + } + return Sum(xs); + } + } + if let Sum(xs) = e { + Sum(xs.into_iter().map(|e| e.normalize_linear_comb()).collect()) + } else { + unreachable!(); + } + } + Mul(xs) => Mul(xs.into_iter().map(|e| e.normalize_linear_comb()).collect()), + _ => self, + } + } + + // Find multiplications with repeated elements and turn them into pows + fn normalize_pow(self) -> Self { + use Expr::*; + match self { + Neg(e) => Neg(Box::new(e.normalize_pow())), + Sum(xs) => Sum(xs.into_iter().map(|e| e.normalize_pow()).collect()), + Mul(xs) => { + let mut elems = Vec::new(); + let mut pow: Option<(Self, u32)> = None; + for x in xs { + let x = x.normalize_pow(); + if let Some((base, exp)) = pow { + if x == base { + pow = Some((base, exp + 1)); + } else { + if exp == 1 { + elems.push(base); + } else { + elems.push(Pow(Box::new(base), exp)); + } + pow = Some((x, 1)); + } + } else { + pow = Some((x, 1)); + } + } + if let Some((base, exp)) = pow { + if exp == 1 { + elems.push(base); + } else { + elems.push(Pow(Box::new(base), exp)); + } + } + Mul(elems) + } + _ => self, + } + } + + /// Simplify the expression in places where it can be partially evaluated + pub fn simplify_move(self, p: &BigUint) -> Self { + let ip = BigInt::from(p.clone()); + let e = self._simplify(p, &ip); + let e = e.normalize_linear_comb(); + let e = e.normalize_pow(); + e + } + + /// Simplify the expression in places where it can be partially evaluated + pub fn simplify(&mut self, p: &BigUint) -> &mut Self { + let e = mem::replace(self, Expr::Const(BigUint::zero())); + let e = e.simplify_move(p); + *self = e; + self + } + + /// Take a list of multiplicands and return a Mul expression whith the multiplication of + /// coefficients evaluated + fn _mul_const(xs: Vec>, p: &BigUint) -> Expr { + use Expr::*; + let mut mul_const = BigUint::one(); + let mut mul_exprs = Vec::new(); + for x in xs { + match x { + Const(f) => mul_const = mul(mul_const, &f, p), + e => mul_exprs.push(e), + } + } + if mul_exprs.len() == 0 { + return Const(mul_const); + } + let mut xs = Vec::new(); + if !mul_const.is_one() { + xs.push(Const(mul_const)) + } + xs.extend_from_slice(&mul_exprs[..]); + Mul(xs) + } + + /// Apply "a * b % p" where a and b are expressions. Evaluate coefficient multiplication in + /// the resulting expression. + fn _normalize_mul(a: Expr, b: Expr, p: &BigUint) -> Expr { + use Expr::*; + match (a, b) { + (Const(a), Const(b)) => Const(mul(a, &b, p)), + (Mul(mut xs), Mul(ys)) => { + xs.extend_from_slice(&ys[..]); + Self::_mul_const(xs, p) + } + (e, Mul(xs)) => { + let mut ys = vec![e]; + ys.extend_from_slice(&xs[..]); + Self::_mul_const(ys, p) + } + (Mul(mut xs), e) => { + xs.push(e.clone()); + Self::_mul_const(xs, p) + } + (a, b) => Mul(vec![a, b]), + } + } + + fn _normalize(self, p: &BigUint) -> Self { + use Expr::*; + // p-1 == -1 + let p_1 = p.clone() - BigUint::one(); + match self { + Neg(e) => Mul(vec![Const(p_1), *e])._normalize(p), + Sum(xs) => { + let xs = xs.into_iter().map(|x: Expr| x._normalize(p)); + let mut sum_const = BigUint::zero(); + let mut sum_exprs = Vec::new(); + for x in xs { + match x { + Const(f) => sum_const = add(sum_const, f, p), + Sum(xs) => { + for x in xs { + match x { + Const(f) => sum_const = add(sum_const, f, p), + e => sum_exprs.push(e), + } + } + } + e => sum_exprs.push(e), + } + } + let mut xs = Vec::new(); + if !sum_const.is_zero() { + xs.push(Const(sum_const)) + } + xs.extend_from_slice(&sum_exprs[..]); + Sum(xs) + } + Mul(xs) => { + // println!("DBG1 {}", Mul(xs.clone())); + let xs = xs.into_iter().map(|x| x._normalize(p)); + // flat muls + let mut ys = Vec::new(); + for x in xs { + match x { + Mul(xs) => { + ys.extend_from_slice(&xs[..]); + } + _ => ys.push(x), + } + } + let xs = ys; + let mut mul_const = BigUint::one(); + let mut mul_vars: Vec> = Vec::new(); + let mut mul_sums: Vec>> = Vec::new(); + + let mut ys: Vec> = Vec::new(); + // Flatten exponentiations + for x in xs.into_iter() { + match x { + Pow(e, f) => (0..f).for_each(|_| ys.push(e.as_ref().clone())), + e => ys.push(e), + } + } + let xs = ys; + + for x in xs { + match x { + Const(f) => mul_const = mul(mul_const, &f, p), + Var(v) => mul_vars.push(Var(v)), + Sum(xs) => mul_sums.push(xs), + _ => { + unreachable!(); + } + } + } + // println!("DBG4 {:?}", mul_sums); + + let mut first = Vec::new(); + if !mul_const.is_one() { + first.push(Const(mul_const)) + } + first.extend_from_slice(&mul_vars[..]); + while mul_sums.len() >= 2 { + let mut result = Vec::new(); + let lhs = &mul_sums[mul_sums.len() - 1]; + let rhs = &mul_sums[mul_sums.len() - 2]; + for a in lhs { + for b in rhs { + result.push(Self::_normalize_mul(a.clone(), b.clone(), p)); + } + } + mul_sums.pop(); + let last_index = mul_sums.len() - 1; + mul_sums[last_index] = result; + } + if mul_sums.len() > 0 { + for e in mul_sums[0].iter_mut() { + *e = Self::_normalize_mul(Mul(first.clone()), e.clone(), p); + } + // println!("DBG2 {}", Sum(mul_sums[0].clone())); + Sum(mul_sums.pop().unwrap()) + } else { + // println!("DBG3 {}", Mul(first.clone())); + Self::_mul_const(first, p) + } + } + Pow(e, f) => { + let e = e._normalize(p); + match e { + Const(b) => { + let mut res = BigUint::one(); + let exp: u32 = f.to_u32().expect("exponent too big"); + // TODO: Implement efficient expmod + for _ in 0..exp { + res = mul(res, &b, p); + } + Const(res) + } + e => Pow(Box::new(e), f), + } + } + _ => self, + } + } + + /// Return the expression in coefficient form + pub fn normalize_move(self, p: &BigUint) -> Self { + self.simplify_move(p)._normalize(p) + } + + /// Return the expression in coefficient form + pub fn normalize(&mut self, p: &BigUint) -> &mut Self { + let e = mem::replace(self, Expr::Const(BigUint::zero())); + let e = e.normalize_move(p); + *self = e; + self + } + + fn _vars(&self, vars: &mut HashSet) { + use Expr::*; + match self { + Const(_) => {} + Var(v) => { + vars.insert(v.clone()); + } + Neg(e) => e._vars(vars), + Pow(e, _) => e._vars(vars), + Sum(es) => es.iter().for_each(|e| e._vars(vars)), + Mul(es) => es.iter().for_each(|e| e._vars(vars)), + } + } + + pub fn vars(&self) -> HashSet { + let mut vars = HashSet::new(); + self._vars(&mut vars); + vars + } + + // TODO: Document the probability of success + // Using Schwartz–Zippel lemma + pub fn test_eq(&self, rng: &mut R, other: &Self) -> bool { + let p = BigUint::parse_bytes(b"100000000000000000000000000000000", 16).unwrap() + - BigUint::from(159u64); + let e1_vars = self.vars(); + let e2_vars = other.vars(); + let mut vars_vec = e1_vars.union(&e2_vars).into_iter().collect::>(); + vars_vec.sort(); + let vars = vars_vec + .into_iter() + .map(|v| (v.clone(), rand(rng, &p))) + .collect(); + let e1_eval = self.eval(&p, &vars); + let e2_eval = other.eval(&p, &vars); + e1_eval == e2_eval + } + + pub fn is_zero(&self) -> bool { + match self { + Self::Const(c) => c.is_zero(), + _ => false, + } + } + + pub fn is_const_not_zero(&self) -> bool { + match self { + Self::Const(c) => !c.is_zero(), + _ => false, + } + } +} + +pub struct ExprDisplay<'a, V: Var, T> +where + T: Fn(&mut fmt::Formatter<'_>, &V) -> fmt::Result, +{ + pub e: &'a Expr, + pub var_fmt: T, +} + +impl<'a, V: Var, T> Display for ExprDisplay<'a, V, T> +where + T: Fn(&mut fmt::Formatter<'_>, &V) -> fmt::Result, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.e.fmt_ascii(f, &self.var_fmt) + } +} + +impl Display for Expr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &V| { + write!(f, "{}", v) + }) + } +} + +impl Expr { + // sumatory terminal + fn is_terminal(&self) -> bool { + matches!(self, Expr::Const(_) | Expr::Var(_) | Expr::Pow(_, _)) + } + + // multiplicatory terminal + fn is_mul_terminal(&self) -> bool { + self.is_terminal() || matches!(self, Expr::Mul(_)) + } + + pub fn fmt_ascii(&self, f: &mut W, fmt_var: &FV) -> fmt::Result + where + FV: Fn(&mut W, &V) -> fmt::Result, + { + use Expr::*; + let fmt_exp = |e: &Self, f: &mut W, parens: bool| -> fmt::Result { + if parens { + write!(f, "(")?; + } + e.fmt_ascii(f, fmt_var)?; + if parens { + write!(f, ")")?; + } + Ok(()) + }; + match self { + Neg(e) => { + write!(f, "-")?; + let parens = !e.is_terminal(); + fmt_exp(e, f, parens)?; + Ok(()) + } + Pow(e, c) => { + let parens = !e.is_terminal(); + fmt_exp(e, f, parens)?; + write!(f, "^{}", c) + } + Const(c) => { + let c_bits = c.bits(); + if c_bits >= 8 && c.count_ones() == 1 { + write!(f, "2^{}", c.trailing_zeros().unwrap()) + } else if c_bits >= 16 { + write!(f, "0x{:x}", c) + } else { + write!(f, "{}", c) + } + } + Var(v) => fmt_var(f, v), + Sum(es) => { + for (i, e) in es.iter().enumerate() { + let (neg, e) = if let Neg(e) = e { + (true, &**e) + } else { + (false, e) + }; + if i == 0 { + if neg { + write!(f, "-")?; + } + } else if neg { + write!(f, " - ")?; + } else { + write!(f, " + ")?; + } + let parens = !e.is_mul_terminal(); + fmt_exp(e, f, parens)?; + } + Ok(()) + } + Mul(es) => { + for (i, e) in es.iter().enumerate() { + let parens = !e.is_terminal(); + fmt_exp(e, f, parens)?; + if i != es.len() - 1 { + write!(f, "*")?; + } + } + Ok(()) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use Expr::*; + + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + fn c(v: u64) -> Expr<&'static str> { + Const(BigUint::from(v)) + } + + #[test] + fn test_scratch() { + let p = BigUint::from(0x1_00_00u64); + // let e = c(2) * c(3) * Var("a") + c(5) + c(5) + Var("b"); + // let e = c(2) * c(3) + c(3) * c(4) + c(5) + c(5) + c(6) + Var("a"); + // let e = (c(2) + Var("a")) * (c(3) + Var("b")) + ((c(4) + Var("c")) * (c(5) + Var("d"))); + // let e = (c(2) - c(1)) * Var("a"); + // let e = (c(1) - c(2)) * Var("a"); + // let e = (c(0xffff)) - (c(0xff00) - (-c(123))) * Var("a"); + // let e = Var("a") - Var("b"); + // let e = c(5) * (Var("a") * (c(1) - c(2)) * Var("b") + Var("c")); + let mut rng = ChaCha20Rng::seed_from_u64(9); + let e = Expr::rand(&mut rng, &p); + println!("raw e: {:?}", e); + println!("e: {}", e); + + let e = e.clone().normalize_move(&p); + println!("e.normalize: {}", e); + + let e = e.simplify_move(&p); + println!("raw e.normalize: {:?}", e); + println!("e.simplify: {}", e); + + let e = e.normalize_move(&p); + println!("e.normalize: {}", e); + } + + #[test] + fn test_display() { + #[rustfmt::skip] + let tests = vec![ + ( + c(2) * c(3) * Var("a") + c(5) + c(5) + Var("b"), + "2*3*a + 5 + 5 + b", + ), + ( + (c(2) + Var("a")) * (c(3) + Var("b")) + ((c(4) + Var("c")) * (c(5) + Var("d"))), + "(2 + a)*(3 + b) + (4 + c)*(5 + d)", + ), + ( + -(c(2) - Var("a")), + "-(2 - a)" + ), + ( + (-c(1) + c(2)), + "-1 + 2" + ), + ]; + for (exp, exp_fmt) in tests { + assert_eq!(format!("{}", exp).as_str(), exp_fmt); + } + } + + #[test] + fn test_simplify() { + let p = BigUint::from(0x10000u64 - 15); + let vars: HashMap<&'static str, BigUint> = { + let mut rng = ChaCha20Rng::seed_from_u64(0); + (0..26) + .map(|i| (&VARS[i..i + 1], rand(&mut rng, &p))) + .collect() + }; + let mut rng = ChaCha20Rng::seed_from_u64(0); + for i in 0..1024 { + let e1 = Expr::rand(&mut rng, &p); + let e2 = e1.clone().simplify_move(&p); + let eval1 = e1.eval(&p, &vars); + let eval2 = e2.eval(&p, &vars); + if eval1 != eval2 { + let s1 = format!("{}", e1); + let s2 = format!("{}", e2); + println!("{} e1: {}", i, s1); + println!("{} e2: {}", i, s2); + } + assert_eq!(eval1, eval2); + } + } + + #[test] + fn test_normalize00() { + let p = BigUint::from(0x10000u64 - 15); + let vars: HashMap<&'static str, BigUint> = { + let mut rng = ChaCha20Rng::seed_from_u64(0); + (0..26) + .map(|i| (&VARS[i..i + 1], rand(&mut rng, &p))) + .collect() + }; + let mut rng = ChaCha20Rng::seed_from_u64(0); + for _i in 0..1024 { + let e1 = Expr::rand_depth(&mut rng, &p, 3); + let e2 = e1.clone().normalize_move(&p); + let eval1 = e1.eval(&p, &vars); + let eval2 = e2.eval(&p, &vars); + assert_eq!(eval1, eval2, "{} -> {}", e1, e2); + } + } + + #[test] + fn test_vars() { + let e = c(2) * c(3) * Var("a") + c(5) + c(5) + Var("b") + (Var("b") + c(3)) * Var("c"); + let vars = e.vars(); + let mut vars_vec = vars.into_iter().collect::>(); + vars_vec.sort(); + assert_eq!(vars_vec, vec!["a", "b", "c"]) + } +} + +#[cfg(test)] +mod tests_with_parser { + use super::*; + use crate::parser::parse_expr; + + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + fn prime() -> BigUint { + BigUint::from(0x10000u64 - 15) + } + + #[test] + fn test_test_eq() { + let mut rng = ChaCha20Rng::seed_from_u64(0); + for (e1_str, e2_str) in [("(a - 5)*(a - 7)", "a*a - a*7 - a*5 + 35")] { + let e1 = parse_expr(e1_str).unwrap(); + let e2 = parse_expr(e2_str).unwrap(); + assert!(e1.test_eq(&mut rng, &e2)) + } + } + + #[test] + fn test_simplify_linear_comb() { + let p = prime(); + let e1_str = "112 + r_word*(164 + r_word*(133 + r_word*(93 + r_word*(4 + r_word*(216 + r_word*(250 + r_word*(123 + r_word*(59 + r_word*(39 + r_word*(130 + r_word*(202 + r_word*(83 + r_word*(182 + r_word*r_word*(229 + r_word*(192 + r_word*(3 + r_word*(199 + r_word*(220 + r_word*(178 + r_word*(125 + r_word*(126 + r_word*(146 + r_word*(60 + r_word*(35 + r_word*(247 + r_word*(134 + r_word*(1 + r_word*(70 + r_word*(210 + 197*r_word)))))))))))))))))))))))))))))"; + let e2_str = "112*r_word^0 + 164*r_word^1 + 133*r_word^2 + 93*r_word^3 + 4*r_word^4 + 216*r_word^5 + 250*r_word^6 + 123*r_word^7 + 59*r_word^8 + 39*r_word^9 + 130*r_word^10 + 202*r_word^11 + 83*r_word^12 + 182*r_word^13 + 0*r_word^14 + 229*r_word^15 + 192*r_word^16 + 3*r_word^17 + 199*r_word^18 + 220*r_word^19 + 178*r_word^20 + 125*r_word^21 + 126*r_word^22 + 146*r_word^23 + 60*r_word^24 + 35*r_word^25 + 247*r_word^26 + 134*r_word^27 + 1*r_word^28 + 70*r_word^29 + 210*r_word^30 + 197*r_word^31"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.simplify_move(&p); + // println!("{:?}", e1.normalize_linear_comb()); + let s2 = format!("{}", e2); + assert_eq!(s2, e2_str); + } + + #[test] + fn test_normalize_linear_comb_bug_1() { + let p = prime(); + let e1_str = "1*BYTECODE_q_enable*(1 - 1*(1 - 1*(1 - tag)*(1 - tag[1]))*(1 - BYTECODE_q_last))*(code_hash - (((((((((((((((((((((((((((((((197*r_word + 210)*r_word + 70)*r_word + 1)*r_word + 134)*r_word + 247)*r_word + 35)*r_word + 60)*r_word + 146)*r_word + 126)*r_word + 125)*r_word + 178)*r_word + 220)*r_word + 199)*r_word + 3)*r_word + 192)*r_word + 229)*r_word + 0)*r_word + 182)*r_word + 83)*r_word + 202)*r_word + 130)*r_word + 39)*r_word + 59)*r_word + 123)*r_word + 250)*r_word + 216)*r_word + 4)*r_word + 93)*r_word + 133)*r_word + 164)*r_word + 112))"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.clone().simplify_move(&p); + println!("{}", e2); + + let vars: HashMap = { + let mut rng = ChaCha20Rng::seed_from_u64(0); + let mut vars: Vec = e1.vars().into_iter().collect(); + vars.sort(); + vars.iter() + .map(|v| (v.to_string(), rand(&mut rng, &p))) + .collect() + }; + let eval1 = e1.eval(&p, &vars); + let eval2 = e2.eval(&p, &vars); + assert_eq!(eval1, eval2); + } + + #[test] + fn test_simplify_pow() { + let p = prime(); + let e1_str = + "4*(r_word + r_word*r_word + r_word*r_word*r_word + r_word*r_word*r_word*r_word)"; + let e2_str = "4*(r_word + r_word^2 + r_word^3 + r_word^4)"; + // TODO: Debug parser with this + // let e1_str ="f05*w77*w78*w79*w80*(1 - w76)*(w26 - (w26[-1]*2^0 + w25[-1]*2^1 + w24[-1]*2^2 + w23[-1]*2^3) + 2*(w25*2^0 + w24*2^1 + w23*2^2) + r_word*(w28 - w28[-1]) + r_word*r_word*(w27 - w27[-1]) + r_word*r_word*r_word*(w38 - w38[-1]) + r_word*r_word*r_word*r_word*(w37 - w37[-1]) + r_word*r_word*r_word*r_word*r_word*(w36 - w36[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*(w35 - w35[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w34 - w34[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w33 - w33[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w32 - w32[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w31 - w31[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w30 - w30[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w29 - w29[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w05 - w05[-1]) + r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*r_word*(w69 - (w69[-1] + 2^8*w70[-1]) + 2^8*w70))"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.simplify_move(&p); + // println!("{:?}", e1.normalize_linear_comb()); + let s2 = format!("{}", e2); + assert_eq!(s2, e2_str); + } + + #[test] + fn test_normalize01() { + let p = prime(); + let e1_str = "1*5*(1 - (1 - (1 - 0)*(1 - tag[1]))*(1 - 0))"; + // let e1_str = "1 - (1 - tag[1])"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.normalize_move(&p); + // let e2 = e2.normalize_move(&p); + println!("{}", e2); + } + + #[test] + fn test_simplify01() { + let p = prime(); + let e1_str = "(1 - 0)*1"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.simplify_move(&p); + println!("{:?}", e2); + println!("{}", e2); + } + + #[test] + fn test_simplify02() { + let p = BigUint::from(2u64).pow(256) - BigUint::from(1539u64); + let e1_str = "1*1*1*(5 + 5 - (r.b00 + 2^8*r.b01 + 2^16*r.b02 + 2^24*r.b03 + 2^32*r.b04 + 2^40*r.b05 + 2^48*r.b06 + 2^56*r.b07 + 2^64*r.b08 + 2^72*r.b09 + 2^80*r.b10 + 2^88*r.b11 + 2^96*r.b12 + 2^104*r.b13 + 2^112*r.b14 + 2^120*r.b15 + carryLo*2^128) + 2^8*5 + 2^16*5 + 2^24*5 + 2^32*5 + 2^40*5 + 2^48*5 + 2^56*5 + 2^64*5 + 2^72*5 + 2^80*5 + 2^88*5 + 2^96*5 + 2^104*5 + 2^112*5 + 2^120*5 + 2^8*5 + 2^16*5 + 2^24*5 + 2^32*5 + 2^40*5 + 2^48*5 + 2^56*5 + 2^64*5 + 2^72*5 + 2^80*5 + 2^88*5 + 2^96*5 + 2^104*5 + 2^112*5 + 2^120*5)"; + let e1 = parse_expr(e1_str).unwrap(); + let e2 = e1.simplify_move(&p); + println!("{}", e2); + } +} diff --git a/tools/polyexen/deps/polyexen/src/grammar.pest b/tools/polyexen/deps/polyexen/src/grammar.pest new file mode 100644 index 0000000..ea07999 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/grammar.pest @@ -0,0 +1,21 @@ +dec = @{ ASCII_DIGIT+ } +hex = @{ ASCII_HEX_DIGIT+ } +hex_0x = _{ "0x" ~ hex } +num = _{ hex_0x | dec } +index = _{ "[" ~ "-"? ~ ASCII_DIGIT+ ~ "]" } +var = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "," | "." | ":" | ";" | "?" | "@" | "_" )* ~ index? } + +operation = _{ add | subtract | multiply | exp } + add = { "+" } + subtract = { "-" } + multiply = { "*" } + exp = { "^" } + +expr = { term ~ (operation ~ term)* } +term = _{ neg | subterm } +neg = { "-" ~ subterm } +subterm = _{ num | var | "(" ~ expr ~ ")" } + +calculation = _{ SOI ~ expr ~ EOI } + +WHITESPACE = _{ " " | "\t" } diff --git a/tools/polyexen/deps/polyexen/src/lib.rs b/tools/polyexen/deps/polyexen/src/lib.rs new file mode 100644 index 0000000..d034d9c --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/lib.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate pest_derive; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate static_assertions; + +pub mod analyze; +pub mod expr; +pub mod parser; +pub mod plaf; diff --git a/tools/polyexen/deps/polyexen/src/parser.rs b/tools/polyexen/deps/polyexen/src/parser.rs new file mode 100644 index 0000000..24979de --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/parser.rs @@ -0,0 +1,153 @@ +use crate::expr::{Ex, Expr}; +use num_traits::ToPrimitive; + +use num_bigint::BigUint; + +extern crate pest; + +use pest::{error::Error, Parser}; + +#[derive(Parser)] +#[grammar = "grammar.pest"] +struct ExprParser; +use pest::{iterators::Pairs, pratt_parser::PrattParser}; + +lazy_static! { + static ref PRATT_PARSER: PrattParser = { + use pest::pratt_parser::{Assoc::*, Op}; + use Rule::*; + + PrattParser::new() + .op(Op::infix(add, Left) | Op::infix(subtract, Left)) + .op(Op::infix(multiply, Left)) + .op(Op::infix(exp, Left)) + }; +} + +pub fn parse_expr_pairs(expression: Pairs) -> Ex { + use Expr::*; + PRATT_PARSER + .map_primary(|primary| match primary.as_rule() { + Rule::dec => ( + Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 10).unwrap()), + true, + ), + Rule::hex => ( + Const(BigUint::parse_bytes(primary.as_str().as_bytes(), 16).unwrap()), + true, + ), + Rule::var => (Var(primary.as_str().to_string()), true), + Rule::neg => (Neg(Box::new(parse_expr_pairs(primary.into_inner()))), true), + Rule::expr => (parse_expr_pairs(primary.into_inner()), false), + _ => unreachable!(), + }) + // lcont and rcont tell wether the lhs and rhs terms belong to the same expr or not + .map_infix(|(lhs, lcont), op, (rhs, rcont)| { + ( + match op.as_rule() { + Rule::add => match (lhs, rhs, lcont & rcont) { + (Sum(mut es), rhs, true) => { + es.push(rhs); + Sum(es) + } + (Sum(mut lhs_es), Mul(rhs_es), _) => { + lhs_es.push(Mul(rhs_es)); + Sum(lhs_es) + } + (lhs, rhs, _) => Sum(vec![lhs, rhs]), + }, + Rule::subtract => match (lhs, rhs, lcont & rcont) { + (Sum(mut es), rhs, true) => { + es.push(Neg(Box::new(rhs))); + Sum(es) + } + (lhs, rhs, _) => Sum(vec![lhs, Neg(Box::new(rhs))]), + }, + Rule::multiply => match (lhs, rhs, lcont & rcont) { + (Mul(mut es), rhs, true) => { + es.push(rhs); + Mul(es) + } + (Mul(mut lhs_es), Sum(rhs_es), _) => { + lhs_es.push(Sum(rhs_es)); + Mul(lhs_es) + } + (lhs, rhs, _) => Mul(vec![lhs, rhs]), + }, + Rule::exp => { + let rhs = match rhs { + Const(c) => c.to_u32().expect("exponent fits in u32"), + _ => unreachable!(), + }; + Pow(Box::new(lhs), rhs) + } + _ => unreachable!(), + }, + true, + ) + }) + .parse(expression) + .0 +} + +pub fn parse_expr(src: &str) -> Result> { + let r = ExprParser::parse(Rule::expr, src)?; + Ok(parse_expr_pairs(r)) +} + +#[cfg(test)] +mod tests { + use super::*; + use Expr::*; + + fn c(v: u64) -> Expr { + Const(BigUint::from(v)) + } + + #[test] + fn test_parse() { + for (e_str, e_expected) in [ + ("123", c(123)), + ("-123", Neg(Box::new(c(123)))), + ("0x42", c(0x42)), + ("-0x42", Neg(Box::new(c(0x42)))), + ("3 + 5", c(3) + c(5)), + ("3 + 5 * a", c(3) + c(5) * Var("a".to_string())), + ("(3 + 5) + 2", Sum(vec![c(3) + c(5), c(2)])), + ("-(1 + 2)", Neg(Box::new(c(1) + c(2)))), + ( + "(9 + 0) * (9 + 1) * (9 + 2)", + Mul(vec![ + Sum(vec![c(9), c(0)]), + Sum(vec![c(9), c(1)]), + Sum(vec![c(9), c(2)]), + ]), + ), + ( + "9 * 0 + 9 * 1 + 9 * 2 - 9 * 3", + Sum(vec![ + Mul(vec![c(9), c(0)]), + Mul(vec![c(9), c(1)]), + Mul(vec![c(9), c(2)]), + Neg(Box::new(Mul(vec![c(9), c(3)]))), + ]), + ), + ] { + let e = parse_expr(e_str).unwrap(); + assert_eq!(e, e_expected, "{}", e_str); + } + // let r = ExprParser::parse(Rule::expr, "-(-1 + 2)"); + // dbg!(&r); + // let e = parse_expr_pairs(r.unwrap()); + // println!("{:?}", e); + // println!("{}", e); + } + + #[test] + fn test_parser_bug_1() { + let e1_str = "f05*w77*w78*w79*w80*(1 - w76)*(w26 - w26[-1]*2^0 + w25[-1]*2^1 + w24[-1]*2^2 + w23[-1]*2^3)"; + let e1 = parse_expr(e1_str).unwrap(); + let e2_str = format!("{}", e1); + assert_eq!(e1_str, e2_str); + } +} diff --git a/tools/polyexen/deps/polyexen/src/plaf.rs b/tools/polyexen/deps/polyexen/src/plaf.rs new file mode 100644 index 0000000..3d11512 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/plaf.rs @@ -0,0 +1,627 @@ +use crate::expr::{self, Column, ColumnKind, ColumnQuery, Expr, PlonkVar as Var}; +use num_bigint::BigUint; +use num_traits::Zero; +use std::collections::HashMap; +use std::fmt::{self, Debug, Display, Write}; + +pub mod backends; +pub mod frontends; + +/// The value of a particular cell within the circuit. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum CellValue { + // An unassigned cell. + Unassigned, + // A cell that has been assigned a value. + Assigned(F), + // A unique poisoned cell. + // Poison(usize), +} + +#[derive(Debug)] +pub struct Witness { + pub num_rows: usize, + pub columns: Vec, + // The advice cells in the circuit, arranged as [column][row]. + pub witness: Vec>>, +} + +/// Adaptor struct to format the witness columns assignments as CSV +pub struct WitnessDisplayCSV<'a>(pub &'a Witness); + +impl Display for WitnessDisplayCSV<'_> { + /// Format witness assignment as CSV + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let this = self.0; + write!(f, "offset")?; + for col in this.columns.iter() { + write!(f, ",")?; + write!(f, "{}", col.name())?; + } + writeln!(f)?; + for row_idx in 0..this.num_rows { + write!(f, "{}", row_idx)?; + for col_idx in 0..this.columns.len() { + write!(f, ",")?; + if let Some(ref v) = this.witness[col_idx][row_idx] { + write!(f, "{}", v)?; + } + } + writeln!(f)?; + } + + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct ColumnWitness { + pub name: String, + pub aliases: Vec, + pub phase: usize, +} + +impl ColumnWitness { + pub fn new(name: String, phase: usize) -> Self { + Self { + name, + aliases: Vec::new(), + phase, + } + } + pub fn name(&self) -> &String { + self.aliases.get(0).unwrap_or(&self.name) + } +} + +#[derive(Debug, Clone)] +pub struct ColumnFixed { + pub name: String, + pub aliases: Vec, +} + +impl ColumnFixed { + pub fn new(name: String) -> Self { + Self { + name, + aliases: Vec::new(), + } + } + pub fn name(&self) -> &String { + self.aliases.get(0).unwrap_or(&self.name) + } +} + +#[derive(Debug, Clone)] +pub struct ColumnPublic { + pub name: String, + pub aliases: Vec, +} + +impl ColumnPublic { + pub fn new(name: String) -> Self { + Self { + name, + aliases: Vec::new(), + } + } + pub fn name(&self) -> &String { + self.aliases.get(0).unwrap_or(&self.name) + } +} + +#[derive(Debug, Clone)] +pub struct Challenge { + pub name: String, + pub alias: Option, + pub phase: usize, +} + +impl Challenge { + fn new(name: String, phase: usize) -> Self { + Self { + name, + alias: None, + phase, + } + } + fn name(&self) -> &String { + self.alias.as_ref().unwrap_or(&self.name) + } +} + +#[derive(Debug, Default, Clone)] +pub struct Columns { + /// List of witness columns. These are called "advice" in halo2. + pub witness: Vec, + /// List of fixed columns. + pub fixed: Vec, + /// List of public columns. These are called "instance" in halo2. + pub public: Vec, +} + +/// Polynomial identity constraint +#[derive(Debug, Clone)] +pub struct Poly { + pub name: String, + // pub query_names: HashMap, + pub exp: Expr, +} + +/// Lookup constraint +#[derive(Debug, Clone)] +pub struct Lookup { + pub name: String, + pub exps: (Vec>, Vec>), +} + +/// Shuffle constraint +#[derive(Debug, Clone)] +pub struct Shuffle { + pub name: String, + pub exps: (Vec>, Vec>), +} + +/// Copy Constraint +#[derive(Debug, Clone)] +pub struct CopyC { + pub columns: (expr::Column, expr::Column), + pub offsets: Vec<(usize, usize)>, +} + +/// Circuit general information +#[derive(Debug, Default, Clone)] +pub struct Info { + /// Field modulus / Size of the field + pub p: BigUint, + /// Number of rows. This is always a power of 2 in halo2. + pub num_rows: usize, + /// List of challenges used. The challenge API is a proving system extension applied to pse's + /// fork of halo2: https://github.com/privacy-scaling-explorations/halo2/pull/97 + pub challenges: Vec, +} + +#[derive(Debug, Default, Clone)] +pub struct Metadata { + pub query_names: Vec<(Expr, HashMap)>, +} + +/// Plonkish Arithmetization Format +#[derive(Debug, Default, Clone)] +pub struct Plaf { + /// Circuit general information + pub info: Info, + /// Column information + pub columns: Columns, + /// List of polynomial identity constraints + pub polys: Vec, + /// Matadata + pub metadata: Metadata, + /// List of lookup constraints + pub lookups: Vec, + /// List of shuffle constraints + pub shuffles: Vec, + /// List of copy constraints + pub copys: Vec, + /// Assignment values to the fixed columns. None is used for non-assigned values, which means + /// a 0 value. + pub fixed: Vec>>, +} + +pub struct VarDisplay<'a> { + pub v: &'a Var, + pub plaf: &'a Plaf, +} + +impl Display for VarDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use Var::*; + match self.v { + Query(ColumnQuery { column, rotation }) => { + self.plaf.fmt_column(f, column)?; + if *rotation != 0 { + write!(f, "[{}]", rotation)?; + } + } + Challenge { index, phase: _ } => { + write!(f, "{}", self.plaf.info.challenges[*index].name())? + } + } + Ok(()) + } +} + +#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Cell { + pub column: Column, + pub offset: usize, +} + +impl expr::Var for Cell {} + +impl Display for Cell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use ColumnKind::*; + write!( + f, + "{}{:02}", + match self.column.kind { + Witness => "w", + Public => "p", + Fixed => "f", + }, + self.column.index + )?; + write!(f, "[{}]", self.offset) + } +} + +impl Debug for Cell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self) + } +} + +pub struct CellDisplay<'a> { + pub c: &'a Cell, + pub plaf: &'a Plaf, +} + +impl Display for CellDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.plaf.fmt_column(f, &self.c.column)?; + write!(f, "[{}]", self.c.offset)?; + Ok(()) + } +} + +impl Plaf { + pub fn fmt_column(&self, f: &mut W, c: &expr::Column) -> fmt::Result { + use ColumnKind::*; + write!( + f, + "{}", + match c.kind { + Witness => self.columns.witness[c.index].name(), + Public => self.columns.public[c.index].name(), + Fixed => self.columns.fixed[c.index].name(), + } + ) + } + pub fn fmt_var(&self, f: &mut W, v: &Var) -> fmt::Result { + match v { + Var::Query(ColumnQuery { column, rotation }) => { + self.fmt_column(f, column)?; + if *rotation != 0 { + write!(f, "[{}]", rotation)?; + } + Ok(()) + } + Var::Challenge { index, phase: _ } => { + write!(f, "{}", self.info.challenges[*index].name()) + } + } + } + pub fn set_challenge_alias(&mut self, index: usize, name: String) -> bool { + if let Some(challenge) = self.info.challenges.get_mut(index) { + challenge.alias = Some(name); + true + } else { + false + } + } + + /// Simplify expressions in polynomial constraints, shuffles and lookups. + pub fn simplify(&mut self) { + let p = &self.info.p; + // Polynomial Expressions + for poly in self.polys.iter_mut() { + poly.exp.simplify(p); + } + // Lookups + for lookup in self.lookups.iter_mut() { + for (lhs, rhs) in lookup.exps.0.iter_mut().zip(lookup.exps.1.iter_mut()) { + lhs.simplify(p); + rhs.simplify(p); + } + } + // Shuffles + for lookup in self.shuffles.iter_mut() { + for (lhs, rhs) in lookup.exps.0.iter_mut().zip(lookup.exps.1.iter_mut()) { + lhs.simplify(p); + rhs.simplify(p); + } + } + } + + pub fn alias_map(&self) -> AliasMap { + let mut map = HashMap::new(); + for (index, challenge) in self.info.challenges.iter().enumerate() { + let var = Var::Challenge { + index, + phase: challenge.phase, + }; + map.insert(challenge.name.clone(), var.clone()); + if let Some(alias) = &challenge.alias { + map.insert(alias.clone(), var.clone()); + } + } + for (index, column) in self.columns.witness.iter().enumerate() { + let var = Var::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Witness, + index, + }, + rotation: 0, + }); + map.insert(column.name.clone(), var.clone()); + for alias in &column.aliases { + map.insert(alias.clone(), var.clone()); + } + } + for (index, column) in self.columns.fixed.iter().enumerate() { + let var = Var::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Fixed, + index, + }, + rotation: 0, + }); + map.insert(column.name.clone(), var.clone()); + for alias in &column.aliases { + map.insert(alias.clone(), var.clone()); + } + } + for (index, column) in self.columns.public.iter().enumerate() { + let var = Var::Query(ColumnQuery { + column: Column { + kind: ColumnKind::Public, + index, + }, + rotation: 0, + }); + map.insert(column.name.clone(), var.clone()); + for alias in &column.aliases { + map.insert(alias.clone(), var.clone()); + } + } + AliasMap(map) + } + + pub fn gen_empty_witness(&self) -> Witness { + let mut witness = Vec::with_capacity(self.columns.witness.len()); + for _i in 0..self.columns.witness.len() { + witness.push(vec![None; self.info.num_rows]); + } + Witness { + num_rows: self.info.num_rows, + columns: self.columns.witness.clone(), + witness, + } + } + + pub fn eval_partial(&self, e: &Expr, eval_var: &F, offset: usize) -> Expr + where + V: expr::Var, + F: Fn(&V, usize) -> Expr, + { + use Expr::*; + match e { + Neg(e) => Neg(Box::new(self.eval_partial(e, eval_var, offset))), + Const(f) => Const(f.clone()), + Var(v) => eval_var(v, offset), + Sum(es) => Sum(es + .iter() + .map(|e| self.eval_partial(e, eval_var, offset)) + .collect()), + Mul(es) => Mul(es + .iter() + .map(|e| self.eval_partial(e, eval_var, offset)) + .collect()), + Pow(e, f) => Pow(Box::new(self.eval_partial(e, eval_var, offset)), *f), + } + } + + pub fn resolve(&self, e: &Expr, offset: usize) -> Expr { + self.eval_partial( + e, + &|v: &Var, offset: usize| -> Expr { + match v { + expr::PlonkVar::Query(ColumnQuery { column, rotation }) => { + let offset = (offset as i32 + rotation) + .rem_euclid(self.info.num_rows as i32) + as usize; + match column.kind { + ColumnKind::Fixed => Expr::Const( + self.fixed[column.index][offset] + .clone() + .unwrap_or_else(BigUint::zero), + ), + _ => Expr::Var(Cell { + column: *column, + offset, + }), + } + } + expr::PlonkVar::Challenge { index: _, phase: _ } => { + // TODO: Figure out something better :P + Expr::Const(BigUint::from(1234u64)) + } + } + }, + offset, + ) + } + + pub fn _eval_partial(&self, e: &Expr, witness: &Witness, offset: usize) -> Expr { + use Expr::*; + match e { + Neg(e) => Neg(Box::new(self._eval_partial(e, witness, offset))), + Const(f) => Const(f.clone()), + Var(v) => { + let Cell { column, offset } = v; + match column.kind { + ColumnKind::Witness => { + if let Some(f) = &witness.witness[column.index][*offset] { + Const(f.clone()) + } else { + e.clone() + } + } + _ => e.clone(), + } + } + Sum(es) => Sum(es + .iter() + .map(|e| self._eval_partial(e, witness, offset)) + .collect()), + Mul(es) => Mul(es + .iter() + .map(|e| self._eval_partial(e, witness, offset)) + .collect()), + Pow(e, f) => Pow(Box::new(self._eval_partial(e, witness, offset)), *f), + } + } +} + +pub struct AliasMap(pub HashMap); + +/// Adaptor struct to format the fixed columns assignments as CSV +pub struct PlafDisplayFixedCSV<'a>(pub &'a Plaf); + +impl Display for PlafDisplayFixedCSV<'_> { + /// Format fixed columns assignments as CSV + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let this = self.0; + write!(f, "offset")?; + for col in this.columns.fixed.iter() { + write!(f, ",")?; + write!(f, "{}", col.name())?; + } + writeln!(f)?; + for row_idx in 0..this.info.num_rows { + write!(f, "{}", row_idx)?; + for col_idx in 0..this.columns.fixed.len() { + write!(f, ",")?; + if let Some(ref v) = this.fixed[col_idx][row_idx] { + write!(f, "{}", v)?; + } + } + writeln!(f)?; + } + Ok(()) + } +} + +/// Adaptor struct to format the entire Plaf as toml except for the Fixed Column assignments +pub struct PlafDisplayBaseTOML<'a>(pub &'a Plaf); + +impl Display for PlafDisplayBaseTOML<'_> { + /// Format entire Plaf as toml except for Fixed Columns assignments + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let this = self.0; + writeln!(f, "[info]")?; + writeln!(f, "num_rows = {}", this.info.num_rows)?; + writeln!(f, "p = {}", this.info.p)?; + writeln!(f)?; + + writeln!(f, "[info.challenges]")?; + for ch in &this.info.challenges { + write!(f, "{} = {{ phase = {}", ch.name, ch.phase)?; + if let Some(alias) = &ch.alias { + writeln!(f, ", alias = \"{}\" }}", alias)?; + } else { + writeln!(f, "}}")?; + } + } + writeln!(f)?; + + writeln!(f, "[columns.public]")?; + for c in &this.columns.public { + writeln!(f, "{} = {{ aliases = {:?} }}", c.name, c.aliases)?; + } + writeln!(f)?; + + writeln!(f, "[columns.fixed]")?; + for c in &this.columns.fixed { + writeln!(f, "{} = {{ aliases = {:?} }}", c.name, c.aliases)?; + } + writeln!(f)?; + + writeln!(f, "[columns.witness]")?; + for c in &this.columns.witness { + writeln!( + f, + "{} = {{ phase = {}, aliases = {:?} }}", + c.name, c.phase, c.aliases + )?; + } + writeln!(f)?; + + for p in &this.polys { + writeln!(f, "[constraints.polys.\"{}\"]", p.name)?; + write!(f, "c = \"")?; + p.exp + .fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| { + this.fmt_var(f, v) + })?; + writeln!(f, "\"")?; + } + writeln!(f)?; + + for l in &this.lookups { + writeln!(f, "[constraints.lookups.\"{}\"]", l.name)?; + writeln!(f, "l = [")?; + for (lhs, rhs) in l.exps.0.iter().zip(l.exps.1.iter()) { + write!(f, " [\"")?; + lhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| { + this.fmt_var(f, v) + })?; + writeln!(f, "\",")?; + write!(f, " \"")?; + rhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| { + this.fmt_var(f, v) + })?; + writeln!(f, "\"],")?; + } + writeln!(f, "]")?; + } + writeln!(f)?; + + for l in &this.shuffles { + writeln!(f, "[constraints.shuffles.\"{}\"]", l.name)?; + writeln!(f, "l = [")?; + for (lhs, rhs) in l.exps.0.iter().zip(l.exps.1.iter()) { + write!(f, " [\"")?; + lhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| { + this.fmt_var(f, v) + })?; + writeln!(f, "\",")?; + write!(f, " \"")?; + rhs.fmt_ascii(f, &mut |f: &mut fmt::Formatter<'_>, v: &Var| { + this.fmt_var(f, v) + })?; + writeln!(f, "\"],")?; + } + writeln!(f, "]")?; + } + writeln!(f)?; + + for c in &this.copys { + writeln!(f, "[[constraints.copys]]")?; + write!(f, "columns = [\"")?; + this.fmt_column(f, &c.columns.0)?; + write!(f, "\", \"")?; + this.fmt_column(f, &c.columns.1)?; + writeln!(f, "\"]")?; + writeln!(f, "offsets = [")?; + for (a, b) in &c.offsets { + writeln!(f, " [{}, {}],", a, b)?; + } + writeln!(f, "]")?; + } + writeln!(f)?; + + Ok(()) + } +} diff --git a/tools/polyexen/deps/polyexen/src/plaf/backends/halo2.rs b/tools/polyexen/deps/polyexen/src/plaf/backends/halo2.rs new file mode 100644 index 0000000..9dedc46 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/plaf/backends/halo2.rs @@ -0,0 +1,433 @@ +use crate::{ + expr::{self, ColumnKind, ColumnQuery, Expr, PlonkVar as Var}, + plaf::{Plaf, Witness}, +}; +use halo2_proofs::{ + circuit::{Cell, Layouter, RegionIndex, SimpleFloorPlanner, Value}, + halo2curves::group::ff::{Field, PrimeField}, + plonk::{ + Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, FirstPhase, Fixed, + Instance, SecondPhase, ThirdPhase, VirtualCells, + }, + poly::Rotation, +}; +// use halo2_proofs::plonk::{Challenge as Halo2Challenge}; +use num_bigint::BigUint; +use std::{collections::HashMap, fmt::Debug}; + +/// Type that implements a halo2 circuit from a Plaf +#[derive(Debug)] +pub struct PlafH2Circuit { + pub plaf: Plaf, + pub wit: Witness, +} + +impl PlafH2Circuit { + pub fn instance>(&self) -> Vec> { + let public_len = self.plaf.columns.public.len(); + let mut instance_vec = vec![Vec::new(); public_len]; + + if public_len > 0 { + for copy in &self.plaf.copys { + let (left_col, right_col) = ©.columns; + + let (witness_col, public_col, offsets) = match (left_col.kind, right_col.kind) { + (ColumnKind::Witness, ColumnKind::Public) => { + (left_col, right_col, copy.offsets.clone()) + } + (ColumnKind::Public, ColumnKind::Witness) => ( + right_col, + left_col, + copy.offsets.iter().map(|(l, r)| (*r, *l)).collect(), + ), + (ColumnKind::Public, _) | (_, ColumnKind::Public) => { + unimplemented!("constraints between public and fixed column not supported") + } + _ => continue, + }; + + for (witness_offset, public_offset) in offsets { + if instance_vec[public_col.index].len() <= public_offset { + instance_vec[public_col.index].resize(public_offset + 1, F::ZERO); + } + instance_vec[public_col.index][public_offset] = self.wit.witness + [witness_col.index][witness_offset] + .as_ref() + .unwrap() + .to_field(); + } + } + } + instance_vec + } +} + +#[derive(Debug, Clone)] +pub struct H2Columns { + advice: Vec>, + fixed: Vec>, + instance: Vec>, + // challenges: Vec, +} + +#[derive(Debug, Clone)] +pub struct H2Config { + columns: H2Columns, +} + +struct H2Queries(HashMap<(ColumnKind, usize, i32), Expression>); + +impl H2Queries { + fn new() -> Self { + Self(HashMap::new()) + } + + fn get( + &mut self, + meta: &mut VirtualCells<'_, F>, + columns: &H2Columns, + kind: ColumnKind, + index: usize, + rotation: i32, + ) -> Expression { + let e = self + .0 + .entry((kind, index, rotation)) + .or_insert_with(|| match kind { + ColumnKind::Witness => meta.query_advice(columns.advice[index], Rotation(rotation)), + ColumnKind::Public => { + meta.query_instance(columns.instance[index], Rotation(rotation)) + } + ColumnKind::Fixed => meta.query_fixed(columns.fixed[index], Rotation(rotation)), + }); + e.clone() + } +} + +trait ToField { + fn to_field(&self) -> F; +} + +impl> ToField for BigUint { + fn to_field(&self) -> F { + let mut repr: [u8; 32] = [0; 32]; + let f_le = self.to_bytes_le(); + repr[..f_le.len()].clone_from_slice(&f_le); + F::from_repr_vartime(repr).expect("value in field") + } +} + +trait ToHalo2Expr { + fn to_halo2_expr( + &self, + meta: &mut VirtualCells<'_, F>, + columns: &H2Columns, + queries: &mut H2Queries, + ) -> Expression; +} + +impl> ToHalo2Expr for Expr { + fn to_halo2_expr( + &self, + meta: &mut VirtualCells<'_, F>, + columns: &H2Columns, + queries: &mut H2Queries, + ) -> Expression { + use Expression::*; + match self { + Expr::Const(f) => Constant(f.to_field()), + Expr::Var(v) => match v { + Var::Query(ColumnQuery { + column: expr::Column { kind, index }, + rotation, + }) => queries.get(meta, columns, *kind, *index, *rotation), + Var::Challenge { index: _, phase: _ } => { + // FIXME: Figure out a way to use challenges + // meta.query_challenge(columns.challenges[*index]) + Constant(F::from(0x100)) + } + }, + Expr::Sum(es) => { + let mut iter = es.iter(); + let first = iter.next().unwrap().to_halo2_expr(meta, columns, queries); + iter.fold(first, |acc, e| { + acc + e.to_halo2_expr(meta, columns, queries) + }) + } + Expr::Mul(es) => { + let mut iter = es.iter(); + let first = iter.next().unwrap().to_halo2_expr(meta, columns, queries); + iter.fold(first, |acc, e| { + acc * e.to_halo2_expr(meta, columns, queries) + }) + } + Expr::Neg(e) => -e.to_halo2_expr(meta, columns, queries), + Expr::Pow(e, n) => { + if *n == 0 { + Constant(F::from(1)) + } else { + let e = e.to_halo2_expr(meta, columns, queries); + (1..*n).fold(e.clone(), |acc, _| acc * e.clone()) + } + } + } + } +} + +#[allow(dead_code)] +struct _Cell { + region_index: RegionIndex, + row_offset: usize, + column: Column, +} + +assert_eq_size!(_Cell, Cell); + +fn new_cell(column: Column, offset: usize) -> Cell { + let cell = _Cell { + region_index: RegionIndex::from(0), + row_offset: offset, + column, + }; + // NOTE: We use unsafe here to construct a Cell, which doesn't have a public constructor. This + // helps us set the copy constraints easily (without having to store all assigned cells + // previously) + unsafe { std::mem::transmute::<_Cell, Cell>(cell) } +} + +impl> Circuit for PlafH2Circuit { + type Config = H2Config; + type FloorPlanner = SimpleFloorPlanner; + type Params = Plaf; + + fn without_witnesses(&self) -> Self { + Self { + plaf: self.plaf.clone(), + wit: Witness { + num_rows: self.wit.num_rows, + columns: Vec::new(), + witness: Vec::new(), + }, + } + } + + fn params(&self) -> Self::Params { + // TODO: Avoid cloning by storing Plaf in a RefCell + self.plaf.clone() + } + + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { + let plaf = ¶ms; + // Allocate columns + let mut advice_columns = Vec::new(); + for column in &plaf.columns.witness { + advice_columns.push(match column.phase { + 0 => meta.advice_column_in(FirstPhase), + 1 => meta.advice_column_in(SecondPhase), + 2 => meta.advice_column_in(ThirdPhase), + _ => panic!("Advice column at phase {} not supported", column.phase), + }); + } + let mut fixed_columns = Vec::new(); + for _column in &plaf.columns.fixed { + fixed_columns.push(meta.fixed_column()); + } + let mut instance_columns = Vec::new(); + for _column in &plaf.columns.public { + instance_columns.push(meta.instance_column()); + } + + let to_column_any = |col: &expr::Column| -> Column { + match col.kind { + ColumnKind::Witness => advice_columns[col.index].into(), + ColumnKind::Public => instance_columns[col.index].into(), + ColumnKind::Fixed => fixed_columns[col.index].into(), + } + }; + + // Enable equality for copy constrains + for copy in &plaf.copys { + meta.enable_equality(to_column_any(©.columns.0)); + meta.enable_equality(to_column_any(©.columns.1)); + } + + // let mut challenges = Vec::new(); + // for challenge in &self.plaf.info.challenges { + // challenges.push(match challenge.phase { + // 0 => meta.challenge_usable_after(FirstPhase), + // 1 => meta.challenge_usable_after(SecondPhase), + // 2 => meta.challenge_usable_after(ThirdPhase), + // p => panic!("Challenge phase {} not supported", p), + // }); + // } + let columns = H2Columns { + advice: advice_columns, + fixed: fixed_columns, + instance: instance_columns, + // challenges, + }; + + // Name columns for lookups + for (index, column) in columns.advice.iter().enumerate() { + meta.annotate_lookup_any_column(*column, || plaf.columns.witness[index].name()); + } + for (index, column) in columns.fixed.iter().enumerate() { + meta.annotate_lookup_any_column(*column, || plaf.columns.fixed[index].name()); + } + + // Set polynomial constraints + meta.create_gate("main", |meta| { + let mut queries = H2Queries::new(); + let mut constraints: Vec<(&'static str, Expression)> = Vec::new(); + for poly in &plaf.polys { + constraints.push(( + Box::leak(poly.name.clone().into_boxed_str()), + poly.exp.to_halo2_expr(meta, &columns, &mut queries), + )); + } + constraints + }); + + // Set lookups + for lookup in &plaf.lookups { + meta.lookup_any(Box::leak(lookup.name.clone().into_boxed_str()), |meta| { + let mut queries = H2Queries::new(); + let mut map = Vec::new(); + for (lhs, rhs) in lookup.exps.0.iter().zip(lookup.exps.1.iter()) { + map.push(( + lhs.to_halo2_expr(meta, &columns, &mut queries), + rhs.to_halo2_expr(meta, &columns, &mut queries), + )); + } + map + }); + } + + // Set shuffles + for shuffle in &plaf.shuffles { + meta.shuffle(Box::leak(shuffle.name.clone().into_boxed_str()), |meta| { + let mut queries = H2Queries::new(); + let mut map = Vec::new(); + for (lhs, rhs) in shuffle.exps.0.iter().zip(shuffle.exps.1.iter()) { + map.push(( + lhs.to_halo2_expr(meta, &columns, &mut queries), + rhs.to_halo2_expr(meta, &columns, &mut queries), + )); + } + map + }); + } + + Self::Config { columns } + } + + fn configure(_meta: &mut ConstraintSystem) -> Self::Config { + unreachable!(); + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "main", + |mut region| { + // Name columns + for (index, column) in config.columns.advice.iter().enumerate() { + region.name_column(|| self.plaf.columns.witness[index].name(), *column); + } + for (index, column) in config.columns.fixed.iter().enumerate() { + region.name_column(|| self.plaf.columns.fixed[index].name(), *column); + } + for (index, column) in config.columns.instance.iter().enumerate() { + region.name_column(|| self.plaf.columns.public[index].name(), *column); + } + + // Assign fixed columns + for (index, column) in self.plaf.fixed.iter().enumerate() { + for (row, value) in column.iter().enumerate() { + if let Some(value) = value { + region.assign_fixed::<_, F, _, _>( + || "", + config.columns.fixed[index], + row, + || Value::known(value.to_field()), + )?; + } + } + } + let to_column_any = |col: &expr::Column| -> Column { + match col.kind { + ColumnKind::Witness => config.columns.advice[col.index].into(), + ColumnKind::Public => config.columns.instance[col.index].into(), + ColumnKind::Fixed => config.columns.fixed[col.index].into(), + } + }; + // Set copy constraints + for copy in &self.plaf.copys { + let (left_col, right_col) = ©.columns; + + if left_col.kind == ColumnKind::Public || right_col.kind == ColumnKind::Public { + continue; + } + let left_col = to_column_any(left_col); + let right_col = to_column_any(right_col); + for (left_offset, right_offset) in ©.offsets { + region.constrain_equal( + new_cell(left_col, *left_offset), + new_cell(right_col, *right_offset), + )?; + } + } + // Assign advice columns + for (index, column) in self.wit.witness.iter().enumerate() { + for (row, value) in column.iter().enumerate() { + if let Some(value) = value { + region.assign_advice::<_, F, _, _>( + || "", + config.columns.advice[index], + row, + || Value::known(value.to_field()), + )?; + } + } + } + Ok(()) + }, + )?; + + // Set public inputs + for copy in &self.plaf.copys { + let (left_col, right_col) = ©.columns; + + let (witness_col, public_col, offsets) = match (left_col.kind, right_col.kind) { + (ColumnKind::Witness, ColumnKind::Public) => { + (left_col, right_col, copy.offsets.clone()) + } + (ColumnKind::Public, ColumnKind::Witness) => ( + right_col, + left_col, + copy.offsets.iter().map(|(l, r)| (*r, *l)).collect(), + ), + (ColumnKind::Public, ColumnKind::Public) => { + panic!("Cannot copy from public to public") + } + _ => continue, + }; + for (witness_offset, public_offset) in offsets { + let cell = new_cell( + (*config.columns.advice.get(witness_col.index).unwrap()).into(), + witness_offset, + ); + + layouter.constrain_instance( + cell, + *config.columns.instance.get(public_col.index).unwrap(), + public_offset, + )?; + } + } + Ok(()) + } +} diff --git a/tools/polyexen/deps/polyexen/src/plaf/backends/mod.rs b/tools/polyexen/deps/polyexen/src/plaf/backends/mod.rs new file mode 100644 index 0000000..edf7922 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/plaf/backends/mod.rs @@ -0,0 +1 @@ +pub mod halo2; diff --git a/tools/polyexen/deps/polyexen/src/plaf/frontends/halo2.rs b/tools/polyexen/deps/polyexen/src/plaf/frontends/halo2.rs new file mode 100644 index 0000000..e85f2d4 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/plaf/frontends/halo2.rs @@ -0,0 +1,789 @@ +use crate::{ + expr::{self, get_field_p, ColumnKind, ColumnQuery, Expr, PlonkVar as Var}, + plaf::{ + CellValue, Challenge, ColumnFixed, ColumnPublic, ColumnWitness, CopyC, Lookup, Plaf, Poly, + Shuffle, Witness, + }, +}; +use halo2_proofs::{ + circuit::Value, + halo2curves::group::ff::{Field, PrimeField}, + plonk::{ + Advice, Any, Assigned, Assignment, Challenge as Halo2Challenge, Circuit, Column, + ConstraintSystem, Error, Expression, Fixed, FixedQuery, FloorPlanner, Instance, Selector, + }, + poly::Rotation, +}; +use num_bigint::BigUint; +use num_traits::One; +use std::{collections::HashMap, fmt::Debug, ops::Range}; + +#[derive(Debug)] +struct WitnessAssembly { + // k: u32, + // The instance cells in the circuit, arranged as [column][row]. + instance: Vec>, + // The advice cells in the circuit, arranged as [column][row]. + advice: Vec>>, + // A range of available rows for assignment and copies. + usable_rows: Range, + challenges: Vec, + // region: Option<(String, HashMap, String>)>, + // regions: HashMap, String>>, +} + +impl Assignment for WitnessAssembly { + fn enter_region(&mut self, _name: N) + where + NR: Into, + N: FnOnce() -> NR, + { + // self.region = Some((name().into(), HashMap::new())); + } + + fn exit_region(&mut self) { + // let (name, annotations) = self.region.take().unwrap(); + // self.regions.insert(name, annotations); + } + + fn enable_selector( + &mut self, + _: A, + _selector: &Selector, + _row: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + Ok(()) + } + + fn query_instance(&self, column: Column, row: usize) -> Result, Error> { + assert!( + self.usable_rows.contains(&row), + "row={}, usable_rows={:?}", + row, + self.usable_rows + ); + + self.instance + .get(column.index()) + .and_then(|column| column.get(row)) + .map(|v| Value::known(*v)) + .ok_or(Error::BoundsFailure) + } + + fn assign_advice( + &mut self, + _: A, + column: Column, + row: usize, + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into, + { + assert!( + self.usable_rows.contains(&row), + "row={}, usable_rows={:?}", + row, + self.usable_rows + ); + let cell = self + .advice + .get_mut(column.index()) + .and_then(|v| v.get_mut(row)) + .ok_or(Error::BoundsFailure)?; + + let mut known = false; + to().into_field().evaluate().map(|f| { + known = true; + *cell = CellValue::Assigned(f); + }); + if !known { + return Err(Error::Synthesis); + } + + Ok(()) + } + + fn assign_fixed( + &mut self, + _: A, + _column: Column, + _row: usize, + _to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into, + { + Ok(()) + } + + fn copy( + &mut self, + _left_column: Column, + _left_row: usize, + _right_column: Column, + _right_row: usize, + ) -> Result<(), Error> { + Ok(()) + } + + fn fill_from_row( + &mut self, + _col: Column, + _from_row: usize, + _to: Value>, + ) -> Result<(), Error> { + Ok(()) + } + + fn get_challenge(&self, challenge: Halo2Challenge) -> Value { + Value::known(self.challenges[challenge.index()]) + } + + fn push_namespace(&mut self, _: N) + where + NR: Into, + N: FnOnce() -> NR, + { + // TODO: Do something with namespaces :) + } + + fn pop_namespace(&mut self, _: Option) { + // TODO: Do something with namespaces :) + } + + fn annotate_column(&mut self, _annotation: A, _column: Column) + where + A: FnOnce() -> AR, + AR: Into, + { + } +} + +/// Assembly to be used in circuit synthesis. +#[derive(Debug)] +struct Assembly { + // k: u32, + fixed: Vec>>, + // permutation: permutation::keygen::Assembly, + copies: HashMap<(Column, Column), Vec<(usize, usize)>>, + selectors: Vec>, + // A range of available rows for assignment and copies. + usable_rows: Range, + _marker: std::marker::PhantomData, + region: Option<(String, HashMap, String>)>, + regions: HashMap, String>>, +} + +impl Assignment for Assembly { + fn enter_region(&mut self, name: N) + where + NR: Into, + N: FnOnce() -> NR, + { + self.region = Some((name().into(), HashMap::new())); + } + + fn exit_region(&mut self) { + let (name, annotations) = self.region.take().expect("exit from a region"); + self.regions.insert(name, annotations); + } + + fn enable_selector(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + assert!( + self.usable_rows.contains(&row), + "row={} not in usable_rows={:?}", + row, + self.usable_rows + ); + + self.selectors[selector.index()][row] = true; + + Ok(()) + } + + fn query_instance(&self, _: Column, row: usize) -> Result, Error> { + assert!( + self.usable_rows.contains(&row), + "row={}, usable_rows={:?}", + row, + self.usable_rows + ); + + // There is no instance in this context. + Ok(Value::unknown()) + } + + fn assign_advice( + &mut self, + _: A, + _: Column, + _: usize, + _: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into, + { + // We only care about fixed columns here + Ok(()) + } + + fn assign_fixed( + &mut self, + _: A, + column: Column, + row: usize, + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into, + { + assert!( + self.usable_rows.contains(&row), + "row={}, usable_rows={:?}", + row, + self.usable_rows + ); + + let cell = self + .fixed + .get_mut(column.index()) + .and_then(|v| v.get_mut(row)) + .ok_or(Error::BoundsFailure)?; + + let mut known = false; + to().into_field().evaluate().map(|f| { + known = true; + *cell = CellValue::Assigned(f); + }); + if !known { + return Err(Error::Synthesis); + } + + Ok(()) + } + + fn copy( + &mut self, + left_column: Column, + left_row: usize, + right_column: Column, + right_row: usize, + ) -> Result<(), Error> { + assert!( + self.usable_rows.contains(&left_row) && self.usable_rows.contains(&right_row), + "left_row={}, right_row={}, usable_rows={:?}", + left_row, + right_row, + self.usable_rows + ); + + // TODO: Sort columns + let columns = self + .copies + .entry((left_column.clone(), right_column.clone())) + .or_insert_with(|| Vec::new()); + columns.push((left_row, right_row)); + Ok(()) + } + + fn fill_from_row( + &mut self, + column: Column, + from_row: usize, + to: Value>, + ) -> Result<(), Error> { + assert!( + self.usable_rows.contains(&from_row), + "row={}, usable_rows={:?}", + from_row, + self.usable_rows + ); + + for row in self.usable_rows.clone().skip(from_row) { + self.assign_fixed(|| "", column, row, || to)?; + } + + Ok(()) + } + + fn get_challenge(&self, _: Halo2Challenge) -> Value { + Value::unknown() + } + + fn push_namespace(&mut self, _: N) + where + NR: Into, + N: FnOnce() -> NR, + { + // Do nothing; we don't care about namespaces in this context. + } + + fn pop_namespace(&mut self, _: Option) { + // Do nothing; we don't care about namespaces in this context. + } + + fn annotate_column(&mut self, annotation: A, column: Column) + where + A: FnOnce() -> AR, + AR: Into, + { + let (_, ref mut annotations) = self.region.as_mut().expect("annotate in a region"); + annotations.insert(column, annotation().into()); + } +} + +pub fn gen_witness, ConcreteCircuit: Circuit>( + k: u32, + circuit: &ConcreteCircuit, + plaf: &Plaf, + challenges: Vec, + instance: Vec>, +) -> Result { + let n = 1 << k; + + let mut cs = ConstraintSystem::default(); + let config = ConcreteCircuit::configure_with_params(&mut cs, circuit.params()); + + let instance = instance + .into_iter() + .map(|mut instance| { + if instance.len() > n - (cs.blinding_factors() + 1) { + return Err(Error::InstanceTooLarge); + } + + instance.resize(n, F::ZERO); + Ok(instance) + }) + .collect::, _>>()?; + + let advice = vec![vec![CellValue::Unassigned; n]; cs.num_advice_columns()]; + + let mut assembly: WitnessAssembly = WitnessAssembly { + // k, + instance, + advice, + usable_rows: 0..n as usize - (cs.blinding_factors() + 1), + challenges, + // region: None, + // regions: HashMap::new(), + }; + + ConcreteCircuit::FloorPlanner::synthesize( + &mut assembly, + circuit, + config, + cs.constants().clone(), + )?; + + let mut witness = plaf.gen_empty_witness(); + + for i in 0..plaf.columns.witness.len() { + let column = &mut witness.witness[i]; + for (j, cell) in assembly.advice[i].iter().enumerate() { + if let CellValue::Assigned(v) = cell { + column[j] = Some(BigUint::from_bytes_le(&v.to_repr()[..])); + } + } + } + + Ok(witness) +} + +pub fn expression_to_var(e: &Expression) -> Option { + use Var::*; + match e { + Expression::Fixed(q) => Some(Query(ColumnQuery { + column: expr::Column { + kind: ColumnKind::Fixed, + index: q.column_index(), + }, + rotation: q.rotation().0, + })), + Expression::Advice(q) => Some(Query(ColumnQuery { + column: expr::Column { + kind: ColumnKind::Witness, + index: q.column_index(), + }, + rotation: q.rotation().0, + })), + Expression::Instance(q) => Some(Query(ColumnQuery { + column: expr::Column { + kind: ColumnKind::Public, + index: q.column_index(), + }, + rotation: q.rotation().0, + })), + Expression::Challenge(c) => Some(Challenge { + index: c.index(), + phase: c.phase() as usize, + }), + _ => None, + } +} + +#[allow(dead_code)] +fn convert_query_names( + map: &HashMap, String>, +) -> HashMap { + let mut new_map = HashMap::new(); + use Var::*; + for (e, name) in map.iter() { + if let Some(v) = expression_to_var(e) { + if let Query(q) = v { + new_map.insert(q, name.clone()); + } + } + } + new_map +} + +#[derive(Copy, Clone, Debug)] +pub struct _FixedQuery { + /// Query index + pub index: Option, + /// Column index + pub column_index: usize, + /// Rotation of this query + pub rotation: Rotation, +} + +assert_eq_size!(_FixedQuery, FixedQuery); + +fn new_fixed_query(index: Option, column_index: usize, rotation: Rotation) -> FixedQuery { + let fixed_query = _FixedQuery { + index, + column_index, + rotation, + }; + unsafe { std::mem::transmute::<_FixedQuery, FixedQuery>(fixed_query) } +} + +fn replace_selectors_no_compress(expr: &mut Expression, fixed_offset: usize) { + *expr = expr.evaluate( + &|constant| Expression::Constant(constant), + &|selector| { + Expression::Fixed(new_fixed_query( + None, + fixed_offset + selector.index(), + Rotation(0), + )) + }, + &|query| Expression::Fixed(query), + &|query| Expression::Advice(query), + &|query| Expression::Instance(query), + &|challenge| Expression::Challenge(challenge), + &|a| -a, + &|a, b| a + b, + &|a, b| a * b, + &|a, f| a * f, + ); +} + +pub fn get_plaf, ConcreteCircuit: Circuit>( + k: u32, + circuit: &ConcreteCircuit, +) -> Result { + let compress_selectors = true; + let n = 1 << k; + + let mut cs = ConstraintSystem::default(); + let config = ConcreteCircuit::configure_with_params(&mut cs, circuit.params()); + + // let degree = cs.degree(); + + assert!( + n >= cs.minimum_rows(), + "n={}, minimum_rows={}", + n, + cs.minimum_rows() + ); + + let mut assembly: Assembly = Assembly { + // k, + fixed: vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns()], + copies: HashMap::new(), + selectors: vec![vec![false; n as usize]; cs.num_selectors()], + usable_rows: 0..n as usize - (cs.blinding_factors() + 1), + _marker: std::marker::PhantomData, + region: None, + regions: HashMap::new(), + }; + + ConcreteCircuit::FloorPlanner::synthesize( + &mut assembly, + circuit, + config, + cs.constants().clone(), + )?; + + // Number of fixed columns before converting selectors into fixed columns + let num_fixed_columns_orig = cs.num_fixed_columns(); + let cs = if compress_selectors { + let (cs, selector_polys) = cs.compress_selectors(assembly.selectors.clone()); + // TODO: Turn selectors in query_names into new selector expressions from fixed columns + assembly + .fixed + .extend(selector_polys.into_iter().map(|poly| { + let mut v = vec![CellValue::Unassigned; n]; + for (v, p) in v.iter_mut().zip(&poly[..]) { + *v = CellValue::Assigned(*p); + } + v + })); + cs + } else { + cs + // Substitute selectors for the real fixed columns in all gates + // for expr in cs + // .gates_mut() + // .iter_mut() + // .flat_map(|gate| gate.polynomials_mut().iter_mut()) + // { + // replace_selectors_no_compress(expr, num_fixed_columns_orig); + // } + // Substitute non-simple selectors for the real fixed columns in all + // lookup expressions + //for expr in cs.lookups_mut().iter_mut().flat_map(|lookup| { + // lookup + // .input_expressions + // .iter_mut() + // .chain(lookup.table_expressions.iter_mut()) + //}) { + // replace_selectors_no_compress(expr, num_fixed_columns_orig); + //} + // Substitute selectors for the real fixed columns in all query_name expressions + // TODO: + // for (sel_expr, _map) in cs.query_names_mut().iter_mut() { + // replace_selectors_no_compress(sel_expr, num_fixed_columns_orig); + // } + // cs.num_fixed_columns += cs.num_selectors(); + + // assembly.fixed.extend(assembly.selectors.iter().map(|col| { + // let mut v = vec![CellValue::Unassigned; n]; + // for (v, p) in v.iter_mut().zip(&col[..]) { + // *v = CellValue::Assigned(if *p { F::ONE } else { F::ZERO }); + // } + // v + // })); + // cs + }; + + let mut plaf = Plaf::default(); + let p = get_field_p::(); + plaf.info.p = p; + + plaf.info.num_rows = 2usize.pow(k); + let challenge_phase = cs.challenge_phase(); + for i in 0..cs.num_challenges() { + let phase = challenge_phase[i]; + plaf.info + .challenges + .push(Challenge::new(format!("ch{}_{}", i, phase), phase as usize)); + } + + for i in 0..cs.num_fixed_columns() { + let name = if i < num_fixed_columns_orig { + format!("f{:02}", i) + } else { + // This should only happen when `compress_selectors = true`, otherwise + // `num_fixed_columns_orig == cs.num_fixed_columns()` + format!("s{:02}", i - num_fixed_columns_orig) + }; + plaf.columns.fixed.push(ColumnFixed::new(name)); + } + // If `compress_selectors = true`, then there should be 0 selectors in `cs`. + for i in 0..cs.num_selectors() { + let name = format!("s{:02}", i); + plaf.columns.fixed.push(ColumnFixed::new(name)); + } + for i in 0..cs.num_instance_columns() { + plaf.columns + .public + .push(ColumnPublic::new(format!("i{:02}", i))); + } + let column_phase = cs.advice_column_phase(); + for i in 0..cs.num_advice_columns() { + plaf.columns.witness.push(ColumnWitness::new( + format!("w{:02}", i), + column_phase[i] as usize, + )); + } + for (column, name) in cs.general_column_annotations().iter() { + match column.column_type() { + Any::Advice(_) => plaf.columns.witness[column.index()] + .aliases + .push(name.clone()), + Any::Fixed => plaf.columns.fixed[column.index()] + .aliases + .push(name.clone()), + Any::Instance => plaf.columns.public[column.index()] + .aliases + .push(name.clone()), + } + } + + for (_region_name, region) in assembly.regions { + for (column, name) in region.iter() { + let name = name.clone(); + match column.column_type() { + Any::Advice(..) => plaf.columns.witness[column.index()].aliases.push(name), + Any::Fixed => plaf.columns.fixed[column.index()].aliases.push(name), + Any::Instance => plaf.columns.public[column.index()].aliases.push(name), + } + } + } + + for gate in cs.gates() { + let name = gate.name(); + let len_log10 = (gate.polynomials().len() as f64).log10().ceil() as usize; + for (i, poly) in gate.polynomials().iter().enumerate() { + let exp = if !compress_selectors { + // Substitute selectors for the real fixed columns in all gates + let mut poly = poly.clone(); + replace_selectors_no_compress(&mut poly, num_fixed_columns_orig); + Expr::::from(&poly) + } else { + Expr::::from(poly) + }; + // let exp = exp.simplify(&p); + if matches!(exp, Expr::Const(_)) { + // Skip constant expressions (which should be `p(x) = 0`) + continue; + } + plaf.polys.push(Poly { + name: format!( + "{} {:0decimals$} -> {n}", + name, + i, + decimals = len_log10, + n = gate.constraint_name(i) + ), + // query_names: query_names.clone(), + exp, + }); + } + } + // TODO: Add support for query_names in halo2 + // plaf.metadata.query_names = cs + // .query_names() + // .iter() + // .map(|(selector, map)| (Expr::::from(selector), convert_query_names(map))) + // .collect(); + + for lookup in cs.lookups() { + let name = lookup.name(); + let lhs = lookup.input_expressions(); + let rhs = lookup.table_expressions(); + let (lhs, rhs) = if !compress_selectors { + // Substitute non-simple selectors for the real fixed columns in all + // lookup expressions + let (mut lhs, mut rhs) = (lhs.clone(), rhs.clone()); + lhs.iter_mut() + .chain(rhs.iter_mut()) + .for_each(|ref mut exp| replace_selectors_no_compress(exp, num_fixed_columns_orig)); + ( + lhs.iter().map(|e| Expr::::from(e)).collect(), + rhs.iter().map(|e| Expr::::from(e)).collect(), + ) + } else { + ( + lhs.iter().map(|e| Expr::::from(e)).collect(), + rhs.iter().map(|e| Expr::::from(e)).collect(), + ) + }; + plaf.lookups.push(Lookup { + name: name.to_string(), + exps: (lhs, rhs), + }) + } + + for shuffle in cs.shuffles() { + let name = shuffle.name(); + let lhs = shuffle.input_expressions(); + let rhs = shuffle.shuffle_expressions(); + let (lhs, rhs) = if !compress_selectors { + // Substitute non-simple selectors for the real fixed columns in all + // shuffle expressions + let (mut lhs, mut rhs) = (lhs.clone(), rhs.clone()); + lhs.iter_mut() + .chain(rhs.iter_mut()) + .for_each(|ref mut exp| replace_selectors_no_compress(exp, num_fixed_columns_orig)); + ( + lhs.iter().map(|e| Expr::::from(e)).collect(), + rhs.iter().map(|e| Expr::::from(e)).collect(), + ) + } else { + ( + lhs.iter().map(|e| Expr::::from(e)).collect(), + rhs.iter().map(|e| Expr::::from(e)).collect(), + ) + }; + plaf.shuffles.push(Shuffle { + name: name.to_string(), + exps: (lhs, rhs), + }) + } + + let column_any_to_kind = |ct: &Any| match ct { + Any::Advice(_) => ColumnKind::Witness, + Any::Fixed => ColumnKind::Fixed, + Any::Instance => ColumnKind::Public, + }; + for ((col_a, col_b), offsets) in assembly.copies { + plaf.copys.push(CopyC { + columns: ( + expr::Column { + kind: column_any_to_kind(col_a.column_type()), + index: col_a.index(), + }, + expr::Column { + kind: column_any_to_kind(col_b.column_type()), + index: col_b.index(), + }, + ), + offsets, + }); + } + for i in 0..cs.num_fixed_columns() { + let mut fixed = vec![None; n]; + for (j, cell) in assembly.fixed[i].iter().enumerate() { + if let CellValue::Assigned(v) = cell { + fixed[j] = Some(BigUint::from_bytes_le(&v.to_repr()[..])); + } + } + plaf.fixed.push(fixed); + } + // If `compress_selectors = true`, then there should be 0 selectors in `cs`. + for i in 0..cs.num_selectors() { + let mut fixed = vec![None; n]; + for (j, enabled) in assembly.selectors[i].iter().enumerate() { + if *enabled { + fixed[j] = Some(BigUint::one()); + } + } + plaf.fixed.push(fixed); + } + + Ok(plaf) +} diff --git a/tools/polyexen/deps/polyexen/src/plaf/frontends/mod.rs b/tools/polyexen/deps/polyexen/src/plaf/frontends/mod.rs new file mode 100644 index 0000000..edf7922 --- /dev/null +++ b/tools/polyexen/deps/polyexen/src/plaf/frontends/mod.rs @@ -0,0 +1 @@ +pub mod halo2; diff --git a/tools/polyexen/rust-toolchain b/tools/polyexen/rust-toolchain new file mode 100644 index 0000000..31a28ae --- /dev/null +++ b/tools/polyexen/rust-toolchain @@ -0,0 +1 @@ +nightly-2024-02-16 diff --git a/tools/polyexen/src/circuit.rs b/tools/polyexen/src/circuit.rs new file mode 100644 index 0000000..807060d --- /dev/null +++ b/tools/polyexen/src/circuit.rs @@ -0,0 +1,127 @@ +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::bn256::Fr, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance, Selector}, +}; +use summa_solvency::chips::merkle_sum_tree::{MerkleSumTreeChip, MerkleSumTreeConfig}; + +#[derive(Clone)] +pub struct SummaMSTChipConfig { + mst_config: MerkleSumTreeConfig, + advices: [Column; 3], + instances: [Column; 3], +} + +impl SummaMSTChipConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let advices: [Column; 3] = std::array::from_fn(|_| meta.advice_column()); + let instances: [Column; 3] = std::array::from_fn(|_| meta.instance_column()); + let selectors: [Selector; 2] = std::array::from_fn(|_| meta.selector()); + + let mst_config = MerkleSumTreeChip::<1>::configure(meta, advices, selectors); + for col in &advices { + meta.enable_equality(*col); + } + for col in &instances { + meta.enable_equality(*col); + } + + Self { + mst_config, + advices, + instances, + } + } +} + +pub struct SummaMSTChip { + current_hash: Fr, + sibling_hash: Fr, + swap_bit: Fr, +} + +impl SummaMSTChip { + #[allow(dead_code)] + pub fn init_empty() -> Self { + Self { + current_hash: Fr::zero(), + sibling_hash: Fr::zero(), + swap_bit: Fr::zero(), + } + } +} + +impl Circuit for SummaMSTChip { + type Config = SummaMSTChipConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self { + current_hash: Fr::zero(), + sibling_hash: Fr::zero(), + swap_bit: Fr::zero(), + } + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + SummaMSTChipConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> std::result::Result<(), Error> { + let mst_chip = MerkleSumTreeChip::<2>::construct(config.mst_config); + + let current_hash = layouter.assign_region( + || "assign current hash", + |mut region| { + region.assign_advice( + || "current hash", + config.advices[0], + 0, + || Value::known(self.current_hash), + ) + }, + )?; + + let sibling_hash = layouter.assign_region( + || "assign sibling hash", + |mut region| { + region.assign_advice( + || "sibling hash", + config.advices[1], + 0, + || Value::known(self.sibling_hash), + ) + }, + )?; + + let swap_bit = layouter.assign_region( + || "assign swap bit", + |mut region| { + region.assign_advice( + || "swap bit", + config.advices[2], + 0, + || Value::known(self.swap_bit), + ) + }, + )?; + + let (next_left_hash, next_right_hash) = mst_chip.swap_hashes_per_level( + layouter.namespace(|| "swap"), + ¤t_hash, + &sibling_hash, + &swap_bit, + )?; + + layouter.constrain_instance(next_left_hash.cell(), config.instances[0], 0)?; + layouter.constrain_instance(next_right_hash.cell(), config.instances[1], 0)?; + layouter.constrain_instance(swap_bit.cell(), config.instances[2], 0)?; + + Ok(()) + } +} diff --git a/tools/polyexen/src/main.rs b/tools/polyexen/src/main.rs new file mode 100644 index 0000000..f68de65 --- /dev/null +++ b/tools/polyexen/src/main.rs @@ -0,0 +1,454 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +use std::{ + collections::{HashMap, HashSet}, + fmt, + fs::File, + io::{self, Write}, + path::Path, +}; + +use env_logger::Env; +use halo2_proofs::{halo2curves::bn256::Fr, plonk::Circuit}; +use num_bigint::BigUint; +use polyexen::{ + analyze::{bound_base, find_bounds_poly, Analysis, Bound}, + expr::{Expr, ExprDisplay, Var}, + plaf::{ + frontends::halo2::get_plaf, Cell, CellDisplay, Lookup, Plaf, PlafDisplayBaseTOML, + PlafDisplayFixedCSV, + }, +}; + +mod circuit; + +// Base on https://github.com/ed255/polyexen-demo/blob/main/src/bin/demo.rs +fn main() { + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + + // let c = circuit::SummaMSTChip::init_empty(); + let c = summa_solvency::circuits::merkle_sum_tree::MstInclusionCircuit::<4, 2, 4>::init_empty(); + let k = 12; + + let analysis = do_circuit_analysis(k, &c); + analysis.write_files("mst").unwrap(); +} + +#[derive(Default, Debug)] +struct VarPointers { + polys: Vec, + lookups: Vec, + copys: Vec, +} + +fn do_circuit_analysis(k: u32, c: &impl Circuit) -> AnalysisResult { + let mut plaf = get_plaf(k, c).unwrap(); + plaf.simplify(); + + let p = BigUint::parse_bytes(b"100000000000000000000000000000000", 16).unwrap() + - BigUint::from(159u64); + let mut analysis: Analysis = Analysis::new(); + + let cell_fmt = + |f: &mut fmt::Formatter<'_>, c: &Cell| write!(f, "{}", CellDisplay { c, plaf: &plaf }); + let mut var_map: HashMap<_, VarPointers> = HashMap::new(); + + // Output poly var -> raw poly index + let mut raw_polys = Vec::new(); + for offset in 0..plaf.info.num_rows { + for poly in &plaf.polys { + let mut exp = plaf.resolve(&poly.exp, offset); + exp.simplify(&p); + if exp.is_zero() { + continue; + } + log::trace!( + "\"{}\": {}", + poly.name, + ExprDisplay { + e: &exp, + var_fmt: cell_fmt + } + ); + // Fill bounds in analysis.vars_attrs + find_bounds_poly(&exp, &p, &mut analysis); + + for var in exp.vars() { + let pointers = var_map.entry(var).or_insert(VarPointers::default()); + pointers.polys.push(raw_polys.len()); // push poly index in raw_polys + } + raw_polys.push(ResolvedPoly { + name: poly.name.clone(), + expr: exp, + }); + } + } + + let bound_base = bound_base(&p); + let mut var_bounds = Vec::new(); + for (cell, attrs) in &analysis.vars_attrs { + if attrs.bound == bound_base { + continue; + } + log::trace!( + "{} bound {:?}", + CellDisplay { + c: cell, + plaf: &plaf + }, + attrs.bound + ); + + var_bounds.push((cell.clone(), attrs.bound.clone())); + } + + let mut raw_lookups = Vec::new(); + for offset in 0..plaf.info.num_rows { + for (lookup_num, lookup) in plaf.lookups.iter().enumerate() { + let Lookup { name, exps } = lookup; + let exps_lhs: Vec<_> = exps + .0 + .iter() + .map(|exp| { + let mut exp = plaf.resolve(&exp, offset); + exp.simplify(&plaf.info.p); + exp + }) + .collect(); + if exps_lhs.iter().all(|exp| exp.is_zero()) { + continue; + } + for exp in &exps_lhs { + for var in exp.vars() { + let pointers = var_map.entry(var).or_insert(VarPointers::default()); + pointers.lookups.push(raw_lookups.len()); // push lookup index + } + } + raw_lookups.push(ResolvedLookup { + name: name.clone(), + exprs_num: (exps_lhs.clone(), lookup_num), + }); + log::trace!("["); + for (i, exp) in exps_lhs.iter().enumerate() { + if i != 0 { + log::trace!(", ") + } + log::trace!( + "{}", + ExprDisplay { + e: &exp, + var_fmt: cell_fmt + }, + ); + } + log::trace!("] in ["); + for (i, exp) in exps.1.iter().enumerate() { + if i != 0 { + log::trace!(", ") + } + log::trace!( + "{}", + ExprDisplay { + e: &exp, + var_fmt: |f, v| plaf.fmt_var(f, v) + }, + ); + } + log::trace!("] # {}", name); + } + } + + let mut raw_copys = Vec::new(); + for copy in &plaf.copys { + let (column_a, column_b) = copy.columns; + for offset in ©.offsets { + let cell_a = Cell { + column: column_a, + offset: offset.0, + }; + let cell_b = Cell { + column: column_b, + offset: offset.1, + }; + + log::trace!( + "{} - {}", + CellDisplay { + c: &cell_a, + plaf: &plaf + }, + CellDisplay { + c: &cell_b, + plaf: &plaf + } + ); + + let pointers = var_map + .entry(cell_a.clone()) + .or_insert(VarPointers::default()); + pointers.copys.push(raw_copys.len()); + let pointers = var_map + .entry(cell_b.clone()) + .or_insert(VarPointers::default()); + pointers.copys.push(raw_copys.len()); + raw_copys.push((cell_a, cell_b)); + } + } + + let mut copy_sets = Vec::new(); + let mut cleared = HashSet::new(); + let mut dup_vars_count = 0; + for (index, (cell_main, cell_b)) in raw_copys.iter().enumerate() { + if cleared.contains(&index) { + continue; + } + cleared.insert(index); + let mut next = vec![cell_b.clone()]; + let mut copy_set = HashSet::new(); + while let Some(cell) = next.pop() { + if cell == *cell_main { + continue; + } + copy_set.insert(cell.clone()); + if let Some(pointers) = var_map.get(&cell) { + for copy_index in &pointers.copys { + if cleared.contains(copy_index) { + continue; + } + cleared.insert(*copy_index); + let (cell_a, cell_b) = raw_copys[*copy_index].to_owned(); + next.push(cell_a); + next.push(cell_b); + } + } + } + dup_vars_count += copy_set.len(); + copy_sets.push((cell_main, copy_set)); + } + log::debug!("dup_vars_count={}", dup_vars_count); + + for copy in ©_sets { + log::trace!( + "{} <- [", + CellDisplay { + c: copy.0, + plaf: &plaf + } + ); + for (i, copy_cell) in copy.1.iter().enumerate() { + if i != 0 { + log::trace!(", "); + } + log::trace!( + "{}", + CellDisplay { + c: copy_cell, + plaf: &plaf + } + ); + } + log::trace!("]"); + } + + // Apply copy constraint replacements + for (cell_main, copy_set) in ©_sets { + for cell in copy_set { + if let Some(pointers) = var_map.get(cell) { + for poly_index in &pointers.polys { + let poly = raw_polys.get_mut(*poly_index).unwrap(); + poly.expr + .replace_var(cell, &Expr::Var((*cell_main).to_owned())); + } + for lookup_index in &pointers.lookups { + let lookup = raw_lookups.get_mut(*lookup_index).unwrap(); + for exp in lookup.exprs_num.0.iter_mut() { + exp.replace_var(cell, &Expr::Var((*cell_main).to_owned())); + } + } + } + } + } + + AnalysisResult { + polys: raw_polys, + lookups: raw_lookups, + var_bounds, + plaf, + } +} + +trait ExprReplaceVar { + fn replace_var(&mut self, v: &V, replacement: &Expr); +} + +impl ExprReplaceVar for Expr { + fn replace_var(&mut self, v: &V, replacement: &Expr) { + use Expr::*; + match self { + Const(_) => {} + Var(_) => { + *self = replacement.clone(); + } + Neg(e) => e.replace_var(v, replacement), + Pow(e, _) => e.replace_var(v, replacement), + Sum(es) => es.iter_mut().for_each(|e| e.replace_var(v, replacement)), + Mul(es) => es.iter_mut().for_each(|e| e.replace_var(v, replacement)), + } + } +} + +struct AnalysisResult { + polys: Vec, + lookups: Vec, + var_bounds: Vec<(Cell, Bound)>, + plaf: Plaf, +} + +impl AnalysisResult { + fn write_files(&self, name: &str) -> Result<(), io::Error> { + if !Path::new("out").exists() { + std::fs::create_dir("out")?; + log::debug!("create out dir") + } + + let mut base_file = File::create(format!("out/{}.toml", name))?; + let mut fixed_file = File::create(format!("out/{}_fixed.csv", name))?; + let mut polys_file = File::create(format!("out/{}_polys.toml", name))?; + + write!(base_file, "{}", PlafDisplayBaseTOML(&self.plaf))?; + write!(fixed_file, "{}", PlafDisplayFixedCSV(&self.plaf))?; + write!(polys_file, "{}", DisplayPolysBaseTOML::from(self))?; + + if !self.lookups.is_empty() { + let mut lookups_file = File::create(format!("out/{}_lookups.toml", name))?; + write!(lookups_file, "{}", DisplayLookupsBaseTOML::from(self))?; + } + + Ok(()) + } +} + +struct ResolvedPoly { + name: String, + expr: Expr, +} + +struct DisplayPolysBaseTOML<'a> { + var_bounds: &'a Vec<(Cell, Bound)>, + polys: &'a Vec, + plaf: &'a Plaf, +} + +impl<'a> From<&'a AnalysisResult> for DisplayPolysBaseTOML<'a> { + fn from(value: &'a AnalysisResult) -> Self { + DisplayPolysBaseTOML { + var_bounds: &value.var_bounds, + polys: &value.polys, + plaf: &value.plaf, + } + } +} + +impl fmt::Display for DisplayPolysBaseTOML<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let cell_fmt = |f: &mut fmt::Formatter<'_>, c: &Cell| { + write!( + f, + "{}", + CellDisplay { + c, + plaf: &self.plaf + } + ) + }; + + for (c, bound) in self.var_bounds { + writeln!( + f, + "[constraints.resolved_polys.vars.\"{}\"]", + CellDisplay { + c, + plaf: &self.plaf, + } + )?; + writeln!(f, "bound = {}", bound)?; + } + writeln!(f)?; + + for p in self.polys { + writeln!(f, "[constraints.resolved_polys.\"{}\"]", p.name)?; + write!(f, "c = \"")?; + write!( + f, + "{}", + ExprDisplay { + e: &p.expr, + var_fmt: cell_fmt, + } + )?; + writeln!(f, "\"")?; + } + + Ok(()) + } +} + +struct ResolvedLookup { + name: String, + exprs_num: (Vec>, usize), +} + +struct DisplayLookupsBaseTOML<'a> { + lookups: &'a Vec, + plaf: &'a Plaf, +} + +impl<'a> From<&'a AnalysisResult> for DisplayLookupsBaseTOML<'a> { + fn from(value: &'a AnalysisResult) -> Self { + DisplayLookupsBaseTOML { + lookups: &value.lookups, + plaf: &value.plaf, + } + } +} + +impl fmt::Display for DisplayLookupsBaseTOML<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let cell_fmt = |f: &mut fmt::Formatter<'_>, c: &Cell| { + write!( + f, + "{}", + CellDisplay { + c, + plaf: &self.plaf + } + ) + }; + + for l in self.lookups { + writeln!( + f, + "[constraints.resolved_lookups.\"{}\"_\"{}\"]", + l.exprs_num.1, l.name + )?; + write!(f, "l = [")?; + for (i, exp) in l.exprs_num.0.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!( + f, + "{}", + ExprDisplay { + e: &exp, + var_fmt: cell_fmt + }, + )?; + } + writeln!(f, "]")?; + } + + Ok(()) + } +}