From d963210dc6d6877fd279c421bf6499bdd81a387a Mon Sep 17 00:00:00 2001 From: alinat Date: Wed, 2 Oct 2024 08:47:48 +0300 Subject: [PATCH 01/19] add vergrth --- Cargo.lock | 1622 +- Cargo.toml | 1 + tvm_tests/Cargo.toml | 55 + tvm_tests/src/main.rs | 7 + tvm_vm/Cargo.toml | 42 + tvm_vm/src/executor/engine/handlers.rs | 6 +- tvm_vm/src/executor/mod.rs | 2 + tvm_vm/src/executor/zk.rs | 1131 ++ tvm_vm/src/executor/zk_stuff/bn254/api.rs | 56 + tvm_vm/src/executor/zk_stuff/bn254/mod.rs | 79 + .../zk_stuff/bn254/poseidon/constants.rs | 13124 ++++++++++++++++ .../executor/zk_stuff/bn254/poseidon/mod.rs | 306 + .../src/executor/zk_stuff/bn254/verifier.rs | 192 + tvm_vm/src/executor/zk_stuff/curve_utils.rs | 194 + tvm_vm/src/executor/zk_stuff/error.rs | 54 + tvm_vm/src/executor/zk_stuff/mod.rs | 26 + tvm_vm/src/executor/zk_stuff/utils.rs | 73 + tvm_vm/src/executor/zk_stuff/zk_login.rs | 657 + 18 files changed, 17541 insertions(+), 86 deletions(-) create mode 100644 tvm_tests/Cargo.toml create mode 100644 tvm_tests/src/main.rs create mode 100644 tvm_vm/src/executor/zk.rs create mode 100644 tvm_vm/src/executor/zk_stuff/bn254/api.rs create mode 100644 tvm_vm/src/executor/zk_stuff/bn254/mod.rs create mode 100644 tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs create mode 100644 tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs create mode 100644 tvm_vm/src/executor/zk_stuff/bn254/verifier.rs create mode 100644 tvm_vm/src/executor/zk_stuff/curve_utils.rs create mode 100644 tvm_vm/src/executor/zk_stuff/error.rs create mode 100644 tvm_vm/src/executor/zk_stuff/mod.rs create mode 100644 tvm_vm/src/executor/zk_stuff/utils.rs create mode 100644 tvm_vm/src/executor/zk_stuff/zk_login.rs diff --git a/Cargo.lock b/Cargo.lock index 64a1c4eb..66b3ba62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,17 @@ dependencies = [ "syn 2.0.71", ] +[[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.22.0" @@ -223,6 +234,222 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest 0.10.7", + "sha2 0.10.8", + "tracing", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "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", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-groth16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1d1472e5cb020cb3405ce2567c91c8d43f21b674aef37b0202f5c3304761db" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-std", + "derivative", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-secp256r1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[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" @@ -290,6 +517,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_ops" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" + [[package]] name = "autocfg" version = "1.3.0" @@ -311,6 +544,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.2.0" @@ -323,6 +562,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +[[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" @@ -335,6 +580,36 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bellpepper" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae286c2cb403324ab644c7cc68dceb25fe52ca9429908a726d7ed272c1edf7b" +dependencies = [ + "bellpepper-core", + "byteorder", + "ff", +] + +[[package]] +name = "bellpepper-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8abb418570756396d722841b19edfec21d4e89e1cf8990610663040ecb1aea" +dependencies = [ + "blake2s_simd", + "byteorder", + "ff", + "serde", + "thiserror", +] + [[package]] name = "bincode" version = "1.3.3" @@ -344,6 +619,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -356,6 +646,58 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[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 = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[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 = "blake2s_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -390,6 +732,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bls12_381" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" +dependencies = [ + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "blst" version = "0.3.12" @@ -402,6 +757,29 @@ dependencies = [ "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", + "ec-gpu", + "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" + [[package]] name = "bstr" version = "0.2.17" @@ -434,6 +812,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[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.16.1" @@ -548,6 +932,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets 0.52.6", ] @@ -607,11 +992,23 @@ dependencies = [ "atty", "bitflags 1.3.2", "strsim 0.8.0", - "textwrap", + "textwrap 0.11.0", "unicode-width", "vec_map", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "textwrap 0.16.1", +] + [[package]] name = "clap" version = "4.5.9" @@ -630,7 +1027,7 @@ checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" dependencies = [ "anstream", "anstyle", - "clap_lex", + "clap_lex 0.7.1", "strsim 0.11.1", ] @@ -646,6 +1043,15 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.7.1" @@ -690,6 +1096,27 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.17.0" @@ -805,6 +1232,32 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap 3.2.25", + "criterion-plot", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + [[package]] name = "criterion" version = "0.5.1" @@ -817,7 +1270,7 @@ dependencies = [ "clap 4.5.9", "criterion-plot", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -838,7 +1291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -897,6 +1350,18 @@ 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", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -936,6 +1401,19 @@ dependencies = [ "cipher 0.2.5", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -963,6 +1441,54 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.71", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.71", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -990,6 +1516,17 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468 0.6.0", + "zeroize", +] + [[package]] name = "der" version = "0.7.9" @@ -997,6 +1534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -1007,6 +1545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1020,6 +1559,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.71", +] + [[package]] name = "destructure_traitobject" version = "0.2.0" @@ -1038,6 +1590,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +[[package]] +name = "diffy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27ec7cef89a63c063e06570bb861b7d35e406d6885551b346d77c459b34d3db" +dependencies = [ + "ansi_term", +] + [[package]] name = "diffy" version = "0.3.0" @@ -1063,6 +1624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -1094,14 +1656,78 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ec-gpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd63582de2b59ea1aa48d7c1941b5d87618d95484397521b3acdfa0e1e9f5e45" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "signature", + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "thiserror", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", ] [[package]] @@ -1110,8 +1736,8 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", "sha2 0.10.8", @@ -1125,6 +1751,26 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[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", + "group", + "pem-rfc7468 0.7.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1169,66 +1815,201 @@ dependencies = [ ] [[package]] -name = "external-ip" -version = "4.3.0" +name = "external-ip" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f23e6dbb3f352cb0d6641268b8f984cc4941834b7a31198caf35190d69334b7" +dependencies = [ + "cargo-upgrades", + "futures", + "igd", + "log", + "rand 0.8.5", + "reqwest", + "trust-dns-resolver", +] + +[[package]] +name = "extfmt" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48fe53466ab1f4ea6303bf9d7a0ca8060778590f09fd6c3304cc817aeb9935d" + +[[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 = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "fancy_constructor" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "fastcrypto" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9ea2139faa96e4d713803b7777b8fd2d5c245858b1644c08d3220f407149c6" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-secp256r1", + "ark-serialize", + "auto_ops", + "base64ct", + "bech32", + "bincode", + "blake2", + "blst", + "bs58", + "curve25519-dalek-ng", + "derive_more", + "digest 0.10.7", + "ecdsa", + "ed25519-consensus", + "elliptic-curve", + "eyre", + "fastcrypto-derive", + "generic-array", + "hex", + "hex-literal", + "hkdf", + "lazy_static", + "num-bigint 0.4.6", + "once_cell", + "p256", + "rand 0.8.5", + "readonly", + "rfc6979", + "rsa", + "schemars", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3", + "signature 2.2.0", + "static_assertions", + "thiserror", + "tokio", + "typenum", + "zeroize", +] + +[[package]] +name = "fastcrypto-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0c2af2157f416cb885e11d36cd0de2753f6d5384752d364075c835f5f8f891" +dependencies = [ + "convert_case 0.6.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fastcrypto-zkp" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f23e6dbb3f352cb0d6641268b8f984cc4941834b7a31198caf35190d69334b7" +checksum = "d2510946ae11008ca0c5d11e8acf7168914bcc5cf5d770eae8c03ad3d1526872" dependencies = [ - "cargo-upgrades", - "futures", - "igd", - "log", - "rand 0.8.5", + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-groth16", + "ark-relations", + "ark-serialize", + "ark-snark", + "blst", + "byte-slice-cast", + "derive_more", + "fastcrypto", + "ff", + "im", + "itertools 0.12.1", + "lazy_static", + "neptune", + "num-bigint 0.4.6", + "once_cell", "reqwest", - "trust-dns-resolver", + "schemars", + "serde", + "serde_json", + "typenum", ] [[package]] -name = "extfmt" -version = "0.1.1" +name = "fastrand" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48fe53466ab1f4ea6303bf9d7a0ca8060778590f09fd6c3304cc817aeb9935d" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] -name = "failure" -version = "0.1.8" +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "backtrace", - "failure_derive", + "bitvec", + "byteorder", + "ff_derive", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "failure_derive" -version = "0.1.8" +name = "ff_derive" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" dependencies = [ + "addchain", + "cfg-if", + "num-bigint 0.3.3", + "num-integer", + "num-traits", "proc-macro2", "quote", "syn 1.0.109", - "synstructure", -] - -[[package]] -name = "fancy_constructor" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.71", ] -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1296,6 +2077,12 @@ dependencies = [ "percent-encoding", ] +[[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" @@ -1391,8 +2178,10 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", + "zeroize", ] [[package]] @@ -1441,6 +2230,19 @@ dependencies = [ "thiserror", ] +[[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.26" @@ -1453,7 +2255,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1470,6 +2272,21 @@ dependencies = [ "crunchy", ] +[[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.5" @@ -1522,6 +2339,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.8.1" @@ -1696,6 +2522,12 @@ 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.3.0" @@ -1739,6 +2571,26 @@ dependencies = [ "xmltree", ] +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "index-fixed" version = "0.3.1" @@ -1762,6 +2614,17 @@ dependencies = [ "web-sys", ] +[[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", + "serde", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1769,7 +2632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -1792,7 +2655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c77a3ae7d4761b9c64d2c030f70746ceb8cfba32dce0325a56792e0a4816c31" dependencies = [ "ahash", - "indexmap", + "indexmap 2.2.6", "is-terminal", "itoa", "log", @@ -1856,6 +2719,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1880,11 +2752,23 @@ dependencies = [ "wasm-bindgen", ] +[[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.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1892,6 +2776,16 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libloading" version = "0.8.4" @@ -1902,6 +2796,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.1.3" @@ -2039,7 +2939,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -2110,6 +3010,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + [[package]] name = "memmap2" version = "0.9.4" @@ -2173,6 +3082,25 @@ dependencies = [ "tempfile", ] +[[package]] +name = "neptune" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06626c9ac04c894e9a23d061ba1309f28506cdc5fe64156d28a15fb57fc8e438" +dependencies = [ + "bellpepper", + "bellpepper-core", + "blake2s_simd", + "blstrs", + "byteorder", + "ff", + "generic-array", + "log", + "pasta_curves", + "serde", + "trait-set", +] + [[package]] name = "nix" version = "0.26.4" @@ -2206,7 +3134,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -2214,6 +3142,17 @@ dependencies = [ "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.6" @@ -2222,6 +3161,24 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", ] [[package]] @@ -2286,7 +3243,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -2298,6 +3255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2430,6 +3388,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "overload" version = "0.1.1" @@ -2442,6 +3406,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2465,6 +3450,30 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ec-gpu", + "ff", + "group", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.8.0" @@ -2483,6 +3492,24 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2521,14 +3548,36 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +dependencies = [ + "der 0.6.1", + "pkcs8 0.9.0", + "spki 0.6.0", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.9", + "spki 0.7.3", ] [[package]] @@ -2583,6 +3632,28 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "pprof" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196ded5d4be535690899a4631cc9f18cdc41b7ebf24a79400f46f48e49a11059" +dependencies = [ + "backtrace", + "cfg-if", + "criterion 0.4.0", + "findshlibs", + "inferno", + "libc", + "log", + "nix", + "once_cell", + "parking_lot", + "smallvec", + "symbolic-demangle 10.2.1", + "tempfile", + "thiserror", +] + [[package]] name = "pprof" version = "0.13.0" @@ -2591,7 +3662,7 @@ checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb" dependencies = [ "backtrace", "cfg-if", - "criterion", + "criterion 0.5.1", "findshlibs", "inferno", "libc", @@ -2600,7 +3671,7 @@ dependencies = [ "once_cell", "parking_lot", "smallvec", - "symbolic-demangle", + "symbolic-demangle 12.9.2", "tempfile", "thiserror", ] @@ -2651,6 +3722,15 @@ dependencies = [ "yansi 0.5.1", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -2725,6 +3805,12 @@ 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.7.3" @@ -2796,6 +3882,24 @@ dependencies = [ "rand_core 0.5.1", ] +[[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 = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rayon" version = "1.10.0" @@ -2816,6 +3920,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "readonly" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -2922,6 +4037,16 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "rgb" version = "0.8.45" @@ -2946,6 +4071,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" +dependencies = [ + "byteorder", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sha2 0.10.8", + "signature 2.2.0", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3056,6 +4202,30 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.71", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -3084,6 +4254,40 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der 0.7.9", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "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 = "secstr" version = "0.5.1" @@ -3155,13 +4359,24 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "serde_json" version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ - "indexmap", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3199,13 +4414,41 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3247,6 +4490,16 @@ dependencies = [ "digest 0.10.7", ] +[[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" version = "0.3.17" @@ -3277,12 +4530,19 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[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", ] @@ -3306,6 +4566,16 @@ dependencies = [ "time", ] +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.9" @@ -3355,6 +4625,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + [[package]] name = "spki" version = "0.7.3" @@ -3362,7 +4642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.9", ] [[package]] @@ -3371,6 +4651,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "str_stack" version = "0.1.0" @@ -3401,6 +4687,24 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "symbolic-common" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b55cdc318ede251d0957f07afe5fed912119b8c1bc5a7804151826db999e737" +dependencies = [ + "debugid", + "memmap2 0.5.10", + "stable_deref_trait", + "uuid", +] + [[package]] name = "symbolic-common" version = "12.9.2" @@ -3408,11 +4712,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71297dc3e250f7dbdf8adb99e235da783d690f5819fdeb4cce39d9cfb0aca9f1" dependencies = [ "debugid", - "memmap2", + "memmap2 0.9.4", "stable_deref_trait", "uuid", ] +[[package]] +name = "symbolic-demangle" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79be897be8a483a81fff6a3a4e195b4ac838ef73ca42d348b3f722da9902e489" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common 10.2.1", +] + [[package]] name = "symbolic-demangle" version = "12.9.2" @@ -3421,7 +4736,7 @@ checksum = "424fa2c9bf2c862891b9cfd354a752751a6730fd838a4691e7f6c2c7957b9daf" dependencies = [ "cpp_demangle", "rustc-demangle", - "symbolic-common", + "symbolic-common 12.9.2", ] [[package]] @@ -3494,6 +4809,12 @@ dependencies = [ "unicode-width", ] +[[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" @@ -3530,6 +4851,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + [[package]] name = "thiserror" version = "1.0.62" @@ -3776,7 +5103,7 @@ version = "0.22.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" dependencies = [ - "indexmap", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -3818,6 +5145,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[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]] @@ -3901,7 +5249,7 @@ dependencies = [ "chrono", "failure", "hex", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "serde", "serde_json", @@ -3955,8 +5303,8 @@ dependencies = [ "anyhow", "base64 0.21.7", "crc 3.2.1", - "ed25519", - "ed25519-dalek", + "ed25519 2.2.3", + "ed25519-dalek 2.1.1", "failure", "hex", "log", @@ -4007,7 +5355,7 @@ dependencies = [ "indicatif", "lazy_static", "log", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "predicates", "qr2term", @@ -4051,7 +5399,7 @@ dependencies = [ "chrono", "crc 3.2.1", "dirs", - "ed25519-dalek", + "ed25519-dalek 2.1.1", "failure", "futures", "graphql-parser", @@ -4066,7 +5414,7 @@ dependencies = [ "log", "log4rs", "lru", - "num-bigint", + "num-bigint 0.4.6", "num-derive", "num-traits", "pbkdf2 0.8.0", @@ -4099,7 +5447,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "zeroize", - "zstd", + "zstd 0.13.2", ] [[package]] @@ -4179,7 +5527,7 @@ dependencies = [ "hex", "lazy_static", "log", - "num-bigint", + "num-bigint 0.4.6", "num-traits", "serde", "serde_derive", @@ -4202,6 +5550,44 @@ dependencies = [ "tvm_types", ] +[[package]] +name = "tvm_tests" +version = "2.2.7" +dependencies = [ + "anyhow", + "ark-ff", + "ark-std", + "base64 0.13.1", + "base64ct", + "criterion 0.4.0", + "diffy 0.2.2", + "ed25519 1.5.3", + "ed25519-dalek 1.0.1", + "fastcrypto", + "fastcrypto-zkp", + "hex", + "lazy_static", + "libloading 0.6.7", + "log", + "log4rs", + "num", + "num-bigint 0.4.6", + "num-traits", + "pprof 0.11.1", + "pretty_assertions", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "similar", + "tvm_assembler", + "tvm_block", + "tvm_types", + "tvm_vm", + "zstd 0.11.2+zstd.1.5.2", +] + [[package]] name = "tvm_tl_codegen" version = "2.2.7" @@ -4225,10 +5611,10 @@ dependencies = [ "base64 0.21.7", "blst", "crc 3.2.1", - "criterion", - "curve25519-dalek", - "ed25519", - "ed25519-dalek", + "criterion 0.5.1", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "ed25519-dalek 2.1.1", "failure", "hex", "lazy_static", @@ -4237,7 +5623,7 @@ dependencies = [ "num", "num-derive", "num-traits", - "pprof", + "pprof 0.13.0", "rand 0.8.5", "serde", "serde_json", @@ -4252,26 +5638,52 @@ name = "tvm_vm" version = "2.2.7" dependencies = [ "anyhow", - "criterion", - "diffy", - "ed25519", - "ed25519-dalek", + "ark-bls12-381", + "ark-bn254", + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-groth16", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "base64ct", + "bls12_381", + "blst", + "byte-slice-cast", + "criterion 0.5.1", + "derive_more", + "diffy 0.3.0", + "ed25519 2.2.3", + "ed25519-dalek 2.1.1", "failure", + "fastcrypto", + "ff", "hex", + "itertools 0.12.1", "lazy_static", - "libloading", + "libloading 0.8.4", "log", "log4rs", + "neptune", "num", + "num-bigint 0.4.6", "num-traits", - "pprof", + "once_cell", + "pprof 0.13.0", "pretty_assertions", "rand 0.8.5", + "schemars", + "serde", + "serde_json", "similar", "thiserror", "tvm_block", "tvm_types", - "zstd", + "typenum", + "zstd 0.13.2", ] [[package]] @@ -4310,6 +5722,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.1.13" @@ -4416,6 +5834,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4772,13 +6196,22 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x25519-dalek" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "rand_core 0.6.4", "serde", "zeroize", @@ -4869,13 +6302,32 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.0", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0c9687f4..c8fcd27e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "tvm_tl_codegen", "tvm_types", "tvm_vm", + "tvm_tests" ] [workspace.package] version = "2.2.7" diff --git a/tvm_tests/Cargo.toml b/tvm_tests/Cargo.toml new file mode 100644 index 00000000..383a64bd --- /dev/null +++ b/tvm_tests/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "tvm_tests" +version.workspace = true +rust-version.workspace = true +authors.workspace = true +repository.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +tvm_block.workspace = true +tvm_types.workspace = true +tvm_assembler = {workspace = true, features = ['gosh']} +tvm_vm = {workspace = true, features = ['gosh']} + +libloading = '0.6' +log4rs = '1.2' +pprof = { features = [ 'criterion', 'flamegraph' ], version = '0.11' } +pretty_assertions = '1.3' +criterion = '0.4' + + + +ed25519 = '1.2' +ed25519-dalek = '1.0' +anyhow = "1.0.79" +hex = '0.4' +lazy_static = '1.4' +log = '0.4' +num = '0.4' + +rand = '0.7' +diffy = { optional = true, version = '0.2.2' } +similar = { features = [ 'bytes' ], optional = true, version = '2.2.0' } +zstd = { default-features = false, optional = true, version = '0.11' } +fastcrypto-zkp = "0.1.3" +fastcrypto = "0.1.8" +ark-std = "0.4.0" +ark-ff = "0.4.2" + +base64ct ={ version = "1.5.3", features = ["alloc"]} + +base64 = "0.13" + +serde = "1.0.197" +serde_derive = "1.0.197" +serde_json = "1.0.114" +serde_repr = "0.1.18" + +num-traits = "0.2.18" +num-bigint = "0.4.6" + + +[lints] +workspace = true diff --git a/tvm_tests/src/main.rs b/tvm_tests/src/main.rs new file mode 100644 index 00000000..349e894f --- /dev/null +++ b/tvm_tests/src/main.rs @@ -0,0 +1,7 @@ + +mod test_zk; +mod test_zk_; +mod test_framework; + +fn main() { +} diff --git a/tvm_vm/Cargo.toml b/tvm_vm/Cargo.toml index 862f2bb8..52caf6d2 100644 --- a/tvm_vm/Cargo.toml +++ b/tvm_vm/Cargo.toml @@ -27,6 +27,46 @@ zstd = { default-features = false, optional = true, version = "0.13.0" } tvm_block.workspace = true tvm_types.workspace = true +serde_json.workspace = true +#serde.workspace = true + +#bellman = { git = "https://github.com/zkcrypto/bellman" } +bls12_381 = "0.8" + + +ark-bls12-381 = "0.4.0" +ark-bn254 = "0.4.0" +ark-ec = { version = "0.4.1" } +ark-ff = { version = "0.4.1", features = ["asm"] } +ark-groth16 = { version = "0.4.0", default-features = false } +ark-relations = "0.4.0" +ark-serialize = "0.4.1" +ark-snark = "0.4.0" +blst = "0.3.11" +byte-slice-cast = "1.2.2" +ark-crypto-primitives = { version = "0.4.0", features = ["r1cs", "prf"] } +ark-r1cs-std = "0.4.0" +ark-std = "0.4.0" + + +num-bigint = { version = "0.4", default-features = false, features = ["rand"] } +#fastcrypto-zkp = "0.1.3" + +fastcrypto = "0.1.8" #only temporary +neptune = { version = "13.0.0", default_features = false } + +once_cell = "1.16" +schemars = "0.8.10" +serde = { version = "1.0.156", features = ["derive"] } +#serde_derive = "1.0.200" +#serde_json = "1.0.93" +derive_more = "0.99.16" +base64ct ={ version = "1.5.3", features = ["alloc"]} + +itertools = "0.12.0" +typenum = "1.13.0" +ff = {version = "0.13.0", features = ["derive"]} + [dev-dependencies] criterion = "0.5.1" libloading = "0.8.1" @@ -34,6 +74,8 @@ log4rs = "1.2.0" pprof = { features = ["criterion", "flamegraph"], version = "0.13.0" } pretty_assertions = "1.4.0" +serde = { version = "1.0.156", features = ["derive"] } + [features] fift_check = [] gosh = ["tvm_block/gosh", "diffy", "similar", "zstd"] diff --git a/tvm_vm/src/executor/engine/handlers.rs b/tvm_vm/src/executor/engine/handlers.rs index d6642921..032c9203 100644 --- a/tvm_vm/src/executor/engine/handlers.rs +++ b/tvm_vm/src/executor/engine/handlers.rs @@ -49,6 +49,8 @@ use crate::stack::integer::behavior::Signaling; use crate::types::Exception; use crate::types::Status; +use crate::executor::zk::*; + // ( - ) fn execute_nop(engine: &mut Engine) -> Status { engine.load_instruction(Instruction::new("NOP")) @@ -391,7 +393,9 @@ impl Handlers { .set(0x26, execute_ecc_mint) .set(0x27, execute_exchange_shell) .set(0x29, execute_calculate_validator_reward) - .set(0x30, execute_calculate_min_stake); + .set(0x30, execute_calculate_min_stake) + .set(0x31, execute_vergrth16) + .set(0x32, execute_poseidon_zk_login); } self.add_subset(0xC7, &mut c7_handlers) } diff --git a/tvm_vm/src/executor/mod.rs b/tvm_vm/src/executor/mod.rs index c6dd95f9..1a1a36f6 100644 --- a/tvm_vm/src/executor/mod.rs +++ b/tvm_vm/src/executor/mod.rs @@ -36,6 +36,7 @@ mod stack; pub mod token; mod tuple; mod types; +pub mod zk_stuff; pub use engine::*; use tvm_types::BuilderData; @@ -46,6 +47,7 @@ use tvm_types::Result; #[cfg(test)] #[path = "../tests/test_executor.rs"] mod tests; +pub mod zk; pub trait Mask { fn bit(&self, bits: Self) -> bool; diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs new file mode 100644 index 00000000..4de0234d --- /dev/null +++ b/tvm_vm/src/executor/zk.rs @@ -0,0 +1,1131 @@ +use crate::executor::Engine; +use crate::types::Status; + +use ark_bn254::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ff::BigInteger; +use ark_ff::PrimeField; +use num_bigint::BigUint; +use schemars::JsonSchema; +use derive_more::From; +use serde::Serialize; +use serde::Deserialize; + +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt::Error; + +use tvm_block::GlobalCapabilities; +use tvm_types::error; +use tvm_types::BuilderData; +use tvm_types::ExceptionCode; +use tvm_types::GasConsumer; +use tvm_types::UInt256; +use tvm_types::SliceData; + +use base64ct::{Base64UrlUnpadded,Encoding}; + +use std::str::FromStr; +use std::time::Instant; + +pub use ark_bn254::{Bn254, Fr as Bn254Fr}; +use ark_groth16::{Groth16, PreparedVerifyingKey, Proof, VerifyingKey}; +use ark_snark::SNARK; + + +use crate::error::TvmError; +use crate::executor::engine::storage::fetch_stack; +use crate::executor::types::Instruction; +use crate::stack::integer::serialization::UnsignedIntegerBigEndianEncoding; +use crate::stack::integer::IntegerData; +use crate::stack::StackItem; +use crate::types::Exception; +use crate::utils::{bytes_to_string, unpack_string_from_cell}; +use crate::utils::pack_data_to_cell; +use crate::utils::unpack_data_from_cell; +//use once_cell::sync::Lazy; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use serde_json::Value; +use thiserror::Error; +use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; +use crate::executor::zk_stuff::curve_utils::Bn254FrElement; +use crate::executor::zk_stuff::error::ZkCryptoError; +use crate::executor::zk_stuff::utils::split_to_two_frs; +use crate::executor::zk_stuff::zk_login::{Claim, hash_ascii_str_to_field, hash_to_field, MAX_HEADER_LEN, MAX_ISS_LEN_B64, PACK_WIDTH}; +use crate::stack::StackItem::Cell; + + +pub type ZkCryptoResult = Result; + +/// Size of scalars in the BN254 construction. +pub const SCALAR_SIZE: usize = 32; + +#[derive(Debug, From)] +pub struct FieldElementWrapper(pub(crate) ark_bn254::Fr); + +impl FieldElementWrapper { + /// Deserialize 32 bytes into a BN254 field element using little-endian format. + pub(crate) fn deserialize(bytes: &[u8]) -> ZkCryptoResult { + if bytes.len() != SCALAR_SIZE { + return Err(ZkCryptoError::InputLengthWrong(bytes.len())); + } + Fr::deserialize_compressed(bytes) + .map_err(|_| ZkCryptoError::InvalidInput) + .map(FieldElementWrapper) + } + + /// Deserialize a vector of bytes into a vector of BN254 field elements, assuming that each element + /// is serialized as a chunk of 32 bytes. See also [`FieldElement::deserialize`]. + pub(crate) fn deserialize_vector( + field_element_bytes: &[u8], + ) -> ZkCryptoResult> { + if field_element_bytes.len() % SCALAR_SIZE != 0 { + return Err(ZkCryptoError::InputLengthWrong(field_element_bytes.len())); + } + let mut public_inputs = Vec::new(); + for chunk in field_element_bytes.chunks(SCALAR_SIZE) { + public_inputs.push(FieldElementWrapper::deserialize(chunk)?); + } + Ok(public_inputs) + } +} + + +pub type CircomG1 = Vec; + +/// A G2 point in BN254 serialized as a vector of three vectors each being a vector of two strings +/// which are the canonical decimal representation of the coefficients of the projective coordinates +/// in Fq2. +pub type CircomG2 = Vec>; + +/// A struct that stores a Bn254 Fq field element as 32 bytes. +#[derive(Debug, Clone, JsonSchema, Eq, PartialEq)] +pub struct Bn254FqElementWrapper(#[schemars(with = "String")] [u8; 32]); + +impl std::str::FromStr for Bn254FqElementWrapper { + type Err = ZkCryptoError; + + fn from_str(s: &str) -> Result { + let big_int = Fq::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; + let be_bytes = big_int.into_bigint().to_bytes_be(); + be_bytes + .try_into() + .map_err(|_| ZkCryptoError::InvalidInput) + .map(Bn254FqElementWrapper) + } +} + +impl std::fmt::Display for Bn254FqElementWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let big_int = BigUint::from_bytes_be(&self.0); + let radix10 = big_int.to_string(); + f.write_str(&radix10) + } +} + +// Bn254FqElement's serialized format is as a radix10 encoded string +impl Serialize for Bn254FqElementWrapper { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bn254FqElementWrapper { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; + std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) + } +} + +/// A struct that stores a Bn254 Fr field element as 32 bytes. +#[derive(Debug, Clone, JsonSchema, Eq, PartialEq)] +pub struct Bn254FrElementWrapper(#[schemars(with = "String")] [u8; 32]); + +impl Bn254FrElementWrapper { + /// Returns the unpadded version of the field element. This returns with leading zeros removed. + pub fn unpadded(&self) -> &[u8] { + let mut buf = self.0.as_slice(); + + while !buf.is_empty() && buf[0] == 0 { + buf = &buf[1..]; + } + + // If the value is '0' then just return a slice of length 1 of the final byte + if buf.is_empty() { + &self.0[31..] + } else { + buf + } + } + + /// Returns the padded version of the field element. This returns with leading zeros preserved to 32 bytes. + pub fn padded(&self) -> &[u8] { + &self.0 + } +} +impl std::str::FromStr for Bn254FrElementWrapper { + type Err = ZkCryptoError; + + fn from_str(s: &str) -> Result { + let big_int = Fr::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; + let be_bytes = big_int.into_bigint().to_bytes_be(); + be_bytes + .try_into() + .map_err(|_| ZkCryptoError::InvalidInput) + .map(Bn254FrElementWrapper) + } +} + +impl std::fmt::Display for Bn254FrElementWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let big_int = BigUint::from_bytes_be(&self.0); + let radix10 = big_int.to_string(); + f.write_str(&radix10) + } +} + +// Bn254FrElement's serialized format is as a radix10 encoded string +impl Serialize for Bn254FrElementWrapper { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bn254FrElementWrapper { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; + std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) + } +} + +/// Convert Bn254FqElement type to arkworks' Fq. +impl From<&Bn254FqElementWrapper> for Fq { + fn from(f: &Bn254FqElementWrapper) -> Self { + Fq::from_be_bytes_mod_order(&f.0) + } +} + +/// Convert Bn254FrElement type to arkworks' Fr. +impl From<&Bn254FrElementWrapper> for Fr { + fn from(f: &Bn254FrElementWrapper) -> Self { + Fr::from_be_bytes_mod_order(&f.0) + } +} + +/// Deserialize a G1 projective point in BN254 serialized as a vector of three strings into an affine +/// G1 point in arkworks format. Return an error if the input is not a vector of three strings or if +/// any of the strings cannot be parsed as a field element. +pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result { + if s.len() != 3 { + return Err(ZkCryptoError::InvalidInput); + } + + let g1: G1Affine = + G1Projective::new_unchecked((&s[0]).into(), (&s[1]).into(), (&s[2]).into()).into(); + + if !g1.is_on_curve() || !g1.is_in_correct_subgroup_assuming_on_curve() { + return Err(ZkCryptoError::InvalidInput); + } + + Ok(g1) +} + +/// Deserialize a G2 projective point from the BN254 construction serialized as a vector of three +/// vectors each being a vector of two strings into an affine G2 point in arkworks format. Return an +/// error if the input is not a vector of the right format or if any of the strings cannot be parsed +/// as a field element. +pub(crate) fn g2_affine_from_str_projective(s: &CircomG2) -> Result { + if s.len() != 3 || s[0].len() != 2 || s[1].len() != 2 || s[2].len() != 2 { + return Err(ZkCryptoError::InvalidInput); + } + + let g2: G2Affine = G2Projective::new_unchecked( + Fq2::new((&s[0][0]).into(), (&s[0][1]).into()), + Fq2::new((&s[1][0]).into(), (&s[1][1]).into()), + Fq2::new((&s[2][0]).into(), (&s[2][1]).into()), + ) + .into(); + + if !g2.is_on_curve() || !g2.is_in_correct_subgroup_assuming_on_curve() { + return Err(ZkCryptoError::InvalidInput); + } + + Ok(g2) +} + + +/// A Groth16 proof in the BN254 construction. Thin wrapper around `ark_groth16::Proof::`. +#[derive(Debug, From)] +pub struct ProofWrapper(pub(crate) ark_groth16::Proof); + +impl ProofWrapper { + /// Deserialize a serialized Groth16 proof using arkworks' canonical serialisation format: https://docs.rs/ark-serialize/latest/ark_serialize/. + pub fn deserialize(proof_points_as_bytes: &[u8]) -> ZkCryptoResult { + ark_groth16::Proof::::deserialize_compressed(proof_points_as_bytes) + .map_err(|_| ZkCryptoError::InvalidInput) + .map(ProofWrapper) + } +} + + +/** + Here there are third party zk login Groth16 verification keys taken for now for tests + todo: will be replaced by our keys later + todo: move all key data to json config file (?), use hash as id +**/ + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +//static GLOBAL_VERIFYING_KEY: Lazy> = Lazy::new(global_pvk); + +/// Corresponding to proofs generated from prover-dev. Used in devnet/testnet. +//static INSECURE_VERIFYING_KEY: Lazy> = Lazy::new(insecure_pvk); + +//static ZKP_VERIFYING_KEYS: Lazy>> = Lazy::new(keys); + +//todo: will contain our keys later, key ould be a hash of verification key +/*fn keys() -> HashMap> { + let mut h = HashMap::new(); + h.insert(0, insecure_pvk()); + h.insert(1, global_pvk()); + h +}*/ + +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +fn insecure_pvk() -> PreparedVerifyingKey { + // Convert the Circom G1/G2/GT to arkworks G1/G2/GT + let vk_alpha_1 = g1_affine_from_str_projective(&vec![ + Bn254FqElementWrapper::from_str( + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "9383485363053290200918347156157836566562967994039712273449902621266178545958", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ]) + .unwrap(); + let vk_beta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4252822878758300859123897981450591353533073413197771768651442665752259397132", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "21847035105528745403288232691147584728191162732299865338377159692350059136679", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + let vk_gamma_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + let vk_delta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + + // Create a vector of G1Affine elements from the IC + let mut vk_gamma_abc_g1 = Vec::new(); + for e in [ + vec![ + Bn254FqElementWrapper::from_str( + "20701306374481714853949730154526815782802808896228594855451770849676897643964", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "2766989084754673216772682210231588284954002353414778477810174100808747060165", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "501195541410525737371980194958674422793469475773065719916327137354779402600", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "13527631693157515024233848630878973193664410306029731429350155106228769355415", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + ] { + let g1 = g1_affine_from_str_projective(&e).unwrap(); + vk_gamma_abc_g1.push(g1); + } + + let vk = VerifyingKey { + alpha_g1: vk_alpha_1, + beta_g2: vk_beta_2, + gamma_g2: vk_gamma_2, + delta_g2: vk_delta_2, + gamma_abc_g1: vk_gamma_abc_g1, + }; + + // Convert the verifying key into the prepared form. + PreparedVerifyingKey::from(vk) +} + +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +fn global_pvk() -> PreparedVerifyingKey { + // Convert the Circom G1/G2/GT to arkworks G1/G2/GT + let vk_alpha_1 = g1_affine_from_str_projective(&vec![ + Bn254FqElementWrapper::from_str( + "21529901943976716921335152104180790524318946701278905588288070441048877064089", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "7775817982019986089115946956794180159548389285968353014325286374017358010641", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ]) + .unwrap(); + let vk_beta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "6600437987682835329040464538375790690815756241121776438004683031791078085074", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "16207344858883952201936462217289725998755030546200154201671892670464461194903", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "17943105074568074607580970189766801116106680981075272363121544016828311544390", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "18339640667362802607939727433487930605412455701857832124655129852540230493587", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + let vk_gamma_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + let vk_delta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "19260309516619721648285279557078789954438346514188902804737557357941293711874", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "2480422554560175324649200374556411861037961022026590718777465211464278308900", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "14489104692423540990601374549557603533921811847080812036788172274404299703364", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "12564378633583954025611992187142343628816140907276948128970903673042690269191", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + + // Create a vector of G1Affine elements from the IC + let mut vk_gamma_abc_g1 = Vec::new(); + for e in [ + vec![ + Bn254FqElementWrapper::from_str( + "1607694606386445293170795095076356565829000940041894770459712091642365695804", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "18066827569413962196795937356879694709963206118612267170825707780758040578649", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "20653794344898475822834426774542692225449366952113790098812854265588083247207", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "3296759704176575765409730962060698204792513807296274014163938591826372646699", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + ] { + let g1 = g1_affine_from_str_projective(&e).unwrap(); + vk_gamma_abc_g1.push(g1); + } + + let vk = VerifyingKey { + alpha_g1: vk_alpha_1, + beta_g2: vk_beta_2, + gamma_g2: vk_gamma_2, + delta_g2: vk_delta_2, + gamma_abc_g1: vk_gamma_abc_g1, + }; + + // Convert the verifying key into the prepared form. + PreparedVerifyingKey::from(vk) +} +/////////////////////////////////// + + +/* +{ + "protocol": "groth16", + "curve": "bn128", + "nPublic": 1, + "vk_alpha_1": [ + "16083174311393072332126484955039141051820368387551336007741432494536231879877", + "11995344593741129498206341608147577676708407993917230939676252851997423446210", + "1" + ], + "vk_beta_2": [ + [ + "7017589137241388812217334676878160715759313595646525247042913539379033763831", + "9588720105182136304988839277158105754318461657916765428451866781594135026063" + ], + [ + "2484424409632768920146683103978991861859052149379216050446911519906662584090", + "3390288516800701266276631045627865236740814264026178914799455551851945389106" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ], + [ + "1", + "0" + ] + ], + "vk_alphabeta_12": [ + [ + [ + "21714733147969646607026510860825588717650100219981797829057062263408210680902", + "3537008011880168200043686742311687201724399812943751195896776782786770376237" + ], + [ + "17603627875319511470028150667626739231437882724082498094331281187463632527978", + "16387102395026382896078557475195975755625086402782579280728310209714363840057" + ], + [ + "10167039699419387719397961362130358913333446306472876910740079573026549091749", + "6683396731874395214442048077624848369375657254618428851285341246028721012664" + ] + ], + [ + [ + "12883624783449422144000099623629921455607648590216105687641263583110919278339", + "9384401935718213548370561215738644696157076909382807246189505166565439193274" + ], + [ + "11443428859064566845483530360939187689156386007731719272145725927626704316158", + "534441300427034362842952165392761749478350428105140492258092586110074096069" + ], + [ + "1626464416056203606908509147988281610862706785412523317944442421120459947696", + "14642919198945900947469533820505010212370261142917394368657515679029120182987" + ] + ] + ], + "IC": [ + [ + "11760611693671517707466601638901224388668992590928868758649168369215563295744", + "15842561259007247784907604255150260908812200067246900457940460682994649597353", + "1" + ], + [ + "9960247968913608540350443520882802417817484595360267448450266543686043480996", + "11040490439713280236989540698814598402024610465375008410116396264618122562865", + "1" + ] + ] +} + */ + + + +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +fn my_test_pvk_1() -> PreparedVerifyingKey { + // Convert the Circom G1/G2/GT to arkworks G1/G2/GT + let vk_alpha_1 = g1_affine_from_str_projective(&vec![ + Bn254FqElementWrapper::from_str( + "16083174311393072332126484955039141051820368387551336007741432494536231879877", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11995344593741129498206341608147577676708407993917230939676252851997423446210", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ]) + .unwrap(); + /* + "16083174311393072332126484955039141051820368387551336007741432494536231879877", + "11995344593741129498206341608147577676708407993917230939676252851997423446210", + */ + + + let vk_beta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "7017589137241388812217334676878160715759313595646525247042913539379033763831", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "9588720105182136304988839277158105754318461657916765428451866781594135026063", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "2484424409632768920146683103978991861859052149379216050446911519906662584090", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "3390288516800701266276631045627865236740814264026178914799455551851945389106", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + /* + [ + "7017589137241388812217334676878160715759313595646525247042913539379033763831", + "9588720105182136304988839277158105754318461657916765428451866781594135026063" + ], + [ + "2484424409632768920146683103978991861859052149379216050446911519906662584090", + "3390288516800701266276631045627865236740814264026178914799455551851945389106" + ] + */ + + + + + + let vk_gamma_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + + /* + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ] + */ + + + + + let vk_delta_2 = g2_affine_from_str_projective(&vec![ + vec![ + Bn254FqElementWrapper::from_str( + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ) + .unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str("1").unwrap(), + Bn254FqElementWrapper::from_str("0").unwrap(), + ], + ]) + .unwrap(); + + /* + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634" + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531" + ] + */ + + // Create a vector of G1Affine elements from the IC + let mut vk_gamma_abc_g1 = Vec::new(); + for e in [ + vec![ + Bn254FqElementWrapper::from_str( + "11760611693671517707466601638901224388668992590928868758649168369215563295744", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "15842561259007247784907604255150260908812200067246900457940460682994649597353", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + vec![ + Bn254FqElementWrapper::from_str( + "9960247968913608540350443520882802417817484595360267448450266543686043480996", + ) + .unwrap(), + Bn254FqElementWrapper::from_str( + "11040490439713280236989540698814598402024610465375008410116396264618122562865", + ) + .unwrap(), + Bn254FqElementWrapper::from_str("1").unwrap(), + ], + ] { + let g1 = g1_affine_from_str_projective(&e).unwrap(); + vk_gamma_abc_g1.push(g1); + } + + /* + [ + [ + "11760611693671517707466601638901224388668992590928868758649168369215563295744", + "15842561259007247784907604255150260908812200067246900457940460682994649597353", + "1" + ], + [ + "9960247968913608540350443520882802417817484595360267448450266543686043480996", + "11040490439713280236989540698814598402024610465375008410116396264618122562865", + "1" + ] + ] + */ + + + + let vk = VerifyingKey { + alpha_g1: vk_alpha_1, + beta_g2: vk_beta_2, + gamma_g2: vk_gamma_2, + delta_g2: vk_delta_2, + gamma_abc_g1: vk_gamma_abc_g1, + }; + + // Convert the verifying key into the prepared form. + PreparedVerifyingKey::from(vk) +} + + +pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { + let start = Instant::now(); + engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16_NEW"))?; + fetch_stack(engine, 3); + + let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; + println!("from vergrth16 vk_index: {:?}", vk_index); + + let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; + let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; + println!("from vergrth16 value public_inputs_as_bytes: {:?}", public_inputs_as_bytes); + + let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; + let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; + println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); + + let proof = ProofWrapper::deserialize(&proof_as_bytes)?; + let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; + let x: Vec = public_inputs.iter().map(|x| x.0).collect(); + + let vk = if (vk_index == 0) { + insecure_pvk() + } else if (vk_index == 1) { + global_pvk() + } else { + my_test_pvk_1() + }; + + + //ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; + println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); + //todo: add alternative for elliptic curve (may be we need bls curve also?), read from stack curve id + let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) + .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); + + let duration = start.elapsed(); + + println!("Time elapsed by vergrth16 is: {:?}", duration); + + let succes = res.is_ok(); + println!("res: {:?}", res); + let res = if (succes) { + boolean!(res.unwrap()) + } + else { + boolean!(false) + }; + println!("res: {:?}", res); + + engine.cc.stack.push(res); + + Ok(()) +} + +pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { + let start = Instant::now(); + engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16"))?; + fetch_stack(engine, 3); + + let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; + println!("from vergrth16 vk_index: {:?}", vk_index); + + + let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; + let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; + println!("from vergrth16 value public_inputs_as_bytes: {:?}", public_inputs_as_bytes); + + let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; + let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; + println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); + + let proof = ProofWrapper::deserialize(&proof_as_bytes)?; + let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; + let x: Vec = public_inputs.iter().map(|x| x.0).collect(); + + let vk = if (vk_index == 0) { + insecure_pvk() + } else if (vk_index == 1) { + global_pvk() + } else { + my_test_pvk_1() + }; + + //ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; + println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); + //todo: add alternative for elliptic curve (may be we need bls curve also?), read from stack curve id + let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) + .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); + + let duration = start.elapsed(); + + println!("Time elapsed by vergrth16 is: {:?}", duration); + + + let succes = res.is_ok(); + println!("res: {:?}", res); + let res = if (succes) { + boolean!(res.unwrap()) + } + else { + boolean!(false) + }; + println!("res: {:?}", res); + + engine.cc.stack.push(res); + + Ok(()) +} + +fn pop(barry: &[u8]) -> &[u8; 8] { + barry.try_into().expect("slice with incorrect length") +} + +pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { + engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; + //fetch_stack(engine, 4); + fetch_stack(engine, 5); + + let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; + let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; + println!("from poseidon value zkaddr: {:?}", zkaddr); + + /*let epk_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; + let epk_as_bytes = unpack_data_from_cell(epk_slice, engine)?; + println!("from poseidon value epk_as_bytes: {:?}", hex::encode(epk_as_bytes.clone()));*/ + + let header_and_iss_base64_slice = SliceData::load_cell_ref(engine.cmd.var(1 /*2*/).as_cell()?)?; + let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; + println!("from poseidon value header_and_iss_base64: {:?}", header_and_iss_base64); + + let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2 /*3*/).as_cell()?)?; + let modulus = unpack_data_from_cell(modulus_slice, engine)?; + println!("from poseidon value modulus: {:?}",modulus); + + + let eph_pub_key = engine + .cmd + .var(3 /*4*/) + .as_integer()? + .as_builder::(/*PUBLIC_KEY_BITS*/ 256)?; + + let eph_pub_key_bytes = eph_pub_key.data(); + + println!("from poseidon value eph_pub_key_bytes: {:?}",eph_pub_key_bytes.len()); + println!("from poseidon value eph_pub_key_bytes: {:?}",eph_pub_key_bytes); + + let max_epoch_ = engine + .cmd + .var(4 /*4*/) + .as_integer()? + .as_builder::(/*PUBLIC_KEY_BITS*/ 64)?; + + let max_epoch_bytes = pop(max_epoch_.data()); + let max_epoch = u64::from_be_bytes(*max_epoch_bytes); + + println!("from poseidon value max_epoch: {:?}",max_epoch); + + println!("from poseidon value max_epoch_bytes: {:?}",max_epoch_bytes.len()); + println!("from poseidon value max_epoch_bytes: {:?}",max_epoch_bytes); + + + //let max_epoch = 10; //todo: read from stack later + //let max_epoch = 142; + + let public_inputs = calculate_poseidon_hash( + &*zkaddr, + &*header_and_iss_base64, + &eph_pub_key_bytes/*epk_as_bytes*/, + &modulus, + max_epoch + ).unwrap(); + + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("from poseidon public_inputs_as_bytes : {:?}", public_inputs_as_bytes.clone()); + //println!("from poseidon public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + engine.cc.stack.push(Cell(public_inputs_cell)); + + Ok(()) + +} + + +pub fn calculate_poseidon_hash( + address_seed: &str, + header_and_iss_base64: &str, + eph_pk_bytes: &[u8], + modulus: &[u8], + max_epoch: u64) -> Result/**/ { + /*if header_base64.len() > MAX_HEADER_LEN as usize { + return Err(ZkCryptoError::GeneralError("Header too long".to_string())); + }*/ + + let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); + let addr_seed = (&address_seed).into(); + + let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); + + let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); + + let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); + + let header_base64 = v["headerBase64"].as_str().unwrap(); + println!("header_base64 {}", header_base64); + + let issBase64Details = v["issBase64Details"].as_object().unwrap(); + println!("issBase64Details {:?}", issBase64Details); + + let index_mod_4 = issBase64Details["indexMod4"].as_i64().unwrap().to_string(); + + println!("index_mod_4 {:?}", index_mod_4); + + let iss_base64_details_value = issBase64Details["value"].as_str().unwrap(); + + println!("iss_base64_details_value {:?}", iss_base64_details_value); + + let index_mod_4_f = + (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); + + let iss_base64_f = + hash_ascii_str_to_field(&iss_base64_details_value, MAX_ISS_LEN_B64).unwrap(); + let header_f = hash_ascii_str_to_field(&header_base64, MAX_HEADER_LEN).unwrap(); + let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); + + poseidon_zk_login(vec![ + first, + second, + addr_seed, + max_epoch_f, + iss_base64_f, + index_mod_4_f, + header_f, + modulus_f, + ]) +} + + + + + diff --git a/tvm_vm/src/executor/zk_stuff/bn254/api.rs b/tvm_vm/src/executor/zk_stuff/bn254/api.rs new file mode 100644 index 00000000..687d373b --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/bn254/api.rs @@ -0,0 +1,56 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; +use crate::executor::zk_stuff::bn254::{FieldElement, Proof, VerifyingKey}; +use crate::executor::zk_stuff::error::ZkCryptoError; + +//#[cfg(test)] +//#[path = "unit_tests/api_tests.rs"] +//mod api_tests; + +/// Size of scalars in the BN254 construction. +pub const SCALAR_SIZE: usize = 32; + +/// Deserialize bytes as an Arkwork representation of a verifying key, and return a vector of the +/// four components of a prepared verified key (see more at [`PreparedVerifyingKey`]). +pub fn prepare_pvk_bytes(vk_bytes: &[u8]) -> Result>, ZkCryptoError> { + PreparedVerifyingKey::from(&VerifyingKey::deserialize(vk_bytes)?).serialize() +} + +/// Verify Groth16 proof using the serialized form of the prepared verifying key (see more at +/// [`crate::bn254::verifier::PreparedVerifyingKey`]), serialized proof public input and serialized +/// proof points. +pub fn verify_groth16_in_bytes( + vk_gamma_abc_g1_bytes: &[u8], + alpha_g1_beta_g2_bytes: &[u8], + gamma_g2_neg_pc_bytes: &[u8], + delta_g2_neg_pc_bytes: &[u8], + proof_public_inputs_as_bytes: &[u8], + proof_points_as_bytes: &[u8], +) -> Result { + if proof_public_inputs_as_bytes.len() % SCALAR_SIZE != 0 { + return Err(ZkCryptoError::InputLengthWrong(SCALAR_SIZE)); + } + + let pvk = PreparedVerifyingKey::deserialize(&vec![ + vk_gamma_abc_g1_bytes, + alpha_g1_beta_g2_bytes, + gamma_g2_neg_pc_bytes, + delta_g2_neg_pc_bytes, + ])?; + + verify_groth16(&pvk, proof_public_inputs_as_bytes, proof_points_as_bytes) +} + +/// Verify proof with a given verifying key in [struct PreparedVerifyingKey], serialized public inputs +/// and serialized proof points. +pub fn verify_groth16( + pvk: &PreparedVerifyingKey, + proof_public_inputs_as_bytes: &[u8], + proof_points_as_bytes: &[u8], +) -> Result { + let proof = Proof::deserialize(proof_points_as_bytes)?; + let public_inputs = FieldElement::deserialize_vector(proof_public_inputs_as_bytes)?; + pvk.verify(&public_inputs, &proof) +} diff --git a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs new file mode 100644 index 00000000..81c45ab2 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs @@ -0,0 +1,79 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +#![warn(missing_docs, unreachable_pub)] +#![deny(unused_must_use, missing_debug_implementations)] +//! Groth16 verifier over the BN254 elliptic curve construction. + +use crate::executor::zk_stuff::bn254::api::SCALAR_SIZE; +use ark_bn254::{Bn254, Fr}; +use ark_serialize::CanonicalDeserialize; +use derive_more::From; +use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; + +/// API that takes in serialized inputs +pub mod api; + +/// Groth16 SNARK verifier +pub mod verifier; + +/// Poseidon hash function over BN254 +pub mod poseidon; + +/// Zk login structs and utilities +//pub mod zk_login; + +/// Zk login entrypoints +//pub mod zk_login_api; + +/// Zk login utils +//pub mod utils; + + + +/// A field element in the BN254 construction. Thin wrapper around `api::Bn254Fr`. +#[derive(Debug, From)] +pub struct FieldElement(pub(crate) ark_bn254::Fr); + +/// A Groth16 proof in the BN254 construction. Thin wrapper around `ark_groth16::Proof::`. +#[derive(Debug, From)] +pub struct Proof(pub(crate) ark_groth16::Proof); + +/// A Groth16 verifying key in the BN254 construction. Thin wrapper around `ark_groth16::VerifyingKey::`. +#[derive(Debug, From)] +pub struct VerifyingKey(pub(crate) ark_groth16::VerifyingKey); + +impl Proof { + /// Deserialize a serialized Groth16 proof using arkworks' canonical serialisation format: https://docs.rs/ark-serialize/latest/ark_serialize/. + pub fn deserialize(proof_points_as_bytes: &[u8]) -> ZkCryptoResult { + ark_groth16::Proof::::deserialize_compressed(proof_points_as_bytes) + .map_err(|_| ZkCryptoError::InvalidInput) + .map(Proof) + } +} + +impl FieldElement { + /// Deserialize 32 bytes into a BN254 field element using little-endian format. + pub(crate) fn deserialize(bytes: &[u8]) -> ZkCryptoResult { + if bytes.len() != SCALAR_SIZE { + return Err(ZkCryptoError::InputLengthWrong(bytes.len())); + } + Fr::deserialize_compressed(bytes) + .map_err(|_| ZkCryptoError::InvalidInput) + .map(FieldElement) + } + + /// Deserialize a vector of bytes into a vector of BN254 field elements, assuming that each element + /// is serialized as a chunk of 32 bytes. See also [`FieldElement::deserialize`]. + pub(crate) fn deserialize_vector( + field_element_bytes: &[u8], + ) -> ZkCryptoResult> { + if field_element_bytes.len() % SCALAR_SIZE != 0 { + return Err(ZkCryptoError::InputLengthWrong(field_element_bytes.len())); + } + let mut public_inputs = Vec::new(); + for chunk in field_element_bytes.chunks(SCALAR_SIZE) { + public_inputs.push(FieldElement::deserialize(chunk)?); + } + Ok(public_inputs) + } +} diff --git a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs new file mode 100644 index 00000000..5f817ba2 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs @@ -0,0 +1,13124 @@ + + +use crate::executor::zk_stuff::Fr; +use ff::PrimeField; +use neptune::hash_type::HashType; +use neptune::poseidon::PoseidonConstants; +use neptune::Strength; +use once_cell::sync::Lazy; +use typenum::Unsigned; +use typenum::{U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9}; + +#[derive(Debug)] +pub(crate) struct Constants { + pub(crate) constants: Vec>, + pub(crate) matrices: Vec>>, + pub(crate) full_rounds: usize, + pub(crate) partial_rounds: Vec, +} + +/// Load constants for the poseidon hash function. +pub(crate) fn load_constants() -> Constants { + let (constants_strings, matrices_strings) = constants(); + + let constants = constants_strings + .iter() + .map(|c| { + c.iter() + .map(|ci| Fr::from_str_vartime(ci).unwrap()) + .collect() + }) + .collect(); + + let matrices = matrices_strings + .iter() + .map(|m| { + m.iter() + .map(|mi| { + mi.iter() + .map(|mij| Fr::from_str_vartime(mij).unwrap()) + .collect() + }) + .collect() + }) + .collect(); + + Constants { + constants, + matrices, + full_rounds: 8, + partial_rounds: vec![ + 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, + ], + } +} + +macro_rules! define_poseidon_constants { + ($constants:expr, $ui:ty) => {{ + let n = <$ui>::to_usize(); + let i = n - 1; + let m = &$constants.matrices[i]; + let c = &$constants.constants[i]; + PoseidonConstants::new_from_parameters( + n + 1, + m.clone(), + c.clone(), + $constants.full_rounds, + $constants.partial_rounds[i], + HashType::::Sponge, + Strength::Standard, + ) + }}; +} + +// TODO: CONSTANTS are not needed after all constants are loaded because they are cloned into the POSEIDON_CONSTANTs. +static CONSTANTS: Lazy = Lazy::new(load_constants); +pub(crate) static POSEIDON_CONSTANTS_U1: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U1)); +pub(crate) static POSEIDON_CONSTANTS_U2: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U2)); +pub(crate) static POSEIDON_CONSTANTS_U3: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U3)); +pub(crate) static POSEIDON_CONSTANTS_U4: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U4)); +pub(crate) static POSEIDON_CONSTANTS_U5: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U5)); +pub(crate) static POSEIDON_CONSTANTS_U6: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U6)); +pub(crate) static POSEIDON_CONSTANTS_U7: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U7)); +pub(crate) static POSEIDON_CONSTANTS_U8: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U8)); +pub(crate) static POSEIDON_CONSTANTS_U9: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U9)); +pub(crate) static POSEIDON_CONSTANTS_U10: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U10)); +pub(crate) static POSEIDON_CONSTANTS_U11: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U11)); +pub(crate) static POSEIDON_CONSTANTS_U12: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U12)); +pub(crate) static POSEIDON_CONSTANTS_U13: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U13)); +pub(crate) static POSEIDON_CONSTANTS_U14: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U14)); +pub(crate) static POSEIDON_CONSTANTS_U15: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U15)); +pub(crate) static POSEIDON_CONSTANTS_U16: Lazy> = + Lazy::new(|| define_poseidon_constants!(CONSTANTS, U16)); + +/// Constants taken from poseidon-ark. +fn constants() -> (Vec>, Vec>>) { + let c_str: Vec> = vec![ + vec![ + "4417881134626180770308697923359573201005643519861877412381846989312604493735", + "5433650512959517612316327474713065966758808864213826738576266661723522780033", + "13641176377184356099764086973022553863760045607496549923679278773208775739952", + "17949713444224994136330421782109149544629237834775211751417461773584374506783", + "13765628375339178273710281891027109699578766420463125835325926111705201856003", + "19179513468172002314585757290678967643352171735526887944518845346318719730387", + "5157412437176756884543472904098424903141745259452875378101256928559722612176", + "535160875740282236955320458485730000677124519901643397458212725410971557409", + "1050793453380762984940163090920066886770841063557081906093018330633089036729", + "10665495010329663932664894101216428400933984666065399374198502106997623173873", + "19965634623406616956648724894636666805991993496469370618546874926025059150737", + "13007250030070838431593222885902415182312449212965120303174723305710127422213", + "16877538715074991604507979123743768693428157847423939051086744213162455276374", + "18211747749504876135588847560312685184956239426147543810126553367063157141465", + "18151553319826126919739798892854572062191241985315767086020821632812331245635", + "19957033149976712666746140949846950406660099037474791840946955175819555930825", + "3469514863538261843186854830917934449567467100548474599735384052339577040841", + "989698510043911779243192466312362856042600749099921773896924315611668507708", + "12568377015646290945235387813564567111330046038050864455358059568128000172201", + "20856104135605479600325529349246932565148587186338606236677138505306779314172", + "8206918720503535523121349917159924938835810381723474192155637697065780938424", + "1309058477013932989380617265069188723120054926187607548493110334522527703566", + "14076116939332667074621703729512195584105250395163383769419390236426287710606", + "10153498892749751942204288991871286290442690932856658983589258153608012428674", + "18202499207234128286137597834010475797175973146805180988367589376893530181575", + "12739388830157083522877690211447248168864006284243907142044329113461613743052", + "15123358710467780770838026754240340042441262572309759635224051333176022613949", + "19925004701844594370904593774447343836015483888496504201331110250494635362184", + "10352416606816998476681131583320899030072315953910679608943150613208329645891", + "10567371822366244361703342347428230537114808440249611395507235283708966113221", + "5635498582763880627392290206431559361272660937399944184533035305989295959602", + "11866432933224219174041051738704352719163271639958083608224676028593315904909", + "5795020705294401441272215064554385591292330721703923167136157291459784140431", + "9482202378699252817564375087302794636287866584767523335624368774856230692758", + "4245237636894546151746468406560945873445548423466753843402086544922216329298", + "12000500941313982757584712677991730019124834399479314697467598397927435905133", + "7596790274058425558167520209857956363736666939016807569082239187494363541787", + "2484867918246116343205467273440098378820186751202461278013576281097918148877", + "18312645949449997391810445935615409295369169383463185688973803378104013950190", + "15320686572748723004980855263301182130424010735782762814513954166519592552733", + "12618438900597948888520621062416758747872180395546164387827245287017031303859", + "17438141672027706116733201008397064011774368832458707512367404736905021019585", + "6374197807230665998865688675365359100400438034755781666913068586172586548950", + "2189398913433273865510950346186699930188746169476472274335177556702504595264", + "6268495580028970231803791523870131137294646402347399003576649137450213034606", + "17896250365994900261202920044129628104272791547990619503076839618914047059275", + "13692156312448722528008862371944543449350293305158722920787736248435893008873", + "15234446864368744483209945022439268713300180233589581910497691316744177619376", + "1572426502623310766593681563281600503979671244997798691029595521622402217227", + "80103447810215150918585162168214870083573048458555897999822831203653996617", + "8228820324013669567851850635126713973797711779951230446503353812192849106342", + "5375851433746509614045812476958526065449377558695752132494533666370449415873", + "12115998939203497346386774317892338270561208357481805380546938146796257365018", + "9764067909645821279940531410531154041386008396840887338272986634350423466622", + "8538708244538850542384936174629541085495830544298260335345008245230827876882", + "7140127896620013355910287215441004676619168261422440177712039790284719613114", + "14297402962228458726038826185823085337698917275385741292940049024977027409762", + "6667115556431351074165934212337261254608231545257434281887966406956835140819", + "20226761165244293291042617464655196752671169026542832236139342122602741090001", + "12038289506489256655759141386763477208196694421666339040483042079632134429119", + "19027757334170818571203982241812412991528769934917288000224335655934473717551", + "16272152964456553579565580463468069884359929612321610357528838696790370074720", + "2500392889689246014710135696485946334448570271481948765283016105301740284071", + "8595254970528530312401637448610398388203855633951264114100575485022581946023", + "11635945688914011450976408058407206367914559009113158286982919675551688078198", + "614739068603482619581328040478536306925147663946742687395148680260956671871", + "18692271780377861570175282183255720350972693125537599213951106550953176268753", + "4987059230784976306647166378298632695585915319042844495357753339378260807164", + "21851403978498723616722415377430107676258664746210815234490134600998983955497", + "9830635451186415300891533983087800047564037813328875992115573428596207326204", + "4842706106434537116860242620706030229206345167233200482994958847436425185478", + "6422235064906823218421386871122109085799298052314922856340127798647926126490", + "4564364104986856861943331689105797031330091877115997069096365671501473357846", + "1944043894089780613038197112872830569538541856657037469098448708685350671343", + "21179865974855950600518216085229498748425990426231530451599322283119880194955", + "14296697761894107574369608843560006996183955751502547883167824879840894933162", + "12274619649702218570450581712439138337725246879938860735460378251639845671898", + "16371396450276899401411886674029075408418848209575273031725505038938314070356", + "3702561221750983937578095019779188631407216522704543451228773892695044653565", + "19721616877735564664624984774636557499099875603996426215495516594530838681980", + "6383350109027696789969911008057747025018308755462287526819231672217685282429", + "20860583956177367265984596617324237471765572961978977333122281041544719622905", + "5766390934595026947545001478457407504285452477687752470140790011329357286275", + "4043175758319898049344746138515323336207420888499903387536875603879441092484", + "15579382179133608217098622223834161692266188678101563820988612253342538956534", + "1864640783252634743892105383926602930909039567065240010338908865509831749824", + "15943719865023133586707144161652035291705809358178262514871056013754142625673", + "2326415993032390211558498780803238091925402878871059708106213703504162832999", + "19995326402773833553207196590622808505547443523750970375738981396588337910289", + "5143583711361588952673350526320181330406047695593201009385718506918735286622", + "15436006486881920976813738625999473183944244531070780793506388892313517319583", + "16660446760173633166698660166238066533278664023818938868110282615200613695857", + "4966065365695755376133119391352131079892396024584848298231004326013366253934", + "20683781957411705574951987677641476019618457561419278856689645563561076926702", + "17280836839165902792086432296371645107551519324565649849400948918605456875699", + "17045635513701208892073056357048619435743564064921155892004135325530808465371", + "17055032967194400710390142791334572297458033582458169295920670679093585707295", + "15727174639569115300068198908071514334002742825679221638729902577962862163505", + "1001755657610446661315902885492677747789366510875120894840818704741370398633", + "18638547332826171619311285502376343504539399518545103511265465604926625041234", + "6751954224763196429755298529194402870632445298969935050224267844020826420799", + "3526747115904224771452549517614107688674036840088422555827581348280834879405", + "15705897908180497062880001271426561999724005008972544196300715293701537574122", + "574386695213920937259007343820417029802510752426579750428758189312416867750", + "15973040855000600860816974646787367136127946402908768408978806375685439868553", + "20934130413948796333037139460875996342810005558806621330680156931816867321122", + "6918585327145564636398173845411579411526758237572034236476079610890705810764", + "14158163500813182062258176233162498241310167509137716527054939926126453647182", + "4164602626597695668474100217150111342272610479949122406544277384862187287433", + "12146526846507496913615390662823936206892812880963914267275606265272996025304", + "10153527926900017763244212043512822363696541810586522108597162891799345289938", + "13564663485965299104296214940873270349072051793008946663855767889066202733588", + "5612449256997576125867742696783020582952387615430650198777254717398552960096", + "12151885480032032868507892738683067544172874895736290365318623681886999930120", + "380452237704664384810613424095477896605414037288009963200982915188629772177", + "9067557551252570188533509616805287919563636482030947363841198066124642069518", + "21280306817619711661335268484199763923870315733198162896599997188206277056900", + "5567165819557297006750252582140767993422097822227408837378089569369734876257", + "10411936321072105429908396649383171465939606386380071222095155850987201580137", + "21338390051413922944780864872652000187403217966653363270851298678606449622266", + "12156296560457833712186127325312904760045212412680904475497938949653569234473", + "4271647814574748734312113971565139132510281260328947438246615707172526380757", + "9061738206062369647211128232833114177054715885442782773131292534862178874950", + "10134551893627587797380445583959894183158393780166496661696555422178052339133", + "8932270237664043612366044102088319242789325050842783721780970129656616386103", + "3339412934966886386194449782756711637636784424032779155216609410591712750636", + "9704903972004596791086522314847373103670545861209569267884026709445485704400", + "17467570179597572575614276429760169990940929887711661192333523245667228809456", + ], + vec![ + "6745197990210204598374042828761989596302876299545964402857411729872131034734", + "426281677759936592021316809065178817848084678679510574715894138690250139748", + "4014188762916583598888942667424965430287497824629657219807941460227372577781", + "21328925083209914769191926116470334003273872494252651254811226518870906634704", + "19525217621804205041825319248827370085205895195618474548469181956339322154226", + "1402547928439424661186498190603111095981986484908825517071607587179649375482", + "18320863691943690091503704046057443633081959680694199244583676572077409194605", + "17709820605501892134371743295301255810542620360751268064484461849423726103416", + "15970119011175710804034336110979394557344217932580634635707518729185096681010", + "9818625905832534778628436765635714771300533913823445439412501514317783880744", + "6235167673500273618358172865171408902079591030551453531218774338170981503478", + "12575685815457815780909564540589853169226710664203625668068862277336357031324", + "7381963244739421891665696965695211188125933529845348367882277882370864309593", + "14214782117460029685087903971105962785460806586237411939435376993762368956406", + "13382692957873425730537487257409819532582973556007555550953772737680185788165", + "2203881792421502412097043743980777162333765109810562102330023625047867378813", + "2916799379096386059941979057020673941967403377243798575982519638429287573544", + "4341714036313630002881786446132415875360643644216758539961571543427269293497", + "2340590164268886572738332390117165591168622939528604352383836760095320678310", + "5222233506067684445011741833180208249846813936652202885155168684515636170204", + "7963328565263035669460582454204125526132426321764384712313576357234706922961", + "1394121618978136816716817287892553782094854454366447781505650417569234586889", + "20251767894547536128245030306810919879363877532719496013176573522769484883301", + "141695147295366035069589946372747683366709960920818122842195372849143476473", + "15919677773886738212551540894030218900525794162097204800782557234189587084981", + "2616624285043480955310772600732442182691089413248613225596630696960447611520", + "4740655602437503003625476760295930165628853341577914460831224100471301981787", + "19201590924623513311141753466125212569043677014481753075022686585593991810752", + "12116486795864712158501385780203500958268173542001460756053597574143933465696", + "8481222075475748672358154589993007112877289817336436741649507712124418867136", + "5181207870440376967537721398591028675236553829547043817076573656878024336014", + "1576305643467537308202593927724028147293702201461402534316403041563704263752", + "2555752030748925341265856133642532487884589978209403118872788051695546807407", + "18840924862590752659304250828416640310422888056457367520753407434927494649454", + "14593453114436356872569019099482380600010961031449147888385564231161572479535", + "20826991704411880672028799007667199259549645488279985687894219600551387252871", + "9159011389589751902277217485643457078922343616356921337993871236707687166408", + "5605846325255071220412087261490782205304876403716989785167758520729893194481", + "1148784255964739709393622058074925404369763692117037208398835319441214134867", + "20945896491956417459309978192328611958993484165135279604807006821513499894540", + "229312996389666104692157009189660162223783309871515463857687414818018508814", + "21184391300727296923488439338697060571987191396173649012875080956309403646776", + "21853424399738097885762888601689700621597911601971608617330124755808946442758", + "12776298811140222029408960445729157525018582422120161448937390282915768616621", + "7556638921712565671493830639474905252516049452878366640087648712509680826732", + "19042212131548710076857572964084011858520620377048961573689299061399932349935", + "12871359356889933725034558434803294882039795794349132643274844130484166679697", + "3313271555224009399457959221795880655466141771467177849716499564904543504032", + "15080780006046305940429266707255063673138269243146576829483541808378091931472", + "21300668809180077730195066774916591829321297484129506780637389508430384679582", + "20480395468049323836126447690964858840772494303543046543729776750771407319822", + "10034492246236387932307199011778078115444704411143703430822959320969550003883", + "19584962776865783763416938001503258436032522042569001300175637333222729790225", + "20155726818439649091211122042505326538030503429443841583127932647435472711802", + "13313554736139368941495919643765094930693458639277286513236143495391474916777", + "14606609055603079181113315307204024259649959674048912770003912154260692161833", + "5563317320536360357019805881367133322562055054443943486481491020841431450882", + "10535419877021741166931390532371024954143141727751832596925779759801808223060", + "12025323200952647772051708095132262602424463606315130667435888188024371598063", + "2906495834492762782415522961458044920178260121151056598901462871824771097354", + "19131970618309428864375891649512521128588657129006772405220584460225143887876", + "8896386073442729425831367074375892129571226824899294414632856215758860965449", + "7748212315898910829925509969895667732958278025359537472413515465768989125274", + "422974903473869924285294686399247660575841594104291551918957116218939002865", + "6398251826151191010634405259351528880538837895394722626439957170031528482771", + "18978082967849498068717608127246258727629855559346799025101476822814831852169", + "19150742296744826773994641927898928595714611370355487304294875666791554590142", + "12896891575271590393203506752066427004153880610948642373943666975402674068209", + "9546270356416926575977159110423162512143435321217584886616658624852959369669", + "2159256158967802519099187112783460402410585039950369442740637803310736339200", + "8911064487437952102278704807713767893452045491852457406400757953039127292263", + "745203718271072817124702263707270113474103371777640557877379939715613501668", + "19313999467876585876087962875809436559985619524211587308123441305315685710594", + "13254105126478921521101199309550428567648131468564858698707378705299481802310", + "1842081783060652110083740461228060164332599013503094142244413855982571335453", + "9630707582521938235113899367442877106957117302212260601089037887382200262598", + "5066637850921463603001689152130702510691309665971848984551789224031532240292", + "4222575506342961001052323857466868245596202202118237252286417317084494678062", + "2919565560395273474653456663643621058897649501626354982855207508310069954086", + "6828792324689892364977311977277548750189770865063718432946006481461319858171", + "2245543836264212411244499299744964607957732316191654500700776604707526766099", + "19602444885919216544870739287153239096493385668743835386720501338355679311704", + "8239538512351936341605373169291864076963368674911219628966947078336484944367", + "15053013456316196458870481299866861595818749671771356646798978105863499965417", + "7173615418515925804810790963571435428017065786053377450925733428353831789901", + "8239211677777829016346247446855147819062679124993100113886842075069166957042", + "15330855478780269194281285878526984092296288422420009233557393252489043181621", + "10014883178425964324400942419088813432808659204697623248101862794157084619079", + "14014440630268834826103915635277409547403899966106389064645466381170788813506", + "3580284508947993352601712737893796312152276667249521401778537893620670305946", + "2559754020964039399020874042785294258009596917335212876725104742182177996988", + "14898657953331064524657146359621913343900897440154577299309964768812788279359", + "2094037260225570753385567402013028115218264157081728958845544426054943497065", + "18051086536715129874440142649831636862614413764019212222493256578581754875930", + "21680659279808524976004872421382255670910633119979692059689680820959727969489", + "13950668739013333802529221454188102772764935019081479852094403697438884885176", + "9703845704528288130475698300068368924202959408694460208903346143576482802458", + "12064310080154762977097567536495874701200266107682637369509532768346427148165", + "16970760937630487134309762150133050221647250855182482010338640862111040175223", + "9790997389841527686594908620011261506072956332346095631818178387333642218087", + "16314772317774781682315680698375079500119933343877658265473913556101283387175", + "82044870826814863425230825851780076663078706675282523830353041968943811739", + "21696416499108261787701615667919260888528264686979598953977501999747075085778", + "327771579314982889069767086599893095509690747425186236545716715062234528958", + "4606746338794869835346679399457321301521448510419912225455957310754258695442", + "64499140292086295251085369317820027058256893294990556166497635237544139149", + "10455028514626281809317431738697215395754892241565963900707779591201786416553", + "10421411526406559029881814534127830959833724368842872558146891658647152404488", + "18848084335930758908929996602136129516563864917028006334090900573158639401697", + "13844582069112758573505569452838731733665881813247931940917033313637916625267", + "13488838454403536473492810836925746129625931018303120152441617863324950564617", + "15742141787658576773362201234656079648895020623294182888893044264221895077688", + "6756884846734501741323584200608866954194124526254904154220230538416015199997", + "7860026400080412708388991924996537435137213401947704476935669541906823414404", + "7871040688194276447149361970364037034145427598711982334898258974993423182255", + "20758972836260983284101736686981180669442461217558708348216227791678564394086", + "21723241881201839361054939276225528403036494340235482225557493179929400043949", + "19428469330241922173653014973246050805326196062205770999171646238586440011910", + "7969200143746252148180468265998213908636952110398450526104077406933642389443", + "10950417916542216146808986264475443189195561844878185034086477052349738113024", + "18149233917533571579549129116652755182249709970669448788972210488823719849654", + "3729796741814967444466779622727009306670204996071028061336690366291718751463", + "5172504399789702452458550583224415301790558941194337190035441508103183388987", + "6686473297578275808822003704722284278892335730899287687997898239052863590235", + "19426913098142877404613120616123695099909113097119499573837343516470853338513", + "5120337081764243150760446206763109494847464512045895114970710519826059751800", + "5055737465570446530938379301905385631528718027725177854815404507095601126720", + "14235578612970484492268974539959119923625505766550088220840324058885914976980", + "653592517890187950103239281291172267359747551606210609563961204572842639923", + "5507360526092411682502736946959369987101940689834541471605074817375175870579", + "7864202866011437199771472205361912625244234597659755013419363091895334445453", + "21294659996736305811805196472076519801392453844037698272479731199885739891648", + "13767183507040326119772335839274719411331242166231012705169069242737428254651", + "810181532076738148308457416289197585577119693706380535394811298325092337781", + "14232321930654703053193240133923161848171310212544136614525040874814292190478", + "16796904728299128263054838299534612533844352058851230375569421467352578781209", + "16256310366973209550759123431979563367001604350120872788217761535379268327259", + "19791658638819031543640174069980007021961272701723090073894685478509001321817", + "7046232469803978873754056165670086532908888046886780200907660308846356865119", + "16001732848952745747636754668380555263330934909183814105655567108556497219752", + "9737276123084413897604802930591512772593843242069849260396983774140735981896", + "11410895086919039954381533622971292904413121053792570364694836768885182251535", + "19098362474249267294548762387533474746422711206129028436248281690105483603471", + "11013788190750472643548844759298623898218957233582881400726340624764440203586", + "2206958256327295151076063922661677909471794458896944583339625762978736821035", + "7171889270225471948987523104033632910444398328090760036609063776968837717795", + "2510237900514902891152324520472140114359583819338640775472608119384714834368", + "8825275525296082671615660088137472022727508654813239986303576303490504107418", + "1481125575303576470988538039195271612778457110700618040436600537924912146613", + "16268684562967416784133317570130804847322980788316762518215429249893668424280", + "4681491452239189664806745521067158092729838954919425311759965958272644506354", + "3131438137839074317765338377823608627360421824842227925080193892542578675835", + "7930402370812046914611776451748034256998580373012248216998696754202474945793", + "8973151117361309058790078507956716669068786070949641445408234962176963060145", + "10223139291409280771165469989652431067575076252562753663259473331031932716923", + "2232089286698717316374057160056566551249777684520809735680538268209217819725", + "16930089744400890347392540468934821520000065594669279286854302439710657571308", + "21739597952486540111798430281275997558482064077591840966152905690279247146674", + "7508315029150148468008716674010060103310093296969466203204862163743615534994", + "11418894863682894988747041469969889669847284797234703818032750410328384432224", + "10895338268862022698088163806301557188640023613155321294365781481663489837917", + "18644184384117747990653304688839904082421784959872380449968500304556054962449", + "7414443845282852488299349772251184564170443662081877445177167932875038836497", + "5391299369598751507276083947272874512197023231529277107201098701900193273851", + "10329906873896253554985208009869159014028187242848161393978194008068001342262", + "4711719500416619550464783480084256452493890461073147512131129596065578741786", + "11943219201565014805519989716407790139241726526989183705078747065985453201504", + "4298705349772984837150885571712355513879480272326239023123910904259614053334", + "9999044003322463509208400801275356671266978396985433172455084837770460579627", + "4908416131442887573991189028182614782884545304889259793974797565686968097291", + "11963412684806827200577486696316210731159599844307091475104710684559519773777", + "20129916000261129180023520480843084814481184380399868943565043864970719708502", + "12884788430473747619080473633364244616344003003135883061507342348586143092592", + "20286808211545908191036106582330883564479538831989852602050135926112143921015", + "16282045180030846845043407450751207026423331632332114205316676731302016331498", + "4332932669439410887701725251009073017227450696965904037736403407953448682093", + "11105712698773407689561953778861118250080830258196150686012791790342360778288", + "21853934471586954540926699232107176721894655187276984175226220218852955976831", + "9807888223112768841912392164376763820266226276821186661925633831143729724792", + "13411808896854134882869416756427789378942943805153730705795307450368858622668", + "17906847067500673080192335286161014930416613104209700445088168479205894040011", + "14554387648466176616800733804942239711702169161888492380425023505790070369632", + "4264116751358967409634966292436919795665643055548061693088119780787376143967", + "2401104597023440271473786738539405349187326308074330930748109868990675625380", + "12251645483867233248963286274239998200789646392205783056343767189806123148785", + "15331181254680049984374210433775713530849624954688899814297733641575188164316", + "13108834590369183125338853868477110922788848506677889928217413952560148766472", + "6843160824078397950058285123048455551935389277899379615286104657075620692224", + "10151103286206275742153883485231683504642432930275602063393479013696349676320", + "7074320081443088514060123546121507442501369977071685257650287261047855962224", + "11413928794424774638606755585641504971720734248726394295158115188173278890938", + "7312756097842145322667451519888915975561412209738441762091369106604423801080", + "7181677521425162567568557182629489303281861794357882492140051324529826589361", + "15123155547166304758320442783720138372005699143801247333941013553002921430306", + "13409242754315411433193860530743374419854094495153957441316635981078068351329", + ], + vec![ + "11633431549750490989983886834189948010834808234699737327785600195936805266405", + "17353750182810071758476407404624088842693631054828301270920107619055744005334", + "11575173631114898451293296430061690731976535592475236587664058405912382527658", + "9724643380371653925020965751082872123058642683375812487991079305063678725624", + "20936725237749945635418633443468987188819556232926135747685274666391889856770", + "6427758822462294912934022562310355233516927282963039741999349770315205779230", + "16782979953202249973699352594809882974187694538612412531558950864304931387798", + "8979171037234948998646722737761679613767384188475887657669871981433930833742", + "5428827536651017352121626533783677797977876323745420084354839999137145767736", + "507241738797493565802569310165979445570507129759637903167193063764556368390", + "6711578168107599474498163409443059675558516582274824463959700553865920673097", + "2197359304646916921018958991647650011119043556688567376178243393652789311643", + "4634703622846121403803831560584049007806112989824652272428991253572845447400", + "17008376818199175111793852447685303011746023680921106348278379453039148937791", + "18430784755956196942937899353653692286521408688385681805132578732731487278753", + "4573768376486344895797915946239137669624900197544620153250805961657870918727", + "5624865188680173294191042415227598609140934495743721047183803859030618890703", + "8228252753786907198149068514193371173033070694924002912950645971088002709521", + "17586714789554691446538331362711502394998837215506284064347036653995353304693", + "12985198716830497423350597750558817467658937953000235442251074063454897365701", + "13480076116139680784838493959937969792577589073830107110893279354229821035984", + "480609231761423388761863647137314056373740727639536352979673303078459561332", + "19503345496799249258956440299354839375920540225688429628121751361906635419276", + "16837818502122887883669221005435922946567532037624537243846974433811447595173", + "5492108497278641078569490709794391352213168666744080628008171695469579703581", + "11365311159988448419785032079155356000691294261495515880484003277443744617083", + "13876891705632851072613751905778242936713392247975808888614530203269491723653", + "10660388389107698747692475159023710744797290186015856503629656779989214850043", + "18876318870401623474401728758498150977988613254023317877612912724282285739292", + "15543349138237018307536452195922365893694804703361435879256942490123776892424", + "2839988449157209999638903652853828318645773519300826410959678570041742458201", + "7566039810305694135184226097163626060317478635973510706368412858136696413063", + "6344830340705033582410486810600848473125256338903726340728639711688240744220", + "12475357769019880256619207099578191648078162511547701737481203260317463892731", + "13337401254840718303633782478677852514218549070508887338718446132574012311307", + "21161869193849404954234950798647336336709035097706159414187214758702055364571", + "20671052961616073313397254362345395594858011165315285344464242404604146448678", + "2772189387845778213446441819361180378678387127454165972767013098872140927416", + "3339032002224218054945450150550795352855387702520990006196627537441898997147", + "14919705931281848425960108279746818433850049439186607267862213649460469542157", + "17056699976793486403099510941807022658662936611123286147276760381688934087770", + "16144580075268719403964467603213740327573316872987042261854346306108421013323", + "15582343953927413680541644067712456296539774919658221087452235772880573393376", + "17528510080741946423534916423363640132610906812668323263058626230135522155749", + "3190600034239022251529646836642735752388641846393941612827022280601486805721", + "8463814172152682468446984305780323150741498069701538916468821815030498611418", + "16533435971270903741871235576178437313873873358463959658178441562520661055273", + "11845696835505436397913764735273748291716405946246049903478361223369666046634", + "18391057370973634202531308463652130631065370546571735004701144829951670507215", + "262537877325812689820791215463881982531707709719292538608229687240243203710", + "2187234489894387585309965540987639130975753519805550941279098789852422770021", + "19189656350920455659006418422409390013967064310525314160026356916172976152967", + "15839474183930359560478122372067744245080413846070743460407578046890458719219", + "1805019124769763805045852541831585930225376844141668951787801647576910524592", + "323592203814803486950280155834638828455175703393817797003361354810251742052", + "9780393509796825017346015868945480913627956475147371732521398519483580624282", + "14009429785059642386335012561867511048847749030947687313594053997432177705759", + "13749550162460745037234826077137388777330401847577727796245150843898019635981", + "19497187499283431845443758879472819384797584633472792651343926414232528405311", + "3708428802547661961864524194762556064568867603968214870300574294082023305587", + "1339414413482882567499652761996854155383863472782829777976929310155400981782", + "6396261245879814100794661157306877072718690153118140891315137894471052482309", + "2069661495404347929962833138824526893650803079024564477269192079629046031674", + "15793521554502133342917616035884588152451122589545915605459159078589855944361", + "17053424498357819626596285492499512504457128907932827007302385782133229252374", + "13658536470391360399708067455536748955260723760813498481671323619545320978896", + "21546095668130239633971575351786704948662094117932406102037724221634677838565", + "21411726238386979516934941789127061362496195649331822900487557574597304399109", + "1944776378988765673004063363506638781964264107780425928778257145151172817981", + "15590719714223718537172639598316570285163081746016049278954513732528516468773", + "1351266421179051765004709939353170430290500926943038391678843253157009556309", + "6772476224477167317130064764757502335545080109882028900432703947986275397548", + "10670120969725161535937685539136065944959698664551200616467222887025111751992", + "4731853626374224678749618809759140702342195350742653173378450474772131006181", + "14473527495914528513885847341981310373531349450901830749157165104135412062812", + "16937191362061486658876740597821783333355021670608822932942683228741190786143", + "5656559696428674390125424316117443507583679061659043998559560535270557939546", + "8897648276515725841133578021896617755369443750194849587616503841335248902806", + "14938684446722672719637788054570691068799510611164812175626676768545923371470", + "15284149043690546115252102390417391226617211133644099356880071475803043461465", + "2623479025068612775740107497276979457946709347831661908218182874823658838107", + "6809791961761836061129379546794905411734858375517368211894790874813684813988", + "2417620338751920563196799065781703780495622795713803712576790485412779971775", + "4445143310792944321746901285176579692343442786777464604312772017806735512661", + "1429019233589939118995503267516676481141938536269008901607126781291273208629", + "19874283200702583165110559932895904979843482162236139561356679724680604144459", + "13426632171723830006915194799390005513190035492503509233177687891041405113055", + "10582332261829184460912611488470654685922576576939233092337240630493625631748", + "21233753931561918964692715735079738969202507286592442257083521969358109931739", + "15570526832729960536088203016939646235070527502823725736220985057263010426410", + "9379993197409194016084018867205217180276068758980710078281820842068357746159", + "20771047769547788232530761122022227554484215799917531852224053856574439035591", + "20468066117407230615347036860121267564735050776924839007390915936603720868039", + "5488458379783632930817704196671117722181776789793038046303454621235628350505", + "1394272944960494549436156060041871735938329188644910029274839018389507786995", + "5147716541319265558364686380685869814344975511061045836883803841066664401308", + "14583556014436264794011679557180458872925270147116325433110111823036572987256", + "11881598145635709076820802010238799308467020773223027240974808290357539410246", + "1566675577370566803714158020143436746360531503329117352692311127363508063658", + "212097210828847555076368799807292486212366234848453077606919035866276438405", + "7447795983723838393344606913699113402588250391491430720006009618589586043349", + "7626475329478847982857743246276194948757851985510858890691733676098590062312", + "148936322117705719734052984176402258788283488576388928671173547788498414614", + "15456385653678559339152734484033356164266089951521103188900320352052358038156", + "18207029603568083031075933940507782729612798852390383193518574746240484434885", + "2783356767974552799246444090988849933848968900471538294757665724820698962027", + "2721136724873145834448711197875719736776242904173494370334510875996324906822", + "2101139679159828164567502977338446902934095964116292264803779234163802308621", + "8995221857405946029753863203034191016106353727035116779995228902499254557482", + "502050382895618998241481591846956281507455925731652006822624065608151015665", + "4998642074447347292230083981705092465562944918178587362047610976950173759150", + "9349925422548495396957991080641322437286312278286826683803695584372829655908", + "11780347248050333407713097022607360765169543706092266937432199545936788840710", + "17875657248128792902343900636176628524337469245418171053476833541334867949063", + "10366707960411170224546487410133378396211437543372531210718212258701730218585", + "16918708725327525329474486073529093971911689155838787615544405646587858805834", + "18845394288827839099791436411179859406694814287249240544635770075956540806104", + "9838806160073701591447223014625214979004281138811495046618998465898136914308", + "10285680425916086863571101560978592912547567902925573205991454216988033815759", + "1292119286233210185026381033809498665433650491423040630240164455269575958565", + "2665524343601461489082054230426835550060387413710679950970616347092017688857", + "13502286133892103192305476866434484921895765252706158317341618311553476426306", + "686854655578191041672292972738875170071982317195092845673566320025160026512", + "9315942923163981372372434957632152754092082859001311184186702151150554806508", + "17166793131238158480636170455452575971861309825745828685724097210995239015581", + "4443784618760852757287735236046535266034706880634443644576653970979377878608", + "21470445782021672615018345703580059646973568891521510437236903770708690160080", + "6932852445473908850835611723958058203645654625170962537129706393570586565567", + "17078326120157725640173982185667969009350208542843294226397809921509565607842", + "19251873001736801921864956728611772738233338338726553113352118847732921831266", + "13062907978694932362695258750558734366820802962383346229947907261606619788585", + "16576609187793673559170206379939616900133457644695219057683704871664434872406", + "17140499059660867342372156843620845644831519603574612796639429147195776838516", + "16226688173010504218547945848523900236290532501559570164276462499487632388445", + "2806068123803905806401128967330263340459046260107112845068533446899070326517", + "17788735370835052317224182711467216134690146479710634688273650370951230404901", + "9840665370904113434661468973557421114403401847108482949465899631150766783733", + "17357287363046228581837055771327121704742940914150998420465281177406182088510", + "8956082469997974864521346025916496675956939495318858500685756691488425559998", + "10583741436561099911914917245130852199607666337956354910388730829023746895549", + "15241902639811607164983030447109332729761435946009172128089506810551693978973", + "10889882303914055687481932975789161945462141459528413507160087442461090813788", + "19789561133254944544821898921133697408237804586549835559829396563401674817160", + "20741336668287037026472434608739333171202674306575625457456116338034432647230", + "17864073449995977742930566850933082711031717858550870842712972350665650521079", + "6017691253505466300212182439349954426085752315661098358839308909771637792741", + "5209125836207196173669497054522582922896061838702136844305036341250990710540", + "8138726312837322624537330169363664364899441867118983214176695868443641051381", + "15491983986041746833254372934846748393213690608865689646440909282144232382678", + "5054332867608171303802774230688792431028169804536607979111644888500809938980", + "15427030776591294577308915282298854681562344215287630895931797573417982096417", + "21754057982677295571284116502193272661309010996970316384923307174180521790164", + "16265286590463120486705206231835953324076688991892805307349612983237844034032", + "17679791107777049796013011282788633179411040182820636236163074053597517790779", + "4281652562868629887097957174897458165728741859103571825874408386197225591996", + "9168010397863299719604788533602757515513214141450093775967322808686129400625", + "17584182367226175071087689123358883902969885218985589531538416263709138156515", + "15671512310414658663135385639435845966109237059155734764323312289873534719186", + "10536294659491685326297777845632759824567028904726211134518740400643540109527", + "13431319759608247201135260841651365578663315527795431484765940626659812285319", + "9584697124715190200241839387725546204368618031045071660911490086723434692561", + "5180327104839158483066851400960171505063442195966219343315555549982472660055", + "18888217223053385111625483360538133292128748730565502371803782424772027937822", + "19535732913737027522540340630296365525208404217634392013266346283017745945894", + "8577759627886344995887423695190093296190181539234301534326157005220006624466", + "16793670928407147476673650839110019799844249677846432113010280456483595763987", + "13926032620965299897272071104154310460519723329016284975305942957859374938463", + "4794697578055472890255676575927616606591024075768967985031137397587590174501", + "3529566190782060578446859853852791941913086545101307988176595267965876143250", + "3975008029239568933166738482470827494289192118694622729549964538823092192163", + "17739094873244464728483944474780943281491793683051033330476367597242349886622", + "7367136451127531266518046223598095299278392589059366687082785080179161005418", + "11175297939460631138047404082172242706491354303440776362693987984031241399771", + "21687543815463985355165197827968086406938428974327951792877419032069230058777", + "21156136641989461785420005321350884477682466566148802533375726181416623358719", + "17347558768803521970212188258074365309929638984714303299899732035040892048478", + "16293716234695956076322008955071091921491953458541407305955104663269677475740", + "4206144021605871396668976569508168522675546062304959729829228403361714668567", + "19988050626299122864942213847548542155670073758974734015174045163059179151544", + "747972634423324369570795147739377097591383105262743308036321386836856106229", + "4612470951309047869982067912468200581649949743307592869671537990797895413707", + "9630852913694079049153027193127278569487291430069466630362958024525616303220", + "17941539917430916523930519432495442476511211427972760202450248798031711471474", + "20332911350443969653703295317915788278109458962706923653715140186132935894113", + "21764801803055897327474057344100833670291402543384934706514147201527191846513", + "18792043166429470991157980448329308661526906138700725174612608941551872082876", + "12308177224490762720061048892842527800271687977085172836705858261595655154325", + "6234555076867437297776538521925679658360922070165740193866337972293380196151", + "4651047048822067434403056477377459986292934655827821636179452835839127581305", + "4762047093602693619418269784972874862577325737690375448572644958129932507374", + "12373514879531674477721132062882065826558811149582829246378921774344318418269", + "452512704634345955634014968317367844987135264395068376894497483188243356523", + "21642936370936057063268550589361090955573362743817395689260298777690935495218", + "16170209200627740434842090607802586195654207376087117044989637541681675086276", + "11682826760471401430136435257946377996085824742031456481961511737883954750045", + "20628055165039718158878805520495324869838279647796500565701893698896698211929", + "16438375313036818694140277721632185529697783132872683043559674569424388375143", + "4855690425141732729622202649174026736476144238882856677953515240716341676853", + "11680269552161854836013784579325442981497075865007420427279871128110023581360", + "7052688838948398479718163301866620773458411881591190572311273079833122884040", + "10339199500986679207942447430230758709198802637648680544816596214595887890122", + "16310974164366557619327768780809157500356605306298690718711623172209302167675", + "4572051236178600578566286373491186377601851723137133424312445102215267283375", + "20933392620931420860078756859763708025350478446661033451436796955762857910093", + "10145870387395991071594748880090507240612313913083518483680901820696866812598", + "11173854866888110108878560284050142518686158431744851782991510385755602063727", + "3895357290105797542988795070918100785105415165483657264407967118738833241858", + "16358886674154007883356717944805100413481233709808000948036974385803613296849", + "10544067501284177518983466437755150442726536257903869254459488412549270232123", + "10495171258604974589451578238018388630585794890815982293891430761424812600427", + "13820724103604550843562070971473423552484851063169471886037640613650155173554", + "2334954333435579600152488915208745055087482119087065911968347050969338669409", + "15100284614446277058846085121308897497066957549089629374506920751044105723791", + "8493821960754696376711287628276980042183127459347650448500304251148421115590", + "18612435536889941393944858783110719304584209891406420832295898519317994950798", + "362101794940079733974215941991047456600874474038781578925062694203564740952", + "11020033081956343850903875701444955317664141075326494650405276926536449284939", + "9396289482656518627529185765935649373549564165735162258912975312413185691167", + "6879055176150676925438486069371149089824290576271090206945130252868108043422", + "12466610601804566637227883322591924115458766539177061670432424956205788935144", + "6570302110526154075173287644133038486970998888099669190857256824048085590052", + "20997862990590350605775941983360263378441519274215787225587679916056749626824", + "2642485040919927233352421501444361753154137311893617974318977215281720542724", + "18832940311494549247524002614969382413324906834787422940144532352384742506504", + "18751288968473015103659806087408412890105261892140397690496125593160830694164", + "13938622158186434739533995447553824444480420613323252752005511269934155122652", + "12878982657080117316101160964182202074759312554860119090514406868768962707099", + "13757859113119127982418426758782225628393556023865807897214601826218702003247", + "11817871682869491875135867072669251115204978941736982465520516648114811792373", + "11336448548896065624515261709306933490181794458266726453198857687608284871020", + "194970717714150352477887371297168267861902418496792228400198694925721020795", + "4999282817977533227652305360183045040853565298259070645110453061034932285549", + "17094174197873140035316532568922652294881600587639905417701074492648767414173", + "8484251464872873032022789624790167173458682056313339863651348894878144808746", + "10260366716129057466862964875306868898686918428814373470382979997177852668590", + "549263552864476084904464374701167884060947403076520259964592729731619317724", + "10052714818439832487575851829190658679562445501271745818931448693381812170889", + "1735373362835209096342827192021124337509188507323448903608623506589963950966", + "7998373949540733111485892137806629484517602009122941425332571732658301689428", + "9035170288660659483243066011612158174896974797912618405030929911180945246244", + "6458619567307414386633203375143968061892762498463026121155477954682976784731", + "12314261817227551876673777186352972884847144237148169773300066404053441924532", + "19869454329688183813243851218196625862680921049019496233616575272637276975230", + "20326917073492686652690019138603910654692396590122884746951129061818467704300", + "20403270805536666081472738304916561119325397964511536801752236086414818653063", + "2865941730880218719188224311916978807415673142487507504983320505748719154068", + "20614246027521726470902405957496110178017768563127335842405314212897493119848", + "12060194341463088508348622863463208827312128863463014006529428845777217660299", + "1128906798719793375274166820235650701301189774851381709919492584451845983197", + "19670876372911656158743764425809421400123168087389888660308456184201759209723", + "5647230694522866559497222129254930524469944430191328619422533907417776118543", + "318629082509194371490189248876734616088516535434806492900653650176451776632", + "13685970881538585172319228162662520285656571966985351768743970447782846353365", + "8283840607829148567836919316142994745766280854211662326632930274668867638198", + "8968895518159422029900464138741638511289476298837958524156654785428413265371", + "10061801991000917366002570579819627134666386452411986168205986791283562415829", + ], + vec![ + "6652655389322448471317061533546982911992554640679550674058582942754771150993", + "2411464732857349694082092299330329691469354396507353145272547491824343787723", + "21491443688002139478732659842894153142870918973450440713149176834049574486740", + "20196926676989483530222124573030747187074792043523478381149800153065505592963", + "12986278951352369831003505493892366673723882190521699331613883287145355738793", + "21126146258242782643168619000295062005037298340836817770565977031890883232034", + "15509665795506578582538177431401381655815033647735781734613703976071034655246", + "6989769181472743404364681671283889685042701491627165526899522083327752110839", + "7062179885254277466334896166987547257487047183881628199983668518000910197987", + "13842521112365108087725039904948872289730786568469683976372377853164252494752", + "3830559505943186272618534143266118508463381443414165428900505002474439179836", + "17704863473432653834041116667846189591617394753001613253930974854399793083900", + "875580502229441633079974792778818749112423694973231971690365132230865385439", + "1971134273535892826573832061354985059300866001765691176219451252512658771248", + "4865738840363990164915013008693722144676933915103280504727326977328013515878", + "1148603338028060679975883868174895825055359423662532941509525326937127571764", + "17506086433923270253695698017062834613463718526046463655503742220257039588796", + "21580033018107258179208198773211859664893072138803756118939260252922297665067", + "15411900706973212043830142913959920716501447427702082030760032355626616412240", + "12219699506725448409610279620972339448030565224304464695714944121760832152291", + "4525719544192047521328360848269156485222470829314314216955024799558286708479", + "19667371373588322336224317159113441765198420040800065314868656839300028747331", + "18916925604689704279265158984702141998345424765142129953154245912230835240445", + "12789343981741773931665143789673052782408749041041266509485929045869073416222", + "3094428508959717445577232225505810354980663487713729230015754183012845687401", + "18544590634480965569098056786078005630500574069468005220462377474861119476492", + "20990087440247450018723844204951613913840993427110495085701200965767234569705", + "17552251989761134508416634118845221324472178264364440017634233349418103869223", + "21000797802575507763447855752602183842956182733750968489641741136166640639409", + "19292751508591545849778577901067988044973302547209758604667395356943370737868", + "18314088316445539319869442180584299715533304874169767778761887632882728399870", + "15003745150856597539000559910957155642193629735521291045949652201905498569732", + "7839443900003691950104175747634267110464104444913379977500178134209666299140", + "13568305490393393394812598233983935295266242465548739772708079888867621061127", + "6453005227995051361096639028742707098785560656441339640433794156400437698140", + "1420171596348195609536167209221442141824294918625468780931400849866478645240", + "8347329128252205996443084339884155586061343024498283583400215109265013719709", + "7893774494551056447960817286805128884970061671041428326788899872964096959040", + "8970476243368194065341537088653900235777512204874037182428362347342487241690", + "239049405935404678508864874854718951364753739466303321590415544572014148257", + "15772878921699764223771017074289335629553777447709755479885293350677783703695", + "5416082112919155131434995906647355834510201879607888732259087164602171650389", + "4384524908062410354304345761652962203632712291085564157560146286207296352050", + "4210984612917608245844011498198864216639269565627982123611519493203177283139", + "18816442907032290878644773027005263628136050677095986565400687355912498966559", + "21443510232279945782338486087712914668515437675585863788610958361560172084515", + "3234314779308300525339049581669531363375743827111579883853941968586490182859", + "11029499234949696730080035941750777601416171837281021031653841244636590396063", + "11145210633226924132308292113124660576759662647204939721872338908644906571564", + "4583160563963432761409369246361117506465307518522062239686649163525543782173", + "9813992026757562966842771727657080117609486122615087352428596024939855084450", + "10084171857039480706430282187972782725948479260179367780776125786119489581409", + "3874212709197875589640151274548083098712939093643165182881681226579903752816", + "21595542491397091124739711708612983479307589335640792812157875295064235960610", + "2068530815441314105493629066002923150651375034543842424822712297257260726954", + "2673459852071215292298131389250564595426361004231758522146794940265552265806", + "8591046256746588406353455230465605224309754008961178558834659065898923355164", + "1020055192431352394776887540248098706183934464205704158014904833376067287118", + "11085709480582865378042656141271006552092494690130782253913953070642865919312", + "5673844083530503489429922596812992664928167369104420134641855283771127716005", + "10492199162275168254265892158402955076490959375050993042712629236807564461542", + "2280843393156259739329331366624245275580688891778782679394848304764573859886", + "6807797027131305026345508953353882265754363485246407959111359919046340709440", + "12692191384043938397944633973317584101723715998700063415107128429315536223446", + "19818676957110967644349139912613239435706480354664804036688552936554140369382", + "18055602608192644695569077694296748842203151828348990995792087204755925787339", + "20934555391215769430553078793246717148484784880715746179415906355043590089450", + "11420705181439111353998210442417752592951340005396931802449360401461783159557", + "19878854521263746227125001670931867821366047088989510542865511663910116386085", + "8568201846715449867087132677683368912214864824182424933182820310911278496552", + "19198701614488576617610339232794062430644024620523684127268879880793305460015", + "15262122764244854433806270478871594904740306012582364033343126589996733802868", + "6412758421155818207287638337822550233376667015263373809976157264137577776202", + "17371585001641430978766734501830788427263945848682170096055857509304472649262", + "20262970042379497707724791203314262108784948621691331141565359315001027736581", + "3859750447119748295302212198327542106766447958113540005985799287718502362717", + "1172269945800307665458943534144481495673510885455899148864236015097947176746", + "8164247467959680477306326470118519335673181279975551434197731340070491876250", + "4513977811114181395323888111232002391599397736872779927267726121435887238972", + "1075250595927474080680862736233039825365918646878264905022213616210377518447", + "18658420120424372681792175914064174056413842231969276203770574969914576681364", + "17769673440848360838244654765103041739044212539359630263894092078288342647801", + "4319086204044362848967484441065231939136453667264715596505827197873119273506", + "11221173270629292820060668122527062274557317856738971635698169204652845111606", + "8635411372759272135249379415383299350267629947167809163276219879514948820576", + "926977621651476360285369760355547766944001783780761167546467658394097283069", + "17702143780592866375901805387463459229828093905183622296234691441436877570082", + "629612289140842594504574984021125242351317893847688437087866691775821981724", + "19990548577495092294245865870717186004301934545721835081514347926537975465539", + "7124830628609719908679298707909792306162298058570958688501370177898647946696", + "14620227791860703231425817538142948793892390269806790476396226159679984968174", + "18495581997440241868332244230687799183899751339442721677540757155760745277888", + "16922065056093401385376103551657968760602009001905886435813054626317776258714", + "9969610601962874779035054685661667941954971427956866645694064022029705170229", + "15281641269114187762159685323068136816556739502211864119670902056596295644116", + "12114994625438879103001132949163961965524612903017200394727056658298824651596", + "4840986177718281128440833017205097196672382395936939379498412745183060615212", + "12847307562796769659308999092658905656250954898192781948610713494470441775991", + "20290096217351155282642224215178246911041509999959311313223857240001143893317", + "16151664509646153154405691138084115125600386733136285504828908979176781265710", + "13848845391482751436287906247470303487958950799995701248612703022979890932133", + "6335716166231441585596963683321661194889815181545222079376536449814718259931", + "1824302750039354704619545544386637317858342555634601563660279997221547953768", + "11327469654081586239268713126961534952233559223228327222485848924908493444712", + "10077703415170135154603829433031861799853903739210136452726077323833067256620", + "16368073884579385814331927334821006319227867093692644942500207970751483237405", + "10621580796499573269115131164341885791299038227955222944695715163010783205295", + "2099241376651019397894434242565225315652133572870234550073686122343103853816", + "17104632243449417396641550271977294699471083572885397875525767745512335891599", + "1935453754847256492223646005402770357836971113012418013930273797463411526183", + "7492761611332930896292052363224494314920390056637668407353957465667515477934", + "16836705924460095689555600825174696605443212968244843485187771119291716736958", + "16995495500678141665340056658079449793587669420913589967848082091551329904176", + "16097379973857697753436437302681608056543122759719328497348770844548177814262", + "17476569537128329379528694049566216604638194592812108658767104922628767500420", + "17997217989870184804787026924935938133194070033518938653831611194683423549591", + "17573343771046232580761295935281170028624495346579002725814597714902588657750", + "2450087639204541254902859018960918562514681200270997307467560465282168310665", + "17288084325555056222618040923753050382954155896826087372317882602328092535440", + "21837047676579063581498107773514419735425738753079336764356909012851439336687", + "370061273472837873736743292149368449614309676635341873070086681342317566380", + "420725183996224279379885018872359102189091670793820517618337092091910692771", + "4966571645678139143731798992823327185758562224229132271884647901363447388530", + "5039558223429273757296118284876763395391635773837549121798873235133698166026", + "14663152729953724779401067486012084029581847325524052152795817923033297673686", + "7201040456590575809960214033959496417566605177095808543357813677845263237276", + "16872945504528960415453618286121813996587432836152082188694652370255998768595", + "4914824783780909279212078186433590922437371437384817332713271291839616026466", + "17503018483514413315464207189113334433424965178631599286655188843769810245465", + "4087750571011463387872022799241315348852213278729592692674275176152296405923", + "4006961923780091252337105595934918049936238157468198971234322013673884171131", + "4481908842184366902145805444001507554481032302978790080019710161108326487967", + "13532316826436461968093937893872910736305115143550039673102602344678825540956", + "11602986656925867325907196773754426955346837006705269228226729102186031417465", + "15306992574062791537454541745213815567999895856471097922112648012979731636068", + "4497571735611504561173050536899411999551839050319538712220770383407135602945", + "2571242673174714867278075260451133687893879636121064640779554188161591611843", + "7070272070524747733177730083966686149849667613589868731851816020060781720851", + "1308310289745495626002351437755820460104812708071634598163946330870933261232", + "9483468192990391193401121929514821570714432121414330663623018046165053411090", + "7317568349845215930675847155716598288688799068821709820024570206796617676748", + "1918505733423704616434273602054555051755671749253598966287072464475922854850", + "15158168161084905689406532256983805923258003804476527617207287404280855731962", + "6855540174355511438343304861678411868002455139032857270673849263857877330771", + "5989863238360846166935911112885654223487221280254816980802479355446167746774", + "20283337058688740322296928691341300752003492063748410749625272920572074851396", + "18957132189629332408653055312790838576277703952267542471751593810468444454136", + "15764518568966520670995753676429154315765754748131847346608706222194564055358", + "7192524197002826721654253762628934164676539329903087107420445743247046038858", + "142950766663597487919643890566358241353679421113406309294925836697585309311", + "15012262168187689680572958978610204856600235635916074406168861726626292993057", + "20795666834671497603181209610179324236645779324677512349797033323222380300794", + "12650341271833683789775531792948185319868795529390391267833516836256688318306", + "5597700232877580665749288204589530549415282468176625525368428476461504532052", + "20949303924691159143653175365242293984396858344688574262804199947001630916385", + "10746523145835332938672833282581864816136388045771578294905302886974358762209", + "4998982766221590779170630035756820066555357949247521575936385387288356143784", + "6936999580131731861735955554005106460473097800566952971315565150681540640020", + "6670695360676548472482680016233507548657051302712214051977034166870814430578", + "12210816592786563975173850937247594401582085430897698766795696447223454826466", + "14933901149105284237676334791785996160108290333321693498322435129559137152007", + "3848529433916624869590379003597911090976938589461403388133685310398004369431", + "12778805225074604003024964969486878839359935515509480774809299341511161183802", + "3288267180428684202786697419666969564766921974531343432588030535602163038467", + "1272672432174256751826350693883913844502039730140570583479554071765667798207", + "21130828804874452930669244946376257892693846272313548250936991077452679117587", + "21254559353072473881932828401787134230282801383134765683324465204971002861493", + "4116075860631781527931204624078712926526805345818156200756399332393348685924", + "17435888597009729827411190999389277840088354756277916760187756022854497211746", + "15837398163415665169712832984380121382150588321621493928953938599666110830812", + "17988638446757562417082379159769772097890681265659458369075768452342579854303", + "8144561030363576879343874888624208577604401139613622673042754207987577727758", + "20020299925602421262203305284307419339160247406220693128040712457114283033661", + "2945951415037890626891130390523013930737768652394758977777336357159436605764", + "1505954324723537402640844232704189835623922400329086438898375859826553573763", + "11851584491756305117491374581845512067704002072833714119284164514457248861803", + "14471204965036278214508938537949717553799007630471016532866101610339050785912", + "7163557293233604902868673807221391042191134560333950452577270522828534690707", + "17291625782465108601367695465389799786592304061550212130987221355832952230827", + "10240907112109243116543462081552827576656826251172050843989873656917271396422", + "20702261919346727858635106264046787321170414155594199951578791234276181642650", + "16678253307828004252292273162411388452019952018258857370242272543091326285541", + "19810917631941180098047817620026253706643400683524412974923209268916769874447", + "3357220165225360610202375608872621445880880830154732998557832689480921421791", + "4392285438534542495332422274902727975330102148971785438164412161504066619105", + "14642025133729666610167675086855441462580619607677226879159952689184960379911", + "18142623439987890999821892559271093087005885278955082040377769578204898750505", + "11769399023330099592616157336702104329646487200891911089287290893650532639221", + "7261353756299584174448625214367175510387913706095214313669922259027644778060", + "10406994568199070863112470594593301582798997458844791396920771226539013327304", + "7475277967562870216712397220016587384793504784585573136176313471517144184018", + "9598064630327104406929367986473441777975480987434868213697837347643980267620", + "21137410002545951849752865514437404724653771608225272412595423069852350320648", + "12345612867231779996383303763804719815752861524077922121654106906093103051400", + "16461750199070055335468534730937701659470268635084522644824623393184528879703", + "7829250842543018165409887731515254191943527926556191989558018633300783421935", + "19801151644322693878208767560968285812646931156576102755771403150148125880648", + "808770634664491371274943928223981161442027957963181999892266696287962813461", + "2298122748772261447929855283951027113218922003687701626762072351622993276571", + "17407798064458858450209051887305178872029674498718760624162479511390762310526", + "18585562277464562541666582720366573863334618817908062612923861658144918595030", + "733976598693219656339731904831283238690050114241501938501377743874139460889", + "11316063986696838098122262534148335669847478050407756877728672233736962269417", + "17614529714381496379478130066245111825610297227468263851608027100133421612826", + "12110694197729365219340374599835523099651939156213930558791147158357810646901", + "4337343008663255658976574468931581484970687989356019720784093082313510905405", + "1379188959674402095268172673987199124815512095460112504778179157481327937561", + "3116148242507754420428768481157196067508084836097458698846114802493377512591", + "13306507137873332434793374848948087993544118494881134631519748904811343155566", + "18496878480807017010077624766326681523549495609998881196570603040242554712562", + "3940126764022508707486095199473913866137718790062498893812401335738707507732", + "10030078765792498033316282784150304209584388923549357286679864120250994473810", + "18519871685760382462428068450331593474924737719734568498029727699878543899254", + "12599428893576891013523136950822667754415283296587096197120138265392279834128", + "16038578953099895530943034305356008247313649524436132877362941968861459073483", + "14319233878082524834510736727226054073026413911339853399113450188859080424272", + "13710161613540579690732775978855380876556751245265568031703536595040993113748", + "14958726446649273856607176275240008023824615720456760403465034344703779274727", + "20935428111942360630758629263346308597806819928838924586682307174931367773605", + "5826394436548487315966647466017047216786257295199620110266250301500717796281", + "31401797997389676486806123612280306684597605608110075525648021056710776011", + "10784171495708237485952707518956314344821522727746927291389338644844400581452", + "11604345371765580191117799693565193618158448665352599382713281103552305960442", + "1378145039624937931836538950217364481423707761527018494355648047365613434790", + "10284294167221806561993937798090888689421933711157676807977401896199778472860", + "8233695574758520342808807499924062869636681352769371531557726871630696672029", + "6570581391072134029876349038190171593169496519436674767949949730275868319732", + "4026501263908027819614805027945064360196399012004574117767831931274788631138", + "21091098569404004244061462065218203986433580687172854429523306262593782053656", + "20711772916118045406356429185975897495222240215931761100801599257137350834799", + "3165519312799351250309462589160165591299333587158531489859211268084164422251", + "16470663723473939739601217501478624726068461799539012562455639586886033078064", + "15672299304945968727435591100602007503785845873606917887638890765525875123857", + "21393538327627889838198844493522533627143658125568123117776524944297103649079", + "7688819203734248199049004650451546300187194458173935784579101984183800649342", + "6609663518412297884695057080546416278366560290439222127471462938252865438638", + "3476303650597281786976907813110835564442121684386467570637538230409080744769", + "20633582549754495054832414039299188930065286005370053173386561254823483851717", + "18067076834611402459142612082327591538480657933568191619109271502102126814407", + "157209609820117793892254328219308970217366919934739036156851508233236414461", + "1848396116513925340973398423998379465460554039715233953825786874352442451413", + "188642786730195655565401615804782553245486295156304142809552609651873793325", + "540089254487190924787439362270708251103955915909358626209177199653451469720", + "12796274768956950589847157187031845061404119522843128177103898080653493269942", + "1785666356337148874573621868025910291826158842346617719666738769156993598966", + "20649919247042517528354490854561347316237285929352042389729444382153378749538", + "9568390566108569727471722677925269460696523515877621230569682954652430518787", + "8590683334740232786825518158771304803451657249486419816607179533515442407283", + "9321198393538172042803957409292145345834077448228642847843261373640165958582", + "3651905214805616378360839954289447530035139753215923648216350128870943481828", + "1324345422558073117779462079218851558068746895262914344818945294328678893083", + "6666363895154434021620869731925915051086919707989020578203743660669796175288", + "9850757893972463103359995012900314323213006625927501272997539940766979170137", + "10214293226445704940138790188111862069675188797488928722469679760666574484266", + "16862124085118494177559484642483513597285992646267864845521573612482278871023", + "9172340118369291059693735314505606817316211450324955429310200429408035954801", + "1968992755714619414656181112336357119271845800144345284299978250769356388249", + "17192498940296212027365280042755701662136570107224000496521552617655679821443", + "10063385968535643122430064779260670089120686456635080613693015398478175344193", + "20101961459945738562625328882763768836449780661345042148985756598106706734632", + "12704305975772252539534386080950631076046431529894091327218544197389260775334", + "3008242816727585639441748210631464697850194693570485141354082562181236010097", + "7797705698071555811456747812384107102104184812467361013142453143842134807658", + "19323240331433203844038522035479659453946066968727795017745942269828428751105", + "1698137797127320576751729191866734754105401103859852376273763815257758421427", + "17656850887825900397821271738817912328294075224643535784810269137125067875996", + "20755447986835730799031196367323817361150623932048563112034040627213597261325", + "6221130271964372280138992636208062417325313096379273438539556580491430711297", + "11042709376363248213366896208587241517252100440844476816212498352999929578287", + "987361321094619571176752720390429919723900732295551211263814448408232028205", + "15077982986114392945859048373768437818569856001604485167476360943078774679228", + "6278894644165961404521866714059972066255652200107181684047812674333675794053", + "2649747800006903047073625320829560088088800522557851927539477888486006072675", + "2636278052351769676017824297717609512488651850924228608531372135635042762078", + "816232991472315395984098922575496846552245086608787214581606973359616326446", + "14372687274434205592004117128588852491871014819273428668840779210928924573820", + "7351401720390274950322621121981079413650308506660552567079785209176949174210", + "10275293929161727274572318228903710245677747557851999483919909420098936352013", + "14869686444606195206734119702227763209172799407142930791211203702643805341518", + "937617196362766626935279232045712623531859540210120280128165029613358941709", + "21331527351771920568751070369057714014285398281585036009305608379072813379081", + "4305436470381074948146072259605215282335211631970525440530773004228212378618", + "5894273721571292784412707230481346442881109207745969297947253583203466014760", + "6512250441044591603946512492071171861967500633638753443182294740883123881284", + "20863871952569294813936866452848141274047362082838805921071316386912981651979", + "18788566662709810970880679984141390717017951403407913908833463086244783373013", + "7784927597396249543149135503684024377171301321636804832597181795981969626201", + "13818519831569592521516488188127966399245767953522268350556654747680372036664", + "10515208647860053151690062640705322684876580250632027862984821874343071549235", + "797604926079325807488629085866693514275115789253871397971708541758696512985", + "8741784289526985522570446847275649913333939699807282742190607491216732972386", + "20966712704043418981047968701828936463778140093909973286855779694780086635828", + "11359697297415630167449040380538108774924967116147664240213257348125754475868", + "8070907838094569287067982462230761680706116783989613960066342967469297961118", + "1868550288036217638713133945402464194193242298015503906068429633793800456561", + "198709459347510170000840600179608479136663571567208109852828485236018304733", + "1601154135701845545733926027872374554514541574822026314034696802419388627041", + "4363994778006302991481199477873248350039564117453810275561422974475581105893", + "773054378219982710451611471050404495804413666789496412742983455527754059148", + "5209426340109575519362014651321132459061755868557415513439993327176584352934", + "16124961412020675839394907565568143713078242978522632778625312854364651991011", + "20812496670075231301471694692369245988519082317145989298573032859079075730004", + "3312489967581906638742585802390894285073229440039144559060030129184388053832", + "2967475373447822846542676378804990140732835322255774209561143670843223463335", + "19744585401442299381952694102570931935735276268739851233412754166721728873141", + "20026293345566344685499234599699178313754630774489046573312844763673073616936", + "2611303659034102517884318354550433047021831422518437228002960700934925644951", + "6230291832603218406134986471162106408091661326026848531605999413028246206577", + "9126162046556730019959291776456914453189657463686708035601186672661595109020", + "18827736146609035067773173111376739253733288103277133456626928961785293662143", + "2328703958261360872869074208611873245571971231035163763965210852182760438390", + "13796410059666172174899788866809560044715551934510722965495280798363043241416", + "1593663256684781552813616365605526150610454082601584196604084376715746899324", + "1565874145189898288764434737762721576951043839540107044892767693968417810945", + "8709849304563896945461696717753976956465219721409993781555147204068634555572", + "2994256803561260177499267243802460581941891553208150783951937342406846377191", + "10452746656507347152042187616753027475507881362159944564077673851918869542550", + "20130580998875572619695450234900655050996104101008767761546912649074040426200", + "18926933358104691474037431437316089682088433006245222723356764715400831411716", + "3783551594057498940671877156409957274854990650480535806320220142873170375307", + "7919031943604095374667473717154511882451510130166237539514111182596247372692", + "14518552587329209714850286012780632801030157943402419401997576700600952906519", + "4770764028263701271241862755569969531641408032906982530346384375773459918490", + "10866502826034731763529371496585294375373238783964914673031891984092997621879", + "4234148117462322266937279401468367908013627589417699250592523530383852950379", + "10747942066055887965185603234524367638106812660210378090215017248140719240336", + "2587411532912868255102795810490361867789634574022411742057853375399270197531", + "17350061113113681344498080520518808976916692173267298878258722510332360424059", + "16490282364669098969805528215926442920328903121380947471680517193373377657129", + "9274691782659584680377375192682066090127280485689527337429804211265749864190", + "7630965482352419767782717986075793694403609453648729580916814032587325374653", + "9483872310024003776681196467845329825094379763716541754956796450187787638623", + "12182966986735661215639970080491757244218854808156498220088212871061979325833", + "1853790963611367149183440339188924598268644281518961106776656221408171642714", + "17425077915972423995335545370701802959607559878032910147159424242864219303096", + "14571075346526399549826264845894977639678567831720652860528738036970272895919", + "5627701855249158721927849603102149698163511782011562166637339712383551336091", + "3620805686755372260289125555061886982808014642356719556961142525373021656729", + "11556995641752009899073583627136467840237831247117281278719511600076965602980", + "18960242154096055221658318882298412299294886669455506299567210308762501113202", + ], + vec![ + "9174141306060971809979631725764298697615039980311809306145004207410652431953", + "4847693924685156250211477469465516228032151306221739650606132660616428517315", + "19669833054057639609249840291533340493211768292967819468538893000195036768991", + "19800508893433268850924828171290876015556093796000695603651522426066333836892", + "8244699449852279148780456022144420353408196866113049322676048275081354214716", + "1563672068712965454176533719400672258364596155638916268717470967009721945171", + "12723223712027468580318230235559705540011996847167975439677647504573149248849", + "19944398841194165937952509356635863229327574447452745793253427406349161295763", + "21218058308392585368594275702746106483411305671883946244077923955757637296177", + "18442884961885927579732373746933397748806426938144021013884176466434407012116", + "11138408360119814115926439449668526422561003790198269766757675305576549475808", + "12724564576884231109847024566806896391934587839830522481308995309797961575379", + "4897733190252075532660075013731462724561461746919488679609618967302541674417", + "4797748331306263412471031924618974997396620231469532262170060449304337691527", + "8626839560132907403537141283531395025838110825355541158539075100658769738351", + "6096293906324574249636975851522292408228519044739444932687579741964974917617", + "2351617695830568421216396081605990689071283678701192113347036659596049514149", + "3045682390398203085155257535118136303069379656645406266260961816947178911890", + "6935829264874515341379952008241845470659188886156484974987865751370715745075", + "19847439266968955911971997829840067368072860877451092633069920565944933744280", + "12795097343831149148337906863235678514689648096503928066579129201713661539889", + "10424580232112390318877053133877999442988769389050776486274146627765228950235", + "11651452649618223740363812212607761589812354035139843126315028745587570714609", + "21307929358023177131550002602820591970791247513576735567457471459920519084552", + "2579908580162153663820021562014873149811195641589016321720930006635393981680", + "8198198178555784054784079137247244121807775986273563786249987394640289859893", + "17176088986876377315956611075288620878117708836881362200541916957398026761276", + "671389874397910339333118510595007038137908096657753354622355890021074216004", + "19161949137729278558310070194809106779119877882343914445178348849980058405327", + "10827554013954037091657804154642286174226562252063767377995268439458401752538", + "11693672899474469123468133710607776304784343543318650064064636202512816205843", + "7026547767612627656560992117440221331093280829523426249915938274837157551621", + "14422968137896343032446633683271253661000603582016449215470992885331170459671", + "7685352543184863430081115767111935982586458632527708735083385591291346555502", + "14089009391529192464370954954330128327830078875414722902347666490457756695535", + "8424161061743752192085022963953944100289245618074575727145394775891645849043", + "9809236779073852557054640507912802523501426410996355424610807253990040160483", + "14100245203768962710288059230665566265892855964739454261791429988929622355986", + "7775683622333704945225255741567928967674629526812606133980425422182282014012", + "8739247215686497264451630351996892836638898510934389758205488381695687859658", + "9431876969679115468275053745264413939426444105271849398322497961102606290132", + "257914055321743732506701382989022126153391940932933566664491918941925247878", + "21801414068435960590201256257290267142214176965736081788536576642934903066059", + "9465495933537134443327560834432669768951376466867005153580146079082722525723", + "7862366214258716333873810314803222267215825847232397599183717032713290878315", + "10701164906390193792620967030790214270231326273599373762943959252633779929633", + "11951628827727068395937910010248864431667047516686609553745879936868276916066", + "14268744039571470490378560085356767818183790841094115879980723591887874138419", + "14468215915818797151199796266933432577607248341385185700017147731054148927023", + "1523824033338639123415809477892820349580561577160869448927791050266158538520", + "13559991428776910947424645696251487328999214391124402586267086012691140984198", + "18151203063828433535061866995346135260543721730169485344610433976436663085882", + "13436242600153492361692256644258899977135098134175123174795293078081801647137", + "9384556671429507406657070680351030238568956203341356106463890924933167416522", + "20321079285577981781556986944841048777999006905303986053275199507771332527205", + "13510502130738135726695195328780836716597947131948116750163533622597187969844", + "20903049289119144354363108865308751668897757360882852151457514926552553533040", + "5611953645512225417723205546533389174830971368309601830751921473015551069534", + "8816886019615642422040038431962872654062471314244185285424018745071289038220", + "16751828354835345790163611999302863949792305206769993810746019449909446216365", + "10421654749141018171116296259626916395875529220250947127973888230084671091757", + "6065225315766552671037285757918350882361743810888619479819895087632281975681", + "5737755346739850738724717271213687543479332312420206954339242459110768587128", + "14770522272891919220644639305274656491731294860310497013287297810648680944682", + "2777394791070450473479179489594969793054480209411136328689318984981401732197", + "10039559932930709555975364107098145624058027439566384376771787183526929807647", + "20757756003754261934858081777796652436155530474748550156383127600004580439167", + "13253166894715452480712170898662712132411702335275401581167208877688374856806", + "2037004052447343668129085129987646907388123739343356363273464870501805506884", + "21829471491172175426560705585746893969222010633542962882847909490991398830669", + "5130395545419191392223692116621486075405299333195732914002649716762739787586", + "20333821730990393095934147177227294218344864602777744425090741435432040213391", + "13629653802252084129446975515814037702423511189484562534040643669977716900228", + "18489091892360842692678715136565494502607711254719045543684163289077857041829", + "21380328601365035012832876315565064374684993115210423862017233170195286906080", + "2280052193465635727584791148501382679094142036232980037838088033232747821762", + "21415541711468815972744677841317235994302058341802530962394281077076174148777", + "17146992672828650459975820445250769505470616910596779130798889014378635881076", + "21676475584514120109058208398560066698690773910598518925936412952356431597439", + "18337052978997482578725645166749278142628133291693686105612531426715865276143", + "14864089429815580405957698645045711801464462794754089671996837547347950054532", + "10834607317840698149140890207826430113987295440254355899459691878793978994131", + "1157143498448645320415276909137008396665083714591338741616893578930275511205", + "5027542104048754930085470328670427788489455916338375169351586496298129661248", + "1922685817237874482932428650501872692326329693528175054457715565489676406535", + "3071473720617798005831658342971536643616129392641449174655528578463370685788", + "21091078808046042460442535848913779439792606439995062001271357804782672390627", + "19773167374024045118471391738750949555178717045037157435777574972149053404157", + "6418695831178793575992210834992785624340084513619644969535805236049937971859", + "6317875495482489567338519005308431806047606843913867465201005132273298011425", + "18001249545956637376455848019549801116909661454019565655561439372098476761813", + "15530167556609139699164228289904946047951254183080358784988008899829027775935", + "8702757129830652230304011519426558036441096750485189115358314568895250616455", + "6369986882953061252605652398893489899416599935424066958291402945530517772170", + "6842894437627604179732847187262933342846269043996061072487488027804029200046", + "20951621154051947571647917571547811655800779287153833018533872651413529893817", + "1219277535080749134805291725937516331501172121638812333911793209536894469364", + "11704605822590166851511022757496386950530399074796545751042566537118336773236", + "5983427701962592508775640503988144495847156070437130549832329402380170245893", + "20169091361583397776908351163571343158517532527313940288212943504015977979442", + "3347733015762117176159731683196584632702931062411889821726902331981723958255", + "16217509027282489850987935065936382820558307489954122630844029918951230268972", + "10781269196927764524006466217779648732772805761839205677745819812868343369087", + "10568911823766972365218731330080733630028238366288098114239172953421915095075", + "5568774544682750792074131352530555554984876659733959079036284517928264996437", + "17854353469028651373397049175548228061144941710027186166132671198740388767529", + "6573034112757039329551886086829829282007989555105157401271097204633906940776", + "14069627287078359391137554212536883450595451640858724555679971658981340584258", + "21119713641590541511025673864154852875977162278614553796484277752677323191505", + "12802116677235410441672624559825044917295689876859311183079161588690810005363", + "16037054471696658545113065872215787085337497333273419984439267709950724531124", + "11698654309680908244303850432833183602706804558317993513795996394673734185716", + "15147889780127043019188099948246961619198549928908180192590946633702778981583", + "3657342516407201801006680507925024451922115018712017224805778401726428603983", + "19776786467141868744713630352693556348834540992018636838044610844396164981103", + "7980994848490005281733955776875257044050741738176865989521982608944874160873", + "12415191330803073018395217955802011585094769098717180100014182475381600382452", + "9300986814650530426668152137665814177758578011365736727321578452726378799933", + "4412208980274764197258090802604347599791567698589180187154608728755887977460", + "2582317668924231956058541757507620542434237159213236485179804217989764223164", + "19860814395849792324574773787600734118308975251437485131415273418632757301303", + "2765909129639570206766170018363951893338720647679193401532780051354569922989", + "5402210382809272147099442645489124829067576777592680891367494969197685281513", + "21011104174655621871977821285307554463403659856745964274018020456838460357574", + "7018364707286303918877589672878574811337524823085078243421192184715151775983", + "136380103284908296988715215087018020601815024625535396780012012453684253071", + "15953315437474610448052466140270091879233956524793052736202793153707558909889", + "5912305909658884889781037379491781973092020933879206417274479331390062715252", + "21575635295587180789566592951559325743281772394055590203112195979769645712827", + "1541325805478255472079288730846072146731241030100908414806224735345400173350", + "17207219201921814683730773200330679841907450967511507012179337438654141678023", + "18266907794578843029196926509122804272900478710738403531664855427655744759655", + "1204224895193276222782842236712348692319665277014183965830735736728887994581", + "4023246588034712778784328407820569751989619386134504404739514704773521558127", + "9064437981037864995763386367268294611921404895425171966596873454090899491243", + "18733802217274421976148972926716884457128521840010001893311936746027998476583", + "684088380644531080099595788833220377905013807951051638705160997709156627273", + "11994830816367980341637110785269531718699655485484715851375754143223090344544", + "1831724566362300629700078416489434571462666430381219293205871349415506993475", + "476710745682537342427691635955087951551678644045621275039835625280220347951", + "3586272766499559446129476613035465343616602918105042144185864609818186807939", + "21220348736799044560439132291243370111879983677197111626309132298278891334631", + "13683795063599185801186093771702503913590598475095473714851383723199050309401", + "16118007386401646906425171859166434660243697555307927508268622819509657450614", + "20930641024767526790605168032291665313905337763598128831404465184891980632233", + "8098646212401100552303711812039666794078834386731698810205195111722330322418", + "11585783577173465460243373201831086724911159484415020913089605532852648999143", + "6939053275662244505087635417541857793206828446247848992283188764105131966721", + "12798043540382494855660472922674138947867597503468216532170157050160462426199", + "20713389801600667412553956346192236970217099413304167366340548074880917096741", + "8708207547232102069057776099666995672015399188924281674772351753887161579745", + "16016293152251662056020528248861487281148011452459422778601663166015837379163", + "14324897997637439510797191208789711173129460994362368408063402682894248793270", + "5652996184880208428967511742390474289004021508049280419259474250332590598159", + "9877106633097964013050071703002221796318046172981334418310092241450453368579", + "5385816971548914185604875069230499528103133871233951354186676373318036241822", + "8683091293306949708478955451280670950858818602696102489349595054818146782362", + "16854975838650963077652189417311897888852709425835763860743171659164792100482", + "2485160816649177905834265823672532710299580013309324666453183278408904845122", + "13571692148185502188613896013359942531817915076247598483272449919094247957149", + "11899399615412173136098732970606292047945698835588882297719609812145308198009", + "16827672312681684936590464376780346837611857292837989006980972390576065571472", + "15588237822592586948064701827497915157359094833395277985658706133691498343174", + "18356642512438827417103800170157877145465512961188328254773957819312191285168", + "21642368145757804795143182901389223409544979732781450480847315495418822041608", + "13104082060493963869934085622104709047787444250961437496674916673804812287386", + "1561532086277971111804773016487251313460788916643968126116038406859074212104", + "2718320602791009266532615731130512762296058687816604986701989820504700684864", + "6182683520717583142027400659687593712743548729948584058329789905227082638908", + "5757242145794370726637363237313640925174531077560764545993554185332488520899", + "13688467192244237790806289073845563960119021610896694359815485764764608925981", + "12528461541936459922472167643986446262977222390263675720335825628163511159437", + "4897268894447399415795897967133432014527122426051771866816059363418177665482", + "764332419588242767884018802335623760055144509861323437945071732931233600264", + "11755468878196093893190753985692714003062307843033761257593209352165323938879", + "6006022813561851182403581780143813226749481175437001910923100661321563995672", + "13901542382190510449243772206670622017835690746895066410475076631498053123535", + "17648853891656481911225897080296737974064729032668806126284849597245044343224", + "15106333841965710929952896897521673254279668876709612770907537801609875568099", + "20899315415025260484895459315726322363345188136910564549344894025053466430346", + "1409310408943258102775009950750654615881913956151269414096059752250092035807", + "3899088673345731523976816322438172722785832982334214339521575164464706226294", + "21406686765584824639201351330529610299177537976609066339927938099572420696135", + "9121591670793901722224770893633585291275002987585289305307167711146944200595", + "10711764678410479049841945177317023555168593838022414378232020467195337241279", + "6599257303974597452501135281719536074294806740553273627128065549267140155175", + "2142616913275380526921597026822750992917222975992774063376747381991404337593", + "16361086527663411948363284957489078505159658832010445114438602510508720771278", + "17122647864721668762640781848678028227021534122268561738445496382823789619088", + "21708018685042482318786273055293241752114005312590172460099480713746031274624", + "8303630654111760473056607545365338851734309857718959193970615705292826806179", + "3658686547507488906491014260011151850549759409901579684176172268581462329020", + "7720024124908065424512743488999250878143598904717873371853608249805302871508", + "8805244918657836956533473437651380347005779399042661429698187314657501156241", + "6303681354794120075893215838935586592706844702088252970663343726024171795351", + "21512507181643408509426104627003618425209526633080701556628608990726677651135", + "11835373417333287523801757951049679177935522717858158305516568595764125190183", + "13059698839045014411602727811400239840163533672024084777768305507840091151855", + "17635240655824524168378284083397931667938326555447077097306236826752492079430", + "3374412791113107178205006579112630099131939030015047870738873452427211677886", + "649711083340882271985565833699379436167716866997851102439037906608755280128", + "20002805138014565226408902156524463368767807620908543995020210484077706418135", + "11071355197960433041624284534649121637702414580710232237233568479006159191217", + "1105441595020980635809093220782460032826849883993030969714432603468135735502", + "9652765957610682812348919340146799318537766051849796416434577860126024594091", + "19248299650856496267902926731608572596705132576830681367365128976226233392929", + "15285802367070100569572399512275861017714681455564415244982064571963339715277", + "19970416835730683993734843405673457882587154729456022607061085470691843864556", + "1017865638757684714433500504002748241987153668285974836527484933462490771227", + "17284848056169793253916338792235498052654877955690514601079806604278964099314", + "11718277105372928962350331838305733149270432706448484259807630484543527733952", + "6670793378364949883511003949124179112275066568088468958915163969545409700112", + "17088789393958965094855662340742013087397643056458490270185660553870734946796", + "1930788514812600942005320214284180860980345276633471423966020111188605196111", + "8844343159753729614645407314580317697758296041737296276765583948670245312842", + "16657939543606018325703787748629433167511611178952563626096990460124133990109", + "15333343644239485619497914931918504163396626751908652058758135581206765801100", + "16533875915742793452819179569144271760125646811168930162441077117553849625884", + "19679534317472082858641184998487299940737032844519038845860980362664393659234", + "16385719932525604857740698205965045007053424961009717093945644387917936681719", + "14490521084213123170781774542655088188106794646066074998587858678154251198444", + "6386781978322405984893078797365492485297499058328348606653460996474947075858", + "17508047533433736707046937662428611868296556965172642086594091783148965906980", + "14904597000414815084666285064575232635645852687797347860862157463159487771060", + "14979972442969995336727018758631782107138089738395941038626891064816880204567", + "5299243186271864957800928637599294208954109271450189950375274196644046222516", + "16189884555052883188473617525411302750109401983487269295700675997730645714379", + "1645560170870292006287241616671417605853047420339675073261660626733726665673", + "17866745974872498136933906591373095763114066893081150553715211393380040095383", + "5744849574386643500716045532645657520001448510343827372577217716983339773799", + "14021966200238971589811034967347517039341058556783068950884921208853167419283", + "1201178089866013320759085637098781870734315826415474628546655403142858044361", + "5875644793836087035760988842421852197052681650818034527831700615895391179258", + "10875065950479466897559006840696567433921014267247530366235539292597441428702", + "2221662399199449388725697795500999209427453463134383582414172135385907744785", + "9758513532658579204941116584445291102215928928145103503086996542188799521709", + "20879593323317766577775570558015407573466986714590017262168011643343469361329", + "17225846522404915080676699509636264825833159640824918876741681229188434930856", + "15189442986691997434021855855358620506645387296294217783597931695143376252483", + "15973617135551858849206811241799666696907820418171736027820254766840973764431", + "11888113439449420418408437784450952639345990804839507528208325036625374967083", + "12365920814385241227394825974928370916184942218042429533600397623369545597697", + "11966175169612449906889690852332416255478894176917636726028104087408060623141", + "11163554022908212145274813635928762748847331295589087669583554722521180712379", + "15273476004030808005186443499782264987539818978741159793745891769358221570633", + "2013969196885866182480519514425192091338553670034650196068995589691938248955", + "5008975446746271526106846692137145404766553748264648461545948417006052208130", + "3926749194225734582453671614337621250954608160208554883789519551411469033731", + "1635544156808471185144068767649088695307748439189898784051754434524720057896", + "17144944482517962143604430553750908864860079758005337246916094084534304051981", + "13823503533305241872793740090687668844401004819859520464168798913603662683770", + "16335911272023134851779534303717879370955813837529588982953758998930285394340", + "14467284210444150699969889681308566002886261365990840091849371665183151060295", + "10578205764525658336257882813734672799527733392763965031628376897794294290414", + "18771425328697137255453620743509164311086906349726510394566012237817674245865", + "21804626093983212038528370352039806004465345685985435415809095637323683466452", + "12056805308954301132385034564357716323176447186932453788072119595595483786736", + "14307195735327805282612857510308008767450554777122724855715789120735513378827", + "6848201070063637295416045855906784325422580350462489495889308309540335269587", + "631364713487758647973016689203003205602593076699875191323345338325349259049", + "16214655556434201961140525501007839859074077768660052713461045928979956365067", + "20940788212183642266181811368870506130164462254923655617893660245551698033523", + "8257440848494309435270838240795567828478627302119374684511017376568090372435", + "13701089242130867705897643891164147923878521147124165292045879194108024940909", + "6895272953337895406509859406973110417619874994579965619097329249292199573333", + "530437169778092455975584310016745919549274205817234464915791595041990209639", + "9008612822403008353420189298381046023002474279157557733428254452507266389025", + "14863423501786052071018008300345884780479084379412157784789951872243409629758", + "20091026239041315645045502002997446404106877721183777765607724358538559881231", + "11103877261161399045807234470901399725912406134008627937945079980590775715243", + "21529163495181909351665093277427712610965764606448489357319207727176092439794", + "19540446772694448035410067193880900774391072899517686330271100773183944540294", + "17549510450820803306426739851959754252204444648959723652883552677325100583689", + "12252518814610348662318155253547558779974557529822012236107550517806390105567", + "8058115132085119666951861652409945532276905989404523986413207631657437321956", + "15916100116790431839835734530362130437167135501074855072245598938219364570910", + "14256533476494466694764843270015662315303617568641801280831873052211753536970", + "17865471381417606502707639037418669122823481329049436020149405646709537112534", + "14015711483636570179335132940981982618090553643653746531174110949872682031017", + "6075776171664976866533080327142904134938121198707020111533599997509054627652", + "6357981809351565370498807027309828058036389418343890944791766504532174516243", + "15145296985037303761634018005118672316118004891352906450983918852209191841446", + "2473672396516437070485250176897956191104549656554290725379242542480862701754", + "11059085933391482002269653121188853142706883316754376424538662772943167665341", + "14804069155713123448375113552227724310276294677318593116834685772120057819258", + "10146378656966122923223443263705119557842694560695035707977826044606938090895", + "21828309590915152213768434346306434851424116996828875020020066586363340244814", + "15568879616082229996551157805731419126872501425454775741945679993142071548779", + "17504079509060638501918729619244098692140123800571022969294759717277257664716", + "2998311560047298465700351970612785742605093777116697796464434026101441410385", + "20229972737818088327107446854254558628041027965197447598027135778783710740259", + "14884874200763033520375899992902136897590350894844904733314191389520252900641", + "9619409751736964504139815024141276029474791187139050183491749032619248817404", + "11534029087676783672833531415041588991838838078174102967049055562568798961925", + "17106297093375816944137015955705541133308466659538554159312635106186252148471", + "21676736161168806529097919794022110433487869702564846859065695507460463414524", + "12596447704589377083704857810305080195761099125652005594925931498073219198049", + "310943124066162607352831846280730445558498286205117614171844835745706684432", + "16013029710570597613246104892930389004941711962070683476555063566372534206859", + "14282564976066063966062366540992448474634085812789771416509095817495183298269", + "20757241092771652500911491636894210910134068426068355089789205706892703219255", + "17084251309147907751212619949757520468224028014308500329099194408342072624132", + "14680350698112448759886861002622963534698534998651150537754386791270019720748", + "17739512731440543100681958009173086667000199263945053345384367808940651002571", + "8967486063900234709994801661246451094429250620940593387993430620369318619734", + "3906067814916986286272005884942051451306945488494283077675304366798199289520", + "2517004675157816404807349457307096161030587393097616279110332574293494030636", + "9995302877359286298434340810356550712107485295049220989690824504445305103587", + "12849909876017357260683411536833847986127911582040960825577300322066595609115", + "18074515800779889507358182860997188274134395074469953155084226981497567860114", + "6692811728183968363967959295970424292426462800383828091752006855360167264617", + "17859827663908740084792157440799065184931609649811664442236242315795442091367", + "12243409340804252499520308602187370739653046835019551522661290645230850934962", + "3009118420068966587115224335717185828292538080040896739662684632413054772046", + "15856202298588272962175258696610233941787471472716811521132004805327415486141", + "7549804594729480554341356998842376772514802673462970334329441043324983960866", + "6390806437030742378988258255983502109201709511321162596105974797942236431761", + "17370236522182003753669946647208335160124999930136364231371998757664000198520", + "2261672244214630177095236704932243497157963117166120717011661647779055001646", + "17325026196605130064689259977831126468940872193987407658419640959345091161632", + "3631641025220845885502691330008982895233731506600778684638817282531001457735", + "8656561399441987116927438675277763317789561532507396244334062468892541066084", + "4069166732330197412844703565599514109399373916243310212229125901351402003915", + "19808198732373520522982274785888742523226720967259539531129335924093928174880", + "8555796834031869022510134190573521699378201702450788201649007358450530423866", + "17759660636058865290579521740750449606781204755231964378855563896473545202303", + "1335826395218609619260020055566056869243760115287254209950063597653055872566", + "21596200365241795669701682696176077888309278223833581800772036945674858315765", + "12619752319673193899296833725747186284394167228468888029626464753793997178599", + "17420588547980145067421969830249755561311178399975476925894947008643385243007", + "10337481272389772505654575850886249605422739785111225132545740838911222864209", + "17928431631046752749930349099366498612885288622404560316665023363985966878427", + "3075798659324203306711977985120251896073145961913793478792728028765206521425", + "4639500613932181914847461422373341918892878975546430906324216810326467690534", + "15396322795715441250300995201889120935591602515487993982711884319616897970533", + "6391276937505284102735701938724106665734769352007891548547667448647832351929", + "6811373320779057384916660178551330838095673247430496448933336925226142036083", + "6590973140323934807800215988687710942074412987201753370126190631819398102173", + "19364648614154949386936259588484266535262135334799266379433252509193375956715", + "4702754284612371917466042550086249683933140314858807272591351280832918881874", + "1081036249074169248236179367049085684430282426446509768147097371368406374049", + "18548093223441988703029589168425055383154624592689171393242936199350770119589", + "11098999608073377668352846814752381891400020647878345005629685447730764310163", + "16001262992680194260590639872321865154716987495605624862471107193457192704714", + "21696229443869118415905915570780926763029898831113534481730746953640692230062", + "11716215712634983607563947056324900205144202447594949676250978337464771243867", + "1778908113733035314726603632369389424542091991692308812147944884836647395775", + "4019081204388123040098634987844274011285321286777408246805308194144238418480", + "3473266952388383063447927231564219811787341139731701190625605897592140631276", + "10457881304788072618845101933412333126160339089704353596608910674508961127232", + "14926101732700077295531234099443522459232814784151318061435025890154852791802", + "4036967072197259618286839959572768559469665646019907384624959071646231971399", + "12776716624632228928613396031717959431597335742467953143594165782617234803915", + "18894783424164609284436913400522166453255844750192864579927645453695213022195", + "6303809107919167113924303987533838414137996606980561570652539716097058487126", + "4729698693443803882717817492985796053343431875965792864932005291979914613160", + "1645790034267553926884568714540144778649055395816210525904813567839945991808", + "8138260225269705405100573121045873922755899939885385491610389913906979427176", + "680936760009829486282006800072001712155424246576949107399338687767760991887", + "17240357869291182045663678468827695873425113788704614245279840174870850373113", + "19100963939745621863641468371111320143895293700517367016077996431570157414340", + "16188989656090417148189510820963186890780289777598053654241741803194118100843", + "18027402882394597868782011288920739982398714370069420860949975937357531046151", + "17780529984916796963712255733293310230026423072958099290880849386941451922559", + "20004531511171838591303710792081846238092292916166965045929062171308088520097", + "13855731634251510230399834192704620793850325654395687428672253016405315169901", + "16872938837392115669581040432902657478544143723662502779821325505282093696739", + "2541555081244462826761076743762714962901590548271316707071685417008817634653", + "5136424039269088350807839181761422963254683236279333039713142751702136147963", + "19216238128964101420135465007632926445321991494181045543846024053552797518994", + "18868537488540023742258053821537824724371813776839672880900985865823137839953", + "18246710415801024039719497716350501105591286880983169809863166130543617917249", + "20608694004331631709610739723463009412162748201282986294016482926528443868949", + "11318113915971658853560322943565673154831611543653209084299774855226816037778", + "16240989418312335385576389959938922684406585560688799437547298624184839261343", + "16171299673760267132909753100946681733778389681324959987573199154235691694977", + "8036823955656422391918380552495301547890420665617977624790236120392727764522", + "20269862530534739231936251654244170650781428788816658397167110617927916774329", + "2368678892744667199202318323282128737449992006513656480477288092472671147090", + "4618078962163037429845764284139891171861860687111566735174912070413086829215", + "12695350627501306162901105159009497730633599768443844225981772758225613194238", + "16356283146491744069785034066388746989409816380917535719898337817088223419024", + "6407893217596287850421377738867081146106659458551198123106454022096864887316", + "18168868018352364136212098098453930600797374324006271488950341490483455519349", + "18352629174410142476418438008157117497168118524562206830585500251463010761689", + "4344169393287991961961456515301754172943022039566219343212376057129143739343", + "19424839806870716108478074501405697296961947409763509419111261767390677718987", + "5796037897847804302272999466834285170265203646465480652521088328457333766863", + "17402105801450379889120987010453669096275392789725153915905747267778100864362", + "15540989618743824352651126288511222263828123668208146479603617243655978402205", + "945810410725426921570254447269595873973858272778720657523509910503434094174", + "6962323734045776666289031609372270190654631739266635759799844631053633876675", + "11382945272742312954364642163371436855283161775445664525053938433459897196647", + "18940251871958826726849623572811640436342841713786099464305053400421580490631", + "13969540696178305383564753026163726563325318478290740131984853424331762285147", + "4841983966001277917879506889862519614692143906356361564304719688757862622407", + "8939049562492171082419559182596894186639203815268680721033389307282239000385", + "19265363396776097866041313346787101192508520582744521467413665478819721956884", + "337106861429123598189388456471513480497137213511877011021531147545809512194", + "251367482782327915297484770356856386307188967585026711663629212746150191478", + "19506616511267234489421548744907283107923549136620297132842391511025844759064", + "20633589633280372440758096707466273580151526293980868749421563697429194761212", + "18833062060138888612708634036427140134887774731041742144004707524569102994071", + "2927291160590267909596732410727396533948837350308818016906834558527125752899", + "7095572562193114209617459307511041110255341231707924363346373597653253806883", + "14274988113217913224290208839851596837329960221329537670822013510325939323091", + "9965830780560026128320556230399915681196410289456547935188741323403719404039", + "10333365845496980935202034863900757172839454015352626511769637076650624839070", + ], + vec![ + "15193892625865514930501893609026366493846449603945567488151250645948827690215", + "8655680243784803430516500496316192098841666200175185895457692057709359214457", + "11710807066713707084726423334946631888369490193496350458331067367713412617049", + "15442364818086019103203999366702499670382575019009657513015496640703659810202", + "1358747428976145481402682338881091555771254635226375581638965497131373838774", + "15658002471767984962034589730824699545808755102240624650914676102923421241582", + "6420480504329990097173256112095253518339231893829818344055438052479612135029", + "15457172495394305353698644252424643614748461590123908880271021612601244389162", + "5745943350537490600340174787616110056830333091917248931684290284533019091654", + "3877253492903478989342845512796806320713689655633086736499730391667425329322", + "11257677301507982757739320943403112189613848490812422490591766717141506751601", + "16906586852467953445509312290627525856126394969718997799028223470195783329296", + "15263589725854108297280528692120758129000336125328939290924952731952242586386", + "21735940039489460025710098364749096267519151075908323637361429746399161905338", + "20023056608360522105358681147781839024069418874082333862551226466128829664291", + "5677500725280079960679484373333947430817198394184436922575072427342643665917", + "3080516739494460477657748111767941482024045797587058388950619118994388252853", + "21486496065617100719537932626843898998311175055335457507845650282870586541596", + "5371049178920102602305531530023787518286335086323221270202212974241707302466", + "3074817222296007572297581554183445947239252698770067839721345984255386069425", + "19180807038569629573914331337874446591506172622522351734982093457681161813141", + "16937785199372956273358037645552299688842385008757508130180245705952406225194", + "1688218397616770248184651775433764527272029131542529408516364801909017591719", + "16315958669815317541884966612581197291281164499674338063931623110684590850347", + "6218230753007070123505625054833158632732536069700963073464625252554943737669", + "17774528060285257656595928889288330429565059134928074258373583886985960212139", + "16197131592052727313460949906369199026477758140133103701908949020106767192893", + "13418604038232148873269488320329340508522225417123160144993642839875173062296", + "7265658443160253752317166706266927598319661172006072732797351716897681315157", + "17200150079219747370109251547638276280610591698078334228421747259741754887", + "8627121890622175767416692555014275717515106888840919734160364408960047296494", + "14546964505431549758350267964924534495477687922558528647552728692912697049247", + "17132720822762740343718421124251772119916072270451579802112353604446214831761", + "234333065870376500756753915306346778417056884715946003873280290982247600083", + "18375643491701271245209094287106352436174133929245169725584150600992143374298", + "5158448692161567615645197008737390561357077078129599243188536485308363800282", + "614161645152783610732075198073600394068518413590650990586931263981193439341", + "12661793104597977909223565537293318966803153852970198322604479648383643541371", + "13041905650419760925682179803296711066088286278603171065755078690359168540579", + "15006023590144168506070897325649191051975999212058008674224953860265667513015", + "4983349941266961584317889823965291023669365981564144622292227613558024302012", + "482274340065333833495445682213681402212945945150526736364263233985449810602", + "3966893131006556898236790392613869798057510088913626163333804949895810673044", + "20923301526284527685000591080290190641416245135554916208054502046381491809443", + "20838692384005825835959734210506718428443540957544929066941550833051093000166", + "8282357714606447781782716442854085217089572080066047419459610560432999443766", + "5410651444876169088887579490283094453001167796545260026969919887357676973543", + "15276966646285075387317940436655285872037988805762800567413073418506412856419", + "15066911464727337689573664613158712498015597773345106524271610486257089622849", + "14583790985054968382519116885383608902981814292128186470697458065499359610203", + "12059090796146479535492139954279038037217093044815277624197659219529427760034", + "7273811886044732271171500579064359282424476926867187108258957006777685922641", + "1463086899665237074608503061872751147444637332808872866814340325832200880984", + "4403177494620214359779479537027014449448686844655371530169401219256448130398", + "10860968418848589590932601250051274256181778387706764281989724391784015147562", + "5268786978207139542368199165627108325282167169564314266747401266496556301775", + "10683355823176907476704511935094343405052640940909677712096702771871787224727", + "12998090263935761477316698114799901126086030852595294916463464609721875730852", + "21401280461419124637791689956622923839426783908187419462727763377498739154778", + "9827224472048063173905906705579289843819400982583185823840008976971109664519", + "6215804144039763858354471461864183189301201862376216122255322421321775987311", + "15461308489200344015891625455653488930440613755785081602434124530381300882814", + "19336334695450889400681207491394600659946256404722006637851709906131899294790", + "1712331165786355540802697725399423752392267480553199895882357858951999960061", + "18153038525983970702748717571053178456148003321236490384959117581005013333018", + "1080183517033034908031748897211289245459330899463186432840251241943892326023", + "8948022108193679628295152361559653763100984324221629445749311939820327674857", + "9553342289560502306921915013446606435600388298465288181461633559299564421155", + "12714965617376828547637017050548818007690047452402682720666099310241001848988", + "10945704657865102635748104464461970844653553427083981539165832149959193156197", + "17511714411688352203059545713591160825310809755917403629838415797949261359373", + "9253691969419856285051096287845246422848295397226841130282244592511676512433", + "12218945350859454581754463621617733341764245716874083264842931063272433793037", + "15268139709971695434346690496076067658968455677120655340969837725391575270485", + "7948825129295102283421620705853168119104356217418364837218892682579042520651", + "6887299291348589691868712194070626390224806410428583073294593431810559288717", + "3610235157455454109573625364057240708256027358184031380521552355839155549623", + "16532488069063334064099666525339953823111673083177894678898823509406678724969", + "19317517725107761280217103201908049748015068578935276576200982249386084367574", + "14980901224290526859762385599553818204548992110637275324411078408232697158492", + "7741797285700915051013289492475875831764653137095445146268474269974647962596", + "11964233864746181868467810392101989052496076326472717372132104394243614334823", + "12746657111181947224582102380049766839578185276220682311596480990298620200286", + "6408726946032901840418309506578019708113712492100046332894630652186614300568", + "20959261828945984489015610988397031913577918654575078054490013338416801523934", + "3173674599420546165852740604987014294355430358334465189504551707066179193914", + "16110281513253204315524614633789708146700074483476149119440509845258215816735", + "17135377580103690088853370572199271964414896742342749305424508776150797285064", + "1405769920008485935711505753346340073052795087429311991287498566024570212365", + "19088073362945853867763169651582894739272002359692597239222895238839593467749", + "19897231284455588615416169252449008151349728648961637517447194842672488184146", + "20476415629812014715153863754869742189693986277342067785614833846523246536739", + "11074321446706734150375041020583051611133090415774365192315805856051215270782", + "15231367549323128694183572409135806408519505225209496441892541205465727777072", + "10515952069292929457050921929301902464262874744159361114100398880194109971971", + "3216370118771824418364829250073852356774095079734089790620447714552849459645", + "1940445924652458480775282556203659335417827058983719042726494187979000691704", + "7899310668555694144370607061960060230071621529123669746309839400642332452086", + "3125410912833939638823760577011271607678545358020637189655641109813198731542", + "2980079409624774815878860133121670095839651294537928173829312563570356348730", + "3766498515736372882285796238406751547889526137955288498682767455795237989580", + "21751217522789414135074956130080241003845828660310903627224390345319859795839", + "4947229586642010378772262640583556676497656670779800090478805824039760706318", + "2168676839236948809859825591626629233985269801981092020040909992251312517552", + "21172906642114648036685108008020762271569381607092920279879047961076646303327", + "882675742500939602754673078407141697482716600335919344527751158504426951699", + "20942968937722199705624825492102184647835614761458159157410261242387423597787", + "21880640497503102067412608072166388563991106464538369680846671301780353850077", + "17593472026567804917122179982860735087124786197105685847979050530954084564297", + "4492875530722152383516030266828166766820778742874238188105265500984280376666", + "6799763500412433367637987497601148507907071065930142757525839585946238894092", + "7812331664758167657763399273963290017340604299019483750344476103319142702775", + "2222332747647756867926707541092465789402467819000336747029352557749400316077", + "20438798382149666667185974604464532451975024544676922060351031604444896151494", + "16155157103796724378615022758633778903205872772589663310774455593497441785913", + "20281325298063880945091623185126257485818350714264176365501683813650871716911", + "4922178080989486450454493110764936742315495846015561426329316977670113220071", + "19579063976700768282784922967523980346960151903154507737857728349662090787824", + "2458828873355000645851832396764221987760639423132968569631493912353159373462", + "21166618206785010755521994106737991950548963896649678270059527421944129497211", + "9131643699583013708059191290958290089892787165715294157378879201986981390031", + "1820371114511473946932363841206094088983972935646887524223011276305844153307", + "7264184404232663540867032945940974372967974872966180860960243405462016972362", + "11228656105550475045610757902396386402555430893045183008968975441800824215261", + "7151503559113638565935009743218857812859208253653498318591469659718664783964", + "16876040581364499037941813142092448836399042253618385783944016186340703846779", + "10334125383426918152464737478646460879481305348617711177774418125714273980769", + "18900559046103390399749767994653107625464807708680067464279674225251110804100", + "18685667289312169245526749652972366835289568864080726348092618145885982989561", + "19970582871354083670567197978171723431124602481748785146813441774826500485907", + "15873472427137024971035326229485784626398898771525077832924901475242073457867", + "9090803292122260583635467396769157643561973206888822931647063181944243467413", + "10156295009710074552070572489422360071526675259143523597882131082376797944708", + "18600630374968456966046654667577076758720435487386724419578803020365834014000", + "21292291483064245088298314957584631356250347533568992016547598449487977536460", + "2784266893057214755054197979675795184619614089277590464548240934105557638370", + "21206743389683892419024645604723431382001453245850423743581664552645211926469", + "7915761821775326316473924816837591351530533394717381318596295803119061411675", + "21881095237485064870468603451853549262304643738646051878343976465227744077912", + "2011784725603622472271597952122938645154942022107573948889667939904597454410", + "21059869383015715705096974077910228193608826877524913363323189378554601804559", + "13660545486380051482020817701263881806531607595506890631732662177505270213284", + "10831091042775967380899180760062457635694790868286967266013231823406639854653", + "149288128407476550494800886735600251983375852319258454101603889073198917321", + "4032475033542195421623899365282946172767274020529645277615759958662043553317", + "17860535012887415629230166789742533149365132198763199254812432302158542514395", + "611194463774512114860065022851497908950074400927073001695280142990812150583", + "5518364261187313845085346561539515049557757056751872639492957432879259341390", + "783263978868449790737487156609432867806742277074765259237378374864740012575", + "19059339826992310300213673274315612374137067865428300882729551175173242291657", + "3179709304184015397125565132235783368222831063701934511986753856772139349894", + "10954198701843076039176000728742415722273043852061382139560487789741501275316", + "16411266672500930935370066093245284646483148609897099268661795671514664627451", + "14614816948231085620934132277599546641612327229810158468490195811014141518325", + "2458257206135880430320027516329707989817636936777744813891328347210486074414", + "13549483340434455515002570470395006683062583844603627042649952800864870013910", + "14465927800403373425828183741641078057513049263889255157342086762479739044711", + "4039391352709218793104596256671892882216573882631238721514928981154171136548", + "12750457082077152291009387792121930725761848879916565703854704756389714536037", + "20703941646953337308096638741387402857948436803334980867971163138332859477843", + "20148755487317949638981041809982361196106823990400472213765926589941031736503", + "19035096428824471222963574043396024781574056587456391309795571372815435282399", + "13597108420431213178364236660710194375344287228654817880431599113069659963625", + "16737817219786305757887002253067607822378794077688837656791543060369162185533", + "5164935079689729145670846016031605160169301936105766707946436049006171651941", + "21653381930704765824477248798502813954284378782353810890869232482999795586793", + "2062605478140760101860087118379474541965619844748678233207247884294051836812", + "6841505950265078437298089354417829781031272459823272323626556598403583002674", + "18723551101558427097952125661588457059960574026361073828482106612260297969553", + "7898804490983679270754258611113569895515918945891808074921872907759024464249", + "10882278698112390755842292529204069263813359338030917602809789513528936860051", + "19447560013395173052961224723195565400117958329259001072560983848146677205053", + "6251288025262210726686494480483550276704856797649458538460443509657307219922", + "13176666617050786358406074057104742181338809005466316548399895981897535342946", + "20703225796049910173111490454489910459787604528779911406172217267261190895618", + "20336720518722954780604743873837334696992422089627753769439653667292899832714", + "21420427865372074512365684526694872695798980614525900481233709853915806389425", + "2498895690812694987926199054702295457557454143930759961192198950277119149872", + "18753512301709603592612141197073246313430368834576850495154922324845448997662", + "13229612292359498096055458608547157785066962647476451239567069089111704445000", + "2690879919643532184588441383789963956137193400890598777054187145581183393168", + "14142396602342548413722428497204107502988046500369932366351553161157672540408", + "20448725195660080278132534867269279218381543910636641344871383714386318629041", + "2559459540570011016181396098001618067535109329950570139376049832813577592045", + "2209294835847631004298393339896770055851570184195462947318472391473531519454", + "14610669112573509857774678749257346364319969641690596877040685661582231189775", + "15281088465087253563674405311018738676067395725444151577815750152538449780965", + "8600553033773805414817363397077178137667131851961144771667772828459236208319", + "2748346039979601666392027583251905158817539034260921486084376270967628661657", + "6854960712378511006304629447898292218014632388505703802374806527561178043857", + "20207552563190343462280438839438087615024485494479390954719687107061991587248", + "10281541252271366635718295778088948309847900730867531177275273130071062184625", + "18855605847424121529776135453072696981767402526737712879984848146282568841809", + "4160214035780913418097601322951078913381556877408879904436917334405689553255", + "2122867135885631508183413043949777333811557914428796322029495785048111325437", + "18793959580906171893053069386015945646795465354959679615181136313144978078417", + "1043591673717355695648236328597936528752358227297053230241551190351813693314", + "15686469257015275311444450012704351019335987785561570672026138336552980987277", + "14048856209379833670666148034655599475317994357805584661156301746235313941815", + "1011563953969880478397969933799483261900428580241502003261587014788238280391", + "19240556623066672446907714818724971233422104071815927265423017590508305430997", + "2121904286573815063480388650799381683473766736407678915747169455786741101182", + "6724437969134367395210139771738563153857495313330774537559578422672993498270", + "20206855573383441961836932177838081339503382415601366823182724056749038447809", + "3659051978213562322887447057085386386485486575515693147713900345497451171308", + "21246119528547168535908718411570119652856799993958321864163737649108920924448", + "10446114322905404392321651684574668727564081327779662579984472408056125404335", + "10052242287865403393859620372179811039720807230902452334457123873762222543944", + "6373462744579965543231173757071025010089494620309953425653057223643612177083", + "11716070974813426833631730493593924834405915845847679294742728105127112594434", + "6451284530793440411577197006976867289209413848762574411101073727224316913966", + "20143217291446069633369261481904349401356557325260758866598205109039367201468", + "7741896897172494958877302103827661518814930985518070029789560123401964418102", + "7414486245715284930410091802521351113719159777210731898112598211035848096490", + "6480506916211642204624111742530825907262535747743645014149694168805302825019", + "18349725066341807634895742572304899830893334427067633858521634672944685466440", + "1838291082333887710851505844271184097051704051003105078056248035350245616867", + "19201915197596065583046168024521824662441686729039260890206806469763190071269", + "11253788423541320580105520117231178489492440242200599071301755928628199128159", + "6048832714406694444296771635481934823208451249770515560893368035838759154821", + "6398008918881249487422929614611145638894557821587972164243877575640548705346", + "7013037564266297435879776776659289982125632651326438965546874242685502904730", + "5942504790082366811245813670914617310604940200824079289270465669331434165301", + "14344789199380317440464969138686896230070901882253997360605407637865754361287", + "19920212380356573378521292048728904573841049083972983190424200459025557666792", + "8983390577894750782268266038315113359711163721228398686939390484499979421166", + "14953991148867572055684497824790735528852361750007063016470842397064705671772", + "5592033578501586280289038012647352732276003389059749788953239057845882297561", + "14076883072716069263619564306953450824526010844333044566762059693672378725675", + "11108270411921226463443318601950168860230077781212396032908932369105145901793", + "3681277588815101350213324449908372578846563884174807724121308021640034446476", + "7194753190480156904207319938161903897566477363779122267985209483435838216959", + "21241255448366937244332942306324590869759761073985963892514045368815880517382", + "6203071960722514588958553813186803009742459823360660333787981951206442471249", + "19041823565851118046937769551785013706136778514067168239416647071096062639366", + "4928136619692555022185087228378238193895894009623071873887735418398682287593", + "16266329364886004534411977872528706660422476743809029518681886596981922182359", + "8814684891729998059175829142248330760704444206534875755023421115211106199303", + "11072277000652722690981202459933101924925520292174200155471966778637063588914", + "15889576313969861857250394875354819627977602318110620311480656842740292435237", + "6934515229262494305594741689326968268143898236690173897991110238064230886755", + "16212991575388366798683594066983659236103186124339324856776288894513503543244", + "21100508914867482363389012032457112622475533432309937238082785660233880354422", + "10381104469089401657446748653199843213201270332853172509558263968565255702795", + "8849389605935865968361613766905708889092097013638425059146677490704442276611", + "4826404934194100291623537890117339503344940312401101713754206109744511979962", + "9981819567268652304810465083896863711149056310505889216307212434682251812603", + "16218484218588441290424553684558267080330286201433140852298971691458926313766", + "21317661296916247018967238829275056855142711494630067664736600708605437812892", + "19523923008662567951910986132173659591346561824926093935331274289896011695634", + "21439241836891927940168832009944210084078628922824257988298290967895179737163", + "3818036890597976956138669961319975835941979944306305168232209375279960168960", + "10212547715001519604442389033695156945619060410131175896383181616280631586732", + "956283172524544133830416114111944076629240232397666924807554743752464221045", + "8545109273807246425343308224167362024331960554428088718932211551700420545275", + "5647769597708100114837534314408246331518385631750569421373379085922684908872", + "21776221280695269311212391423788179027868152904973644113087833004348746215729", + "15989020831232836203074762591626149244364214836699154611339161287030952623233", + "9384665943619921791886218744024370375464874104981653298499433530463000935024", + "15469006121097295841026542766455781293432005131673839148320165243166330403027", + "16103671377537767724271717097892044266704736999841135349844319906338275108222", + "842367229428650719054831004741080336526228967970570607897528985803108607790", + "8752325400224955775788313769797750158375262384121380328719514077259567119347", + "4803861091350023344885030428100876947830986453029412601567992550504530969575", + "7917553047944370948250445233027936387189889293110390303835890604428798853681", + "16378323148632546424902611135263436821435778030958161546757828745002247975096", + "19873719885630097137106352132870659633926425645300622070145979694717581586592", + "20324790419158243246762098227260178678767896786893299456278167341205663612964", + "4358908354524026935988729716331497263147669784003421920394531784876541301801", + "14403952632095852077754539203207047943619815438482171213105824864831554185165", + "16410713482142323347391147127545553384558868490870150984280601225023662513809", + "7304216341846662695189617252648753140769311862815448449926830269690397729157", + "16792943782280077475956215580025612636120139194657275471595325031090407485768", + "18494329391227402645175320826355306995912366111176422593669423022411884295357", + "3277597348237827068690736756050060740435013727549848360800059544123155276133", + "9396765756719511114743964794180256605700037182617127755220919249774110852382", + "5637053961584389263881381098869862042993858662768294676971865632259649027245", + "1752142832257643043564515360000718468888861086573246457619082905919623770956", + "14504506574384680785750882507533398260948836347427103366421836731538357314790", + "18947994518078004413210940685748534988014581551965984303066903086446389273117", + "8931855168578615387850254663107425567403115805663142600825724478150698936342", + "10982092525200624040399870568387498905840578524691489797530932831401946309626", + "4738907023206802373255186532236849256768509848242049657234258536668430260775", + "10888145285628319545262252531874405309329869513560101920454793431198094714989", + "4767721624212785367044047554655794533816937807005608600525762243335180089923", + "4054394679973840378112083329204220302222586590732553688297938891619998137578", + "15390471663419625573793381445844013245022413344196724396864223784781333233143", + "690498740448849288977645176879593806019080276382495160049117613302192708860", + "3326968907274045758110436838010900592335267522219473049427145975873344598768", + "19461545874830130561487975864151403334363998126023624462211037468138940028328", + "2255249425919459031033123095731665691066980364231819200773725596456576056043", + "17139538647342063569964264947811360956712827863014723985947727876623459280539", + "262834317961189780923232082352297808796511874872711860311746704570027370416", + "17784213646586812350819691264737755884800773322574478474130308351003659945289", + "9206479615073686723914227166450906925650471865894639492301222855979337534393", + "5955379232184076713510750681781395826148323482009739159408415185190732125682", + "16345512244217240951729073298135981012471478596479891072149124888060645303490", + "20053701095030547796310908765544502773063879272854547881438596069907281565287", + "11519146559536679602608982593432194283609736022486509747046459824035493513614", + "10868663839942247532249591973192159672852196011910414460124452013501564199585", + "12668355291693420029179738224611760713369106517542315102687346083105601320689", + "4091011252347209563858280520339886760216002486858313383741839652119084430270", + "11416347683590132388448480763970462739172261435271326798646502987745949753371", + "4462763980178675172541782335457125059884067698347130082276003539434128058577", + "21728891122467658477520865529973242372850367356840114983386033432316519759391", + "9556106604731806817435679463077765288658189491612307664294729425381901530224", + "5086982973132652080709554654284904229374030594786774699435814748257879554118", + "2278505454992311041650060186856758463754878439802195559533882189615578260695", + "16123495070352975934848591912315341924608875638550779884194576881433498909405", + "13177225503435100563531015597038445430211235761527278782674200718068329833622", + "11626932451843299545922103072142674578946680165802341368625957942237790110177", + "8872973246419344365802198448930136062421718851114220299577394844231810068090", + "11920016786052130191738519934437207519332291620474831138559948859328822621221", + "2773753221970604083383541092979093729869734021029185810064937974430862835870", + "1194583082499114147792330367943150006952486615245506995832323057119894886077", + "15293312601348482070373672684782686300692505365845870624263228679370968807837", + "2292156760291800990693425534213440357167359161992251338587906324724034592198", + "20920049766730284147153707151387304988393631464951398563908410768221002588086", + "3587899345078220957148828249287269521408604837648269936718299413697642586126", + "5857527906708110948691023855516662527925762284342493618496858248142623857037", + "18312267494676788897591109008609888960798722042916784593521762607767538629817", + "18354455618287562133438807735729369657256664914390381320892039403006410339493", + "18594037435499535688023807489676900345345731643180370940972090155512943637000", + "6361231157299815359812386352981667048590510979947935475914610076041390336883", + "6503045850716008738909204934356093641022474278658078426701342798380459107813", + "15826908470360778431798326530563200301151807861414464213699967513881040969457", + "913167165738148713876672473302437265273760468892350716109373788573860454641", + "5163418960719047707254162004625467116036830361107107814320243058319914687515", + "1852750695670141634014249062360862036043602867770163972096325792863710036947", + "16164029969996795952250343426848596535809001568622155377829217918121790073916", + "42291476149937488089591434144089904529405222471677684973768504172369443350", + "1329340386229357940610579826659090359930768580941108555938139535621252899508", + "14087936453397725507000489457270864434699508074557952952329368237400407748133", + "11454917885298514922755456675259734718428103879515668717779418480236210705323", + "17749966508430836878443008025013283275306943216523661550528505419303121693213", + "16617298839486771009961431205770630163409905047728421465641369616889696635464", + "5622873871440608391107520706189063847917690892897751818294742462879871297589", + "13537715561706278379083684257583804567523085149672090320983273122424669242274", + "12609629910090871112615676094781247031353826207267723991911250780907380059468", + "11881347692420971451998583525696964339513193164613288356598017302547676912004", + "3620434358220496198439193226313617496907852030586214671337652678218740406153", + "16586456872124455799862826347901525401871594428044067424833235946565396779382", + "19602593015746956165116919928045364895525104709835703557292833702385934632182", + "2465427491077301663150648330772125184470808854603184374760649420983178107738", + "12521323976712195518272978277895155774288446093713549157148428964880747896725", + "361951232333654306694462853852464888974834703718677826403016226307188397185", + "20048343816024297162848487251896481827914904696805156112188099141327595641104", + "997638030405613623344188782838773314122493364653596616029491564227193697621", + "10932007654988104622042938184134556963651043067553327861790671211490960094259", + "47171599193060570819891696279547021610376047998583333086685382152080932821", + "14669115378939104862697280661831896914139331878760241858539421915983017116504", + "17868874372855679948405169936193924176514630305572838555185339642210810710203", + "10178296575837129106771098084407669500326673901243393867574658658064222502028", + "11497182727976130924559852428316615034304736115488257034951588831868596612725", + "18847036158089242140209840241495282890278502700082131513222116906134183113862", + "15514518995390761662346743876733004358408187550386554449789531199638765348953", + "11474102901522012346251529527050392650125347221410246734211005177721289856415", + "6612195415835443084676700243243174090072629504450965229103970796390091290688", + "11572474094368358234669561324969692616275099241307798860733942350364532366113", + "3855324911963410548772360326122995145790506408472649961229511965629894550308", + "8802640003128749594245736338745752744580147773009816234644244502373660889677", + "15676839305513015047736600040932186843826469281853634239081282896349443894145", + "11124722103091011602185413968164672678635980457394627450785290630813993266691", + "15087674670944618980358596427703842917302233637812357643695687556421910213028", + "457555060782651847600218200815104907046227486293278645126081160142069992497", + "5340353060455057701755599760342180989590806327490432497082435572367648024359", + "3289809733259936118731355294329652879189400852472418229718273887860572748363", + "1821386174933044868215348232606758690922944887434531299978498726875279584854", + "17399236630582894158137572250502674699298844870791766041927951699287421557453", + "16772722824042046255416248879357647708113647471330900665176012648038469814744", + "331374066696126093678097185404981758791664151917354547180452342655690460271", + "5482079579065945934120471179616600325379965440378196448353560421120276746028", + "11861638874356162254375133266687016527365630872709665703116365332534843803431", + "19751278476934230895840638614095718373810690662562196455711240141902305648888", + "21017623330912840225230534280017695045717261514215145256795880310933667407841", + "9692530233397639077769939390011937602190121885296235066426091743618448584134", + "7914031992737639503490179289412369887137436318696390718781298556229610513180", + "5046304088054212585035723354298412694927209198400753780585596829596665931980", + "12735457541003664856181534137486291132119134214862779086936585300598349629287", + "8144204472889944485922664106370529127382213990656088602566223875490414163362", + "5526161442679804982165840590640681348630369336752481706044759543203459722566", + "4665464612431440885211271075488840033628676516298384234452346107374012633528", + "8451965709652752887539585363308640999657377914501438391781526068371105983117", + "18990458193856163728406448194111866469438835810342179114684453609893347662421", + "14602960690767985987882800342208585041637986661619503513589079723840776294824", + "294650277854196485752526848096008214721988745350555311479128101695333774927", + "9930361494944692931597991649915857642608730961125454734483697613693272941776", + "17972565769620820679641368732920396905240248490243886868922250461473059009007", + "11842743032528966560856860268344505094861546674985872961254820091273444880060", + "2260251491209762630871337015316066081541066308706934094017641769176593121838", + "21336986809148977544823484666876006147697590184356254785752148187171367963063", + "15637234083283356311249527335446193685599985235080555266374006156231977517227", + "7637477891046186378249227336975234440873859617986704147458186423096226771577", + "10435340982947407847927678888878882924793449778165415690957335683641419176012", + "21071574044063633264442120715854514033847137356154103023224485568597330648075", + "20085745552872944745120547909310789275453780111307008151203836541147270866122", + "2369255222739182549768488367357061329939116877812397072967912842660453854658", + "3320710154094663715463854219978294133429318041799642537800174050047893035878", + "2437552820481788519744888712380245016748276158860265401041560980354471184914", + "6687580113987208531705167517979176727449238324356562435678492283111952291541", + "13835828959457330678345759960614663723017667326485961761361157914420441377430", + "1823843951353887792473925888956554516299304358703549730900495356152013614424", + "18229384804985230011714562427207966412342158903455811854157839446374012856695", + "4983049472282717134994110428470567601005310848076496400503178535459679438524", + "2047051967230753763135778305592853785901616983565528680886843131244871631064", + "17059505494771925862841990046823342770591010831955480339095397897088168520686", + "5845823714127413134610517798305104245114036685335948729450609519089263487144", + "19810252752845594230307894817800427820113926573704856490871938876757561680148", + "20741340243371419379519807725035036726040739024854919427690724405113594586449", + "17305746835229988220561638584011917989169628535378748397361130724475478785704", + "16273970657972145440112726408308019138099820274904080726219726815138597785735", + "4927605725478881247988642936459897069651251926499343645614635597380235002430", + "4076655226193629464789557616268492785057128805549395585385432329518368497686", + "18134767316186963456589895259454813585756254459227058992203617493951135964914", + "20798436806114056077588608064161229365173163847083955162560624566238528904361", + "8811900287453512972593412116532745098600991077158875340182906101108258578231", + "1611466530857794066271650650204918615746591649578992581483080164777650137733", + "19520757346022691586967284723955378385034675472244175822936613026597514818901", + "8258287931139503595713718829279050060190693609290797346704848518381891359704", + "13807143439443425137076128013998009581746894329904809421858222329599144124143", + "2034200548964915935625429760202284220693125881760822084201315022529206424506", + "20594375914400911567795140472107624446159181622166676420027082349633992663301", + "17773828019575037451999782968066986504577459910353828196403976545023426528432", + "10645884969014005687699860915213473815514464399964009808411811895545112650817", + "3135829883501342672772973577699379927756997243617424917654928164800203666496", + "21807676600134151299257078976418813484444183016737321278512745883771478511369", + "14168063038909284721702678019083222059818438340503980617872573468231611140141", + "19022539506931505257153342575586362988716958060936788031721967221986624233067", + "919797128086310623571009200546035983274688764270933413427846490906074137487", + "10651353481391913627770814216074873532920753703051075188645774021198634943682", + "21601553598752750925049978818528421110707879819831249175157596816870100048288", + "9544964974935674319204796617933096476421551193682156030394816088243121582636", + "17113833205578964054057051521784698139661258340576694677296240312431808476286", + "9889647672195559279745677506312894570402108521106900082889976819798270827735", + "16028191999932520938901585234936954312994452706490572504997534210876573833649", + "19224701772787524647172128751148104366752057774529591812815327738829591289117", + "8065294760892477625290114823800398061529770004833832691347498933238361039736", + "8385011404987806129246014860479833290406969218526611328586242951296814426438", + "17626526623257098006524211054563886193098683828265081734658432468695686509315", + "9760584950604786147191288118087660976225563461953070125437519145090832114537", + "3282956645059793949082172795607530130101621492305193365378997603911833418463", + "3788543541342252822847978185963388795825378340921321139695221828685330606335", + "5728277403393912877393143174229934529937061751983246730506397742038949251701", + "20532577038632159357383817240596922896191478140446876998140515404169184846609", + "6138500779693128517529525961343097735306947649093633133232282430353593175172", + "16387038830089541476468870208162294639575042754761542956218362331966004300870", + "10184264376398708852688445921404363179240954227345322711923845040842165453208", + "12576299651793170522912156101640799825541149618303513174146382191633847258859", + "1340015400080181141720946234858756484323564628916867888877667239334982793481", + "733959369856163480135680991009606990817015555938726628110611986599242143578", + "11467033813562140192244869512537566463715027496952375979909160849747976831918", + "4619667645046391146577435774790188488541561222783010406420406869960248783331", + "58552761198135931030902257754896948615688045302818928845814661296914920622", + "1199849881730507352706524556330002080538296688430736582840314007371442152147", + "7124502590511184113044595527748024819132713282667933641439666531514739645089", + "8623660134669459112474551498616256867375253975034970808437732784494772311361", + "12655669439191191182341423414424342421477486764113555800095493091893820045534", + "18432703875775002490514477493898870315422995231506677048275960580528644904682", + "15467220287938881354678249472400749704814316816035426814619089032223454845193", + "2851120240492392321044027263769720216640877441121430445737594074121655318176", + "20519914249934881206828098454303256358482675671718589102535780334267934987941", + "17275124961392392047135728713829752470490098022504524438869454049765356211723", + "3323710067527231515807603961736782048796606296990840839366613937968342331886", + "4468708240622802562056471128793253296493002925988003094771284205007772045098", + "9006494818135081033869830730030943407240565201693254355620348420258773924028", + "2624130417875598753127999576825019766166727976335690685433712946223008520912", + "164131399455376615654870570697119442360078693174350746600132391198500093412", + "14931668887432843139264972187415200544679230597820424081936926034478502874299", + "1638753880783574431267395352024193675000113296497173968722590753809640941864", + "15505380865926802396097545843811910443367233632805651511272732002583232431557", + "17973744614207669251901495093091561913998272050499760575282030108740677066624", + "6137688223696761009295745609563284204827706564566466060484103844265403078408", + "14774243062532823236792831566222119634320864630838624098798648826842418775856", + "15864970393171078370207775103899428499600152663946379517190945807315353544891", + "19010063123357565300336230971672519561204810737546730911549311353159512986740", + "12607162829921425080830052984475623157169603642577010527391007035133383807243", + "17803108634879437217723652777640120469990779759700458421844361066182881628345", + "10065874953507223318296028499872542865030107611981933577973812883589535269142", + "3276471432535144390388324850641020151392959100393035635141206272558418581928", + "7532054601401798035926415744768772852833516520318445183340725930886329458991", + "18893822928119227829016544343228228897166113682019317256005502643243867377334", + "15940597493253236451533839310728876441657428995464658827726295547815292644378", + "4268009387843764409267791203070919313017052533005657826253994943184768120896", + "21611251949238422413354051947529388972078300717392131751061464498329326474580", + "12516447001729804412674006874184731098280474050775388553768469608793631490618", + "49838549447142926741568525697026885045023997277705726329780325103507790978", + "19763902910323896567698991616245963026306943100978479625077573937114135803058", + "12029297973430627253212633299020402005457460023136429653800185001711727387314", + "17676997725594777991384952086633589048516371093397126876621255518370680168503", + "10567543371894667303450346380722020266352683222046730266924342174164712049360", + "14583364850544999818712646438016435003942847076919084667364987497592599663937", + "17348091487238815837308569582101875357715798351834275089190053280855958465528", + "8743083090296259283603789316855921930102444739264013461469099560398359267240", + "15114064505647935792598848256320570567717917317803629185764147361301698519005", + "18332675991829764561879941291908436508530604635608341316693114747813051532006", + "1757567731797951053080580099911774643896363235228742197150882457231133285549", + "6526388717947413328592956348507481629843816325885832861915399601868279124246", + ], + vec![ + "8243355230504186170667337521705529968548180153769821936979698914169521362326", + "21549235422807751640146583237936799392598740234259041629069949854834009192195", + "15309683586299089746803554818142261058154570215179112411063662706557055610156", + "12007539402495575255755232938576927941514879725482443887151392201585760698040", + "18793669376013417649313139054009540629720623019893420956495818743913188610515", + "6637074549079529416739232814950531409613090469922787253991308038219905474403", + "3042007484821627445120830225760006405192082634864137749621636257026891883326", + "5337388510268581167254715112479133594089770138749507073603490761032513368106", + "12325446798142239188409242319577957593792614990556679862642230477712636037037", + "676789245562467194073706116744095779362669155912771165373940448756070927910", + "5854747984773506278911353281567883752585612596682487681686710970786834920041", + "11245406467967785626327694659468342056789182160059009120973665143197638081760", + "10395601815816075071544509552592627172226369015806880764151195346316980080894", + "6756096862783612163697577917108261850810460757753491809406999449771712474223", + "1708595072322964393019739105130946639405776432058599259998973103484499438306", + "2817817145890818701877539103826217929456570347854153048034669346981432211659", + "20337270972708498869284875601749656006552838338471813066271573323209168221011", + "19192338172842323468707146045612196807750411464817516820711948717057036544820", + "17223253657227310295312621282100531845543865578630870272599545474783775759681", + "15004735209586276209064505708625280228119288986650187909395010184201059452346", + "3875652974956649356154345677088455126258183810851242537013757276075769588050", + "10514447960615206081458524578173743817818597124482828867666984705327684376752", + "2087647010835075851760610474040959236825470174942075295716631067964093542910", + "5927163251920754154392384551305623830535034440727310604898855074616515892551", + "20585333621997037505291454298836355589763292536744926081563336065939121006537", + "19320876518201905459682928158170419256739531666800973485138890064423348282196", + "15942638804716709831210239594904570403189415026144938623559274984027906868220", + "11197022744936474661934096628367688581641778841814728682794507017845346201383", + "11034020922250561671038205476395109731446686553549026383358725302157324264144", + "7574933006942933995255906769787776608010920618615581322603847524789684181970", + "10061361506744906780155460423367413099657465765582917482575074226383566926764", + "18611343221859570540963418999548488653944851224739716224660835306206658947980", + "17094203924957299390365889251598099482992645049968199405515681968938743421467", + "9407145832890449495071969940777105644547801064593141904558463573167881762713", + "10921438560879150587765515492087524756046482460218342400194862909363870270743", + "15101279960899220452674629307354995123411280418550386595937683027146194547144", + "1872357133681596467751878560069114718371273548294363719900935160833598069645", + "15505500304018853111989216259257978796595506623204851206292254759641600763191", + "2079667978353221447444850850900204451820443725835104896018664141845782871343", + "2852655320672908960411014862634757863509253400797831983637863741066632490909", + "2702824031197306101989338159138451445088523866133498139857862801497066633794", + "14553308731276493692643101846551382187575566516925133957384350697980935154102", + "4314969815396483242407853639218064117498232660761075778657880116870422414637", + "20236724297078811959918602376319440958076910292454596856154100774072250182183", + "6360017115980704736383763605019264589498600998515606807745670287390050560160", + "20856970531105411628054833058646203890148287930330473527735908484791842390307", + "17691356258507144960616314395885779533907781694329041597441621553108536658757", + "4464167934150673174817562382299722091160711333547138388803048452674668158635", + "11538922347277268848344412167140306567742076984016453903533772667841006045703", + "15558861252260038101730449864896864763293561339637017072015859069059083288561", + "931980552683520059135814229579184511049009637966018180567726214946979768011", + "12746506550979326220422215987591117730943427023997792332255149062957909690818", + "16416138987000536018990311324687201169959549714116951891693452597169869821726", + "7473835750915837381583185047008243788613524206396316652305987269933344653773", + "21223994082372071324452834147900730753626104062167370333103771844983134656961", + "11102363694946721470818933128034696027504133564649607436252022322296041603786", + "2666835000155694643357391634256423691785613060199379949509682292216642706081", + "16883033667413528795407641102416904598130659502290474063092941543309042023190", + "13093053604456598783294628038129487761924241298889312497497820946915331319389", + "7426349812936697309541457521193139970366533826612714195359894150484429907425", + "5243217285990182677741567384304278362485372018078770234262925321063263504918", + "21185490040917275396474067542756068684704036418473170810170344320388557093876", + "16181135763579884029508432324330748636846464150219757303321560798898398598349", + "18088358880437096005757355821526785623101357556483672471222924931365890201571", + "20418860027198053484245336569800730261127301261293595190270103940460998981236", + "2058948081811170389115771489993053947061173620273801887242248130631460165879", + "6353796008567532863300373986154930294334380098977007704532496889557690195858", + "15854609649070278722833415779491666201355987522519101725393408435189057056690", + "1355942327518086746604287131396672941922424788908995789539897301592998007690", + "10194046920666955610804398522181498854525794643476895032285888778350918459761", + "18342608728256650520630397534564293474806178807929639999068140223470256007117", + "16101948218093381908101491223075947943147313203969904451859930796280152622017", + "9866645853452683082481412876547916795343134459981103407915522925093474319332", + "9309485422719740772955698359258466728180120624442685713365406080485336040166", + "5201701081505060757054562398073722930344229781365241858092054974705598137660", + "5279555243870694216927790669819597822350327573071817682265773244733785382064", + "10661662716572743893824841881707597899963881485303936548294117975770384660590", + "4306964326426793675768869124893413588264762573088622132302954501394542576141", + "19945975928045383298785833694292459276727208605892865429301546022994613804030", + "5037834331249812829239656466783521330249138768989720606017856991559732121456", + "20693877087308232030611148201802513236570270737947270986743265610517665094074", + "17748932969923719316564673051784340920943155490113289807023660243301385585070", + "16950307665556055391386715682532553772527550247031548278958142572490582126842", + "15034211391483347494286112687349366897258989065045859280146461213731663274520", + "3455096385235320554100221104677124747996171720170690637998043454239897385610", + "11220329458242704347549150795173830262585759464331372299692251819012138352257", + "8230076319752658879891285909687940775399748755759819661970430769188439691274", + "4178690445391578185009939705412120505162313641744671740163024993195883735198", + "18632680236376151061913536149173846032710756800956417249233907621575802688710", + "14168747730472612819827430620596085566004981811676505988180237018638188025380", + "16777617016129912124437138351698263064579177499617525409625791377061066895460", + "403267570119386144603206457308168792379980670187570608148634410971295877610", + "11045890302538505532103216886575539246473207034538532950483165910580782953337", + "2632893274667647784827087132221744991131294771819888858265016332574437797556", + "14022461303364013571172470728150898521630042996798160127819093871974124417229", + "18349129573612583311962846403448135938849737390546876598640066736462315682295", + "8009723611300112743690923532773238474616291315457276539919568488041436720507", + "3287586297388209299132232426281031982329712892122181769502106059441842217623", + "19893256464101780566218598404932657965361824655069879954668551189408491121155", + "21779954643920608321663779655887581582907923850271820082121309309571440586162", + "13938145028737822338330333388496944993576078307754676998341398757402576278690", + "17280605833933949866452995551396279974325968699794264573823990818913515933775", + "11562775307500290654949270847967546133812416593099094805234457839659652146289", + "21556021192476590536800970202944195471695121915357500612310904064652863447972", + "17407055226077297021071802288772735837293135175537846248261973015744713174949", + "21295838064085671525042198277220548723525913660103018392096215316189390548013", + "14589917958236435754986191512564058641868109230240077937707647376289105324812", + "4538073055458854134606640263494592220617270326115451287834630189270577020111", + "21247609438242282269742265796811514090579388884916478939008977411932487423659", + "19263560475610984724826226948356735903574936974192558145730920786586162783055", + "1898614508331499418660051276594019416852890004788354240344418815409520758722", + "13346547977920686435662774643991891597826323722140876186086635239306340843003", + "12144969177194297999321084025481801838621405926243412487948189180755523714531", + "11624156909934489978766768065107924627236090741698411458481638802308500352917", + "8674349037900011131899280296161700067911742760618648557038290076406601619864", + "18627233188669469962636721109716646416813512041955577645627776298400086440228", + "1153719160094308748956884656041023320488424966635003188538565876464091909764", + "8000003066081501211900754070779689975656073731442793160620896624291841806771", + "12069801117560082050163959286673266840809976769131514316118288648293224324822", + "11694828863372498882861202648883355759680038037706633938668096525787115759720", + "1181495201505177954430275085371953511604847831716865494220845031383860562941", + "18321980275956746302814628602546438645691886543647725888694024551609678639266", + "2785661975937033521551267460848061931764727388015171856456622007438303671899", + "15557886094116287182932984983441793820379366058597052543066101158081817575352", + "175179830261452669822497364983291141568331314582563701393865403724263011876", + "10455128373814266139918350629083299308526836847946708764631040462916637941146", + "12622681406523708498691044494295298210175441851465578469593208754136900020434", + "9624138424345877000077746656879336097173254842107184716328214933320809030543", + "11726383465426411877912203592949370178096897707629953853811352568008881233112", + "17566146584557385507728086844334319515338136183689530813551207417981719751958", + "18423839150858891406289385710861955437811779173242111498197433255650436048047", + "17408376662161624435555256564084894291578222902661202310977717110546842356960", + "20995943422377609225953642092578140203148330329113983394181012996247925741957", + "10409490873284794620245703460832015892256721643100501421596423100640512505920", + "15047062105747285153444463303020356100177963702386173227676803770571846532695", + "4535940688608096040988822900684697329863791065464226849059470519882399535780", + "18980357680792173392910397806033731294240363676914829395702138582894418363978", + "16468042735091009392571235146440392007609078458297170996132218787642722263238", + "1869769403621899262774247370472546961521039203681166934356431996537822108263", + "6151829532330885020831674048300360431343535966534922988242884341920915237665", + "14373964388615044752046531046884609884388869283450342961030080770253954449754", + "21429869771065858399481388829822721985084474326196139156050788103070270663923", + "11836916222341149344359827526882466618136359738495035945807998286429671739008", + "4542193081188277792793758113018430324598765345700596639963408884670534634317", + "17262340128494663310404052919129368521415818617921877469042393034218456907650", + "11614110585474201606235056157412783071151951301104822431509283035322273244217", + "17241248261774133453753660970137875514052923171943595080766050681996607133130", + "2990875140768570679733810173464987023133165559726680992079139149034178002777", + "10032389096385585741539206260012253444831624820404318451026478423856181568200", + "8391217416130739565515338215591963109158836617019021044489286448654465296819", + "8553700889274799411012667201578367398970695661169430162294018618925895640041", + "13529692770771168133213371031275281478756443444824139121847596546264553079152", + "14478949636372928879378459122088894160202116364833386541382488835123981766413", + "18528743543311452855194545818079449921167163839226390851954136986727320245809", + "11724222260540829258562889360923785293478512718704276634048783603461995522859", + "2652532822068043785753514309321715043229885635900630208154874285707479247265", + "16473666207635815797882774885364997250503755116232911726426811919269547851975", + "12436631741803099512327160776479880302093882812091908650798222524569929954222", + "13061081443094122428989571162147084312340276850316867585582410062467362267361", + "20909566607465067204267258789556187669343825005173558971220332255443231196363", + "14278016202378252898173761523743422243750790190417896338147106476354187349947", + "7703701752136585609667768350038563449121231460368808945757767724712186009894", + "1622258312841010773225479468430896972269503924285598181547410615000034107894", + "4706114868510775588142857635375822293570353199661120256611528287780303504954", + "12723022498690150801900112713057006417552064300221766812928489357200260312668", + "7736508633931646965699972944684083339925061856252811104228904321699984469949", + "195095354858363944780141950724441876473553677166595890451203685104276178612", + "18877614091447727762374351623731936445361116363480970639310200637662433378180", + "17239262588506530491210045452642505719938421789517734104955853192075731537629", + "3391556611912995522919492308422471958888145521362922265487749943660431330300", + "10164629656754294522862462407441648133619259920942013682702008716587122474446", + "11939828733425435518898229234599966533928666730047925120030711579782543312731", + "17335155958861138542643885799966192412363788951639890938680530110842555336617", + "21068414996957890621467676209673805582866493104159841584377567318112060433438", + "18041291613104743972430309067462668732698702146146761776321539150844598296986", + "6149130772490689572076747194977244577047643214871016443290724757756394340290", + "12105848363324940274456322072887282559016226587661485273111872063034847034485", + "5683957548001811989600472365740829603387405501208071642225953069881259762607", + "16529542077365261070047716411124689196456625611983373158922227651721798753876", + "11961524596519782767188645738887896272947446382672325012202336646508449392990", + "9785728068011868312995387469680578201705397880590293454099364001157116688561", + "18127416268588083447440821307938591826251677223119815897950307944959875167560", + "19296461637807972438220899702591874518336722552660488565818484435311224286288", + "6801016831512114134395242293457679538495311188529990156831889204433183626116", + "2964298470426582070507861407971247200639242211740381994158541687335361446525", + "13485975887078791259342768620261671076376983307468484850600890777864999230190", + "18842264035089067687391583729082424222425351385494040849910540441253540345719", + "14703642210510851071131854548671393020078600676544458548174965732036621712435", + "21220214849253889952179905879367949668848598115028365535238742829171770487419", + "11808561815315084933226034934054773302447242219261466208644893422841430468026", + "13540888692913543742580940929469376532537583430034252053023468103862294761259", + "7244161097354558003276348625436123965060461415149286453943040900234287411785", + "14838699086047571226987010390426316539929576717533827724866261274778253262656", + "14556703155521968503536618488028548581329555701042498979115582733446728182407", + "7681623302896593715513288894378158777679657507901023568046253058158573848701", + "1088441387469941348668229287331864702951247349577784177659963097331109780661", + "7314603916265509104428110912296267885635061026393352039011815022900719549691", + "3986211915826218802854255636104488183733664187834078111248006041750140814882", + "7773946401984571616670752866609685859292708427659817737120107917606152933392", + "2842014599902358831415178364343115068084073955515903534808862171830738904933", + "5310724334723991338015239276468023426385678184604207589409781216959654582406", + "5255222348968955358505450804240823699077014235887887249383824524518164498567", + "4683270496545943333741165516340250527555279356319043788098737100323469078711", + "1419863943011284607504318632953959861647793372073243840131919334395882404459", + "7983638904317557271319561780754076927110887040374328063199742162092282580125", + "5569432847705373609838086039153225563020182698189928344759413994203981320990", + "15459233133041758499623402905899885787129812358908703405750502906067055055230", + "13557004098047782158753673078158469379829777184696159361573537670440394932233", + "15455882302725774286899673141535924396516348007554186719344822187820635072053", + "3420919058826876625284567898132572990967515410265578892047210512917031439632", + "20100418454140979684745740106982178755085746706837715848777042819378494283102", + "2569258507332519764813672456351707773863376375715947817185409500202699032309", + "11051426796304102496144764766958179671506736496976882366028801902480842422589", + "12740229748287653735988491742372785228070141556372656548689214318469788908817", + "21628842595664718258888324339774974922449098458375293925060310284267692457557", + "16339231976272978519029290439531768093693541721039081313180796119705575069472", + "40124736742096746520902512885311967045111742860721554225254094895613700655", + "17732965892472841235257958105891466451086090480423956940377743815006013439", + "21822629194074446176794925064792912534191501981075390813302606875002422233533", + "9308214945046921143097017249780654286051601646816113552080893008307002107495", + "1407926751839535775233537792971129618756456590720440342541085713782189375466", + "5640645423977029900985251540406734874840031539109774937559862819450972865688", + "5033216407501194252797695593441325021622991729008118693554186469034086370061", + "8067057037475400447259522316648004416684453970851364075976857314405950145375", + "3763719773038467529952189678629891209905984306908045328296798459182240539135", + "16939797418368521863388331657892541744299855742774206972703171911218723184714", + "4830944198856568835319759101429165879092462296316662230100861015921313890231", + "12704214658232136513943612645116991664417275945120192627735782298715562058820", + "9273823420095008025667777982828688153052061387261780450903573585273931011552", + "11055274871946976331353174512200687536982312509623944578515862663278819898965", + "6608499500253253446996042326570359354182967780655057286059057541317584758989", + "20888058022129906086941050692798413401844596394165346138911969309287247738108", + "13297667979268130800823342819300433555314639138313483863899090834749801969571", + "18968104066692458124571065270953767119743779337036553042450471941512165236867", + "14932841303199490878640323744926137685749952622800747995690439854118498001885", + "6250599214474930878673138968631643032807502364864165001640712550360147900771", + "13872044280192246670253542029636668414586465840988190477111017540404431909403", + "81456119668307937036914780206985985650137679027930766352442712034886058018", + "8178364156193615628946078892680068624209694278864784660439209878556857933585", + "20847565685305938921688196081711559611104247746032524045765048360946563554616", + "14790603163347071870110696142274029411377352843070075577069234486581346354229", + "18977464663780407707262531952390299277523056655145169930121579582916387871374", + "16780630803676794749613238124686604459373604071531057035207376612438682381040", + "20186476042367781999034353334494913683828163385175556939730585228743410724033", + "6782638209588187356802454014110236225878206067794807253486060610876934918759", + "8993456778572039939715813797180666624819850516232234360679317411311388323391", + "19966302498904269727099815984264954717659138861990152509516897188319443441697", + "20169703794592063233917650314404110898564218327366603108408586484609331826027", + "5979829627203584558315118820578826847995466683728103070319484562170838879477", + "8237679343008214539352062545936737645555361114339038346011678993504862443129", + "12382432100828502258569798167004899872248210099869176340581848176730802349663", + "1568185664985590267262857882936657784210740515169196983171026814738347336756", + "21214766447038120613598232832812136678657988502205964335817205381807920739938", + "7692941991237742474520327457310452870153482370889548010226143053981890424652", + "13595129445265049664221406027681079958478209116108739005508499004805469917071", + "19188096071580221579092496028987371780642557049389322053081699235155567772173", + "17975673380464001374676034638564230054429981676012676440863525293845130019904", + "20841685157342026757711329464299804445471940020955209397956987009823404283299", + "7510778644672212989684926383821874729073504800968951172295535413714975603558", + "5412964648109092367425127656145675316528154462488440576988541278054587052058", + "6998001450950528857399821530729656471745472711969582871968416561472553420135", + "10017795190513370580285083759517584035694996563220913850722002288744022757377", + "12113185651597474067026664715619946415749981707739597619454641751791169267554", + "20451540737363571466111039734160615184627155382583098695879349204357410296631", + "729116950403569953818905038668361626861855541652418271170712441039707291924", + "6874571610670154627346562968411422088198077609945741147515101915358108207688", + "20307824547105117373454598908217917152093200208838326389260620574762152675045", + "8758875530447210792904496135011086289851932865540018278850670496425499052683", + "13224694410602002105805224454797207933944742532123981533211431845662395381395", + "6621493224766717216701548708726891168784911176896760330321592836065310482866", + "13937858022779991611039558948054774910543950212969141252259896915615778617893", + "4917806030251482092362529677296731621677399228082641707762616055246746126061", + "16304922224312728276104330461175394847795848175925462853738047204383447573035", + "16678452722472429203861326329044632626530032631343862086351886162579978046420", + "9974691111613144697061424119079539196535411918411684404824080439336446439564", + "12391128852318795781829794456501239823062804741032268163807689059014957151322", + "16376931186038869228971542812469753097050036606517944132293138523631153279825", + "3057841358487505418761470758562979965285993261118087156094367416201750095404", + "15045409518037090814105826994439679855639635253710791541219370329682069820225", + "13442376736433669968016223589180307683361433436806777011753497283272674012644", + "18917174176736242961299708438032963296686220808211170958894252981698475343631", + "11380920704380401611525239094209208940853859054744619020167150893676619275400", + "5399632748693319676480270098239871368958944610827825094400876104909425716392", + "3072779406768337118240884091792704214322792415195488652476136252175179362880", + "8351873470285292321562674159922105545256148886389216816367528787141186556758", + "19039526722628732399365091326361517675801947890934047817293511021151913744591", + "11316453563295765895775061205389385485172841919365628835333993250531664655988", + "7850755275953939062184858524678116551304016605992491147837939252676680785208", + "189663666172994057560830062107872734380479327839628938168402275701561917176", + "8944554955574110171273295960753608410178793391130829960067372967633462961614", + "7116498249918759493875054905542634690892118438594298685578805598675410965669", + "2535963611074434631003149876163530430931993688129878286594756194015465278460", + "18022460558081751594574692271414706303627866472796139479944146908393139741182", + "15341193598946540230880135952221211503846552166425406354080863978843527894671", + "2942431717153385426545606490874257811230086292797817271859433296359160259239", + "3009774438756820489964746831334449123894740822794580986556997529296717581423", + "9496138301121689616049759054935646143502980987880350156990306735995260671175", + "4076156724842725224174300000468119057699244699381290980710548119313376968129", + "20301500572584246879220468905731058339249778940966192891128325027181404226629", + "12240449395531309263037726882974869058539543342019721791945417590157321444565", + "2734576041547526732946886809654954568832411068107541730145912482251139322538", + "1913611111144137178181099357504813610426696502807761974432419767623037547574", + "8323981703091520786969788588517080546120036429535328021157459160571413370125", + "17608089795804665912003122420873117027406690592641558991713120617999818930151", + "17954961401611739290579723858653246962839079599354059880628870682426849304674", + "7693642591048722104105715300765742636898670019493041402551952316778508785882", + "10925165536949195683545612102300879902373347522535838874708839717193999335745", + "16740598974035404805544189925980303793846400946043080633235004418045311113846", + "3028458114292500648266975052798389647613432243149006395166123161184170940972", + "2817600861932061603203157785548222970685465773360278995551965365313604217882", + "2811366666795973435332404603090484498270752802044239619104866535127344245139", + "6901007103297959557257110184636027233977945890205420866896244199105220459744", + "6811040256124961160848956238308470640308462502755753004833080999365205628787", + "846642049586630199735666112786431409696508103735494916428842550432654381594", + "13061166881718302681365231291832588791959186056326831853549555763101859584396", + "1581547457654855644173875819143310956457964952802128135344084991507959176621", + "12591698412731075291488515328885878994038884715020576113812619060374399968487", + "7129047166046749599109058206849766841261983329246180789653876287940952140294", + "17780920041966559015242418384239510699940753783778307759603993814380170147815", + "11411967002648206460094819913767451172535988461576286592244752756526683869398", + "6535147980143805768211908880661065989475773196469834562468932004056012068981", + "12872366293792794368642323198969017581196463071340612957009439105182673573396", + "3845096876544992085668616039795853840768469571100517631039776002796484609549", + "20386025860348257305841141103130861239832870083066852913792413739711579490278", + "5663975388273723452136125938377376330824298621841190787892884430812699456136", + "20880523335705106555101009571713688438858731841737802690910851430800496104934", + "8664815262171336902475127109386834836220742848950659183106085559300961747316", + "15212672296023611959246835252860546019670000046804751249547303425954183847429", + "3786255974807528210793957400325837912933369979823637013145025357556219775102", + "19646410587152058982763388053845872310164493339475512721275474101828150077273", + "14407426259630290801648546162995549804322572985407158009259933675410180400077", + "1275955073103101917295562169849127375209112030395179332033340866715396722452", + "5487750760448101899937260261898752719887276580825994742322208269609306618405", + "12414079753210256499611439235670285717945909010061941159696368398137523291140", + "18058271753030912252347026705895506604519018890772902865355002646910918153759", + "13935235821735626611156505080089322797654275868806802361406549798199236177528", + "17110498079878546324718511787669387410942622969712445909354000807236690314957", + "10687508266469903792000405420136150569946636272800228999781195239976105560612", + "1277956894120355360649091990517188151791867400124079104247693321263057601099", + "929982009519538400155920125117423265869657236620766216139182914925009802954", + "16559970949358997473575123467518158994842000800881347427572300986319432656507", + "863852544580033885106607226598354103099120172650200980695458006092725115354", + "436810575313416269983882563851323926836428928449351162094565391723605483516", + "6334913013691170767138698286357556285297887475783792365865857018173994149486", + "17785859069146472999908840832788077051672090890508101583397157534162626183973", + "427206014337914391283601765560115825767253196347193816620589108299037926541", + "15115704735938262072587983952645382098893412471333885175144579020987265065203", + "12017969315449748476118643575203596675122272214009056004034938899095907760206", + "20642434407226804845623813766397536183962927868804716012482833199686414302852", + "18982318327848493301474677819747807686491978396022748137991684529478469330097", + "2306193794828709014215315860179466106408084703631347012188232489780230095671", + "7060813397820173935956757571314686808083877731722252822508055423697679476893", + "9925864312610988474999359617458205534034473691089101964213562993662824159034", + "14036238569106986370932971272638702550236692459418895654245682921654874601312", + "9509048813859143088347263336607686057099400727479311504780670742158653486206", + "6842166521132564137619008158396211111980991013087076743268157882198576269675", + "10217353423046013950417213172971567565900229914457220187215408404202554351836", + "18220384419265532097596052952017594673237799959023133602933674050572298730193", + "17866822945198657177461453619458294532377313634196332518543246556611008452933", + "17694368679979949511817467967015330546905282492241200905890171992458134240678", + "18971922685739566979638356009544944454629162680819328093994329160719843056737", + "18684937612086669383439812199377945074448160740155966772829350355651237261795", + "9235876281667970051504588287667786944160228843888838710239865727309603061015", + "6187574163551283282357553100017400574873868151705871779659681332774938473442", + "17196369096305464930639002419417036905613312721767481044644254878990952814786", + "18296927216321111202881056198300973553112302777685079899199090840516364581791", + "4983948188027170589078739023086929105628955321978589464920358286161528573448", + "2276814237931645487686771259585160667452008745791625290365802841496721618760", + "4138273157833414032755498052453436990872835066620446328921138739885868998379", + "5835580830979414828575054128735121537583042482361311845838347096674448689116", + "20992630219061340843601881100837482710979119542034786928296223633950908472388", + "1118381353525339785976839119511758587763620520383755136959051018516094253090", + "10337002023922138844951367775712178432524190386722995225923120494344904079950", + "9765947418137225404722546740514250763898752374389411503005283184253024586058", + "15411836962046751164622748177831913963909013265942110958658714173394711125370", + "20722527012138131360820192152290968950993396481440050289358737370268218859591", + "16585853587281811014582898583977502965045639444130273779047322749735299560207", + "21436098743421172924014781240823435281025352300035264733201366114473419058727", + "14178112462860881459540462916598447735177675761773338824394753907217898488960", + "2590560710846804342662010467713568407285290476715663333366063002353018991264", + "17949223181156469858379065899254284317305309247290121304422294912030586532673", + "6940063127036366626640075420306454154706369567406835284901717013872681276911", + "13212339415583029091219180722363760875223983190396769244985733901171214077679", + "11143838426689049623360248250302972103117784521940658207527698432687552942591", + "4994693363062895106345077091869420711664571716019971952890352464184561249569", + "7785839099197795033948112451740381108555553042322704038905686323540025631473", + "15291655295654923849266753004503491258117644584862711291502217292211074445996", + "18223946690101945712849081159295298164630378278313069852577349403051751559726", + "13247893325056509281811135293440873471348664328435966021736203439379360560346", + "1838627965154116499570588511051176331708387980121591719463695143475045130831", + "21746931323535899361372833028120884537569529325326959379977185108159655128847", + "1569229799996373000993208676467175871896208509249271061977636872731081653113", + "18668959729045139805375896352501526759923123936419773886979446262254907152787", + "12698285530824454564359053510831159718450594302921296519937334733529589738160", + "5743752602883180080321224936560739109224279187008023590149271256478879997507", + "17615461436426765950762679333452659818080751337498512367037395397687644820677", + "4379963027402443949761342437016192165148025657715626365315450970388283739261", + "12622442863880120105122485141053297017921305018805552070109568547893924027508", + "16493349884995741255319414030015325273883108492981717376626952633010860098410", + "11501183900713163689133184470477728399861217340901493951105967658399341986313", + "13184464903575565740074003127437693743650101614906307232173855163739473476900", + "19056993236227362680720448341933549082689888775458266843506880469982452347227", + "1180947252747369471066257076205537751320494098262241412291924855089764608729", + "16229532924404554580195616835338949126663348103713418556119694233568376894947", + "8604714607572995451336310555882946070542334844212691610961393592348706930493", + "8362594100280133221998296898045505539071433915735634439526614339277300552370", + "16399159148365956463951582514857891684943332179297226423628752792536028483990", + "20791958918883897879651946680726738927333774947616022833294686415482396438838", + "6976099533465307077876553477341301102578695004868981952387720840685240842560", + "17588607896443047770053818219711270035985826074286753981361920802895326076124", + "12865981806811655044812914486873432317316688987331760480657262748139002813688", + "19080259696546964979932036247707282742365340353585423017939782931928015046575", + "5475353703257038456872747308072401784844227202792527428899399083236860900298", + "699444932025038530835460727165156424336147795146205258896894678525124927461", + "15695622674480818777943366659102932349783785381339274197766151422625765388038", + "7644428489984569999599080644830401450294253782967784792584750934960812468382", + "2484044190398385977417569061356693291812041338880061938702052957819048506706", + "8456986467797277421685766156179980502998860530369856189405630837033584471075", + "5054041625001826317568038929780665383894838531896986763764007995985738029810", + "5197336058480822437408118036219119090707158130910220019747427914262297331861", + "8896147437242770809876821567936215621570430903276974181159659855796295866923", + "20755757167342693300106178757642141909843395817794855978028122598254488316281", + "12495257799325917448205113238508489684392516282807104246531380538192500498286", + "17639970982424592615983334078785592256655637539816187733799215839326807071148", + "8140016957188286078776165555436655378303814378750387793587919949009492167586", + "17209468066776420206923060639618147772644663380208004030591040036263548572020", + "2619409586309117922582791327977378099828554504012201484641253637770276078843", + "11172679254412598275301264634812740710430873755458899712228629497147611473029", + "16829502099778629987235691213955928527920624415791356237580609633148661633897", + "592799060717298365629187138482067858694007427100574367745567028165989185342", + "16864381084532235865281462338072964457337415344658720676113860956416999505572", + "1015589663070446561434523645329239389344944669662180065723984179503017360337", + "9982212112174542265411457778485410853904388759147308861218634697975431894510", + "5412525702631618381358272227447367851318305617863423359948039591381065713581", + "9852930575259000100332996271562617389630146990442517175422889296173516799181", + "6036993105785310658467845672504384047591296265363803946714632979523201713762", + "1821500632172143873156399122734194851200445368324858351038486833883177057468", + "21556520116213603298246786137688925835788594639953568860110645708136881336676", + "658318860971707056155247027603536846915894897192791739866840963356575472681", + "602842622617647573132938965729563329852165494525296971607175031334298950242", + "1151063223719891516862415316972915766442753873652837551132768558136109394634", + "20030054542089253165409106868864476953251573918915762537158006593968012247497", + "14455078111822464502989472874268580626098857184523941794725425258923962713053", + "1699191450188970110166570608380346465689006650580298122024202987580198200132", + "13971136504849280501801880342723497383580392506287195375689019810750613223527", + "11259011415071078991947983706483998982146186263873384729739331890304233635860", + "17741270384736018529047001790810396141344433078911295725171243367964019815741", + "3617456068852846022110280599700245470402025130645759911795429861830057016581", + "18773989857774369564707484486703863617112883499664601804221477949481034222590", + "391101570414854801618801587626783162239406618115954162053108159404294160435", + "3752824438659815340558915518196975380567589032517034180452547083690665271869", + "13652227089592801810376789544861979384538590096633526007583054323554301421745", + "5753030785259259818058977992956569985665739253964735992489420513570911607", + "12794765444364718066463627091127875266371595037234762762560519184694440318642", + "1844165267423966444579133456200541636533189889959706801468771335509321515822", + "799352162562582415493264759184613437140226428304061991778193411771388762097", + "15915114786946818157476898276501926276831197920612814619300062353559927906953", + "13041871949144831370743756131359537126101784549008553888408794912277392285626", + "1684702427149441531010110315726002248751792272226034774456204740385384491604", + "10195318610969070608511028432066597876456281143783329459466964443360549551082", + "13714193389971576085579160116206487363436474313560046541969781285568217247624", + "12202470771012770210445954644081270058473831351768121852596394422757629850892", + "7784616613742667796197638965440313242748565680231200921682296807888993222090", + "18581613859576442652033888735999982405110741068271804741467526764394720805037", + "14828223806255884089537896775456938290494683211666564494946175120085694803958", + "6191868112332934762674478056112840408041237177775248347690069948259811627101", + "6055199518589075551800066499277675747934144570099354689629636497613775458486", + "20043219892592698889412649805669712950039510114250762278667968995416842502234", + "10591576812697540586115991527347511638405122244793393962099090930538459086772", + "8146910292072979142616688207315340017602882692938548874592904341871514175303", + "15451576003386544225828312996072681331940167554848966592330715947662789205180", + "21156998090948310800651324456525534600543417534335507361948830316109451323115", + "21421497039083336739241851024868234958744697872115637345287618993148799764131", + "8835309990713613011240324096693076755485475658999871502819747407829989219746", + "13102158958973358955423565573049580406238531533936309830903999596178966162490", + "19927703189662863743499379923522860979653455328626544661291243971618992342837", + "18417771183154820005238210056528713167003520086953806649233005148247829186154", + "13242250186667974182640987653516460478853973058739850129463954545512907574522", + "10971901023853281329361069638276077765206234747340067637718378767976633645829", + "20436550472837870181409690438226695091760115955076127106091878852797639823191", + "683842651763399941903331243661454687566310039977770092715404267515366625429", + "3304534668380354910105587611199035768704466410761708200478786163367382500984", + "14327892159763789670354328059011011973128878640806462164819794130243254129821", + "13712101990593648405837473744314130986494510088132644940425089514662460031793", + "1270386163717136732049662990020454155453019401464056820650142849751291739739", + "4559668312052315567004252521434018809625818725552950834596073025095274632653", + "10289456013947128246221059115194021747046925564818529566042034047888244657473", + "6981981682422059144716871555026845840161063380660424650450978975416029699739", + "13275723002453843398308458799872954358948259042779675411059905047590837397361", + "18372074965684100000331046096891533070433189717560527825752357282553296305210", + "6007153627662867365254986874716350833679184737288669421698890656788831322929", + "11557682792813633323168221751485510314542594132819842305598531070629168100143", + "10536598621155464430657941977974614272794233321865085717974545329727298277125", + "20566123440884795144385782557360498238445700080133152934423121801124172346047", + "5484210585392274768700243869223282957415576141086566136019633416151230114084", + "4675266041161206862174450141632759296562489084453522360678052892725376421684", + "14506966485061491552710372008504993235111668026216492386033611735228479487468", + "3682565950309631924420685101131217452257499881999322497664342243267291843503", + "16753306733039910894513530708776251948831720207834805689601646616427039909037", + "11892397629144764406188085785897237236955294380381710017192179450763501663923", + "17027229171478232498721421673139332166581061755210509139252013418924500461243", + "3560458480908782960366816146149753544371185355186140843210760460011482921556", + "2523290942811919827064721825289040221770310594770466909167316010377190569820", + "17586848354290518015476851435178627882600199642491204839902589087637701736514", + "18771893348474501482962831973790983143756587183687952333177929270650139940171", + "6788202157749582404834375771398928959748074435244246320016871403739257327326", + "11025631863450004428764861086496374449453982180198151399523240056816657483248", + "3256907622263919521402687344729539839835290137654795380148237049547054026004", + "729757374802086603625382264910105909740146180896096383332210024077887641124", + "19863253866253150070643618896444516678169346690564661550005769233120838139485", + "12468569017378925985548033310919519222810416238732327538088208928920140959143", + "712344748962578398623451251358410865586764243720605242158768608887082462846", + "8546087066371010720013920767653366050032317738437010080974697619001241722483", + "17144825509786899110344839698077839239721239583625175190269757913667929043953", + "10651563297701188942358589203989937961905153035428112097802788565849122022100", + "19602341346389413323180922571631527509531683866957468565049297030414658843948", + "9238186664745057178430953403953596421917515090260446457039212350976296818523", + "263640414028390180122517954487976369901122460517389747631764885875587715955", + "2311641918305077640172935641310996393584851078677397516017312506521775283636", + "12911852110192471656473443086611566556755106535388637084532737811151296554463", + "10436700004928765835031725654432267178079115705246966695358470216435798181674", + "12755555289896266917759922247555708737024386059041699214870911784508162783525", + "17390583422165077903045260639521919716984664232208360646931078032292219709718", + "7412526952366864882775200227476857681850213243362827192310877977391550357930", + "5016060582872027330190350728607317487069057897723717249157495640519710863591", + "70447200134990075406173842139872041532268968648265338736409860251327029352", + "1545500244158153586647380894391367444874762740407966854865957002078767363820", + "2082567114283705201161441383508830647153064041365131752708347264051557391980", + "7773933577113494097575644205473257493685202208592412633139277067190461074505", + "15907352821797623044340355088248954282080052141018731890243639338361458586983", + "2453390435048874114321626738320866552399505338711520013030652128583351121221", + "9182038581165182763924458518550360578443802241218652973210280653624820005202", + "13176557622325900598244222336641110473108400343854387783748570353220729582767", + "10599983241136666078578113335543683963633036808782400964809769571709020578918", + "1430816790456574892099931300141571059151141389317227589818258647628212654923", + "7207251746626434553568433426934231676780727971853793874008147862305418016123", + "3847365229378532841231862621068765430417579646617713430532944299440264931969", + "922422158589085666348657924088867593873646110588554410818179794404300446471", + "4298485174770134050325487753075508760849575591910135387686931072102416450479", + "9475141350581193757416877790061277619494551108434152557051757495614692231364", + "7750163624390542388958191386016094472536166330496081849246099823270737686866", + "14363173695671306304956071467171940429435853698217676411185837490356013810171", + "3402134714494071567155197273072160417049647120230862441840621369782667867977", + "11378968132153772980874973211734670604659991740586197794619174704886870525408", + "2500862781199005154907185089778932765489906994365960644306361544820582839768", + "21880931942133046355810983155922578513531850539420426025723154879488808270315", + "17850206894189265929807971665186479441938275634968267590809377452033564010382", + "18427883853363251276513100116480886898434829323430684895879968439179171503760", + "18758795974827407022563870795763356401215175366078230621502388363785425038612", + "15672649260544536516531393740985073476934112035694203841471047634286525005174", + "14497479780124030172334631091033639981498927489925809517218125709975200816290", + "11190855071574099336548308963044121660452976926988171712775481672446931541539", + "8339442292395337481335048552147626044800877206694030770577319544121541364092", + "2461178629683239975488518502624530284391365519847067341739449204945212652770", + "3972313936510404965199308344697399140590038866586718833591813109326652018667", + "3224811019580618549699828950033477378112059204060062023677479068506440937528", + "18443657715765406615721041820828109800966587434816919981514222787674698772960", + "666201271764511484388505793135876064418452477237751508215203932379618265382", + "4434899717815685275523711262432486808621984251515429736982413712108987655422", + "14584918585762085382434085071460369807803840154636220934254933165793423091295", + "15646480282455307022430957975574008173154630787861430193406352480280577045711", + "402840791633175231660910669665966910050981784044822648466848382615330599909", + "15437492296189220094817534101128968523410729375545135146260659057729649968314", + "13987760171743052442513877961667805977500573882586118554487715622045738218279", + "12589095501858681021442730872878907609617459069328956803139727387371467358051", + "17551064250089164193025672794811675406761638177060737129533175904585851772273", + "13500706213131978087516005477128059726177752268287240395927379509000435850498", + "7331629294073516250840302816971095420668983701195024195892939287001016568514", + "12949377725980318589136021850295478499564248427839661600142796482665024587971", + "3988955063770305621858590171391799353484164878730082586815877210936858093890", + "20512156157023978986265779260320491356890557397261515752540394821171756173724", + "11624190532749034673782735319581023504009231230729490439584417709012081446066", + "12473562150323140802035699452896239306300376623759190078147999182702752528013", + "21504777935543484323252258287484534200045631968996932563017737909760083499017", + "16104745906544338230790783632377375683831341202924378150021598903321494336736", + "8312554144734150053969625169851557776466370096299754626528722906617398229171", + ], + vec![ + "14715728137766105031387583973733149375806784983272780095398485311648630967927", + "12450793357728630597819493697261391961392738728208603858426218806728799382497", + "4427733724068610336929510244982091587998132283636864368924406075658439074153", + "17863554236640577761956319447874252524561947852685470820159498661269344021716", + "10723868775598272126873918500257797117892409794706524915527428530195343520361", + "8041366806917098496431513544630989490693774700064656765914266570204855843526", + "13046986480231887538692223126751085950758763070227069247275787663666591811005", + "20228999562936372999611354929112125019466353738760451044697249912024766542482", + "14238976012080913074226552202264063302466135977295108038770514743089287570221", + "19486717852389551661121716850619781027370627632295683938875312739716376501717", + "15733057748709959668511822511174594221965585899587926036013893958610587491491", + "12041333229715539748857491855115983195198694619439452683631630426350435252478", + "1829888811413627407640409778757789140470123549237476514374669162490680512211", + "10288898018349095056494632386514957183841700001184195479721999387950102580094", + "7360553146019695788111059047354435502690072975650576744373916804385350955674", + "17476063720528136669048514677420727796180556343667231122803521620226101935369", + "18384724266969916899691009636435516722111206340289089258767862754828208946542", + "11046121967047431151707881264774621308937270618998625466342467829704953599782", + "20018232138773775379089542131722766973741687507582662224374276186775807685863", + "7926534193496947015875888176706209291021745851605316909116853588598743879034", + "8826996877877607049084007876351017199517432230182001641783930871320527792100", + "11760708819943554023765145606995747732169597984739408998714117029765838566505", + "19598000655770319703844060561747179253151181702222064644764822676806532882514", + "15036675263180992517064890091049355832990063162957265821390555448206776251789", + "1053420874580688637503969479036991299021138740018858993455108201424412879748", + "3723543690610038931361367959096800720510056325209292666118208798533818425035", + "4599370243050726453512484851927735252841106375733105184316191846221056036380", + "18291400382386598447603657416871816375751118990979359745849342284893280004873", + "300341627009231088404894405580745838091318300821994947846008201887884150151", + "13332605655619720841053062902143052543375741442250678582318225211621890248982", + "13197729598850829723360679245789196039442968018972826673455394330035263151299", + "510788688496484172389408566109007465667555285205327059265048317979249570221", + "1685584118031999835794907889275254096486823415278284757369286336252006457602", + "15103945090904102223538479231258677032197950627619049222966748226967974852043", + "6653802896618953033344296077900828173967467309849915708475948018848254380036", + "9254803560511166426410537422101769642611302194250107918342410310963831784950", + "17006557344160230194691541621666219420787918477303225545533644141096551358258", + "773112329554511160545400721342977593377624843987783062638455005748446223137", + "6671483881284330250685026918783029584764740571210869197688044338476895092050", + "20812941492969561606721983530907505914064782270990490150214736286311482532652", + "1156984923268097592347582093730300227184163551449762803735684309575717323017", + "15303159756724065068145651405407765401796657934219121639364061501460295743948", + "18999785075801878445291021498876384414176522501978873700451842582224940767334", + "3782716983967799050957535371991538595453996691838733068933109780481907925378", + "810443910646366078824923626573819081371243815242873044781414798707744583851", + "3940687718063184864573934886068875138239553970085689518511531571139105765743", + "1222092197964451545227395363538155091563596468425395922702697716100572937718", + "11901775018663948557424314950737290815973735008800495766054692238446226616230", + "21839369981774608005059280910009281502958794510307248992429390932011110951241", + "819873152679629471918450179717035855395702808145570990556719950289951175212", + "2918016794043041559376798791171848118057043459636680115122516324180788251680", + "10788401265856066217998495397128704450484607734353922353470809976686155443188", + "13599498756047543641157208425687419183141596017402196474108059160235795892976", + "4993390793677030007023804867617329393931635615810976661139461248253851471412", + "973050533401342110180605419751137563184725082821038770229241448201970125921", + "14313276246574487682858906899808269544140218917497205965354285099641091349756", + "18746777136177241043722556179260854313319807637092383577312657349740719965076", + "14517023428366357570216698819722831600577825429761151189605029742824536459972", + "20223198094330596704408798588338060788093323967112845691364940702136543962642", + "2924401185705980722600796492514644487545258803954418619331883216838542308543", + "485440919681570468713530641755278841324413691217763990572458853294843435089", + "21560476826107225363638525612645382878298890750874072774141701406519608285783", + "7856508582404120415593106596945280577031904101959961641860467517902309769386", + "1505151890969527772884247006998953879441745452105187039442954300997320053301", + "18861812597641777105968621029392243993700881183944538936666186678355756609806", + "11964609307983840306843122014689504510236749206766494519381451521217569407396", + "17764783391855759749651949748230026302359698415337858912932633638930034077791", + "16562247632438820849068750036602367255890087581186727955070681252413797347277", + "3341595358840888933968836940161983842834749603437573997372892853189756769506", + "3198140245778498430686233550970322127895441994253754893043542706415030678798", + "9829840339700031668849847901844029075426216057792062644639239580989060312114", + "5999422607425238131817993672620301343082348300090537110946144186609066413585", + "19901271533560906428202710740924807375620638454776660078183104891177283526156", + "16697165654181109350158134734382046723004976300078845885330478879604895897280", + "19171906568090360833249366643372143476587242793789646446664643684138123124668", + "5557557332632668793539639636185643553639926364115539987556075445308999628265", + "4797522865199880517123583692586561796505378758857130153602827907909887751116", + "15409514194242892627651944305634286919424076146534027188938906487506413405089", + "10407013998132974348561594118793213466618426284969698091916131778477581263008", + "2534925381155806875978186916525958864791165037467997034976228683909613017312", + "16140842893634434452708565053572928560639256480905937421023970743339301598617", + "7517617592925372620130293329989654305076737363747701594349097857054039164182", + "17572708764253481596340159581412737527195601517063980704204677005617144607526", + "16697796470163537491131716229045730242536059781538196375577575057386248458494", + "38275164685285960308550480834951641755153240877853193094138358285155638204", + "19780228589871041196871406056718374983456578990309085234484187723923738516508", + "4573417308961077301452769955811063226515352449986725327722241421281202736681", + "4768055042642730073498433238804346134649067788593835428664493008393684000706", + "17566912618951175959416490797476610679702184562687840273697859062459883449046", + "11477598695424707935165112148975667441147635429812599883095916948275334113413", + "3408907078049921938725945268376819484694115736385272440041090673225197146180", + "2488590561390551829094067182419871806900177001183027832070626654223650976899", + "12116557895894464059885135778994901345424716569754903115015740397131803733982", + "15881232965640921626180413777392630630338847181632662075996983398726326426432", + "20914323757596181391651855665547258251038466184617935369425714249299063760685", + "4275923143992397246911855313401177253209967573031785993454148836244404305934", + "13098973753894185378061607442839048669135765294488505596582737281481575045554", + "7995472162206735324879506324600884378126850726543803581430135236761716527753", + "3690915804478314734124615543749602171459078573370790663994412906012450478823", + "1256453655839486811750227055618146120819862944082463957526146264573763714294", + "4406492967670422538631080907830590263463047897583684262207883537903678091970", + "13380843970691717863215678292643800288491103227905602355694129412234174194363", + "19680159398793220289979983679401118779763854719759576408245027038965290325739", + "8515713472495355510508289305321355004480161123461789103991491891201940557902", + "18392703846804297332972535728243845000077361414687818948278976164182674947067", + "19823604647876421559318429394175186838817554072847524297827763377975574273192", + "17719715026846703054856559310322577442906188886145763860157972477138788247667", + "8745282777320550983079435446349157218001552450433897097227622172209480270781", + "3259368608255603766247016957318442624095407655100612967940789373312058996520", + "3379679235619387594255002628664818227413294377266729211815713998759100259668", + "10282673789366804521601844018863748004632586596870138135887183100195194767004", + "8431227731426467642712572981755086675999345721043460063547234289139267810255", + "14117058124827023634266519281629142766485227596060997608233088670325722698559", + "17113232771025226173986361792697170950811880770802373827827162227101499645884", + "9906220434844104062978204733717072107397540599291396561476275675218575564970", + "711369587296778404961826907371863989722457674941832862265420496583620086218", + "10995654568685707735109869974152491589223292425449581061000447170660561828729", + "17197923097868441003908860864777521604587651639410061820516916970875615238246", + "3121715947184842829391029463556305441693293825061846129844634146823663627601", + "8817835750782344079827519863863370969960597321588294656839911940551490704717", + "21074199894730915603594812797833479514843396752652846676596119472522115586998", + "8903588044620722375103549330291845285230849782400990458525441823641905996819", + "7157451412319473873395155428325762769952294079544485671397508107346256362850", + "5366933733103001902997281886950280717532636892191522349820059149392915169558", + "3729196254269053915687004590799382892429870424157270200083981101426772909827", + "3918096703119862723362353838062260616080657756068272173354821697584630247209", + "11073027330528765229119199873305594827907404967404841004751556462671634016839", + "16424651511178205757967439516888026957937418127900739730326874335888617161971", + "17036562818332519536292487256920458988625450115083747105277938048739292827058", + "795554890382567685751618566957270321871701261784565632343709559354970377145", + "633072079840093073847779349151531317793918731920375040247534587265858418734", + "19421194221177975514787747427021411300539454454371387008642591623632727982196", + "9954719107136377193496025917640974425520732567100168938432529522254697824571", + "8674312532180246290069249621352567303340886011365637785384772665860996736758", + "14809129550856657213168714888239735820810817787153747648450536960647330811703", + "18479959092813678391370975524549834571584338614798320263799188362327888537937", + "11754080849414921164216607793483937490683185256818320971638570891360029327056", + "10287736699385961112844233987245832756528102056561178731804188514133469579013", + "14370616700332892416887680617217669883953806003377620695037833373409292189021", + "12131262377053219810698216976753909777223459611599034218924662817794274728701", + "15129974113281645648506209149692470898425572316691306513209191313993708898437", + "7871644959999350003348485402403894487663479920989578076708137744830000430296", + "1576915733292398470896862707357585951921545131195468346129170132189223165938", + "13316238922195025030929715018519212370128739646325014577776776032463179349855", + "15160020868051885495078648274966503057453505806774983308629511566464684311627", + "1692269682153339201433258246771340974628904846837119864247013056373782718416", + "19628837155426033423644376042848583705054394443378101622337255362403724735047", + "19222966046507618124793516210121558272031295169005274768240595331459420997142", + "12990748614547458190976906297393525840623470679364771518133250166378979874463", + "10124996030376091099517250678153357142212975502206884325977282211158514276950", + "17630673366223237394418802287655202715156124721482801416980858260564381593966", + "6743037447395702022066513290929048145404894812633440602191382691018136524423", + "3910195434942407507599129230554588207801501224467133349280934483448828467487", + "2025953242925331197360540874793022332074847486979998082380244277507702608951", + "17290925253475198968609624243667228472127383792887388480830073536530705682760", + "15557314422719360545874148111856256188428921052029295715627017447052250706766", + "19758557148246918190283097589287660972538989627091387035573386136809005998935", + "10859351185398338650386876904094285059182038967427299340069909694684844129362", + "3496018793417449121342556434800740598384008787187762642325224753304909741349", + "13695501250971489187692201493870442254612771332042272465953359508617675704938", + "13572242195808512474816152630443442412961099907068902213470234329372028271256", + "6257061132956659095252686302119011010885219692712894010340612889095488866530", + "4330599809632843338876238530496396340118064854909940219910748808728579051913", + "9157987606978264109338780586425009211347479724574125407732261019832259951031", + "2328698634372378957406958821467382289342903425118775270878244960387352862845", + "20636525922386221727012980541907198653039323429055563362662406273278160984146", + "15847894355448175995216566821171916679432807087340467956339517156584053817157", + "1942360378421747943668019094002571732886982847410366696537432314848905467679", + "9512432294361739988724195228775769058251373607278744642461344881575127503031", + "7373765909536890992660842391636719615263272667672747352621337161184389163446", + "16805165862480928364732162070809175154629112007405963636466097184868514458659", + "7667777941325858499291332847392489530780564386762784335358233711706517931292", + "6446208647487337326336908745536052288215677968074882840304817109073334759485", + "11285516171986135785540153632137541881991922296507010937224736080386568662797", + "10115214387228124714106659470937696440920497755599449040012569123044717722706", + "15485618097017003479590081826451772255273462073640651108645768569284210541135", + "14933383877101576453093795963534828854771957327481830015228527838452944594646", + "12699366929120600543724208703956381057734625711467645612998923493410472579972", + "12636366946456086231704939526732303791619337704833963854669708252203542584210", + "12149350767700952579168066320091211427411187251056390220529300991824437924228", + "7521252564104984899409328139379375498829232271563704354107116269254046402507", + "12033991121152464927378622393121300999333393690763174606686511857615848602007", + "17232776948709347607296344257668859070263618035653710252910881198999758003380", + "8692908682458431891302516268928916165669902656866484222966303081483718910104", + "1253076047322637463481069610081050841277544153675308425513468857300598987482", + "17753389824587331559955818909257943804816005297310986968447179587639048799696", + "5220269242560242526244582743085713945173060875457087963936380952653150665967", + "17126848126303954156127690428371193690154903947228604938919561454676410821149", + "16844245036721981603144243350071451732279678956963696493069130132912694448751", + "16797761350119564409426534689125994845767740388070744929816576998448097719798", + "19353620610135120026060560134469588460709151673182029068633909633596535108020", + "19135326024992044270104645311242450367403619348108625528873986701416220617679", + "17665816362466043406415418194780245586053150534372814020191541209753248047067", + "11399583108978058354832763133747562621839059603612742599115200702193127837394", + "10094334549114303273265943473013412623520307578724043117639269488721170750917", + "21601458494506173036246860827162868889968956934810679234022762622742359366252", + "6386580477827919478878489737663301647954047211008970416851133263802072756591", + "4792043837032853062947152822210390150724912812294333339974827814683543135564", + "20876886123310865680023706563792643033695666593071136348323857270657128199374", + "5931154799422838405687052216230902279350178420072288819326391251206607447359", + "5239679324690579237822809044372316561806419523557737441242604861240795339076", + "10385003741667422202343482240152986976068622687279646189490976516013598227432", + "8464156248644168452015929033942509092145250244998026718035923409819766539834", + "13177537753162628205208392995644675716264814191265988042404781479197639366733", + "5919477377826036950488668794024141041792143979412430063956231337921980979482", + "1351402666854456730370541080745509803482004768817122599092881844387000676155", + "6818673776641149273361875347660949176445649468306471072411086367313332518455", + "1366646945884507587781123424154966453464902291438811059924651777083838835678", + "16219293249111347900064666257423013936256436002819357345030961998874555359000", + "779230149490072246312543789505064727370429119089791148581854356816464370377", + "18480337167389263493513952937037301086055810692872257722500635290543939189393", + "1345414110418158215433956620396568245327910182467730711109133441878095212920", + "12518315654451653143886317929532883727219058399486775127781649065277400104111", + "19716171362713656659833259243590727588692449255201500490000859973307782246016", + "1865072487559894165339723956247507020827160163812334855490266264867949416605", + "8915174456326318257703177400411158958853446829269268103252573093652570933472", + "20191934956657253997484040571514242713447218897800997897558899754776252309230", + "3900170788760364547006546697350123842323924137566872497612605525517074710000", + "2242244954905694264442292936230335662862827521454977184433268725352453968501", + "17212753633823250440920113486091598217346743686574392123683302470302281044057", + "11939276774333100126191320505078174289237596631307779156488772314461752488631", + "361355126674011999247836373885105218009746852422112563922207274436194144681", + "3861054771271956681986534133247127581996350841974597302976225613765246291116", + "19968479093411941747037123171825881488638273087679549521610505739311299462846", + "8537196135596544183619390135426012949552627827993128615534814021127294540392", + "2438879838432432949185118142364194193697006515067980632650379470739663214843", + "10769366200854175394348657213265947929465261545591304593688343101111720627317", + "8455019976119342575889554308499186802278388693477937667704910645050957262689", + "20644389417984700539779514908032253651696357386572813102276555909201716748299", + "8820039786383750409041489202684137325382534899692778928304664068322226640076", + "8636461459675525672530300171201543901107046823820677414340465229975162161919", + "9061524648737340075438868917468774023866583922769991567001812766008277156749", + "7602969742956570438827438826124187210014769304752116695796494779120606534919", + "17880480383024583813657184645997268710007005482705400161841684734099773182094", + "12468433127385453618607022105559942067759302463679348320088817783890080634670", + "5227335513133160328788197758812517500875193491652227971114102085123079105787", + "6151293357148965084809035339276030775032864902311425722089088413878852880603", + "13699219811250783019541356007733829713463891996344484242492968708316395244276", + "20523944015644472920486129305620987253227711059638489683670518491277805771642", + "10421521516830672217871475174620176828341870738569247402138774913961149048583", + "15243709334491280025949017219424981672670169674700467979049999809115231651422", + "15516151337135073170256217447458198066207320794936363948307836943072374966170", + "17337341094266438501679457986886656365327787301649468585664115813920643670255", + "13262611487153423909813660830277859169133522588408913308784951544213550636850", + "18531665394082016871726276363920851282983017715104457591860421181826617619235", + "3700454591945927209171569025131477008196191968736477330379417168348613474972", + "3604972001659087732761769946443190920343158947813896848729866695375607825911", + "20952949990925307134028293094501736726689724950451065635729323134614933963162", + "9405357171465854081502883779215538022417071330241830295392540662303830897477", + "21638057691528924765719568024989208898293733581278465977164525893773900371884", + "1423261214711655336057796638966786076518765517452404205191550645234914655224", + "4051452662373209612509106830833400151748328181316060758960838588997502328136", + "18894191275634392250799133342573131067016712303481664374003128715704286175519", + "8319722910647187566775047002603641370685637216565762886509056643924765393708", + "18376807271218398458453428415456722166053637869198381036620575958015471551748", + "12035584964270041086110602893321059914382792217135345721427943800456312398294", + "12648928151571890511419082198798501903838843998709266232987169892491925610349", + "21412038262513052722667255278175073999553643537758589877888129674442282140610", + "7706735190856341161262212613554225730619876208755452623628315796884166016734", + "10999966015370832078836488333389544875338251739488999274500058322944383211399", + "4088296406085952300442596245852961024918851819760395990644634222875937267642", + "19399822412575078284884340953745677500886533272999950579143260384703504507006", + "3008499431966541245607724530938385192395211534821775780577277325698653345072", + "21447244586691806434401916456546893987941039399147865009673973728056412619884", + "893624395222035047010673050230651164575948871010677581303166873938544655581", + "21402344785412208717452894839332459679574051179708007417742748857146495441368", + "9392712010553327328684355664342647815409597079361837524976044019430681532876", + "11566000613582826375650817776243972243778859250974226949316472392849073658674", + "12900046757905605731200852057204734685283283637014313056501123642345467590346", + "2147232762440136333246788660102778148879449441151868600321283583777116020664", + "16301766972982581403924204059742972933467455194833897714073756335881543890771", + "9546560122931098895129690583175071306095759562194496054583390881525378967396", + "3814097068175987733354103462855355721851435755267819873064912557751073632829", + "10704509016547426355599213335456446765914211024738080860797634337598031536580", + "11921271012710313311785310319425095342886561942032945429395596578758895308264", + "21265249694322068914280109016742517903125526413969519857556032179013285196924", + "7207578215754030787157150149235357460121567678249968060366462431427104673093", + "20820013978092841458072065536574129286011620075823185493370309064760526240362", + "16441600678335369077753559950421185577542163640313037056248177018465084864223", + "297097313501884278852369638329400055327872945847645211148627847628970916078", + "18298084629287541333205519012404334789930413367615524379442280529941257264699", + "15206243674059814574375077493088319889784970587286591062649045683132661681752", + "18726053049188513051286348977772545167577661574609708038977390139794201099882", + "20262858185621074639529176348089123044694437795099449154711162805012934737131", + "2249345697973053772423677422936999849381692933292653912080014325442939977122", + "20814726663898441680439335735982981967722006066824203970896314191676769388296", + "3816485989624386223507317175678560807682224519267326958526058565555245734714", + "16741230612980371365533431648017361867585544111098407772560748428499802539906", + "2436865301432265520692873922135716828388518032014231744012990863912440945389", + "5265261577128499220460184630262997769060828863581478135168474766310582001180", + "20550548783058990082416235781987882123241946829605049684648813233836863290502", + "21523044301008793877416122201092687874337292497403523925455260117417170777735", + "9283421400783174646451499708802113832695004549893166692004850391713463380536", + "17813773547838391112844362681067751767404443478918792865885006908077545151618", + "16486730475669947890512191574075897324037778751496940417084163322433837359720", + "11367125189013824464048785896422572845103707778462525259651446893275289247873", + "4759445724467851058773503846834304672223785226936531021666916376323562671488", + "782273457631193956426744043048759353979593033245260492990657945904665284910", + "13487130697992008212099652811750242205045881544509489831523448570173633517977", + "15621563974535086891768796441515013364217522966350445838133979748032034816142", + "19364835034502915244801518193980688426244659266819997726035650961451415757173", + "21037385853462058267099182407141652124171361973889761119816789091401609511088", + "20434791917020905003166852059282129255412677606775079570484129378535005615291", + "4835039666519156760310260600042269943079463379265872618778854224413385690994", + "17796521681519947552208651467058827825861565135255248123077469895978163706264", + "2823350440792171019111081223801188552138104039380675927963458669980277420276", + "16030935304664378631941573945857397096373696981104104381156313618686049806120", + "17523561865544155408760007908067668065236326734119657233234283826019015377013", + "3861341406966982603014220134107636493882146780655211775629734223927755221098", + "1327887013530867777305056212037691710827939709365211251951525926327942169414", + "16874372098146373517691588057974501095408377103185981262983559391956463291137", + "1335930538845994150082853775454018356383085560294444442667355553131066129276", + "16846954448852864630121063053695845658867759327963014776419090787323732938912", + "1910615356880143423765930148112668984411979710628153215580997630269783916489", + "8793723522335768214688108364110927144836722932802666660252079036893034856492", + "3725321587522884864935206279104882080790553804758085564413847527197687551835", + "17549397166194503933313005107479073474671951786436058351827338574279485542057", + "6575272615526665941236934551769345604089554458721499014263130089965203838692", + "19479945993771870488240738504390121923410154808673876321101554256856036124677", + "15218540520084042504179141700157006972641510542203443030571191341196460163766", + "11605382280428426652337162672330854829498688801746852913129963366330544359414", + "19452583367341408020642116770501289011436457479987875413223766731278874726613", + "2498463382382553480222037299113185800507848748313035345734629490930688205092", + "1815123960727364421144419865126922339611466868807520419660969560789979822474", + "20531692711768862540943545541715345229360673134388506876856593310216372259130", + "21106443640856542784867046664180461359993554892163126756059125921876166419615", + "8538925154199646282458477113696635826112766123791239931164489946578874271866", + "6179996393486486548378164504724190431464526698002381214818146508779777698063", + "1334556948430115939422649531996020210538905726908545666936164977436729124944", + "14555087544451841622469763698691954343538388285983305607235034906273022598676", + "3263678860186354326206053303615515256258748076250020171477442794745232038780", + "1342606052959540554052550853649027290857482440100275878202185177537473434874", + "19067318604617984900108104413860593038444834168491290140413988853573796446193", + "11453576191720077983310542494091726783885546118293459348522522324645101050430", + "3772400828106882724656632136643514300687950364203707059277582466654856015909", + "19928616354232846804233301414766074864065580313304404532140360351457581578733", + "17669618023197654971616078177762451816976570462585423216749814198562722234016", + "20487504497482961764356160511764652912371612840137405927810776425577238052311", + "15959943319286858239034503624455112049217253792773599324329593237810330429519", + "18384331160163107383609864825156022277275076414745740108239579270660154123750", + "11807744905122445070761653068499781933485269571078706728521902995972849333739", + "21636069700028297640587439425598371999203459272489053044479958900301869951268", + "5974406255004817187688462241155741022204236935194897255519053490391727654963", + "18655439470676485950283686008645538637216956533059508817637925480405213882893", + "15164692255429309369428108531856612257028649418370969640920631880841690009016", + "12342219963417210875401056442100023070134657858086394031902694268469750570612", + "481209231155250366998260270814874408671884781003382050138985430923825730090", + "3242985953168013112117560001466320034030784952490866310190327264524235633420", + "13671160391160864796369771052335315926068131063004086507703804642392143876725", + "16716228406804746939632807079686149044089946710213611348848847599210659020138", + "9496049727665863372935045496498617414460003517119878231671018103126084599100", + "16483340875218689502751737973203780724082025375353804209734656041473116836207", + "2627597076078148403546873341483726933849452415436198036537442451261384383723", + "20527956374075302103516613197928664717455732919429461243667758971357150882342", + "11711450220231538029408058975978592998998598526983681112180323327131923215776", + "14877293714143600802178367397934915488570060506993092692625720179311507474506", + "17326201000468992158693082078045140389930457394232528033746431682308160431934", + "8241890704089720408679017565592201736334812957892898769189351788325500937732", + "6134985085876540657808139826388808003135254271482158519839818774839726308917", + "6944918715501093472287921248184355748547193680657762762284351108190443908482", + "20293371855859360749476040038457808453751087076170457949707661658124460443795", + "12686929429491234226470786986230897140429036877303905464553700071658994784104", + "17469937611674874489854850805106365496296990924579100118175990663783068480118", + "4389315288495042551686883151731749050970801790377604942482415778510472384968", + "11356013296312574683565144017425132580728729177241949155779586695189495537084", + "5103616537832821778796048073410908442363049367034544148603830689894368565040", + "17797731362169406634431131949969435652804582561417001546024888062211188454886", + "14413974530545126251158359344156378502844867672748912889426381728267720393327", + "18860675036245741580291857551498220749884348391920381715922087052471051304459", + "2078681010293955893545295223175290151677764183673754633340142745613957031877", + "11594462210573371469687203943585180057860108341927961420756260896877407822187", + "8232172476137304604696594035794651005660416081930158074561971898151387789159", + "16234745736110953717672420346414210260779855851076189537371942811750295876135", + "12403261277735118438898936378116787991453555210970659659639856670648844247938", + "10260185954137740247486488192570496092684935183379388125044125653647328054023", + "12655661577981598013787126068450556825218951206788052328715378240540030673155", + "18875782029492829253540920061867800401544385695523240332551730645990253683286", + "13000939909369679921538945109975441940863265779072482929455684540500587590629", + "239651505606383903278277662841450805219997298453219985892834268956273681444", + "14053674646208577108881262953518523519057705122297176784230960366018789686467", + "3606574524342197944154321263420984044427893927972300192386619594198948706444", + "4925738689374393290519002876270198297196104042467164940497567711764321354393", + "9820857610236925174040210045575219513594477725958302510866127781620764675531", + "8644935227560188528158307606853375529544842899940616765747319983176480635667", + "12589563927120228887319930197852404057542625019034806374830349240796880735981", + "13728987671030134173563628755348391107370774536000844606094840710456114349003", + "15280672692530045491619672502933299001869276703035606138561063102232345967821", + "21236672540209166733321925277807375026701626666734236841532747395149863205571", + "18193368154219306112046312834283644566129199372283662927472078427038205531636", + "17828956732555553542546753429670551891943977601119756829631880115504235233984", + "16641047964358580103472953437535358748387376425127849904658691126285684204504", + "7196281413799658043487145161620082973834461754768351228587249162400339111893", + "21279455923934963235610861427104388147894350922169838127737714784897083581830", + "10868227810739752166142906769497786680491652628709341836398414527811509748689", + "2545479497580424357309396388184225593698470568625667945691755386799845345027", + "18560104754451358950174079457178017278416450108044438296553162755384040068059", + "11209544817144484509471895492404241079181269159060632258040504564376475442191", + "14007605578670373547623429803718323316371456029307063658189484725071020560017", + "19316201371814679831554697580647476192318282119512681720915001227483533198021", + "16788142218280927569387096932066591137887806957079516944927766625343518189548", + "961359518362994763330685811948798278197676602059504713988410706948791494727", + "19776591693739287332042935252284088014720557305781829207369487992244783048185", + "9480779019638564372864984254416095889603560407402750333423136372713778963272", + "7812061847536565125280880398757948966749177710701972331770694629380983832516", + "14806224217889264732099766866344263686300132511433376375954468192761174167878", + "10982734897602724370866115596864634266746118759609469486863878972425453415519", + "9054801238670111257982773992849940941038784597792282084645523468554872244495", + "16788499373458165601983802204061832376825550128562541027433580619384299691535", + "4361212778425224413929793165968418385407821814716394404713983701050982051159", + "21198869506404830651226227162808186595284220877501140400488215541390720176503", + "7255012904510681544072472510832565052731304049336267892176928038570971034121", + "9737409770400739938717035426255379270654933363992002237053138761832402079248", + "14206577906412186888550704503752653056320975796075254442765439825369882967977", + "19036632138581200062386943078412086222459679497578993523004498970778925638274", + "2855178582526872375806959544405581665248537620420194093904041355969926293337", + "12896727255458884273207928529421874672712973447260798892551468479503233439215", + "20930350939164528694912500193219456539952966506926646436560438515643683077210", + "184093243282405111677536457857692693581379037444126410664343605529966199122", + "15658149328429348710722591333703516363901544310832580304722884306208924451465", + "17544235160628712643216064131303569753533519783718786133736357990785709619346", + "9378984995834426590515136439048146470293781405649183047514776402081048834772", + "15827462476470655610816981948418438654022314364182315935007413461648751735708", + "13474113844360907776462232979612140726930720201237003164521648175005015977732", + "1846676454601041085237775396212630553832771346942418764660365576890630152018", + "8958790186410745003596973786908460746144469347369569174866696175944574520886", + "16716100142556090678395507171596864615262575578180211444515549196841601774046", + "17584363243087108058467208592097637069605249776196694465943790236027601639916", + "15462568643993327150997687623907692370120490318886920754261967569094539968909", + "11670427917584674115542198398366950879185738970881616803513412243898491416455", + "5883010686944177614793479335292002976406988590121850032334552332298599405710", + "20848023045403944451304856285219275218146149181988087184275301094312642906291", + "20892609628755793476767683891284835591758207667306100001065280698890821585620", + "11041559416099382923560246079300939393371149141074957197352566129686429429340", + "17004024027027164912556351303862470964296900000646134239805113699616064012220", + "110742314120280698533248152539115345099402903868297760208823130532853128340", + "13611598917097489441998314826578736196564311189470688979687759717921520208428", + "20362978391139708024092837231934567580385484740720090300868417284017430844864", + "4130975720087443718484415210347908638971321493417335260526136858657572592254", + "15799784358302997284875412214187555553319485274948108081666806701893845835839", + "12410480753305882251320943831026503736012757975027018073585110506521877824193", + "11835843853657957571888855948788121206617247107501669280697395787347649231752", + "3326313455005237548503557557286834479752096887215379141590090769222516357133", + "3193633369267878319453517203588676707547172638050950764150162277144428673066", + "3543696055990388683071939150214505536733386566291338758519836333135488212473", + "453840133795717001022433249997110059635014609516452256954528366651276289770", + "10086004265216215714804100477403907145516617200748655771783383139854288214070", + "18938459257787140207383332020952460039308194017940327258304986766920440675756", + "18017538799787896442217663532610710859333377084532654794368604069493775630216", + "5517691591172342790575564654696650661133600869824307632295945043592492062300", + "5846204096126701465613249085053971321249645306247508562697696901334354225619", + "3177064511134248081568628736306700282095095665917536853000298191943047784014", + "7886005759395499452194553110700824805018792487440311729836576312028682853862", + "19249432464407391173245558257296856631584193393398113008165174416171947900609", + "16818455958785909569371690525990846776263170512884599090849081099178789681425", + "16250344336602567919050898941410625842485562539342327155695417850618940905704", + "6273998461375119044609362240019558608655450921258416376794979330773412610302", + "15933077340738498731035173703791932079747269039222967104684412531145625747085", + "17631878023023477567294765381542867314814954498487832435087010633074888584009", + "3387656327342575368928488173891176548794878068816523542226413637288662472792", + "15770343706243316227190526252701886989383556270818375222569120097305537622560", + "21025947829537149117391184273139276031347299127217645728072786010534368285621", + "11728430055160129100077268133090903533902452454196978455625432056779499908581", + "2184576630760971645143677026393147474439766939689140114811262608230414186937", + "20744811853491523948066896610767067484129121010717068573365370365324040781186", + "5378129452609441814399329369785055593231824205814541852039878139773312247469", + "18082900764136659604287793533371380099349929291808230688664846500365863263118", + "10463958995559323021196963984934883570109613942564610388110191948063546468897", + "244120224370345949702567256216804961153505781666838608095297311545160357032", + "17924705581798291273661662368787600134425123985006190354093511903371507000154", + "3107793385049037773698181795186417899797325916401357881664725445733609110598", + "5665818573123185227274537904890713907625420710982346291959547939830358917272", + "967322682615997637785254033877348832211978156650281338584051044602311410196", + "19419941178285529854771216440310658103611219351729270204884834098822007849679", + "6901963792883328370624032472781824547409040392368725235274158498520441238159", + "13721659825627300509722716825333808233371435398666022190921612703736274379535", + "2784281502858555298249063959836879135450746982163416748737579846439268828933", + "9904373282060708277943634486822397019446454722637742217276784802015824898651", + "5782567592658163731724098371574354386783075175203877502094122152538152467682", + "10854330629450460532485325799036675355255970975925867222693267730198057197195", + "7162558805520478103072398765799613453839879264508883857822705210986309908966", + "14561060495007338369036260685346480181377385446422680685283066135483167829865", + "11521954935420160563214644175207412771411940789064933791820101643809540481492", + "3893071612329582305940837979511590531534863287842007408024123330272447072664", + "19982770443796802008915975147614604175753586689418309845602797606117149147490", + "19714753609495058998670661272525609201695470529132258598980221623379639411831", + "10656632215192474178114431876399520721084839753473211054259843433641616176373", + "15519943627473966175746342389219894179761085602008029155282295063466585111230", + "429220418726674010600368106136723992478318707196454289985261340376476917460", + "16943119555428737036287647863079565463224985076466268175824843518378134856246", + "7079268853451648384434335899135383974808119657387366504271184409878695702895", + "5787261347913259367727842908192773692002199385877294080619854106978539332397", + "8254314874636465273639128395147895313719165057850599581478980264860146008069", + "15417738281457065064716789110361253613929614783743035738325702945037527193953", + "8995940809050737092434676062651493038351424361820394016896779859938155003450", + "8930952966754141446126393622188683431566029237395186071059700311531927009283", + "9012970415439810859538557593310902447051948348093454112737452817814629449500", + "21700461010267441715993595978543322483687194036588160210184366057201658507847", + "19191426116308521669196161733982754533604260068907220372422504926794231257150", + "18022413735343984488479130392027693687461867574196874267731354592562070094392", + "13853879871506882218224060020827336496729967255850404386800036291019021382781", + "13303720125164503437055631247918150173085142868095887759030649510172293881844", + "12463581809293287384469946044562671884924464520288697069370030386140109068261", + "20468619377263375923071378952981485015200979956112400596511865225946853604157", + "16682148710681177357125570715056314888342059670705617513402649433802720432267", + "16299073895000203963165709887505572454180623116454760411179563591228007694413", + "6439155427163506786329349605983728674821430800627321435200421453561910062302", + "16531483734580605436075637034861280240342858648848575098901014901746112480232", + "17413802217650584016261506268242623594956116228659732892682224912798301233645", + "19833018739354446018077109493089909435818386368530968355647208939546565982905", + "13005203599293796776324509750491064421128717423989464867065044987475986374420", + "15433711189444672576513248931602290892518442446252602686878477157678233603772", + "11272192842480959445178012145556234469776261923967845001064211055340129168135", + "21349777755000957327199310930646977290027138137542241555905014230683052104267", + "2414795183415356147955181901405712632718942970568205736628916600696077941534", + "13910388410253717440990758214044472114511432613509643223811561885135488623236", + "10073917454281511762447567386654530277776617831005093724557094001489771821135", + "15674657915196276639699997458656008228696751013801231738985398708672037426000", + "12030695425048598984176709301472822771003849589255577773183310838231109921591", + "6658172369461756755506276881582345916252610724131747740625283609123100367529", + "6460801016753822141904293563006139350014125998787400018150863192907944207957", + "10798491465896968361800574703868612181389697312199241920447162078078725409638", + "6331917501914253534943383807348566698937757752033630507696817298838693259937", + "21521172968280414216108032807577565012642487518706778276505136864150789112592", + "11443202152743097070847729825799673217706162711935940510632741405015900516668", + "10360970774813507384412119692215277392320350056791930702078433469299837875151", + "8111678922881662305935841208620197469657237670526301850210945861223648259810", + "3828566775247110089904016755996284741548002327940628727687176763639903716661", + "21019871488460899469684764817167629979753844957147537040703291790231271795829", + "11744049805554498869931942573519884330545637954557542018916739662277241821806", + "4521092770491436085084640166923844634777984445583984077999595768778116564222", + "2428018726292924561718904390333390438951211767580762396913313600061529081905", + "2672992591753804066533616673591169777906973091506536575810912266557203322920", + "5631180351966611479340932319081124575466459942666630580683510336616679680271", + "10149209329290376952496655294191511204529081153402908137750268385347783758010", + "18292794133971639465196495021864699906132845458944945214425906730119328661326", + "21442863185355178191454777233963814974940050392649316620141474331670970354424", + "3768420898310640667772098495371174917665155708578905018940113026409140957987", + "13677778555119984843885943251631654212176086447994430552012266440677394344669", + "13884681165958999171515885225547717032289759601884108191367706162606597842698", + "123196094575938824660055152882088188411485715788351262262924974166600702398", + "1121836698372380581784934880625694675020871234049336489788624481922395781738", + "20941331435492311592529607715649713508861806194386837398916323083940590908651", + "2470912827043971002614412337239267059969980871643559631900987795139200233821", + "10806505189594612637071931546921663393081238567888534876058498530874738324701", + "667951375802630033661777802749339877422061577764798227349674331630120025667", + "18416355600415187627018330134584431345513028652497077471935121971918269469363", + "14167152054564590179475064444026440101215733530475912312508414765738108715862", + "18633695428427030575173671831485026260967985663658201463236228419717189642766", + "152822669216765741203342297512101138657182497046533047369566701489981099230", + "13835701173750333056481994253160471551109858589047436642253159392878873667798", + "3993942321148722649703549241999711668949060533276325947207349685002693878681", + "15582244332423092177434976075689385819450099629893355758782548118218073388706", + "15110236879710270343688993144525012407319759236015974251051640787524859884359", + "5104405092803829419537383694663582438349376353030379488011426113631155364320", + "11034886586481561934231698674217393887518948538322130743646058638919797229737", + "21614370562083755709911993869347579638113152610927033622836963904672826178593", + "11909716327216431973191112809713028257963610176155315584304717743448686635887", + "9670047520194835060472941420215502268522351803257892125345072551055025494562", + "8752044341583145728028411582583224350471084864272507077624316823400738066962", + "20685513123216586620977713797881862528998788503897607377725195418550074311551", + "20219162196364967181713755472576994456615542213293827108438968625041058321145", + "18287830464300889532838439052863785386620820747210980263612361113628554829988", + "10146051396529576924597355409059465520468869175466632446875430377637660889879", + "13466459020798488583841582724067017412922317425102130151754649408559458307937", + "14062280191830459071860023268317938748180670907089383563443465249500572357980", + "18486553995294693573565546696966437493113894571993019524170031057367640632085", + "11156566424349445901806390826392443373766529722049710427351550423908421767094", + "209671637225069235519570008386635562520193585953162475265417907100134848923", + "17226989944018790920809176115775819865824823495740082575382169759054625372382", + "15644589951345053163188258692419292119540702867922222648564209455819510994564", + "3689635641036835670663293726548900381724135109917216986885298700630212836435", + "3367607896403464195671402279459329078003744183784952830994679539910724667259", + "6227320552634621985217890398406127207902736210419315868051857823685244516725", + "7357930890687295365886228617478473072206575811998185548162905341534675558305", + "9337019296542497689612612043175604595811913796434346282222317112981594913389", + "14658782859891978670907070276103444826326577838777644289370207112293812556778", + "1700861002075407761970169168361393086239805454951858464329713573177596208454", + "8422307882422345667268572118847227804767508317685246864132851358134342544918", + "3824678171886439611637777800578730196591582015637069631407414390326082519384", + "7520989644070067743500997565082513560943860081670904302057616063200273050286", + "5278276919931895959830110725703210158384647399821914390314400092195592076331", + "14590632939277529585876696200177152214896495867542780671631701634592299041714", + "14365499645924743985349770983085181263329435144891175678390938245209017764418", + "2519790270252875654107597063434691592006935573176284731324585122712988059511", + "17688843544040778657269233842324532395371012201506418912518394656290716826075", + "16584068781164994465207120381716024087231836173689783891650623302438290695506", + "12224860044594664185598615945328866758529752520066027818906177267571423023661", + "13664317767999211366109254182438581912610775541954425083255023643648887081779", + "19324196860555787958873349597666822462940695051471419602454830948112942481945", + "15338841226759355791277440652242849878000656382388414806186764010001628984934", + "11076363155150973228897602285090741665942726007445165132980573631249449594126", + "11228309866140794620879641097623963859536328868056691748463227126359575786386", + "4762608512226640372168720665137259637840828925512114281702049841301872652787", + "18282645934358125859102195916568492018711932725386725562892735740355836227532", + "12803228415054755333149187333584509982900042807310255834005394843350472605458", + "17675693156369747720817703064233611574822178844066411565804543111769294187197", + "9900029048144575309490519431063332695303076438539483419053219772370202428926", + "3684590949621971596368895784562632626464811455818343794800044114209066071601", + "5443335602638685057982926800093482287199751584817191972983546508574786160090", + "11352900694666160844325992247118358443639716695965864728670968730093466793722", + "9836739435541786452166525951732520477055729763398281521212184905286650567233", + "8222926590877635625730738050718327099397892409701316035188479123499338707893", + "8154558268770648194631329585722892880905143452138234292827603893129808716905", + "20661038342485310632612091028394348057035659683250957045340774030445861865592", + "9136910062528018177460276667688174167129493547069053533874280111057356360561", + "4362513385797089229061458501847196255783651860098500705320631416351847846956", + "2061137061600029258110405980965338431925491466724330216028866028449889153371", + "14607676885409772552908782897874144975643999944034675480739173900267789420534", + "215346512487318428553079809620502708407272005519315271404209452927497999118", + "18044026902282362371439577283764019415115969502361960218708274179281044595578", + "9652478245641134951513165220881528043195466248948069255527062590256621034842", + "20994154929281322813927859895894589885437941429166007529912073756113466975582", + "20752721666010515144550782025078875036488075535083563976118804420187462745253", + "20857028711523544595627940704882176284224509745902984714255291431664146535922", + "9631521770540523913735742126933921923952197512938165111866628665235591582568", + "18950423265182779471595998716023482060645307106263127634953888715515988505533", + "1436791836740130330138273456892846001841969807914099860317370076565131805680", + "18145299176463660895047063984288790313564980703886502044680749544519011424826", + "7008134596456692891696131297028980612714475387065733972352529833092170154127", + "18054087496593103261596842546955317831262607456582498514349407492750291465651", + "2460661191051979147731673103829326449069370361298340160666765010767300969003", + "1121019547339042268901204213478561141018690742635442229019134496736639790078", + "13486140142607002128358893931572108539446504181590991898872881746144618091798", + "14485083458755292442253176062192342099468601222388603924363708902524652589634", + "17684636079328478898730536417772675839399177918554869673260926729643471105206", + "12382939536995562937141167025903251534081453604974163882762565576243762872206", + "5191757256912351314880102858899907666377813090645991709894707944196053941770", + "18397247107649643640823283145149323187327745749077714626730537494597891967945", + "21508632378351416585385353654317189405917247727406155133342616741543833680788", + "19108354768686907995261340253443420621814860995097718380505789237761300853182", + "3649609518051015699386442513879956346519312025847003339036530556474594795760", + "11893851425092314587513815253407979901615516208632062595457152391110352908805", + "13296593391067251947204447959241604616835056311051696511507435925462940176830", + "18493557674615580922923001229788184231889430766683327472934879670006059540367", + "7669746659590113244880799806073731587177781693253502772068846650012974230120", + "19370654200032786851343971085637480775724705092664059950989935645178139099864", + "1331955346226787928500793024038189892044219824334532771311923855914410290305", + "14488880297827410405382492933041130286687512096290491259710680579157544248910", + "6760882547908259908954677726421351194118695606292587659467769365205068189814", + ], + vec![ + "6377232663526537440095439257883018477761342422116697881186123375221738885878", + "851539971462439380385862352460596759101811723695394639617127852578681769809", + "8777577262325190174206575699458733195047013200879424709893142671840513604890", + "21694543997668766291509756109744969193435163886467863962355853609369758783238", + "9577278996811393500051721677710083593799044422389686435650597107832854019185", + "16323954252044716897246121150114593642230197187021287621193086593549237094775", + "9789909425016820105251161906130605326280235056822272235912508431951118212950", + "5766700650277227528545902607164112169119010038912902265869378685414299620760", + "14342521005374081251816746055115831251291272287569749723238975882435091047876", + "2566050045458470252423704003188705777658084864238473334290159653618543192811", + "8762700051029310248153110133778709519032029454737126719215892745208105815416", + "4708553466520767412303631379034292236924119642035476122997253385705160556618", + "4755252554118675759917549980023743559070421272488077422007409392838436797712", + "8781462767081720534606018702554359272062136386754094559457527802951016005606", + "19167810216492792969016670752653089791475857662598893252819620255611011677188", + "12379801295054424513880366937656969081677178004556540562031393564676230427743", + "3873349522143254287251699452075145107916086554326675869006906246349942638560", + "1683302064923931554193379270562867202085645938091131834974486624990867609624", + "2777362700160137801933468204963311934247500177582714816722898763176642740860", + "5330041075666088752029210636784758218847391095319460299231210692948196701638", + "11849341704739004206642161112350419905150271791787570525216826204427280723792", + "7477184099861050355308565098520563835117942875101546634259876195229073147282", + "18811741129290507103385501216699521500514849038287903802256059864942452310117", + "15644162092778325718506673614750051639809307056147336506838023349115605106787", + "15072682042494620166496832302000289519302436589952610199010633012972669445593", + "7385535266916101728534366006042662339391797772494836337087929961280561819695", + "10606300178546340442574451452231017670874690381506662581848460294140286741651", + "343808333592012682122858022517390819973432303579818622412786360520154826142", + "6686378289544833739489172513893542192299224296746579469451376125664696638046", + "9325668720082019512834072623751272154060473105966456255302021143714657867878", + "13237356616132921941407245964289360960304194019926733744472216846697663447262", + "1723892942664599421365079138681309575413323508685958773158319650163306910931", + "6845174279248890961319599668687600484787455619619716546069389087383603254137", + "14429592766972645051919899517480716657546426049902884218808698177731678278944", + "2012555589304829161260427679955782678928810146332132910441113793264100264511", + "15162287124358358727307007568219331690174000191414576263088727973180750593247", + "6171544970310792508799412092397912280594923286679674322244394636145740843662", + "11560360683323732335070294251287274796083850957500974817278726137032659811346", + "7954890646285422519425515982220441977570181574595597355546782742910060927756", + "2121066076676892095526555416241546752515994960009188371572036715916593676611", + "1030002705665772802770205305890036009903459272665864721338890073927102958060", + "16664112528630425414995233349042921759383114978671010908728891678245502701008", + "16224205339340335222764551648549356562936176805367408466634736640263613613659", + "5567916191875465998022755280584031341089937668974064792042640432034217833475", + "10561503261915825576621563677167739482566911623771072553907339314680805249099", + "1281495108038254322634503929806042733441491866895195579580212370919762081047", + "9600700315845518751455006692480832601523246124684033595437676082879283709816", + "15989333248905201890715282122260615227836016238448185882687783867814184655170", + "3846245593630362971844915233982274952290718501967612724027782949411933001202", + "9981027954269438386336412342904724691774209648042702865994578173145958992921", + "8623595877941915162474742420309695649920307514068323484728910858137792561119", + "21103940025922636831675399050467233863786411927021772979799068688191712316972", + "18892924253208304354853962839524897599416779246859691035714354037906441368765", + "17137414752196927825772499610314584261795745874954692214656847237011815603711", + "20412422497099028107138997806006051244688526968840932637543351831550882135155", + "11225636734520002481404086272590673372060731353304957503311626880321065568136", + "18380442589598191047463232737740533198002604231823107797039491680652883496794", + "1080201698768913889646664841066956319958767123758689784419321296338840961295", + "14348402455238680465583355269916779409600823120873923092214453448424409970818", + "3841435364722615893087024818655055436552226081083242159440517874888324292581", + "3408210599862246992363134715624815235769905293647431849706383726509064300506", + "12828232946525727915578787875290899244261094596690184893334123105536745936334", + "5483797730688489537248191960281635992343565537360149542110268773175134131314", + "15646042484365011867018844828962923289034117590475224947755290094723626891273", + "2658047411395048849255440353544966399245817841159701280361972904541325691434", + "19496407504291857422030801612379213952698163884670351003527359060477191854359", + "11599969200544990318778456235768317543324325704256981991953010275435791017626", + "12534635949431553834868179572769836881352677117158862189611147293522496413113", + "14223314197724082301050736397492110631416043159307338723464864105007185825079", + "19822547161504065277026677714514212915462043072809743766437313193660041742198", + "18248624683501549165279508462273639851850239430868786828229911137041335077425", + "1772507929668430466250295341031184282507314702999122972093244182511342701791", + "12698826328883589821004991321815018437184890565199562478819948777685095680390", + "2107256591274868946942358544310209350935597133418111664653447540003390113607", + "8347096431391887603955816523197766644723983907921702200049607244690524226105", + "7546736802459880596530318577784618006564482951653292089248497980343037655783", + "7337317896163766810388205540011597034395961854295494001017429381228506327036", + "7657535373588628884973408484470050620893383237179421367090832333743641042323", + "13132621069544809006163499228792832380417930375502811639756010731409020775733", + "3045981446877420174701593721028589257508837379178848429319604486793747007869", + "1665034234802535695418712526119528879364535660712727125979361452433857586005", + "7153904853002570654968228858836861252211159237410458977141045356668538557384", + "20486065252261216388496191302294274939758504298167574880569796877079451248375", + "21146476302842253436461025615017889905755773199293419435978649511293941220143", + "4692883070549935264853696204165792104522817067387529940796053065681435988854", + "6240088307004733902463222083449545201088681283438656231355545734118814247048", + "11555561118019341206516697020813127391202363312629469259248586095720628837415", + "19260547999655668000047734411254185932378393753746099027853756019009568507886", + "20469506109273046972497148219051635976793704979896239651651205124084812945608", + "1236647274759658638933992315999684238758461477931896092313814863963831171033", + "11384423918232921171964979139440160725835135313593824548598134875347314405204", + "19785250372370249720518667471906851686135385809175031332352733767471970846466", + "4246521523867165828929729227115582186945308737715737226156399485201514735146", + "9952732737001449699912255226665360960719170484486452179287528363081995818191", + "16411145939754797754686024918808322973332629854064127851496226070432060579489", + "18478056933955827759744830164752062474839918604932227276753757763884050277828", + "13204687970556138498219183195522996570326298997850204255083662628089078309770", + "6486083806326529246393301553077241033740361238170679962888274443184188794118", + "9215573806816888307072467120643373006129084289252457249266574218300367297487", + "5157456141970297671458245970390083650482632128904852982724214364911239574334", + "17822680498490868828738779948851745357227318213932493146619109948725716270324", + "8322423511882718045936027421959946860221136505721064786938368517081088404769", + "1146280240837664421126981150154328736275224000612293306261498532925677882509", + "20006445160687044351950305884447426432577260116801089758873885688911862838124", + "13132217654381318972692935199671458140461723506405656953229384472487720023845", + "2321904844688587860096390475332685957247396755436885306389445060312694195758", + "17673723499361727802425795357032445257876321564734597671004472729727016538966", + "17836648739374245973743495166940645001620159031723548669336786509810303589036", + "19509523664323410269318198214695596019790796169778932865716910251136766472034", + "21365014298519541792222476772118358897898683224332026502540401938408420183049", + "2443777802329356458012563966932795162347891060116795715814546844741577072487", + "6373148417441446230918754690291753760232604931431996749195267137425734054207", + "17543938461501434657363693054851238526018672792888706636605942303973500302856", + "13900881200135928840365427722717255359580153642574547892815287601924416317614", + "9982616108044216660339683982954165936737826707471259937628917232293660834440", + "16457765153339087464480638859689501343872608914611554385236118860039346779707", + "6882633521418674793651640056518599843365736128725139938457347614662141371026", + "6558481420440543921623853603383694405865402572023705828527015346924767906364", + "21119564418700154632542186570611885700968350571284986971813890102274419338575", + "15668498634043584871060292933787839904928585875204605204028656239629550300891", + "17754567428791571673016885915321661773655444664247443414002133544771398853149", + "11486839919314218506003227795241691164988634920977758623356018460082101365168", + "7521215937712438604222096500164256001666624136838511497877267672752282058366", + "1168385489601974578347279341199760237159478798101796567718644776242789923601", + "13117296414138131801834212262010987517820472685866772554743932452738843734333", + "7749628482107487230728683638475509704638633069294493147970362304145477016517", + "17102526463093059579604328209955502975564943362848110499048688895825859834607", + "11877937469390065191819717631885427975032604373385026940117533544572408798485", + "9490483077873795676333795591814325768750891664453067983811838122306462917887", + "10191097995163502256819397252907242166733175440759424521233105453843778654820", + "20532048353899648065110204116821557712236052515292993984913500569982446829913", + "17354150523998248091397848718695616500251280749145663998809707730330346369346", + "7747355680464214426243190602078017576496231133574539162185621451748634683393", + "8756715326391069596985357282435500586860011252775122994945356255643854963530", + "21536474090524236379254986352553305027867958936847041677436373000730213533274", + "19764807787330426181831011653714787282097837960248105858049804952757136862708", + "16451394978386784206980716591328721244692005310628203853347165858510983157051", + "9958807580185090358651106618892828843813431270139145526116189671892797920190", + "8667474404638571999095228348352836564567923532278597424241711463350637692261", + "9754527193113710990714009078343561220541479581342251031659489697296746296505", + "11755501121260346797952875679164705763574741595098729931802001980529024314166", + "17343653273660706017905395390969914833245644319150049521732399082825162090569", + "1010378412861729818622385301577181571311206842734096023690850995284550560689", + "12422787992288066268619146495902983268274452848893191113634050431879037454803", + "13351916057777123695069150362950067630454763506856720439068955445038740053267", + "3268740447474291563746626019604727880178668296496938516526099943483641022899", + "17039539378002212101604857371251026489627400179253250833603358068705093844865", + "12719626976782614661983190476189661930540289684710840404911817755168256363569", + "7334691511591452788631693316255271478502517924558055271367172394856435073355", + "4177321927122082121158728850724807513004613701936483594734414988911849675880", + "8517156232219806038206488131493677748028421797072860831547349043281348142926", + "5916342138159497146131772146268734765710150180676587683832045824388433290036", + "21136252379072914855830890952695340864582847490462136128874077543348574696616", + "10470343058787342159878702644341062172468027793693540114390435145428370707552", + "9367903847960780027900264774906616911120367129803429048363499797310012009648", + "9181708529218875829085211480957344367690955470310754169594385873272587183681", + "5161879954208731149141751476094480416185338457043041781556700389106447006281", + "14144603730790033561496908848503636331176898859925995171200576238014458649562", + "17528475461722173509900495818763366567939364295306035018228011778228457876695", + "449678858200791083139507971543902712490268199763356935472396275788444419520", + "16677139862336739737616497869711537864422474730319606529800927093596292773684", + "5307258894824770781811695261046705160386034275400321369052582330095447609528", + "7066455454850758706236264136180958260707829859148436565416678574940588976717", + "17464972536694182038180604993012612781624892485542021128713500864406129068272", + "1827574381303563082711258077787177320452649985803311391711223171032580182910", + "5005224603218153811845694200896301756909926774436577539307979565859865998867", + "13761569869627153404623558442531816440237410187883129666707204029577726405280", + "7377645231791556592153877817212695036000405157132509030366572797100109551371", + "18929000938053222386693378771208400814166536156735504775432130183653620422676", + "10277912490419902146704238375228669373848088391763413912903062245600018539005", + "18100670309576234559559738539779745691447892297890679181953368845735547051936", + "19792596568315968292503371918803163404916721074550555295039247624601141857094", + "6568943725774928078767297883788056758405958920376813493652098209237338819058", + "9708751028820311560873537735196353024741491886920686045780276405320332052014", + "20999195425108372543557431885250084840784235258564621629580763574508120639473", + "4668167020556593094762451685509419403613005848434427529155545560914783238805", + "10260166712816802791730167674468655124354432849926388591536360669342400828562", + "3588854010476278115364011192514859807683141010842317346600561233941024545452", + "955642453625490778540666824328669289325333312941525596301926803494785606357", + "4102026113333601512449185655242077481750021570821512149654744152647996823622", + "12901729067332459436197297782018174449541114313233855185609986472102830633274", + "1432400515841095916662233518576616625504866912337953671606919993429647264779", + "13448330934580056368019676193029108114576729981976748604441994201646531786832", + "18698774355061680075847219006041299002465669495077065798256778682757699200357", + "6114255237222848342826972972054203376750041293553715842262723528673741797160", + "8290432657858704891136963220676191057527195528510584103201077577863568506432", + "10245893420315465808958329213978599152040050245022584266757834865645078424612", + "16235075160725310956334026818354575166666144493784149178325740173109469893465", + "6096223185593495310139379444667947750109489326578429517185410779366192202063", + "15140535409353326038030605492985074291044727716595244779768492745470176024609", + "2176086602170005476358821348469239586548222322021168089824748815230407069862", + "13619789468668594404222482251836770591464929359372018436289664558758704681508", + "8310543107961996371575168146304294641952910047046695374038288287522235989972", + "7738370036488385965043396010845927300705713772735513648600973583706126470834", + "4479339978160586717158719172802732929733916533373426058515465717943672025882", + "4249199078635815430904933856748414549211196022798648243994671515262509861644", + "4217767457132611540965149700331359170343442048612092095364557557503970133933", + "13153296757017742961007840475261159306564053749538202546045661292791402275573", + "4396888098805340064553349190742819413046668458070694926676742098287729413444", + "16734434548572604008363129496559919254718993826492605430831689587940707338899", + "9015659000250675923210953833943081286931414181352124970688626484896488861379", + "7859006238840384066905305454236928888746240833462349287375399918976884871408", + "20111156231978127386472936347996655414872475039138926155687856551161732442682", + "20628144438246471187747981572742727430082255446467380395647482352559593647287", + "10829450719086027299358038584474043478547531034689618353624096053194488185624", + "3900905003848877440680433966861518022290921312029158328541666844523704712962", + "17855611209216805679188603521771950395726550847102335142668673883933213178620", + "3545647030011914165273791133303433140616659042668342263053968795372726840341", + "12285059161807384662955183653994648298401051593713604819454219983692697182696", + "11819552939527124997493513022814576182004246358800352547817016502521627790011", + "14301577158059901977856927221571457807294693699285069296999743154546478489569", + "3571634356329355229397931369891424491520267531585441552581855575412868351910", + "4493956823795845864156868703591503758707793967931549819151350879135230170242", + "18261935892851512416084887686097384445742684392402688030129684935728742717201", + "11603603642132262206403092178979219208473125803069223229133184466185736048060", + "4847487817017177565347080569283215504545281846426948697937793918200171528656", + "4069745589764729706654816299792297539062872486670505242875943264008484198412", + "21282151145529600768369623290936085172906963145870658008436208961308948924585", + "10721916615176439690683002129869911178402752315827226965537395702918089626824", + "20400924989628432852029073867249809947097995745931036434033577251949709693425", + "13612038717302251316998414209460162307179960669236088330389280060785328588738", + "2142054298626034610320009155682451576863946725173133307732467701538715335347", + "6814074799679801916559787533428482395152765022569535278039545933747386331226", + "3320993272550636151137746220977818986579019792097013138902071906802378678391", + "14404588996507110096126959822135132305375204264088975725278990285893078946890", + "19449156048766944910033639666691724350749810714682158108539166281157709899569", + "21600390672948543610212878389553096169635598817477527886039588952230732642418", + "16122909565998431497578901034409662715618749437754826295511086000491610510803", + "3814026203802323919937341565517130280297397500968227915639071188757380515963", + "6912908852134560099979027891279882003635111070588372993239339154823206466274", + "8991012532130902495044589989450658026455069044478725949828656540931441650779", + "19794616058753707346170576299297623557371037336156984230370345545981446397931", + "2577593820399732466692625387687370505160505291664134162589397465829320209836", + "10545990182245838392125531729060296377668723705525703355179325185018108067002", + "12532592142366733026886391992589159605208721772700692225488484422366892623887", + "19135911891605926936423877585461852787990719411437518367185457251216578059981", + "11635603342092216271740512684448806260427922119693878652222869987036671146111", + "7718247137511759231158297248913810065531288952022630354624599924037308251451", + "15449533941190926955831618735652142785144234166497064450979389633622292725920", + "14793399192194938994493676084408874396657844744757917843286252680102153699293", + "9379880417179271734210305738187417887144762048262218697049423795232738616822", + "10001585874846875226646763599153358317197291234293545431914341192928883246454", + "17564611789675170872923370710570629576001514727841256489502945348076745512773", + "13526676577413987112607573245391605865887231830025935262602066777025060147701", + "18771091487566471187260929156402254761992313431761027006794035379840343952064", + "17672790933843778353408361605666344788858296349839035375070469185645819063077", + "10136925806345148466019786355963896194230642602748938687391144254701550469628", + "11669469369568255529354542182318275079656673415035219767446071893709388727608", + "8717156787967537877037123555054580463721012975068417092258849467938967272751", + "3574689732222366081898222156809576015147776290993716837975298246375762980084", + "2936447189567283726966987004410103389002644634186413346432130822474131530801", + "1699723231413680239740710996339133622208402062115605498128909025253321290927", + "20239438661176091033530372775196947702401783521122338633601531691101072063415", + "509222199143055079823531599510182326541217708021228426946045537726376153595", + "12460587031004227589188413497497959758507406039249371767737225675508588807598", + "9172361948368872306701383997811949982264909388810393902913358291336142380374", + "15024321518919789320143737927991052999071746110692384451602809887435324670247", + "19363337726355099236128975299462078599854604247644073095764375371642393487744", + "11352512845451687563998689687452223516295911399723160879302208800753615647616", + "5033097489048897691788022265636063060230313291173145751178865731392231547832", + "9342768693529219155995840295623046316860027403351256239528640640660995546250", + "11343407235843410518451234635552443892628096773317032816539735746541252484029", + "20271637634427257791277080766628733956630399511643807969496831759934416995624", + "12979118904307784600641734806775453265865076574307149193300157552133646759000", + "2609049561347471594361989318849223604030501563821990609941361801853208873325", + "16638136645184843973996251461253142824084602885453534706330402604048300209367", + "6290150467317840195062942193162131367777911299731759519747208884085640022080", + "21846903793348064415550139579740558481601211918214432128739680250084492380404", + "6881355315007836102200696266576401649721953812561017678365140505591991478449", + "11991852144633415808902015898168146769921125504309617193757255165202163636329", + "20579180498569037366675392921380645532641402855187025365767529341564826966764", + "4127941604046459390852849136716344563624191244387948802112999500161867081345", + "12726445769512078351769013120614118104254671239018619408743816227993876252991", + "12822824504588887927083519548290538468815267612767490908011540889502830894241", + "3525790082239104371118456157894419087904422095178764587616607951352330724979", + "5534817540911273750657456222142677256882873311813581893871590176089715612985", + "1615881228089658726040568147025008122728572958650432110106281742560315865517", + "1471725164982594409495579793735446246197281099521356897919523009694047660159", + "1375309198078109412495220212570536673190607625762682203229827372752214429058", + "19114911117517497826908513598723039822664580418797141695087511229965144677908", + "9628666313906709051161166309431160628627430386029173286325286404453712266410", + "21852518218578549606473925058864730694915463701150591631085298334480610743316", + "12775432117186202301959614842766511797651599815903402927721712100175714308106", + "139892473068642488659633517109052420816080027074176062905422560867217142259", + "8678567564479314009205848092936065091488089332028298130303782323700697895584", + "11749646464324896227459490085151303579078783519261033148424203540751860385879", + "20522934943803615109303532925965718163549240564060985032796290524829499285217", + "20661244899066232726889114470941159662948096319289349895724712936883638757146", + "1712076112157842791409364964341168524175271666408017461435914200921357859979", + "5274198338007371549113715286886410970476178374473353058525495747031417868052", + "6737897812641394021946938592351495323837784050553060267876717564065727066209", + "7802413308864463219891658906834234180067201307743855789866460725804890591074", + "10598878996622948168711729113266592565050867869138946404948068606726933771770", + "8999501853368885436259381006393167420075229434053961224100936590306072807402", + "10154159140828416502096070052350440839365634698281866510618130671547713671046", + "10116420503162714112005525549243891887026278400783073704446798028762825422117", + "5545266571933610687233921232979606259360579780771113897229483385986421780729", + "21233107093610116862049125654360754386798111684938073821049243264439651570366", + "5307392033140435516838295705521564813869712246929667484768640666687057034707", + "21375317482759736213193607973501605926935171024163842355374965533706641104549", + "2517892809920213533018018674089754443879541674948230773132283920676903837393", + "14360345633113115894388501084706102426582517876835778852281477705852716869669", + "17053269301717416242405268053150416723822210193991005718303172171427452536837", + "9906602428995106334942925928993621430906117671319208771657883136890126991982", + "10354603022009709342018106446249264303223237761462844795940043835225457441783", + "13398916116699661698644750814188836272580610770712272177556442659081018605804", + "3191149493139822128538617654520106298782669019011287540692938944153323592958", + "4691984423256762483396977170887219469164634656601998705889064679728271695271", + "17844101314007938193168524989091446035911779338131517299817551328197378135054", + "635635940269936042377013194809642013073936660346940411744079076043939544740", + "12630888356903717277892931534313436641457206712723665520324533786104375264085", + "14140466574121870700874387789856251566070511990708575066948924661369491559256", + "20370174501238434846223710470633284656345430614321812270231526837854520663574", + "654339196866659831266130941576738975707930915283825590200406138066808189370", + "5107706503321722709363385752813500904785775244074262870879244969961234309572", + "12198789333458214522406820255828653820578540569170284513887146039452722146485", + "16249136895399135618027043741098607972773831911496869243661084436243711109565", + "11074204104909151859533339603597929732173550047640253831218390211736882449440", + "17207343273400097590016935219508528858538698779767314862863101225959250875891", + "21262587236682681589242692923329018584317630804742733118429592061667487058638", + "2280753183511690306986430331340197673251265546818209861935234085004534230414", + "10254003274920664842497725816382563578440196723429688051808776569200020879745", + "7759959068226022198572347902743272598191759849179433231578496544131111538092", + "14214316923200364820492127575076874888948881174491573576707716667988807435892", + "9095544195644789922175839073929462149959586189940443682544660563790242551416", + "12649782796197868227327830841571149621604197483943737926454728454326532192518", + "16667983042241619901264223140344714132852698906756725392221839503187142280785", + "18383173644675687530390651274503384113459403614974472825953064896216388971884", + "14628141534803375030737634780152921077373561843078668533631869027351905379871", + "4561456211241649459019745200365185624320798675863426759321227045069329801664", + "12289778497980320566229781933786841623485008232338420865642173363101571189872", + "11975067175623680843959076988032062157059134808170430074549557650028254491562", + "13608090049838182253377471459358669610089588259298499702848843266957511619603", + "18788677463812827554544269966162484344784391485047475243938219549074331613206", + "4881667965195655156201239071358064948072146968570883219541497388280721871638", + "16809375763554448903183355905513828131657823301396908506126469252462160193891", + "11654980193951434743713680917141406309927211470940308818720103124789012440740", + "5948986090649283108120495678646398398833638108013243775975352725637369743753", + "13726437662355203524944601292802877111764435687388166013301616156301223567122", + "17457684154769676997584569814978347304006793119360850469355899127743508915640", + "12768218426713967613672155360932690915682228245638743313771591055379281067565", + "18615157783057763780308448635283319685644271696762198401466573335150909781420", + "17036103965935103170115214353570299052411478859579659720326549902160146217969", + "7150547909167136034355368387927463942994048322819447869013206336674786486676", + "2719491185384365067577935615529406253538979948934035375021293885648964670289", + "855254098406697810192507782360318218871612459371212156821698546331701832542", + "17895542168549626634871327801987932137768300191314912757298899767762396172426", + "1291731410872228901975204398582554998148747251553901848273154130903421546804", + "11405841699040163552814729751623598889450140001218648787184675782417123019196", + "20354628821067577915648505449000078769730992376974982139779446148223962828730", + "10728669080369994464716817080074001337835696213713101955141340296929303809038", + "12274798389677182426524706446934567986140214102647161938159083665963012760572", + "9739537323825422719175243872981907235223292084323462340852187679763167385510", + "6755543715589769777862111458854566169790920787355600259792850662088606657716", + "12126305553295538434422174339664597983843351746744739132557070380077267264590", + "21398878068159838390422213444802849205194012142590812651530393856342428295355", + "2774987220129009778448086748836270418387857350731020745311729965596748575420", + "12913355749231079157637607439722332211156795881932799993926379679617800720875", + "14002442102691266344434178456827064608589741346471232083579257521903268988567", + "3222000382376546717389770889292702303294866053055569943089969635516575396692", + "3351662579522271904655802780809448930926900026265684873057471441126697202347", + "8791346592452796050710862947776730913908702488104309880248248201823569029744", + "9103312554290751080966931020955359921020213554904162168782078094097630022273", + "11400762474859869669799163954742952133400547669811496311736883651700759825519", + "21705862854411927719091657128107442151318579935925212397760983799549487960024", + "43293469326476059594440269130071583321324378720711508957751360314337673988", + "15189563636069530033236842376689049504908622054060814965474910283072587672143", + "8828581874201341688220445093730125081012615712886123840297097551587278948881", + "4848334665131642773713411076824550175891079883511516252808850475348208758729", + "12614662329834759430739626588497950629642362637723265950380896878486239042155", + "14266355110863104530316810105072189601641436180167942829728212140901379263956", + "17294822327168915058983104150822364346325840621309612804535067234675456850670", + "455077676048323303580854786776522812365753723694705688462762996845811407009", + "1883008531326217838820507370543781882290544271112198177704053499351851681273", + "4529982458238957976485223202768823175919650810452913863593242825418350872543", + "2955110035783314707155321084983433537364088072013879095266124577362993635626", + "12967684942790110900749491528799008728014372120122130310632754743394775825471", + "2505175694719163834796124853767853797404065196427012487113935936321224863546", + "3664644243909527501109080877083112285282350623935581596506736195569817810680", + "13149615309511991949247749473495035486060198385636687198656459619774102038819", + "11675634552285986901460163850174089221624080337542386824203554725353862698973", + "13792241875469760333807839408609766753472484847219134966123237707758891089388", + "10227619387285566606296112062328719372414665296090743089679008143127205545123", + "12205580044090621048077686897527020579927082420674484835775119696613313405371", + "15208177648579495968812696435767989756568450150931633443711377393141060828911", + "6203604398339912597796330237774861234098507297133105016255969208311447220376", + "8763991852009928642943035844463232737815423121200913107779495834216057423172", + "94997075732443240393502290740081268967228130793200255689370554790238240979", + "5269706528648934838705302424114829386876854870088873864481541735257304941866", + "16262872163060208420029150392453401749302720607531142669546071916932112668551", + "8143677473154806611855981628530143157024134934286519271401846470427527147543", + "11345763412284980808950171535310000445785575947246043879446971501610507015402", + "11334003190684962190461352102674801284421167648666972792173808801060633658405", + "16679481501466111466382494296272414977838924060754574747550155015005991797168", + "8717276046214261706367755700328685033217888501922395351508483646143935055357", + "7961818553714372394804939036958306706260485011393197807672306728909086465660", + "11525513262393719593247460022637862437588876074380005892794471847411833011017", + "606475753731577839300896422047168640216288859417610094202862133247546805011", + "16216814510391154599441870283663624434960433363418315765904453229709017881340", + "15952802892860522124812654660125132147349553268606042022775941410073735145502", + "21186206422036180717988803903908106965745591204944021637150186904241796046981", + "6944713991333056327587649834988524981544213700413795245346955488518554424877", + "10185921515443194095530439914620341794217076478391514698779175769548747359464", + "2855919726997577698604215361496800379220625688194012864111223639042676660976", + "10433229026112136773123800168383892031427061365180473556460194903407247351339", + "19427072191035469870347195569940358526740232693667547123354147821192789102650", + "15644214414239800285411872105206002044880495869535621299007907341206661859610", + "17127893436675976263942308327239908450163069123121279064123261885014993455970", + "14398850115453023364458586202624524741971410970483408578015632196929131043640", + "2352925542671141920909613532344506652984644250240272091365991738093178607788", + "10172679680316429884824619312723045840067903978738893283037233244389430249509", + "5772194565812391639885669321239603226420464592665765672957012371288977540856", + "1472565977275775489403659554782408548523807638115405629626295474159727078930", + "13025952383827165156872004962772766979272981810832459552230024272976389350529", + "17564758020035152957739819749712385631015761969283204715352893305611222727560", + "16405514590762165467156068648660873304776064039873164250553927264160414855875", + "3690038285204558326066250230248548873947936562327070117434442040765096220855", + "17531140782998595396669833094850381400841695523035934903128529012616296113949", + "13168227885444297954910232183764567700890648537512256626187184942939569199780", + "18839532764289221356950914594613087164434882227921649252297932780104554074257", + "15690093187279544523035828189537219904387587938956853550130942856247262425989", + "4880718242480815050016604653617276367751146942554754727539176934739417585000", + "5767740184065294852679113060036925102298292735253600173647375101014669432601", + "15274885987576180935369267696345371924274924872703997373047266442038483500100", + "3761934589481780435501384301483991135823312027596840500386086136996196777919", + "17076314579416028845718050745024649043011795764818118471181221546277962595385", + "15977291426665432194805519962451891500931039499992781917651419845757747435870", + "16614058019242709692964725060926415535596693985378737640811775269245183858531", + "1462290731020299561638622134991867491216642860791478796650694102212515942203", + "15285513431606451603488599544624561225569394909979737124945690710031449859251", + "2108108609418057784389651014871434275919186190456064517027979476451544519949", + "20785453923508177251995968212118965193411372702846000862603422090322205734041", + "10673883530097564269607463521683039178512337022363698173454334902283390457863", + "5454676180617583613153450533396644120109614173104204009158828769649771925347", + "2308424025465899393970422846699273218513861797562089060060302466408498727592", + "7521209677407171946300925747807233725946342430543358547121236461545495788103", + "20573024021944297233730031260403312250074182051596062256738574515403295322803", + "9021049816696497696749267473705619787233696328020950183323376943545740004437", + "1865524799085825018345305851095200435959748376626055576269783687778950437080", + "4246459257342056987998012962024687622955192847494871592608632692951161262129", + "19427245695591302750338395658196139112041609989862338102918570832807123117503", + "21526088318229932910068935959652342185575362039375447361171773752278498069664", + "16191911454644420751852228901282854304136684923356871310294001321086062307024", + "19158667047991453406718020435447139785846629820299132383267410641682384370576", + "17700355947456307421977232728703295781949761612179494776757369350093380226828", + "4397993077875324081650432554749300545148338322818494126385494799541152486594", + "7333345984549245920976934899658584162392463672999208699449239323807521633803", + "16152786000399924760932165522677937364378936868710087711558780050692283598645", + "11094138063712503930108269043784479707229515809275605844595768164840752472377", + "1142389644011176261530925136868504263430131536560167284105696375014595703389", + "7947253178759456244011070491140902256859556283134055577001208685178146652802", + "10134714213573683528928794197545260748403530346308318902760067810116839777206", + "10883490621674448000789965625707254871804535943755669299023415555830424281655", + "3066669045698349285650257964282463204141692000014900401186330770537030238642", + "20081606580658665084706560391544166403289461596409550084066896490552960642479", + "6155695406737593769799569079058291297835886186017961489006277167996716002247", + "8515542419918302650566740947332213674125125387478669670818010011334680546574", + "20110138544602147391149732696810223660265845787019234225223667638537351747051", + "10742562600839811890186721654855708402836531506887842079602293928208078373859", + "1525909842404376057305890458989201366856740974115647536551418424527131666169", + "9234236770964972467234889051483942687447344616202849085905582739078803045160", + "2606008597707158849245186414604531348516676367660138989733829835914698874012", + "11796760152309688912186437926169763667717914107947289133346750725444306914631", + "3851377590989618761627509080069107348568977801140383151662774695134986557597", + "3154796336225549288800236024241376487736097402096695364582935878596928093781", + "5510420220665221034838403251084456079592641926247054056939582862556776533398", + "16879696361470925506825934570612427394067380616879319126544582610342257894977", + "17284649816450637986813517327310560148892948427878914253815654865007623581799", + "2833030338755501226260678429168722114253235114087325082893557705288230185302", + "7251727070132476220556183457711849452579027647540936257172964240637390843337", + "9575600794079237337218029036087316899348403790684983148717343996829930177678", + "5979306342004680208572077566967420789575741134560343288662733429960668391430", + "6933647198431187357226909706624729057428619440859131169201765838043283476077", + "19168763196217781731628598897969332495895458624888700544934409934147951462602", + "19829437720109810470479999873902618673477593710269745617035524777507262876935", + "10801527657674630131387061424571233632050383122132208702068470808513632048030", + "3324631869609728132956796851449123815871495758162118183753705724979320742705", + "15660020223439851550062020388305149722004313049334322631321250103301499692604", + "5967221174170233933880215190156392465136752773253659731223749128915793467895", + "11552412840249358443126681313794466948899653896063684296070673264241626555196", + "18888906666917921069717332466525186303442592625253328171173131193932302764004", + "9002714106167484391528827546180572105064179104525774089102236612700713696717", + "11048302793662652213631623254022096575352405761944396370134943300004028917865", + "16407259962762436968310192538354523615684343650696199890141991953040162326636", + "2164382359471710099213275616027528225843146809226250465653585796261822737346", + "10534211142437421383941598776341383955315039281979396571221999789915575101599", + "10666069653734320813631520107249402109728041265475244772290972049841823847727", + "1065893272480854115563003062650162503958098706206084024581187831004515125777", + "7996693710845330472615496754914137367924796497947601638820266498225398515015", + "779460584637732468426955849206233546264346430125102128427414524469939157403", + "18123487244613769854380966736011971128129435530397043581264858565849669710522", + "16483639590865705054952634993109499660754781472434181022666579985294889582777", + "15847717171578788545161470441065692492419364914649476971042627117577578420712", + "20212509548766945890162316166677458350544092615956421310024681889193656903241", + "11915838540527285091679839305488591026042934314354878896592571753630253407873", + "1911170159637126384084881836969666801716554202345435461162520643252230842951", + "2519681707616189243873692429706701363981726227724944939887394039132311807155", + "10525548620009931418869190498282964825273460634626042574365806552478535675090", + "1007287689974936217568163398662729361983046876939574893360458678319961439943", + "8918601076290071318953673276836220960249911431394510238963515695083601259416", + "1730552670090087588255812224149698933189694835321291448382024953001539943933", + "2692212389857059051251821082045515561682372012597270034725442717100828072430", + "5182752960118030069130081328243349382982053565156074602369672154634481788415", + "4186223293158399083027342405464955373429347225209836842209182753945871255191", + "20698226478040525601636369286446332773903307913544069889209490555501069209140", + "7848961029873906562639009619165977234892385836769337804546327846501965814365", + "13921935366749820642106107225856381492084238464963488385755265898574906919842", + "16615913254044390064369275838835406299949293202833109553557777908673881552518", + "17884323890135880903838623664692905800576770771455839982202688346472867240539", + "7671240599961467753478651569648667266853727017714987691902517051845809028276", + "20540170969725852651721054123169504183251616229771312133024479630289328600435", + "10885911618876068300178014171685162848957603467763239389113505729594133953822", + "1821956738503711086168534921235313501143676686594517809385967874500584768914", + "13900019517803309945097308036151373598859036005433194049333364013307418921490", + "5611521340578197244418404931199594069340846248086844299279812110836336410894", + "3871676825880602831129014665958446397148564007925285835033897270539554583982", + "8660883522091722908446182204212531338997991855689061026827047565345925404852", + "21369377758054514487929500216341215576252815582773920801000959327560535036910", + "2412441365534353741053138780929948381707801794421791967644299920632399699760", + "3962365750665624098182798369136001622041855947680873409890054621414139629589", + "15001230629104674518532645948322038846835064889071294141298776340346988584355", + "14880674002301694876681052915629907300219131310128131182663986425102259721980", + "1824158054562585980316309768551123828629842232225429989383412402628330419987", + "2859240361399565691265380107352020662064288346296545444794991049234114013603", + "5166447910779952920543762328108096228333459621541947567522578212254733957716", + "1007490453560275100906582245944853446313521002614529198832736321283620962455", + "12357031909288499920427512282658173574064133416008366625033457013843709684703", + "4908601693798278768903637729333835430381717019653632816739154645536641464365", + "3707521788266753982537350852704241176639571081938875735935799519005785641932", + "843648473424733414090549470297108007717585086811320449394192229155836735429", + "15745469357122732280411707850429686485179261034785562466267026969795211925342", + "10805521614324416411410037641243182724170403739698507241460822321812492198235", + "12065996971764501469604703952781437881524721789450462435182323617647626062291", + "18470487586372818033539023969236693307855263683332928699228943202064060965843", + "9678881733477238994400069917737562227773718359505757479334487914298656155782", + "14188770590313091787681039051598250350716760439974403531322107017294575035366", + "1689506610383677575502055715917181866056070036146379850885318902788859831848", + "7506643906911078844726412866492372822643011138706243954480387034094577464841", + "8878900588521598109866546176968107824348718386295453778616479348498221694856", + "6870283245627392817090238076492510507322368840526195161203457308149059064709", + "13770891113056770539767147807436112954402870897635701688432832537357791153049", + "8780360192411651104527843471573635887257900701816701590232913021169255451999", + "16171874311798197525909736376097249943669070404511356154621097034937309906406", + "5735048971584791925371366175024708991668126697294479025115320761565490442773", + "13229825087263355390945471875664433936256658682181329545626347347763439801377", + "7075776235062840728475772028477434335481293337646194082436681309306082067951", + "3621624535897102185304108550400513064448572525424419762329290603569136345699", + "8909048763816678806291702062491546272181098732106818908949274412295033032278", + "5679617488269393681126385387791795896201443046828191787132461584904242222704", + "10105279386430545635207898937992374339634464824905552041741267814807859103503", + "1875089455725008938828188584567435691926878726057441578850433616115151436992", + "7477746898926143788312536189451854889707733370802231032871868774692083118085", + "16386910598448767875426039948412876247096832715449382492730559004257126956048", + "6033432876275593677037331179852069653085950234927263672572175689211500790655", + "791047936106933006999775822964245334290371384592876255418502363688874468612", + "3694863804142244539430013086697918876101028434198177049748051320963196192691", + "13376682105243214738309576815193178135837123827716063891638620885853287922296", + "13805679067029770984721773402288418271927678860935425166689344094492548637057", + "17136756160106085935819446871311843510549583818138636089816199715569134828084", + "8109923439508142364330425377154151984256104223553589804214354752109994937475", + "11286249512402084538299269911568404171399278286810916548813396237061620605376", + "2584359677745194465235893977254941998996461095474372764450843406506578038395", + "416048929518775256195106483480946138344969950953407172345234478269849793039", + "13382468529403508085121262401866099849753365548098731797553497976873204205709", + "18439376867491626480684697800985907843592103465829293677253579863338320195923", + "17849262151524731521717998935547978553691621192854239431428238124396600612632", + "14944765584636478787586231666077419063063746476683640145827104348311750508175", + "5770158920816863002535760768793204546036568907423666489027939717423021627834", + "8964766646616906071571735802649575322546984330618572612076303377141821583837", + "12741361066585979303854420163873489016934487106922559130204774618881492938249", + "17155650977068989655844853330647332708031817408933941319367040661444377002549", + "15853135222927269109853709968587618568449580274775781838704992776508260190624", + "18643405831130205120436044797258461126994691116505008303058249039104682298143", + "18381699905134802759607923737176411134148483921733890751508148644565049938661", + "20771413818150322305462626795715653983446198751749952090107489229813229842550", + "6565230743597462418756949526565014729968376635326046194605417268756666319845", + "7773589221172310936780704579925742277511016906417542067089964629576305572209", + "14322739515259154048217383149571029180760938501429981700631245079741667837826", + "2211777926093208827662641428669122029599076421656786665814449320380720581777", + "11959359909854207341226535525210590494408522984553921513181278512110987087969", + "15631964544474412103208297614910610111786652867610037534463100143218625118186", + "6469947677147265061709088012775208497425320831040679910475868641704170242154", + "14273192286218513903657400373354426033843730885130815917604222619132646117025", + "1642305946822726119533692746690241550779067996073465721872854402290979482744", + "12434472654594642340204970901697561562492434882039006954954548364905225683590", + "18258333676501263903599077497799178704676070138517903780843551776313851126197", + "3154393734777301102615783657097778679162307608952237328943250741895135803910", + "21442924273325571860480847088112128477994226721014369494483203254968684948447", + "12633492209679682779165226815843032818326050497846354378961630197925565487104", + "5676035885913185017175294353150288993325590895201150557890586619719458353554", + "7971989338965840486933559372839713095797443968865735128939127037392334228821", + "21734085994605079916025200907658739534755548178328895704833631044593482792710", + "2240615781815075893018901266381250882106533308854256044823388761533658366337", + "19418757086351270137870941178188715468785231202435740939860626745964359442005", + "17658978545567285097910442499706845586224912649469751675828983048696346031860", + "5266889563561183172939683250833485521316204021724495164611029326138684723583", + "11128996685041402949333841527417312168812141699419947558499636572258705639448", + "4876070090528783965375514438749842173086453529590096369168455769565070437109", + "21181864929467364713132566956143162901336986129207766576689052262132856884478", + "6923705508410326350945166370499325965219890886201185955752583121521122421736", + "21369826512764035509040463750392604795868027299873193291279213169276615858803", + "4704097774288345414783119239472343512761071550401447208590340029300816575296", + "19335571041256357691347835994830129551703141581491004773597606130380555930148", + "13594634273515260829141229000646270213542265375428591690952060475706589483636", + "9015254066149037983117828022107604427546915195306105494160093361353622246415", + "4212072016320343773172520900223699632828574585381041109390033407447488634385", + "1102272748190005338904701274717935307889530536456982005034282115032583335111", + "2736300324710728232038909644774832551915915663932530690557461126955645530086", + "4835822801818378290852301048163831283974282641105089345434084063764482095069", + "8984658187927452678459930452346646248663512083082894198317485712426204609811", + "16633394668571656740012069555016467267297836103775110968049070854163114237249", + "19001311544890254637467757524866604779430904938238046630395635640108752440416", + "1519708912837962563938791348422981399413816048437970967955664087668434079252", + "21331841844372791543710397499630585987940452814579176990050363535517182938392", + "8907423080053260966677751803467685389883909962381980865910698188903614425511", + "20461083176034684313938738010980183835826228331514122093950995340802162488751", + "5841016603634386755712428070725428370463826644379529834480138063613116133165", + "6169966163271811065481708286709332934104602048421028222790926506913444959185", + "11123503881380576416779399092503011764979780788355198614717104650873109848686", + "5910862578643213547409014086432565110080048906429291885019036113399453987536", + "15326247930625028665035962093121096584742207235393215425729927190450227004180", + "11869108106148533163877422279522558694860624980410176225979111384418155447592", + "11642189959177792725300751489041811935498998846917246538427709581655066866054", + "17383982459896791073091103411713034950019457760840905433100761135071197717377", + "12914884881288305014413720371780941499071473169305332026567402160980899728234", + "1208570539962036907751277903184876797538221568150857585830629441131315144451", + "2323312703274674937703540014228631818729280611690694743543061204714949346767", + "17526158529185414889134597474769916490357130956125485429641429836800727655323", + "16037781653504828212828867735133494813590828457250361954137565662868257318996", + "5407222038113928707955890035984954296613370389143420455278606330416003035740", + "6601323218218927237946555844476405370566012808107313139506360075146521702852", + "21534867504549849931394770956914633425223988570769925897030241609788158519056", + "11391084204734238133980784274225569005339670690396227409155789097373857915450", + "19888681657658973285687297761078939800531741094128408699392512189997402853670", + "5332577406232753436405602237019361733171667669604896195130680826397119398314", + "9059600173937645065621009092166260440988612068018047518892978276246308722168", + "5301647598491778367767843695092267888185214608095464352349739315757388259345", + "15071875841892141860455823800612444188659593796102096590428526661356131692597", + "435778089283152858387915635050172265804266241934673566488879021420875384052", + "7253178577349028822394834490127746885621571949621301778647260365262978601526", + "1165301643600280009322317413038719889346104283514223548696059636052018656756", + "19642265897347119192967952847445594557926149874981543320111550169192389374838", + "18546070171142820328487316603855788669722411491547154393382552167546945234264", + "7547722208697813989490512139624144757215998986985181672151192221427497361833", + "21765466939205480830726051696775103538365853268148356693813986094780619132689", + "18066916718526031105430041386116904278122614509807635157495047212689329422097", + "5567247965934318360602471432895130358745239227464728512128895794990091560111", + "5268155242325913085615961568740884974081158441192412337454790453319219641639", + "15275184776514682919662155241139211655693258637032715569152004434925162363584", + "2179932316974455074499483491372661376888522799119184614149917286749483028849", + "4621405833740121725678441855520519041228014222881228746009997774516764304847", + "18479339496682302897017710580780845640172065272400836860950352488372424120096", + "18557033214894447033261016367420154444088029564584596463030003672186270737859", + "17200647521217215683722635843299601233863161230648748208816378327209201596867", + "2688200399163263049122461117289599907708945179806531635658550456745433215543", + "17415923022624960613510570384321832458760537169605919976471719634183381965151", + "8535568676654346647569376193583594529721160524940659464514765031328360321359", + "2988350233499987577118772810582267364198360724494195915351933486792072227259", + "6210620559937378902878629998722853418159056595764204463986805098114518009318", + "18310997638100731876764014221687199913435941820864752235028122857262977059320", + "13808863093029019329144013239638801163784179422135484562563156294580677444841", + "12914098780625672320372746314998075565042263956380764233047047668841824625393", + "3305953095296069725576430940963322680842934544212876613078125492458854044556", + "17822002370183286453254419050088898676184956527990121400547957986510775899261", + "14649614548507754711891632411080554775651572143141206447218484052001553765684", + "8109105787614676314388565737575005920261787167569229710081822989465469152070", + "10883787415840547710621559198296269932318487849486120162467244238276174398529", + "19330421887539219495728995383446553835046303504116353064676615752269857951508", + "10124601385542856860656799235536724683363368315551234368605365576161456958605", + "12586681054057195636996904714881904902720157016325364273875514276164279959735", + "3757165144866249284026269096089043031459271594379869902321741804365836799544", + "462405354647627586345675602760959074379157140949064478801734872040710235207", + "1920260561025181767428737283255569518557618670101985233779064285550376374001", + "16427781514757709627041602025461703818581117100125480080881962557048804215419", + "11285710669637766333985664845741699850953316015510407645702772350620723934913", + "12651159368793078896654108663982020308442449053255003548814357252262150375808", + "5416603170144910655254279621683623582654125103494176617805338836184837812634", + "11735378404903665808621855768545179642393017572035737886573368447383433091210", + "12201557541429330882554855185927797569372240536806738921957792139394552229540", + "12315234857861194987612137097457466405047598720463755079786381945885951345726", + ], + vec![ + "3312280834382673867321630616941760639861515464094877629805120494360011490649", + "2977163727414618213643725802224710174200189681501907689708278449275625624600", + "17077799405481633745546679084486353025600250694578521370656758513725453934742", + "16210306379465933080277173890273457210762404430253284947889895341785601089390", + "12306944281360832043572721821716739944034354411349456264300159795863030116042", + "18510116198433364516004461541873904955505055486081639325191415467980353992665", + "20171004681243290383397478639749648403640483231061520437292129889020927831789", + "14216817867363924461443287436236130110420963767734530602158091056747850914504", + "1744244489393376249430799522637230427855625055124494576876957852023791759325", + "7129585843913921821110812028399979173266826966429993304814409727296136874103", + "13988404968409685403326663187671698975733642730286219911002602918437679901860", + "16920638563061193407835052036305459051417920006020130846290964059193276218943", + "13427470979587753937642822251845898994765547507421045262408080469011197338416", + "4951343674183369875263494313821909834781608226183187917185914650592996842297", + "8735432128376864913532575297691608527208524295369583136876379560735670033436", + "11506191123509320764309490571835590914265043835723578099434891464809664894670", + "11860937155601787389575216601739962955686948385964703064981923542694893487713", + "10828014814384016644406621862814561467981545748254521286078083584574739936124", + "4776443388323724363690349417451836132533385226194261923508005690866227183177", + "16639991477904781874568583121789695884424899367435699700192357030587346907362", + "63646460855616590932366082663720069120195784636826940928051354727568777173", + "13872046592464170980392921000435473279488582870563366687909512908597101541579", + "2903974073963148433036990643522953333905364588702098342158750794553468542208", + "13972003294927197976860685316247379324920372226280483226377669417062686947906", + "13868504415208879955736997036981136359599594082926486546672963310629609974499", + "8628454286960990606041697926325623221475249983044062173729208432417417750989", + "11883151436851199698252725037318235080760967011947670552161788839027156740653", + "12343286145222861673187914724623142745362406729785896500578210646320713733295", + "13240444180513188371213070455300718988708567038226911680564203350475184135088", + "17225520781620743741263824011599257737446498734177523099795883619924078366351", + "19655364901125310778629982245392767297984820167114789563931170716695750865678", + "10695212283696096281132213692300627346215324066996398339089365835910730561368", + "17455827037964560948521638828961298975187156274841334841074216120311558804710", + "4382628454630801450077593442523632674983545561122254229775876033334437860489", + "2989679808908579687765205532943224072820070594304724633625888454150084631070", + "11805110513334566809098991762079653200819786354513225301120697798603509678793", + "11155601993809199490094826448585668454159517005968097566996288487138255635079", + "20815808565222781796761554019974947099963702926722486604443826341123930622896", + "13761986205307878615460321377264044874010177269812603883540272922422883198979", + "4128370443753246025606114169149035926146394950057754901868026654335917771101", + "9124459754124711043815747649012164723935008821275709951889811488049411892152", + "9090302853448501945809598864330384875455576758214379286451409039855851539841", + "2611158043123761410817152601927516372222739024190920897371539155273224585905", + "7810155525349201315441227323507184944737106980192978514457375337581213081055", + "15249792920950763850993517571920601821568311809174912509031437118050063777525", + "9921562618684201533699293485620188871082795988970107962425978745591461148033", + "5414565587238798987874533039507833069864773781235217517734130524969939419113", + "11085088558016600803149927568829483866020077054827488081829062938808919799801", + "14625818170426402577283649455001357862456467374537021301451880577607106726350", + "11633423263664104506250995123678976351167359685182986641330218055115412525059", + "850899676511673590463501492472742017261347013078251845952824541653369171366", + "1151196396804070641219917031443763313740170846357000808196046482153806050391", + "14335865562369989392722415692597018596062508514718062574213639729550753584518", + "16165235837546690396792041022833296046736592940683337326949013823518030323769", + "6408098377682813619850142098164780329355428625834955152400958576961120931380", + "21423078154100258346688828020904418548554497199114189102725137286930868022538", + "21410217312460027364452766052404349950133415202888862471159726884511205456308", + "11096458349387432633781125315606380225216758142658673665437375204143306261827", + "8325016245207932555950059013310928498109578689420634828690059159861280125058", + "19120379171572846193451984132488836287003157955913585086569467602620121544962", + "15548527549295346334479152412121638073047322389003226521019746206475690857238", + "18510388922178653264949279980605433471616208226685385338922150015851847524587", + "10348792093961922144290405029634579505420677504732581441616360506905620826544", + "15620530873228503134208333316448182712901874887467615537478242394290577386453", + "20675095206674416295505702734315255961699360732886837937979451051773488542601", + "21623072135556656816074223163769126264910877148099315666172910436076676028248", + "20081866552983231525843337497912436927329172443916196026679813450860013966767", + "18951602909834406133815764463249536936478826139929746486734639774975812472830", + "2378298801465585253495854322066504889300467395616155363977621341822205588163", + "7488881447347091058309495011922138185162376888083687541108039236558708660027", + "7225960736862847948475548065508931552528126330579521291190635548005260333390", + "2970482373109443685421063487292183827150496377598629996362474558885993864176", + "21734396161383902760672518999845141937065773419899625136190973118533490737305", + "18986003927424880427453510819113519633513383085919786483726156674699889468820", + "9438591792749742425198760386567115998731905494024392289196006582112950891516", + "1973470346155075248881651300830631935042830364217214073906277058522882105581", + "13791817954605171888781711015587425735543149752618332811612012047724803625120", + "19907506629242812934309078271817109951335091294976452370249234742626462372763", + "7913144809845970358468253448033359382532594356254540499933138806226450398795", + "18786719915196826164016145948631708915544945593653634575689240810328854731069", + "6216910690440344513687669938632060553287695043116654216600911463719413604341", + "13963849909448408572632889978998938642084255012365277702934245702305832007005", + "15044749345099947962217476120263824356898437745229321420257770262954985403569", + "16364542436173489908162544844694842746117292595057249540926274681176755002520", + "18582462045999492294572047486602601352613220856614634390669602502489215736186", + "17106926147340558311732938581031578597532846523271406141897942990261560966411", + "21322204968737434192679865858477095835509790782891920152044718985713652659654", + "5180799590809942717590072710973007480225145652031514943521639316776384894144", + "17327427769240537767056224186269899694170666500703858813203303301835294225360", + "12795226231932513901983143961810913124288321956641191561823103283353203953207", + "21372571405151778511626450096485639101933984498294796899325401511071517993005", + "17332300051629640554924347563178488077648079908152291094969979591786473880576", + "15196566643676483159109284476812079407469293035334983717971092729005139246767", + "11231435533605861369104078150337976075098864909987541459896164149690464379912", + "2542242881481757350297627187544723135156543853134475677976341602496676452300", + "8414397814915895101029770303847330205837773505982623383796193602695811122514", + "20884120591077768210550361293303217187539921930869577755703150175746557517590", + "890887689926165781226591337399563217015154445631688026491595317246205069769", + "7911456647213080390137926613780820211986390960677915664339039845274033704843", + "8086506254215085366863905182926378819432294332631815038288539116592866850975", + "17073560037383161517623747613125771654997798954263090273202401066518468858416", + "7837662874931236958961077774488634261606966280628598881837875736120392183663", + "1858593536177571875355498014960393860692560832490490994119420708212532861823", + "2029815832061982114925482969267067531992443107339599745974909462412297854269", + "9638056659007828434670080110322180928336402529095853481855440674860675897358", + "12340090961747329883452841216385303705169146011720720105809463143491658552866", + "8529510825845236935037301291679257193837435275552609577171369718448324660013", + "4191225223853834143599110761318464286196261585898512902425773974473427757456", + "21023319679135760820789157052868478773370737850886002789313940767424256194356", + "2142526213326613906831098262446296658577569180284637200640763867788179991570", + "4585042017455545746057351957720948202590802829528217263388726369695890670411", + "10010708638531752335740573636867640657039858389864446260449096531856416238708", + "12350783923218275606957028867683130968505845112714635024839732952215498877130", + "11964414264447046767815837108295373861475122940092369903025175128013924386713", + "18615506936496648840383399989920850970951406181285583088268789582149764054418", + "14310480127014971068920522498055725465578544829224822580493909725079522528728", + "19209887743481507043830894286806384055543596834772181434542567255388724841969", + "9558553005299269735641084020216560749888705968385627813150807919487080187993", + "16359179198438658598155755638987769554841536772865629517841526255130745409879", + "13009386603860183254204895522650012288119732961876401784040013994677688723325", + "16165167702867558446013999607792716532235725666199142971707303433269257270111", + "9526255138490973975321568846030367381138407886665647949792126204681244064012", + "11173959697998471600463637717719289778917744248391051771189332133876606070906", + "8924806383303834750473706479936998674798746387089627706877519918521882863256", + "12086306023907343271920056592137012844278234154616893254064962297944646888123", + "20523426725749375175935122656912302902564898343946638208821839160006976692150", + "5207650950010803883388912523741229153368067016192964642079270816449299041225", + "1323145474328028634780912405048390126320417262412962953050466352509016682042", + "15985641921260285694054233699922160344414776687043687582488491933807565444789", + "13031771899737217701535545098380455304311851135903656399978477292561795000214", + "12687226379083740035799525440904048416465917656850081330730343990236073218003", + "5180214195408850700722613770944601169370584228844657891855699394648642429923", + "1934847650429153525882808430984088614158092322287601778579498068360011630130", + "13221691213669397834454903625729859574410480120034103769424898865047475910400", + "7358428584159841472154153892839275459119229492180053472830555381908577651936", + "10890590867941343184378544765218808644776443230231834463183835780142311216436", + "18106794932751537043075991633023418950145862470753313409722049187095789146702", + "20653121417027117499755994750040261936029675942959877982604976723194002882577", + "14917693547715740204091617501230563717468258023142717832164274356453628117609", + "12588115399854852983923905079011727575933343603816172388719899888494451203866", + "8737187804839661132607601320524529444256555649101505512380882940221377341037", + "20181178129036534248081631452735124104458169744675071995191727629040780050092", + "11847774883596070919125373409969812806188814542338127843683622869859801757028", + "11792352762436629909341171173296810156800556812208317414203786807634354583560", + "5039046929001603921830951923781308597413960825857893817665425268295870771062", + "12894400705986579725245788498699203221654445738734999525700614560206785491732", + "791109735149055364851227398853119460170782218988367975658618461497391330160", + "9962476109282060862882002156903460806939219308562214446822701651882476052460", + "1691961422009775486402337895262889415967004356867228407841177856000156435254", + "13137802539241815005932694907183711832661205367415214501122657136334369092290", + "14887252261014844625921142022701177088174316290502741584519763408145964517832", + "4710184813279024135486906523528903891606006797755655291767343324947631364837", + "3801875732725114698561125696836343357073399124260852478317754268545097096329", + "9198233237012512530002016044631468704269680036230256629514440524866699707396", + "19696310211066978020836317292330659233588020682368119069383469865122133603780", + "3893729283153055478198590025767324126269879907832064182575052081004216821718", + "17970322286541481482483545514302125656124172449128411566036569217140609597331", + "3173691464765770821621367532348960211199783691357143005417355252781889173280", + "2243542900289123996173306626857758207765925487218044091235839910321809834188", + "9813067765525696381929832954440764980538359181380263390331469145209686852182", + "7510903347384066721813722580189668539045635640361656120910145998846374499699", + "6798424040308056706713925899327404372610976624998869962003671422212921682045", + "13151104198292309578579089832681402880200764912297978086539824832412224275732", + "2808835590734075710953411057250272995919027932824027538775542577464926767888", + "12588027297759258617444062604210692398005597744782878589643963326768133974361", + "20852428689501418456174033597851660248293428726014401905473174242849532966301", + "21296758342898944987847487225137782473520558597036376704831839057822676021941", + "17749269130031982625604134600446353874123371420684509963863640790293640598822", + "12696062143950532198094822890688877675740383270827145944853466311043725527586", + "10234631072965977425954576972633890272283449053659669736631819751429358646105", + "15090656934406651728161310654614148547687401766770336347796859883364028754099", + "20297283938807526130287519089364625872430415084303524848853727877999978340129", + "4196012712072569404315829685460688625941300450108222372646584487742105064258", + "7048902004425912498834833883033670218379565315927717075817051690008258707008", + "10997088676112427186865690409423506551772833502185768664867716439827194601092", + "16660341545280246485425051709291678711850828822636537086457121822086705580853", + "7507040282824500274626435275567162035280839409294222666356976034789594111255", + "16582934771732736721752353176711248084060824111646755305570354937871610952840", + "8438441158635690733311342509710555256926785449251473129940736660330253698675", + "5997879363655967621652122271982901641685668225243330913415373444659935275798", + "377781155818540738714095913828188470350179572448699653767572496979822660266", + "21256042944489939677834126729197446597005830228623173527229465226360970832340", + "13462424045682641929202812263623136219335301688716109209361496824976128063539", + "16369985325316675741289392258637854017776166143141100299636544614904713590628", + "19352389303901189710313048379405187204819083083443266317372096723889889111665", + "10276552469336314142974101263431204498273961662600910736694134016860746072245", + "18939965576088516958025629296747895354615121399053610843001474455787438484084", + "16990956322664851054201977827659189601868639970054898553161570861097544812211", + "9274107214677498542007885890977699632511964198928324688228114708372115109190", + "19938102848869576488504727710754065647382136279175127752338128473551869244856", + "10947279549049485525804912961584261533182913140524900494781425525696586998449", + "17561385783620224695956276284426542193322408499898012489406312644517964425011", + "18549237431132768472559432396178388563409301393950605704070488347475233640622", + "4658944912168763919889884489643908669977608714692544551960581141528777169667", + "14358732577825715965736448712278683090180078342840106686279626250756225140484", + "12281258853616996819181958497578187729715864708853144319900642420503103456870", + "4069586715276899433893814672543891090785738315323966746105563017207510306537", + "15392338154382717986608388646339008932890583126043490476751054331156284554276", + "4517279215584833397018875849825808766631742728356316383241841280072723947253", + "11495036315995422771228762992950108862694073551665420165823433137577472792783", + "3488400840286926839516544735442894876148193865245875295688572119503866691461", + "4483680161275568275540790250446502401130629200290761781427443716038558729253", + "3942379126490099533582685851970104926928015397351808560877929535138811915511", + "11401623410099323944960285754389435394954200879740972352984594598244147798394", + "1704354226179051409424294551695786920602664449209459493691051505451583669264", + "6126483205301561395856828080510799275633402498512671992649940369928504550860", + "13606061849345999397793916269931170782757704442972401347887622528829626440142", + "15164492401059698496285802476110470458129619713288710918549993367398699891422", + "3351459252264231792942138342057542378418534651418845818443384064630601195925", + "2825813294993932054460723098369264495005871082754465730530978747926493034970", + "10630213694333677464069113775948160876773011480314305970870772509710784295967", + "17166444840808098079862920467594387590120730690478215313452389257289409232274", + "15584725536763467888732670366582920601197464509911998898151204840990765872853", + "3842723796922381697995350228115144219456021393259361082360164730224542750465", + "4831891679443026612628331848829793784542170442278947325598774522135713804734", + "7600866468317146506151393588648544489445105617254544624521183070936649742997", + "10583687645778325936823793169279337717905917984785560251868239070559362307278", + "6634607933824414124502549710741812867975263049249231353927669720791801705509", + "21200609344869125199593456019818101515444150712862469998882355110348140005358", + "14361714336789127058022203168794208348007919167174968797533361168719704534209", + "1575806469795254200103212820564180016945577757735332906646132503588215912546", + "10628306906313535336091114056786842183955113155572070406112143573768388478883", + "3089301712473516586340147971264840334080312453733093398291612940108596635146", + "8645795529068430110488497380845362622141451911891312096721911200350500642213", + "16022924422796267113820566797422451700895182144910797483992348492987850640540", + "21668559624091676943635408329170173151410363888407430983622558174006481336306", + "2072754212505196807037151376956574080111414803663052483852517767215769333105", + "344312312360359816789223515659978323664333965848417356296539814750513103748", + "8220091259162471818305840126401210949950597324344081712931466340258084434570", + "8081153019090920515448830088459971939645826679918559179389404338475619307845", + "21449241241855558649730447089457892378091011965030006823417837265982774602267", + "6067510299282418337933484892144351034696356612154920492037935939636907603847", + "21026143172839641048848076059364862575379425612028621103404211601411048352556", + "6070438567473697541030303531314185338530006003062193748841965554522662407077", + "8255130291759907832990229603685682560848952190335394603030993899908706198932", + "9546680581091867708464426246566048171085730057856647964775027268282058986619", + "19031748019605060953238957886441808197649034817040423262874632275713470713752", + "17096522586030137478189913833428299115382271406265963567569748424828047092166", + "14391874539708946761001075594593462740437739522325069415219274013650732876769", + "5044944855410335767979170189040984719402886766879289090117403978287180516155", + "12039442478120524220891851909305716836138223152615593874775855237995395028479", + "3523930243951081542915282337519662387190599423550808129910485998252637662407", + "21645562630446380089971004272761942543158290220498842219097308729146973947053", + "9635476273420949200636403482900193969961822409725076345852310152023632001652", + "20108896868320980092863545615065555118659548096203643467891646750271137801454", + "9185755445384903374596265352827852278482253313517817304360514098507824628136", + "15729448650969486701474329849747687235995473855623732466626603841221282908291", + "17997496197003273211403721001065741564292124821674411166555153239941325690779", + "1543484160386036195130212436149054066156454121707864502325718576708010327712", + "16363634132599571248968010449034783328746466576733841612125967259037812456762", + "11430550344567145066773020651025090506980499195413761807852670685184554749682", + "6562474642758509619875130343887830140546824045253242049540363976665708088792", + "3689788469446976140319903688077885060368720863836266384022598571957269060684", + "946161443553297471232017467760713330784613638346698353392670707850882897488", + "17775152994890017803033120420023910950366134526347402563464114996856742054838", + "18013595561755224808896799093133992096629438550898908281663802197342115179235", + "19550347733494203322271272376490635125389454301454207200256111665786140278650", + "12387591141491143807678990173849961323772837586376210707337202980616282598236", + "15615445216195972598868146032329101929277001754848917412471279643674750521844", + "11157377570334948360516367332475698893237579888172217677485190937247699033770", + "7130958205578403403951515578418204249480908544151977781217247531796937245530", + "13077463747714835214281685128657845926832593706922024570198457201391820941874", + "20874866618752897980777992983172936086725928829995747401713185587049763764007", + "9529341163966534350579350780474173060797076273832542721772111561732792505333", + "11142469391388881243303156644691476683457853027534314004453288809998298235798", + "15759641247899199119184149872340402267600476479959598970774176792522105838715", + "4932052011278518183097054145820640615211087138945458940865038794988474891006", + "10432003521315545222242540576886148188507417318972677351911763831484066879233", + "17415623007807480250676335953220588929877876653555913668269587494499596716638", + "6058502442301803313347169632367675883843035525640290470399543491756905404121", + "4937981332834016148179351587580087161307555148093009345111656135565068163315", + "4767276541447291442260238717093680167532207332378535289044385385412677713720", + "3479278227276561004751092786681066281912177752486503430342235086646969267132", + "7943278285140068849348170498689330975011840215116541312829451500334428180149", + "17789865444817191695636689430256327163274376252861234888599341795716694863906", + "11313788642745794682263060233193097297009786646629777858110154245289610960322", + "15451318802981646436556355654707114069777551322432702430595933898879175343955", + "7517270022604650172540378758621070031306040808100514057036893386092388842581", + "10009597627594120061689516706238257978394705225993629762944338270984243419952", + "16287228641302237661911798504390175297327206600486567815634358152959586818336", + "16488249714776419229986970659608164306511103745532215897060984940903927940510", + "13354728687549843942265910857129412843774195483459170542959107134210371522923", + "5514821690255816781301952402733589181643174815400146100135235253605240813486", + "5770103106430309708547950317514210165673407448643264387718101428086149468878", + "2694023365380190286709306630457152471177911482921639231487592222438630988204", + "2596360308486910596331175398746479488324950265788021808703834738076552537175", + "9039714509260386661160667890165090643713802650277924766536703740888044388658", + "9604908742305952316295642934650340892998619318487917447839433792965436657411", + "10397877232904834686750242142278095498016920001087513253065011131758634311960", + "9647356378465005298504489726754445992380752731297711041297431711301119823740", + "2901124847048448064485279495316677205686659456282057720583010224075223188929", + "19604711253175713682339631659824057587938105276478055043815802354580551412854", + "13814073762260094871340458282144499467492241477826265605381954643255652812563", + "19191277082146641271114112092268339387374938745710902056016346575725741574791", + "4351438127825195342433511764688522108908810411430938576079426214421798123584", + "13791103210113222833666019051739255444684344392875106989928046003279497788407", + "21004705702783423413965111534445421935934565517891538415275359891592731977145", + "2271618466337144497382665490697115072125990892802659816927722507215828359501", + "17558902460062424775395394774553055038697408789830072471787389990226026812332", + "19541727150539905151936633341362726755459275099586077305409909896489919664394", + "13692791587272861333747931194991249996571271400946738920492512367046518055252", + "16261859926552105019169611795692937520291616941485096436900016176047007140288", + "13364750885171681175943985569408970262762845797040643237076315743322239541667", + "13621972138767941419375174302334978784396954063748685093059444353200957635883", + "7816366958996751828525267034982378444982423551198678280151852851213963203655", + "5387588357364980194077356588147257085032575072648295273044945567343418708153", + "5561769804258805723102666784326040807434856561620360208220095378441903055863", + "2759015372384926293713393955452664141507032820282479368223024343744582995438", + "13981134543106614704319578938205751472742054796552637642168049339888724312989", + "7990257879146478669584929211133379459065259065980981194790047745364505663434", + "11876127927930413842997415069288338406075999315865409152476435081888707100248", + "16570551097531678234333612414250188586376313376162262758608423816369347322204", + "2912142129158840181609698148893520848427743435752721748118484524307819669362", + "21302711682094568025057587941584825132522581272692339045586256377620698610739", + "12312191496853376716581371884132892074646637957572159612619070514615509157537", + "6766172753918389200603997763713298721859536050788836585740520353915599111166", + "11495484070470791342676704007304510997655718568304345126153023374072812971624", + "20811664890504244597768955277493527673608205732118233091518542968150115526854", + "16063703627762167667966504135478113457485558849729490090362731172389730931393", + "14866560644094965611504947304610358591133796414154206860995591970456047599477", + "14070826318654672995642970624813758954945583937085129314124463556918282721543", + "2479865882631638665546581282869746245766113042059506929860680221143260292935", + "17398990555602339276684995684280302899074008602689308101178965669933564447317", + "608876042484390223586509032355843816374709085426455763238940304845396291392", + "19093816648588316664468783915406437520968219066632631005915358745999525844761", + "6752057404464894771427129594636749868828376343179986455821808045648379935245", + "19888182199106435309043037013966294783272588579928340631894231065863897158437", + "10082296017960550499269875102368612265371627577709879253045116718197037435449", + "14616172738414901831631177911088055616005574740810051337096702495520738285374", + "14075121030661423148825920501776601474873747801291899275268094618775991305078", + "186569155903133115291205664388893859453551519692185893083420327670792162388", + "21299949831814715974370318270705239305629929085336938013302553408219032200083", + "10073139629403946009284887013173459030563893496973388848686052378045073830551", + "1412198475257996126786641438141729921783447169582336707894995512036569315500", + "7779964092821851708726534513875342218194584080198381624983100710844846404634", + "948257338952437735532120031007610523249359469819114853137850805544224196883", + "21258332661476723168534084283213459804574003007208501208541743948207937371185", + "3571248067320885077052671052657329120832155265049255115581589211873377624342", + "18767668432875868101830472546043294158876614861521938962321471373462978174897", + "9300839292250613795491408219504842564421473000721822643979051375966405606193", + "7064697496603343927134791624768930499810256237088252983584462738613126284623", + "11853953981626198865163123682396255427116155876021473995289924391523536239496", + "19771876990095842377875081223218001588478929046615599374496234715810020326293", + "14316898881193279100266501073998404340884941240727243537292505454856307190130", + "14519359582636080510571261582400983934670011637905562203617314435861115398211", + "15526562931305845620715599917553561556373761549853248996847605985788604583130", + "13078262487107679022841832022599167182597313495640194703513299650288211974881", + "8245559318515118189428376002847388656528865763199194533482833563489439004385", + "14003329258302578586391126522614048791257224051921678844212914592624869865893", + "11725000422609501650997806599141176528384787601555518111375908215801780233121", + "16350891150329350826705554113837971740496662498788954571303936439413078899269", + "6411076187467760129645481080704474318810486795627076355267125729971512535475", + "21018151777353913573383620107187764987866574825379316352340980146357643078382", + "11358423056150266238825561031091840555431271536659827607676154506546242135862", + "19065833030377987569441381994102534825367123386452612836837050555888073644388", + "2562667974917478689245733861669928078902565222389031120733094553006681886960", + "3471326938285931978123873023764646019622642761349433536231294291602304868485", + "2563009390241284210001442885151389460822558817932742264596703331331069807625", + "1840397005312580276560341795534676176103474806443827954038672349702326279641", + "13608853165319143662474434916965520937512197511217746962619929048696566631710", + "19629513285164329969551640449451527909298649847319347893901982383162686335860", + "15394390010333989214892827255905093646577605209323130947826658910240751517983", + "12111906652703403073758441298171362667165880553934054594322507856217299245492", + "4297972575899320549167090598678621826992022863628750628394635867928789323371", + "13452780308396674980210210234355016032880538147426066947029982271570560372078", + "2831837563806484576977992168295535809035697292555489411927347217736327891352", + "16435334356674630023459784576727565801947528558756855054741604645713144334059", + "4127342592978010203327455190780821692230702238156658795505993209368069797198", + "19169399182658468533946629204100516992531108319585640665183465573285725904462", + "8598406387986750884545663645357594697293280337319305106433909682884489291980", + "13371924317816745712309163118606793190008424593275425616115063429517298127531", + "6966840677637301630181597160079353321163372268840965853806074036299182143344", + "7360050884120437815429010939441335996325758450523147733433611465713273074289", + "18472779235592140583651215638681270421642809888489121199352426980884551699243", + "20418315222771285674269327640703205319629639584244730201946908647328012868945", + "17026399731940643956418206353642733600139323525975091345342870617418039094945", + "12615211028716399762155462346481728092959316603121559521948867446476882144221", + "12396056279980752806946158389419170236239219009894918041607073720841998512650", + "3020267183116758520311575446823726815087071183512473845404855371056317502914", + "4656542918173262538192266136796850668036544742787442489947994092170369122585", + "6651580153776746866797134628474708113133308603326248742448594405127096716435", + "11937440848975251505322944134185172341897441221500443657141975704868428110206", + "1361826966800566560222081321267933925488529241685130208478269338961124266689", + "19943953771229014728170188452413560878330164558859793245021220185499985258316", + "5000555778712004519940673290591853777960346285299451454158729230859752281548", + "8421588432304272431559534311544652626307929129739056740355326524785204863675", + "20295164315900629557422352618552527295246432971816033569783057482727719683327", + "19373368537162638225474243050103347264636555313351270279300938524044041811781", + "19301584842175411162376576546656332386749822306022512981007234449440059593206", + "10803063363791701506227503212696578672701333662552932509544627248354076467851", + "21190447586310863247879892773912245039992873717104751727825265558975676297878", + "10001943442280168315414950100438358800275893831224620600570013850341287546634", + "11419108205602584425734602189435177828356990665164795815514509894518490834107", + "9176365528060199110731574560388345526295591893454204513780413140739307927521", + "14645264015971411259428809172021065485340465742768211283864072707152051283922", + "2059680394752128527783641175137415159902594391639901766513696812385555753758", + "1362210878544210374207986445190412893419873862912439530157828224644264948744", + "1767020623225215375042202191031932704135774649037849280381750341452687445659", + "12814227243430147774278313161816717185894261558098935373927981841389635793984", + "3650392274313221017884542662769899210301363377135174682150190146413571526895", + "8605030053804448166307797789010404548793085578661466947278557642849458591843", + "16243873345435203695859375103717652101719490281058055690129195139240095336348", + "18253688126813406708458581768662237883226849901952565733241285746065046225854", + "16894577548232574374120767026426945561995165201786189772245769116072691636300", + "6423863987901820348928069732046971656713531289251833729857903917381295249467", + "2313252375346549956530493743826026444705500798866360084159932659530274395286", + "14351648867218654569586186362113600409735374191851776253843321710353903071560", + "12748602702906129786642754668169435482057869301200357523545630557138115816573", + "9709541611470508424169916733595066328177420935464065317839768365879702321494", + "7178910033786777709713498702843323736165699178795466682345863412805925816311", + "3353312211975166615897632007255179570864390972587901806985844706830647691440", + "21333017166590824659869638126407263965780255207193356400088734092911593056348", + "5028007188794597820037691911407426228966175740057746443994889279713514676932", + "10712123321028508395224612143524241532236128389312765281020405990000255535908", + "9585591632158092894254183832493550005011787447364800638915694118244958639233", + "19409055735214428219964362626158681016506721676720000843605743187110212915626", + "7013515054956821958187738653419570061640238138610196975216698509582854871893", + "14195757172805460680435532998286722310304400118130745528870652671654335152142", + "21642947172805342858920270288264451136332732954445458690700494722054302963125", + "17447291201981220908729619112892222175870413627521563259423394750686485556049", + "7142752135376494645636618098683429493620847661912582079125447091506892873792", + "11965386305718013298615263282817897360134689279593443592649060011294217114060", + "3269287439460269094755519346810063037578116295811194645623863516503159243267", + "2159120529508493457616143785556394024190164584915596617279717229000244189542", + "13216089736556667969033672749174760723927614320685905176389819791237404133418", + "5739580235677403106179902507340026453834485061930671765794215270028117113169", + "10146496637166180435280660177294964473638207568055892239396905092844948797979", + "1559489237751880726567698923572583310388557924219345825351973445625480867548", + "2596197625765120503438747432434144655985802369868414306286213301002200644404", + "9161937832793127953923149604860857118908349157525975074572071369698144813595", + "6530106539927673920262526515085998672101393587740796643755609207665748320714", + "3454043461578374982297475090824066193432500488323777575207325753404726668622", + "3344507163548616813143529013320782527939556912905450999614978312225536850079", + "3495919320773160724078129285494188621289377270658655167666727615227933095154", + "5516726577701478990891722326081439827260225708304904918582005618283443949920", + "15205180713187999862939063125387810274995561110852513151225711366795547591281", + "6648123555675422871529580981673252698816139021904779960285680145979314385726", + "15841058754930028584592543963971426098015345537516384042315342065435733026794", + "11980445534925903182700789375967305825089780148976633769394511063611931605378", + "13752792603594569707463845404055123799321888887568435005345905056744143696677", + "451907199992567080921227130990235823262116394775607208182891587168397627680", + "18806959341268394516719451015233616843300011700855654586308376758853129828525", + "11666933396513215238559883168577675591860013867821037377342211197150469047378", + "18261858072527055096686249862512380033913481610225001662137639137871862029384", + "21560391742011390943072232187892257373961479111877969400490351307926336615662", + "21610883506787217615067001898587573081135488752397283684823910785658887961932", + "8408073424459585535553155824732179764716727837637392334926567945546036849813", + "15210371269884178529776581719481988665617111145372052101377092280056914506280", + "12126920168856651470145408021353708994570254510986190646194434994722466503351", + "5069682791790920726869832051575701989172948895827442056320603681340757243410", + "5206562653380935478898854557078389821615981777078527007269200218469247241072", + "20147037355698495391549064646435751868583938479186070809834102358533096530919", + "21648765692141622487379563405180427559394486974406039602691179361899957186441", + "20151743655500786952430656789085402151537047806266385436562459773879995501836", + "5934394754413383977455838937623522376367295023125030069688154658727645145368", + "12603931706566171371403975785994747990660901389421654410200684089833302667483", + "10026374951811566765702661526223829303823304592138671853309110795200798195351", + "20990348049520375634430049514368373247447730079841716683325070058824866344618", + "21619384435032220705428130345438986008128830023896849505537357845578039663569", + "13891656325513979012692764566925054630715484836057215275096343649598208636064", + "10516755320080836193722788097986010349704472844888704193817055904209452357159", + "1187924241706018031195408222997566778745910130631759501304388015015493122577", + "18176236836230977144874543476758297865658817104610686283126581582188371550406", + "12485836949850082215229286502965907740610097753180405472080386359153328488121", + "11294821091195763819640094447903397628795163768975434879119673473115769322204", + "15235618132532149904626305329048631193060570832794115447207190941624057752196", + "5247748280389397626917162873894276536157877881047135043409628106456158304439", + "12327729816009770868743571696284061855435639336028566901611215454206952326402", + "16602949418050455338609614423670909880567257158111141482461606053345944875474", + "19481131052077011331591495382924133179323957631986844309716638852480977994007", + "14534922095860994138017014871440884145230839148117198707882202478464336849118", + "14698138249781405938575978017673685687915842935570150501408655390412744761438", + "2268825110634009232539217412695133214837154986621027045784924577498202527005", + "48564023730318244345588908855562476416102457310638224830024196372769683274", + "13911429573364091016107598756829373924944177606409768266066645212252032518222", + "3072739629129037084628601278178937800555134277149245900071628775426363271424", + "17673164704069533606602950374212967524179027652656167791832581708629862878595", + "13337993423730131992645864661190106010697884214050744564788997133642079615746", + "10864361443255322638825945640705455870794346349925711501403405779308411872877", + "12776251935559898232336391171201768361485692108948381787636663233683642720570", + "5216617488642405414264845781989153364217494006051772154230377224854279460364", + "19003202417167005941636726827739223707886908723467287344441657245420838333458", + "1782933238160323149082341139973263731861637960761110984576354403382733192508", + "14049307335094461452125704957817909153045723261672970005965857346428556786126", + "602292860913070228058919352868668861608870961459967730841598276439118039884", + "4532222937868395031497077142687900610420285824272982687191592830322532698890", + "2099811981776987988652353966067242893298763890123265819355994207644365313244", + "14963517993601358850130080519783504904964131507655857293183966569857011289997", + "5628630657751613134050345890283140633799644494629647136869171968642164797575", + "20616991532748403949152312405329497795753361035307036075488592441729795933793", + "9449735601866166994904286297362590639752895462487835902681383517319419222042", + "4855933188947772127110139132590210785552455770275991391814399396690242166773", + "5236021116842873402180213939626155398638345682608182461380158609761274518585", + "8831771317829874397651604675303149337495578376535991692269465791612651585623", + "3088758799070584868972772977513492687395394215140736055156925465547111629717", + "9647320052871832007164877116869148540664111922421469306708391658695763892785", + "13710265959446629407575266748628250489155448638018691055085275421674700880156", + "3990937300186809757319839603902135620837406120640478356311388415953195593911", + "14183797850975043036582133930342253303942122026304366900989797745492038794070", + "7977072622674677196160507229659485240881624765782396719467815964585050639939", + "19241094982310069445586766283605264689470697759972104264399773392459234417767", + "1955047691838825101723033568109446280275825112435318858983042058841632309045", + "19123726709557210987172343550395139275104840920797922301604764165695899093438", + "11017985516143054945716095457545428692165844636350104202156363406141221710733", + "6698050162913212144220380056054973138261583127187888344395668170533632399574", + "9966258961247618428931643789269822918034016436345337589754558490493039380634", + "5992044103018260979899747087179477222620402658511576502983751749529532417546", + "4323136703775346257297028867845707816483717723305960372757928628051725499745", + "21794175040927871006132858751099842549067139289302899933403157116500725993565", + "4135205477235797120209733594064542822286242795709961420067213468324705376738", + "10502424667236605030274589825431626273558506810276755098371543260305259735173", + "14846816339594032738719600614652189538461600190221870378597670293625955865265", + "2524366986896165752091070306635323844562001546653320749202855717200081979142", + "20323646694453380576115350130108187509393437723558716335846490151009228206070", + "17922328316124774235198837264790120266787900323072144966876142176581863552114", + "1182636510606531787673615350114833983759075243161678674924493347851641505038", + "3207389967170019411093119580069334588690357331504170475184259410760933425232", + "8369192092815635351510306100580533943309224255100566350954698456188479225517", + "12030967886392195699293618525716046167148513246572831396936379799444387335164", + "14022141444250217995147289887822373716179013971005541169826207913322588624137", + "1819830254074794257713310243249746692467827341614315920377358118637602832394", + "5214222934428733796770137135908910242359102117443480657729178969918179851403", + "18138416073511031005117669443972799853597050093891426716335475360173308913456", + "15787040542336098200132680028140910620950068073851656692331927514281562129727", + "821824702031897351041935750619058900741428025283533564678462466715419856156", + "13945650681120508256113693182498673378848691411623235404408416652983710360306", + "21565424898814963463657730321537398782420569248706699928677873449861325896156", + "19609389297655053996872511820224772969554473578452634334180619061868015512289", + "11052162512235765382251445485034453773059444701618444976454738201341222665559", + "12166351899911550354968692629609980749815884172876848625284742219657445788950", + "9357004866878440721090407569238169828150449366762652916034388742054494762892", + "12114234396159313460221530030197986658691629189646106573755288837341527114909", + "20697910091918282046230152102481351960195609070206375824763685775389954486953", + "21217736707553075351032987119547432929010871168087324138739787787951139001106", + "17381364776399568820088774691862728632279841729367582228657079823795538435769", + "20943148878105082737615418415826125298002846495574584317442899738454169666093", + "7269215523851335046672197634746347471983448536436098948086942864058221294848", + "11453469784625194830295468663538063129244082440999065497133984430619118688913", + "21018146386490226380790917971415394820859127890200962707883416995754459780694", + "4499764602796942905287899120539899295087557389188509075023605344029409757976", + "6253534478331781543005728896589051616547370996281199587944537185086057029207", + "11552217017582571341399470106065323830802102428782340770897703340827468796773", + "10819374663920577173719455195284609222419659549106826920462161534187158953031", + "14349899656862395011953779288216924779057701185080247070042551534943737976358", + "909510146269051589147289065017979551607491214019225341737807929286505047312", + "7822991049400510485087251716608572124487352922137650148085367861004077510787", + "725869830997965165130427627260429551001667760503255008495920045139979612999", + "16876874328062330437058858063404447748425817762641981976045186363782457609729", + "5386742002628492275210178331450945300388007254427357938003565527570148075266", + "5628231453725040085705711150750978455046683883113398227942371706440013519778", + "5207331605257641510707403983352805778295440159078505882865873548456617745902", + "10535586157456772677635305329613970037048119551546559771279117980166707049697", + "10634858349767776643334691454267563140934605084766184133586786266071708634005", + "8194830686373761187394649827049013218313677678976649876752071409303459578949", + "7100588172111463994475475315895964854310052675103208262359133193362837864219", + "12698529806569743134165801249102690453926582725077752506169518961941228191732", + "3192504222109013167359339531059877081526474219178099463731713708944911915094", + "4863002263813052668246974534880517465192842993905851311847938713684622052826", + "5692128778265216733946522388190452257048514412064102477216511313048856040820", + "10126422206202050217110361146045359045967276838268265874082659894234609632351", + "5816818864633980489627669987512782856651289984181002178349070605011354887917", + "6571596820513333489228887403836877987952738840623146829273932098108053062770", + "14089943097204317257370418561461590134190932157472606744328891293369209454647", + "15650892875459028952140088123225234819706577582764200222337535746289113550733", + "15234537030902822319330116055095343429285315370864285347784850359841976501754", + "19442144493035982963093880999374393289974808397308087180018619507528159896278", + "4787721462177588970261549242306006751465139812381940463247588627972131957846", + "21188266388402646362923963971922131649215999518682418035026104849712460470697", + "7670120618673949888866627327541465118295930474243507723982310418317698793909", + "5278076033158881738611446681468941913572289692389442858337761263328869905538", + "6812114686357362596670812436414685361641526159356770435320544521002690748983", + "14512519858142345768369977582630083215640443350401036244408402584958380156234", + "2883669043634370578290606585906686768752718215322315377961330865510599230166", + "1390031372189262099215439174834826964629551818632345640955909690959488475368", + "2621604580741170950714666893803390793334876512814103152393976192943909783864", + "16238046050182542127054230631321316896861946156551854572617517416519877517341", + "17244586605437271554745538098470023522850216211045683035769492251097903894816", + "19367233841767536085266806989570452145418274769895229567119343509637411304432", + "60922694691641059020255299196606231058588207683679919735176896931621476211", + "11404572340596870708576661187798839793333697334049619025922813709736021654992", + "19297195320049214749532857744175644917624562154332216539771469808458364580570", + "20000477679980055675786972902810034261882771620364631737011618258163102706803", + "5145215345848317594229128468995966108988375785838942899274867896011577909800", + "12745405048448113216886186019434813760835051470566703617056298583393105029140", + "6134671602520394562619244398452258969460576801019889394876295515660617122846", + "4914589878992627637690178006894707570950584383330674027731006564533772285206", + "12220903700447451099363813812957915640017509928028867600267100643383476677026", + "11628588304761135026225316417404056298817057087404654319307918387873030085506", + "17423007615206678675839176821651284038190814226425327926691523730687305701329", + "8965704645750924279210398083172931641857031322145961884520939048845530423732", + "20213900813945518409362660921232075042618186257655700796304283970465683248159", + "14023473417795456589963878717505287517669917599805973068283274798230783465678", + "9113725901633633321816296721315176702107873006937820201651085782607150391484", + "548172112211359610960958872299753762974328909291797522208085351481742658142", + "21706861375052844683595820457538688901531393763031119579322611763049792865067", + "12400834297098033195346480176669546452877127463842848395269580039592533946307", + "18693408652472113120418656602007998722418946699666834214243410738193362834090", + "5734025542584829419095063290697837279993460564092839068131370421231150830964", + "18924630076511631254945042871273344212804227110396594419618744375738473997458", + "21814215076304113439159605823570645338718666334965210428557308969012775849083", + "15874497347478704100595228569012157674761828758432798819588001847304550645894", + "15630701992043410338260010633128892269216736379332650587736588580296378591400", + "21182316539430719202319661920312710080481096926576230463259085025268931402724", + "13427632056110349253603837202352903590918428276805663374267217475392463207302", + "10911219508671048309975190269088900191221091803425594935965400900508004506426", + "9158857576095512666804740759126852985161480036845995629848333137432364744220", + "3061727900948996735547324485012991687515955796128872254459502313385493651603", + "9484087600338383596528641950981362023967545451847364854943599173866192324557", + "15244438304843092101886329998640757457334825678432810119480500702489267475870", + "966872391220567196912397735096848312956568724961332613947113843660023937964", + "11463695793311663093741054432425795718511021724948561649345772770204331282701", + "4301779131461344863695073848029046722184482171568650483218315300688393400530", + "503085225024315480816360605760267420357374543116157267432728664696709665901", + "2152733644489285468694016160698899213530839938744988003049661235638107035210", + "15311799268435674361916200869320882308334015315600749428161144697607223747926", + "8821276262247279528293843357774532114304424863546634692022624148120506964899", + "15012215707563410212327951685975753138452396938302623171526151974041926043490", + "3832600555460338220245921307060619972944914111584149730708347861160918312276", + "4945512356937128186743764272299580525076021077689098424357488427223926571902", + "6352619611110096346414873193740535134097751304211531527845737802795592283759", + "10487432688972604512516548109465855881572886261854521534610720416206960307854", + "17622489873780167264774227253975567347204222125869234241462457566132215071928", + "7633353550826098030742486107449393642153730338494606903118637850284315354119", + "14024635247358847977026819464107185157647377185834445176147145227141238505750", + "3839080266490755896783758766005919524636645447105234209420661161997449147283", + "14295400414627547924873035695592309131547135626435254888679625991957098691157", + "9699346383521400413122931609905328425995515996718354291677850659748262244552", + "15892775179188924258683368801772704553840476123482448500492733919344870447160", + "20199645131225911044918007618559374867899861460760047877106143132248914945273", + "12001320852019564045161245401305456578767647373680507608908849898281736831048", + "14109337051994798438391426281455499687696832970217465295841248395157195678143", + "16327788711327335703187954019173408665382603544801329348791567767829649582022", + "14165345295389244679058422302892574411018017024852263235622041585515310700440", + "18098328140605761490641355018350075852862336947591383947449899194910504851997", + "17531934292095415392849417096338882004139134123682574245576387314018394586354", + "1733676683546726275638177172968959379163822515869952716090548401850898249951", + "15390925956113897743988821133394062442365524479421281886945584164621467664839", + "6308234777769318028945248133710542338224131559387923000379414195599812605031", + "18195940437872982705964842501287028751711989848794835251153117845868361639502", + "17490283477945958076039190253339223109810835246475119772790163703167194121322", + "15408396829836728115954873718864748500411741345264521674331031030247235075214", + "3551438511462216897614311415123740632223550882497302889988823516019801455881", + "1211190935634033568807015118513121103447278874630092924424376539010769615279", + "17406162668797550222384115208538224445727151774389004540678231208053715695274", + "20479453675762626017106163313206256229631927324901802475043478933123265498282", + "14782425647559744167182627327791886056751281195680302914811546501028210982186", + "925131908338441634745517290354664216337826881101842522634123686010539186420", + "8849707997196192490777875561563208206085973382242717199438345627124299133090", + "2076454320990941741925816538401596397546951763404696804371822796867698785368", + "17173134576726258494214130646402838956462459094351663199002055284799185636563", + "8278507153110957550422039807446721030659313329793830361362606551912544734153", + "21454855413436031867439010732150284197408206511012140387650556740240705522088", + "8938141846612216610282603832016394896549074914747256157702516831379429923666", + "3753004427655295864092888874901033504634515083469621309422669489429783662244", + "2366435134561993720630980767268361780485124472309182242565985427615594260755", + "16165357231356434631067514709216775568766632800191759830231349057343507534434", + "19619001519241758891959372143573350428188652312535228885075978087065138604446", + "18529730720102625006097708392875275467779439015225330756494090875760858662324", + "5652897308997297007169294392190006281027830654965418415676327691132517009477", + "13575260089385236342970650047136574844156206796954949409405285738862382638131", + "13051488122183433321152129519814259420249179451391427892934958106760313757814", + "16675947070785780493219656951197382898525312482169747446344506906972920892954", + "7175175603774065686796811506353067100604576034944842446058484596637779839013", + "1400986416499873501628131339252214540318552035055662222249409246587339999877", + "3464466866466806017745751012761954006390229805750136348643137486103734148919", + "18217858987033907489494644734206558680641423556261333390037659204834788684410", + "8406086726746620686898224574302006639796660679494669881199476338693847188630", + "17762341698784805474670945153199304225802481228485479435097247827908738620552", + "6223712186181276291315191942450380783893133091457934083606193355728586611122", + "4282900419919891825156385371067226030543529098387005106356966928605004273721", + "21245665052422749020204481966374990873300815343268950998971123603215733315757", + "6982432590923765268313576400153302843651774940912624901824133236148956994132", + "14604328114465343527250129263480156133215257207190011581958944554537477242146", + "4419171346687102376610201013900704798965178967312178557853149472731770706501", + "13245918223750947891398096117311260221538002135539665270124077712098715822692", + "3347693769680689230259648405537595614327886881079646330652620517715295020391", + "11097962153704048182055796266608903112109780112107618586656031611021161690259", + "103842991820173997936966388104541957651469231887516072360536421395334472158", + "10458487052445928020397135451416595147106158179032040258831628955988702925482", + "10900270612365580629478084761129851570116267768979394602611763172198923647648", + "9903203205178879991225339006690459919299342990467545909511182892622541268992", + "7206476963459461034052924246171589839665793743462578906114104789862742647145", + "6264046538214382166095990603552597379083154170591970728068583459736905241469", + "15208506074912456921421298757607137779904668310165212805848069781063650192568", + "14399898497646210477881830976333295219807765057833256267205543494652425724063", + "14270878504405431259159385066097540588788179903719271466546150744452837482681", + "2299469207691207005105135549235035285287116575059039549352935321891742095084", + "16821622844104951063765780536072686283845403348056960050391910562149383647957", + "9956020421344380373447956054462292461416421439742573500231969663699680679093", + "15930825774426452340437887971015387876460967360948156787859264923789690195070", + "10985728214199775151782154608793108221074450547445302100877022826701613291080", + "11760641126739413999815391346325702178866867588284525333479386263279622799779", + "12964764722311909921385583909124655151898642200440943348322605636391779313939", + "18379853927966213921019716164768637873544788239921704156188954474082485441441", + "15296912762863693782000299085702814599512114536531293086824435743573000852798", + "11055306663322542945964813101077231103838051414460193023274311763885249453027", + "8057951225246999526336336507654165264870114340865557474750852826611325059180", + "7217454204491887928591297314854022623729750971598154127245160014826014134117", + "14565102336180706753392276751790538414003260023904084675564779334184014612773", + "16932806574869520697162166869588187543526028859439455500295852309668070598166", + "9179898117866495045233038402762881324885778157159220317172535561846474551689", + "18779105085403868166483619694881906385652758088668461143173550878413116028260", + "11214136111470281555815079365242861297786837712776840366750250043823307862209", + "11442992999493383524983810131599863922453401327420664873617599429059754849857", + "16271323289864628346209913310699661044288655850612550590359075955707090062050", + "17108025350334840622180169650569770852833940341473970170517727066627050749958", + "13146248878892216294361188166665572028549000139712229260161108594416711673870", + "11427372820077962289622241022478467149286157602797953190515658164839928300751", + "893014835995617411380095483743111031917691099253220683676712243294883268295", + "8517095300100078150575343693630592663417209558229239005971749331683768522616", + "17927627171733468726764817859266182414919024487868681391571481635385817509424", + "2910874756516541331498135086483127887295864033618596807255973264881493597680", + "10351245804237587891981133156579115865490473264567370459691707360959684413970", + "12694211070090545997357986982035119982901819345677093614248046140600061957940", + "20283022323110075954579979019632104756139185475301167929737027848763705068147", + "15931844873010780159923673780071721836876296130477744289335217834580073984287", + "21827223850924748993974869213271539530659373002293617263857321497283795014386", + "2216130285102621170883691491664557599377015082391517585865064633069426967470", + "11373405503815639839270612384753272139664561558477978654573651197371057815151", + "12313875735580427829620793313088533328915412934622924938520740599744871213525", + "15142465061035421304605695594042142745567585293979295525147576522422528415408", + "19911123862342914329674984568751978176595422003509172434076759943963715219260", + "14262659769499978824697304563726231560538953195673261355416096174585413608681", + "14610683638141173050828300939153196590488444327501938863403192781649951814095", + "6637311287977459850936997036417480664822288091481538821362996372726159029429", + "15501657635921439788956110615190078759397404083654787694613599184616807587119", + "12415917438013473637314666005336278137449129158908612828862230927356476129214", + "3977073659694868689017260754925680384676839395821102222683036599314487912596", + "18021973030966989893231530982789547568199608264409750239459349680822956679629", + "4358661372125150502295103743733014495017362384424029473164385391234779773434", + "12150574573348685676904261170022340625206210894206500162919624199154445311926", + "19059564947466261856206182248882637129860510906425942015878496836349348075264", + "457803388293300831659933030795457353247367081441494540658944608302089214573", + "5212046878650303869536834084593989055518385481488493726863247051727387374999", + "10866963984944634834508529257930003255650324224099527428753028080514409460102", + "1567398629202166035061920213544077752133493577343656913517034032663760331227", + "1641623291671542299150077964313362112100008772415510478337935841080756871031", + "1814807183609065925468700221459835599229505862471630844515076416397596161921", + "18676591284813153230980779135662585498854259214169962891045023401932640144792", + "14582715392475730800118541203172619815507444658499922254753619352141615271717", + "5971201190012257917828174333108220091030383280212145099110362036705465802488", + "9745736062659480171553506036948675113562718355498342585124081392171087285152", + "20654605762814031873434196876396785695406369410937473580199071780191334325949", + "11844011087342569590330041590202444612516395732736950853259915342942395929104", + "12960729918447154570349545809398065983315955190065107446283057843674060399978", + "1912969365260456210218541172655492769437123937988143458973053151759348812779", + "6751278463897225433246228986310134589363747158535699169746372748837067912354", + "1405433090804402720301319240257714728362644500702704160642087476923303165683", + "17334203531491537592342457272578981899701055200802551766264091441355104806736", + "16575765689548766530893504204590870417122916172019674976779799591211403721688", + "12220976854598379181285138460526335801169364473128100040253401652070229420610", + "18565358629024373944198152078259356971563125515748886809957420832630624111647", + "18999218340435052500780578040305741910732238048488832712380773170203478504280", + "828469997232485965462944215365058139980461203417902215718115878220834198655", + "2385864265255813442011864217087321326832147642514277043179825610035123479208", + "11753087538734344167619786844012793078263845468062416000491296071906848786208", + "15297341509659920002867070368227904487875907462849401568145592054120947559782", + "17451904737564664855895845058410281315610351460549944647244100267528838462231", + "16288687708586503845827496209229686543350756101251970070831852982828263987682", + "17372190154611010904681208309570706747429785600046317069452832284803213135091", + "15112572862198958048036722322696004521384539985617885597335257056722713402392", + "3090030985871039557449539908126365491166718509536148045184016492804246563853", + "7579986120189318071341140006570025802626137718385790787108832330451957404666", + "4656625991418301006397045145531617124589866163929416672123076523538862286851", + "19496020801558863926434816068743011465607626373023757648812447085667986307007", + "13805329389975072362759970417944582121050551902725997016013251740633448473430", + "18188229086122124131780255528737492392822604407289151260248713532509782736083", + "14611835504502434276576475613524726992333885650957002636192032800434268523844", + "10917400920268125157880112072188560060076995206390296416305594303287585051306", + "13972231301490257961012583958703459454850999751676553092417436936263553366685", + "18328503113772388769765260234570641415081417900145352728842854263561232438288", + "237123037398988309289930744284813441581716633481073379308753775064025864085", + "1703922543704124573472350868371820728886443372137290454699485327716109471338", + "11303106151640297276547682977648977961130813769323129464984120148868796657869", + "780835119818217499025356174332702814577120774118181250962295467182217505278", + "7513776436281774240010548782707301011961852707217067098086617267751060890346", + "7053386733865795782344919942070418964042982090173077686333893187474076408826", + "15388377229685250353999590264475768848666849601695837177100149716633411294502", + "18619784384287698574679414094727959444475916860934398666937358687019863556637", + "6843956467116800550015577789758902600855297665349663446001269088726857226048", + "15027464760260005079316932218316611292633334115528481474392667994765319146064", + "3113497944921123135464097580210634621999169473508798646842600013742294203321", + "13922875552185745353363519166943408041900501129716418917715862175817917028807", + "6529143033058355347608548436453630783222625692384446386966623567146527415664", + "10224300829854530831381318053279338710395220281107133842738514322747972858570", + "20406735123273907201110501114056492687992916259913310564107896450511212255632", + "14266011897697023567365526625467367950062937074006135166584691625548787309637", + "6266823350995327247595338658995148275348018579417278062676982980758032485160", + "13382224019010393958018966744541120649420499028243672845532376433487586111361", + "17219221786488657036851893458562210759167416100910882352030211878162886142909", + "20162856829897101788693886235042939518715128237037117615656868509223185121680", + "19255871117980259796107225408238738190418971755264416661458453217281817348088", + "14978990393744959794726413403754476561984809686673856442658550453303982912228", + "19671827853594912540136789344716532059747421261482796306917878259275666282337", + "10732390517629598846596313835253769945253387192277550975463036830136687386844", + "17133415435299159639005309603217597288690767318016826234871049396559867937550", + "4238294829801619171082019239832000810131476156600856298143082034448277968560", + "7722327574874647121890494265704613777043492303801725732359520952354380593844", + "12398521387704975769381094211621106917110829744392349946808293674617176531795", + "11200776058775831613393435187103560072186926574904464246036376746754002391683", + "1438209332219971409989076556134294085612745796338690516891328286502107803440", + "2937570830929161760131625263024599999319751748792625900610926821498514203833", + "11043761204766219739712866580984621876221567501998807492499956572251345283273", + "17161703263657344245212174231645949667297741070344916641526821962829393621412", + "18619070492541478298708071132730313137437250499943292747935022132254737182602", + "8379242582671699656964937417808578910591927550726975853520669689659712748923", + "4461581878275014470922963327129159901508275066328903674248853463321568123734", + "8814779309876923204577653695802478749454337142645142889405691969158642344463", + "5916090197404556150255058868159426544438846565532168821258584401868379000295", + "13450130187167769463125976820336122102195298233114472585228206936434118870547", + "16312137321831916960674847439149202523298938366384118998520447019250845846949", + "3523905992883153108179926090860559860264215076129040324355490516029055984441", + "9941544263434232818617581658227915119072214833223636007382930887032695504069", + "5866421591020072450638507367259603444231034674337808358938713064987239652864", + ], + vec![ + "9531912189466476916568861603725087174113765795321185751191491139118805372511", + "19478790955972117697384547134063865214385101762783978876290106323878777065880", + "1060742683967616999946346623778902980408439861665078741681079083728753884980", + "903807389911706192945621790390189278582333785459643079682311503388875632444", + "12234856961774107626670146718644057065701939000315796085771709903680607765980", + "7144222788160875459149511026237781941826966456792731247241581603475033054157", + "20698157631699630824067955298548696950174021158305550220448729049898476869972", + "2568732479597962725718653653192533652726437462680484211279054254158600287844", + "15284734447838568972934847154537240941736455475374750484902463133334986327455", + "11481338136657097309136761414013103615752281785975103234128467186355727286020", + "10612154017018914947135783711517517074090274235061056248497547614631916723906", + "3055604116750189009829046286798613018321687824856056202070161812694453230232", + "15724356578668121294244613323219019733691132614053416867337612541744349705307", + "14233178571890186223833398248040498471414046807101676904418988635462870136058", + "15569884202072601673299042953201725479510195453493088500579693825511613908294", + "2457655896277475748047646151777860503559023325500398204274047419681119270433", + "18721554772384051287322049295337473476448259922773695010270945658995924622719", + "14475562052679553333706265906284533085428658760049287899372861273825967798347", + "15603408794229592986464670990674550905587371918421438132217255356917740776753", + "16291020844798157226549685169153735235751877205762229274467406522127105739380", + "1562912009705461355815110217333069399929165391790667011738168557818438924927", + "11269000847557922376283381139665491298931690005135341373215203639253515983197", + "7952882227157644034022652849613475711023423321505769231128945987664804912273", + "8477623463686474590677390307150152439632807913002306242882220286965657503044", + "16240923770208341542260111895431885216031871921759466016566105290964433552216", + "3342849074804996662671621919352322750206307938435597035721084610748972602222", + "17931702006999673813463835283048793204134166638699010505988519059393386641671", + "20775104403560355444897460398679593487716638645215251442678183285176599574637", + "5119120619161234799144523865081220455479981813019860080498855561756227023701", + "14966757356872002341966020507506536570537078023526508344654458912397759281515", + "4186575643717625662604368224196455420957673000117335440321019421096129003102", + "19732993039041335023904970539797704576579318087957672270477209415993860238993", + "12070985110749915673363345667648496564808814323429491368289711883810537898097", + "11426729904237322553170474047093755836047277723343283963043397762276736900525", + "3316549680511845723553051012477874001156246623643069548980284069093192393275", + "8181145696278572952623145148622555644838658979012817598939443116317742063663", + "5285104126733708771192424010645473580676014333664755598112717745696037070786", + "20879460004955312065246827250994614761073401947673232470833608851757692374701", + "9225423353187148331993357472363957540141522302215231248106234750413173980751", + "15882456781720382955442431000301149138213435084361689595107598612703885378636", + "740238561845104412391944006282242126007894120431256540495139829806405656182", + "180417058725083825889148913143008776006125349068680455724690397852076567353", + "14174293519955274733372251014027762210778831326913295280840585355009025244339", + "8589132560109336742397080501737400189892522466285798728529721670916644735009", + "18608579889305084432265993644262889161778187018060113992221234915464772250895", + "13255562856310211555141734542720764165551582487712004861593515585281326120780", + "20040426996876166323258012360708147873405329072458300306708975663127708222443", + "3623806905318973096995680510049954452579199046783492207512283522220396562822", + "11410684734000900004860241940266501902598169149094443542781697771532926351566", + "17135477854627682759515989387435395911766329083966273406049980901836411403416", + "13593359321772915930716800157828568438953037754245269488538472861500074218774", + "8851367853862849158416384345517193602505667487160151588020171989122435915705", + "8486258745426030087193511835657366486234171438833758681014633470174920075557", + "14747490337504821136965789527401826047053378817043597026988257648138435336926", + "5328238162919446506214025777104049372124957345257645933410622558507658284713", + "11965770224330607826076459132274399741504292999992921785782448737931531131492", + "6397958737008655664539418210486834384969900796875514632281024739857683313517", + "19298424785220686762403958616740155152857782164943661260316780711617884649980", + "20019455348785333548837795973650078300677031008828877476192963238765813699604", + "498876295068369039941891884133922605442597373275805987652958540603151502762", + "15673948845182330978914854481229214769118100412263880346214990198207268219918", + "15636974430517603355685549955558840639961287398389993551242671229593610041279", + "21849352155479133596816471850644588093828045783688624472176874329078465894038", + "3710541309080539224803365587698192640065043989988405183436118622332060826084", + "7400908409303343897763329119747918294591391269311551693625176644493777241247", + "19095563460120996369257805492605849292942048841569757166438202426234116219528", + "7450358777752652255259382961368280387692895530851667830759412613948095056314", + "12616362847029801456780520061399223912377922714639139395311897747307063246381", + "2962396389753936883856793158008198181187288822144777145656778061306062270271", + "20597083262311447290143345580862519411179427096464102505623468932397345199901", + "5990063075931255958499395880323163728626495197217954905778613462408195572191", + "9361904499252311797420064091418454593805808979929563324171298064587942042557", + "15745983602860127054098117502599813732367772584805282887983680577406906842509", + "12155753549127535852899642287036910835293646693799050941038502705904075221647", + "17784550108352452858546269360461997898333463961938370347697582728197589684086", + "2486952113321483072183664368099776164387734014933893158352223909214365526945", + "4903545427310923282188595180893897246459463256398425200307382903876773643166", + "4976787025628832138140129068285715692634473783721132777844066348049003658995", + "17903848557396420363857191109854268785343114927997153696759251220232810232708", + "4112316506554809604392743006504568448930584669405889138267627731770713169451", + "12564921445775298869601661793895717261354052767541351424764087809438338341443", + "21338339987232841174606235608205622863643553456415651377028015070388899605425", + "15088854240518267391884187352051335059960134381458770666979402557846290860043", + "6521785672326022155410896706891346109402758862672817874198014517122929534795", + "17713017733654015756718215699238009705617793897969373435335184169505068045344", + "17520588725173134454654213370481559878188684108641520017594192886986887410727", + "20370353420481573040209617326772538556774101029132132235011046989968543481853", + "1112630910445876674622022594317693604373148988518983600314476620278857862788", + "13947879294001229379895373879944689637841444307211953543137372048528771620266", + "19992733820130513366333925886960985070219788486605690639975080516132656879852", + "20463686239191469605722985205294798392601180601616445763439546206772797296794", + "2399836272490730222789561326076432853292090595513010294231690669763899804691", + "1034212741378241815550350670737161423052400169194393567236687087583799668630", + "11440929010875860174917763753574001672473682534215635955505970318252592490865", + "14189960926817818424784917441574757301766760887770685069486059337906765736963", + "12315331213328078044898516229848174792421271854142211159524426707506661472774", + "19715153274097520886062594899069030152815615989925596868748132112713500919606", + "5263645674775021082527379900656937946372398687742691252725061831191269814647", + "17116922705336407879424247270343125398621621836566941362988393678055183546962", + "12965075932786028962944831711285166109972351055088920502397645336995474504411", + "12016029264981766758974787101200878559176627961323691741528038308088561486007", + "5729800253105809140207889626731612970039128485797787837679696331851897001188", + "12918441439057112476878371772096947366502166083699226943980929800631997660377", + "12122801182972566919042281354391366131886072331873675435499031824985283406080", + "2001381046477673840829875588313268487326797326656965151814712798463828403972", + "19581992323872865003173357646589705276192927057599589666190396129558198469295", + "12032241883699803399815479981073900218390137511663730251199663857029681112519", + "4486673663248066106745570699596745555749344770988892121755846988206654958447", + "5880818668316784480273321916242537222449799562687899946001667784663774949284", + "2395463900919111658295342588362130947823185484448880299307422522723986076206", + "12950983061674357110606111858229311283119838941890561558124046774295323335099", + "2237414129351562764861995011211505967387529547007150899242139479636758409691", + "11297958435815311160313316754342324739290776717531068730041530178142477489469", + "5317255860197359110199894572100590405469568868980740298600361799734023336258", + "20883201721979021051679862781044901365707874143019054645125857460321063446040", + "8182241566037373547703812967620649098015366536333588850170211599244447070966", + "9597640642388296782056528355964209027337895123387144965957122193392739912194", + "17036534143228977344737945793420370811715806669058615712195620745133828881359", + "11612810822316258618979762480131695561483235138506664012253801075650313633340", + "8933421864748994361777741056369848147887887317449099739627452478628920292098", + "14444070019150868677613599250973948199109012042816076287250439535772792130077", + "1409252976182963241946410463334709182528602279352691338387472032099813179046", + "11952347912832393217697966069578145988700552783923451999893230696985016550129", + "20459418532142116378042115609733769114184932636063412849272885250416180990630", + "3551971311295052916014184741437675944777358383038912487497306982998424802991", + "17338671457268891559841041605089015291458737421392337141908035764681448452092", + "20968343054904260510606682646995696017767749421435540168583945905747214877394", + "21712394213185895207403184789091961285240129068046002376558625468598692072071", + "7634967402785998572909457534910529497063727153788753124164657866643377741907", + "19849927917300065970782875128524194424999119369431340457180683372405088384137", + "15012913963479022629048645986836271605475934011232886489828149973693122241964", + "9429717687014890707005420840742234597648724772846627377968206537995029096421", + "2567188197501474210757971384017028034832891166328657542206945684532913152990", + "8254698320328328672738727190211578815599233720695888584349629846354725718490", + "17284254811803472776585305793072871837922263190673228934354908231725144505079", + "14935255735939697495362584034949670161356891451287847368207930876840786524288", + "15799240079228766996307573606262831147697506141321254927976890662889015144612", + "6455095726770008351501849656650198371508317633852287113372325351871125339180", + "13561632639572229898860364095655372109051739280251390860766414218384828962360", + "3063643914261015068338656198636076696013594289440915753234546912875968584726", + "523490668760084285231907250925228161954264885492417167368043075448446094968", + "8963235882996992436242593243282162189452480942366129170093695041925502792493", + "2822355405499444122504244694377602321152414880107322020961544617958820110728", + "9900962978347352867015759419877923426715239847996616012083851486863818525240", + "8479746689369630997477042503538860863372007378750903762662394891426272525808", + "16389683851395581748247134197181679668454182692374139436248933773102047859911", + "53288238128999697340898456182379718764153689572603829218558226366719788005", + "19367926616347613140684682635393090785537600078242140764999539757098535716540", + "15865351283225378120524944291419029041302905726785499676495076019805256191362", + "3306541431760940351422576606963790342897050957331449111434563465335195596604", + "15691440019263506851813897307599578949230726834044329611626721124859202292981", + "5471927110529676053035425189646230106778686168719884591627642899285735629074", + "21754232156244379849332999145646221923063494235010275675811923863906511018870", + "12691978963824033486319665437354495198660382717956695927101804737187302726210", + "18287930615191907073854709805749959615454583394829992950666668999967617218809", + "19651897318700114806760486800306423305046969021116395207725042165875775288623", + "14108212236437313184992367338426565912378398742941435667080068116020546770682", + "16999325425454851471000400176480399381440753089661500361295692310681628123507", + "3115621817064730307934070024882122808835435845590131246374645701268123516395", + "7664237802103239138782764325077413451892718354904226049706189059570344004578", + "10628974555344045044380058670185713528581140293158876652923633181919907860739", + "14113596208322488293154755998142305972509624369829087071590744312673264784912", + "17464956897498328434098241327703906248729109105264442832066471889452262140737", + "3306236514619936703817193243747225028048646569484446722868278187142340885606", + "1623642646505969781806818562148062924427827461950798461560800231691312453957", + "20812904557023426950178015281581063697341146335603865156046444216576536158479", + "19408105996475064309045111496637572365855316086113347445820645560307476671120", + "19899769975875815048945884537401834080401837433178820364413791122141366658704", + "19592039825831921790276944621603771771915464940035526138844575559711905257984", + "16653297576149039984587104062729832787430849403617977005988111857683169262526", + "9600749907793807254814822662348056400280037933879058284466549496283747987313", + "4481371968429561669477332540784950497549507725682080986909471734800926537000", + "901971752662861027246344512729868409066847439697888994727629776003122477075", + "13205641411901359105414809635566186722302364256582520884685762468367549487609", + "8771921370123544696277176259984315154171500395079224159374189372693912295384", + "5174975161282723002634664972730414710732925114695376584668768207090019053678", + "19270513804464040100949263044402755496385234769453916866026752765439740596759", + "21159175882383323828715178134104379154154907971797847682741774730382256211237", + "12713085776674794152643870369276859988930155976989577699924346924648017649124", + "14416880591724909781230787197474161383703110620356522560207527702042764430665", + "5782775977590089860582593877799736603230821040322957359619681360364621989990", + "4476458740184410293724437897879594951652562625859170065641235900450054752275", + "2721806229175990973363729919729809746838498228946916302499795336059265315654", + "20919749045138523262313225773151110447007311142131682485436367417448435698000", + "8313744079461516868330165973726769605125778482558912200259619501953066297351", + "4735608165219550054732197605756732753518722979705458514715803339137012677807", + "7197734920840596436781335789800800949073525267054200029424794448358957228282", + "21023118349982419692339995216673708826739468972915634059252379895041124776477", + "7361684304536881013610906796097454038829033466585052789468836114776912784525", + "20982662530655024673207268539471241193218964077396502472563124088553292010609", + "16223276590978113205386347640415975693035764887550533934078089596214147119142", + "16855050273631391834996719887442993598537594692357829619807594900987141342279", + "9447886870473301829371932239272857617552029212858469830955734178259213680272", + "20832064076469714454949991237859093636177561963691091143340405814107144265638", + "8639667923938888615556970427023258757087537766667818930469506422086574042603", + "17264766416417856804513499340974616744303058001571461329697855072803549043449", + "17850880215521300838724196369662075783108857625488733013926883881070746974079", + "2555423581835096020752363625782761123603321345233444467023623837801470232396", + "287393475373800420687070196983041262901299109116957212897422666775745916878", + "8502409129845334137896426506380979458386453989629214624807418474240644490658", + "17018903560361810748608552810594034468026623560117430817297647108682661433399", + "3048293276213593502083356886493678223968770697826563060833194090969377703128", + "21410637907835525984647506144589609474305790431496436733818309371828966617019", + "11884766464429332615888730245830253775469158860120272524933094891366345545984", + "1404751133279371734382153067811682787285007352946819870030827863597870240066", + "18533103709771766357713924189614422821669511650512088621974348524596673777463", + "2245746843374377731985282335022648129668387693745835052018700591124673151499", + "7164798246992914028921284523335117888604816694373355756451086598952914018661", + "6547792475751145534229851742995938089417776974069115284886265458921995253635", + "20902177810420148842648372790754609922473216539157084210657172695295335305053", + "6725829188763173291829388608607411327488468861041838394166490103857184986505", + "14877246205681405878429147764831613204208078224683457409980647858475648710211", + "12044111044800943869325640584272709159106488829628178962818078442934011738582", + "19605231155471418918091518582371485038913937726379108169052428896528644150703", + "7703294969707260451899023373169584023358521879520637237253564638222384534453", + "8646812596577526500078198446696820195057640949335282980927180585777038852172", + "21737243780210633072252501142816485256289884504027720271756348514717163502438", + "11106629219138713431737722416937344915839184447234152498273695046605412717853", + "10776231601191535915748483208366958548059216019309096513250460388757814780540", + "9570793764533387448268417521329594330897759769553789809193103230402046525968", + "17679865315281322154038759337512810633677645281028940369384987651076506608513", + "20575490035801628850469464797342943234291317406364190353186174477643080398289", + "1245923103633930975302215942611213577964303545113844948930979175833556792302", + "14007490679559289327503467618330290757962057021886611213555145469946035182448", + "11028796735236022300483437389742268989348582903251651368706557599156682851942", + "1556450270937619861275756908441730263281625715497049030992434005539032147429", + "7378353234583563315614681819214067843031828330274954124783678863055213281539", + "14666996645204144598922205770204386241062541706976832276647424877691625110244", + "753795180391574509648864319525512763100129705111118203505048417049290278879", + "14153559413038217294172720643039696432149555359470735393924921410988488820985", + "17643076982867120574893553230100217333463357095994549461637738074442388603622", + "3578933943193517852178000450144796032210613197873582924120228282439809826887", + "15520463167953252157432945917399723977264972626433304226673421190651502497625", + "17211537329205623730168383274756825219539545439487707555783029872192419895198", + "9802003881898384149235538364488830129822967333024012959168976309447054827302", + "4277753965394311084543194762939932271526308682615262493526499362805330624922", + "3936260403240718180440931086768355327655463497858616640513270218914599723610", + "11517607066800361513856730397176372083814736323098377670788083637850655404741", + "2243213365229554429675654538157029776597503775940697016289614299870958139625", + "19764298184704281654348385808308820923079630109704889940202178107926508921613", + "21440201729469627284915716136426033084639303793622913729895539439609852676483", + "18865357344271429482320975819341476664123167289165510208121280487753271844163", + "12062934463233700754743031150573591813637006411260363192982014497532786059086", + "7253500424782653645261846666860267886758998073654253013071356444451212225059", + "17688280285743970528696341296072681725398428119833052669003422836815517127146", + "7296931094727393709963826609746626294291079390951795401509403882666626382710", + "8944898010968990710934167772370816765379846965311172103743060979737069116954", + "2895100563060833104606048044246656016901407622471819180004918143679777127583", + "10049128690674011365994516711808882356477362224046294433720641467109283787161", + "20809590643316933764584815864182144455784236186778450054494378700964393080470", + "2552959198983852034601282535517138215015669324552132996051383405020865478519", + "90024510729703363025920398892759893841503303159824575434815310687587906738", + "2438402150656393945636277445769226062775867161339657212187540106747284678617", + "10290839327200266675482043018636710429195359786802953032677212989307055380477", + "13366445998820331718698457472184546771717827833722684584206646838628538349970", + "12045715338147601791240214774093449384918104627310882799600088155093595426276", + "5295711531017416568724842720044505396040371477829249515344865310124246197980", + "16400063927954668864214504458520657934817841218321732614334739112437744352318", + "21834268150215228276838182444784793459928322632598421948695291555558497507284", + "4036405082017497222204927366812040809401891394189816634089482334837550533053", + "16758010699927998006904853632308429832737059675503937996784758385473294734767", + "6851323788614107612891077153396783509346340795017622764414273403342247098685", + "21242220940510077461844092816930517552035812681947928514550083154475902790925", + "13803558028343943472219115813916734264304316037691831164863336831915596589841", + "3876897423511600793257560948470150518761848801469200306022138001232700430094", + "7873917719931107857936523614722924550340227737594948157729078597073258431354", + "17791290553613199208672721864188024787529313403544902623821727403694762316966", + "4509080040196139117885863635009327583647452661266153933806446923314670630597", + "7350149044068266301432651752105457672961955568647004218727518439545294630219", + "11503072465150450162639608555774152895393875487845468619329760555955360089418", + "20146546283112595992038998747954746814923105695946909075842241737548546646215", + "3500661581148278300592438598016870333493992384875150415517341312342838567317", + "16461061867640825231072403805782329353930546739796841505995525047519357319535", + "17419473457085759867681212087981664406569947154579733189885809269345147937957", + "10330084554893529954763451132860402555512473901655458870771994310647661645739", + "10271306411842332407495000297515719691188342515212338700550984155237667774587", + "6010614376730465540824294088181704678570427743830238021642540164120787031818", + "12211956821531047081164047854393417207581329108889222238958146335322243725690", + "18026227011560759880520787750218090767851915271628616216035782860818091527867", + "18039053385352422125173521135868691523650276298214786020953324823686654441993", + "21572961947836757087236508142423227244602094617521885308238188781724980380450", + "6952631457061838308719934275464119179697248499343745875411129234786468691942", + "19811900079804396120677471049757957457743518480096470411626681111649768726526", + "163137711020707070877550733174177256426010367795106166965347507600009523229", + "1531253433144642057738530256773902523524280331634644205392973718192895734956", + "1179712150612295194734157884657760659826346075044485388437451245699680152105", + "2729710616419138683641657553469892671426309689560939345577118202079250084236", + "14266054344296739494440365684098525973737250786286154516241047965660978988270", + "15026169712587706365294070206936700891511371850326743083547381843796350317368", + "18744742519058537072956390943103111325221767611576688631532967525091526599212", + "6993198712278030093898597400393962073007955430382142820465138278710889662382", + "2553141820754951085470014997086944345325965756649326165555729099768987826967", + "9720940197604032044323074196225989267295799246574437528002073812640512558241", + "17856885570331180579712689563952926777618369125836010409080422245803122826927", + "9316647413775248445962902207564207480723728241070369123275732644991331488677", + "14494957198204561202111268006350266984666563257512595231100502951029167863544", + "20990514914454458611724181917618445270429441499421925167963524958552424564602", + "4471904645719453756418626304970674400441871174741396875599881395188613340474", + "4684361390046158999250125407700867527620809473388545037966531069883415383449", + "21702205249470184149930308057282607474924454457414198304211876480322358864836", + "14125417641286741606705374243071146588481196226954437992372061774013416347499", + "3703736300177825900679993762695155186404123107499914435631005694624510941992", + "11732888492654216406505460448043873705030240266921135732988822696780340208946", + "11933466978112969006229130396464073172307879223153980062784019174478752039844", + "15171000950368540171664824924290660122824429581656415561069429955358449308299", + "10369486846273450968605452628621668108353399309158716739554974304206007657467", + "13426080534643441487992009643036732384216019130391445221701162507604477874092", + "17202835976136422766224805235458239972845135749171745123647755691905320873240", + "13003013510914746051603710434071109936447243726946691715828935535255320452661", + "1672563195387555152025850519159013960714433928303467231569405674199001377183", + "3249806644396047380745964934114987054912135505311534093405371566690536038255", + "10852655605415322578561541069174913253244788503288539822168510897694861970183", + "21180450898750475729531605846185254439124003420647553715507766256141444893981", + "17598208134643261198923845998804266441503487273381944592003474913329048411161", + "10560430398658881239820534975865220513135495522309722014743734708940471341227", + "15940735766678288146218967299383564752403182243037693045705028442779781161429", + "19840721391058424508364187473208857771270089687968326863727366457103504697646", + "15270655938735284505864085399423312069359806468400434801172200215370037695961", + "1774340315063362619348165557959238806046379939754082379283600857530102490105", + "1931473872849034457489264575043647960104881629328524494861951197166741512954", + "16037503795660448209256659529206619750469738788435653064537663524466496564778", + "11157294725944164923451173319705000360949753554936504404517553331688337467555", + "1860977382172821235372346764481514761526862185187436148114012977011560461667", + "7554608809888667328824255380474433026692004240460849082770678269699854930661", + "3812849161473445621072899414157938525926417912914872301607900000816805333995", + "3248257538394266288019799770714987078883986769586407060306626631267726656239", + "8987711810247040851774885826425578893413569065851274558714617106373602624631", + "7002808931888012021033077336936962976185388694934605760542880449764655464580", + "16260071391005121724128685673030785454758719454582904114834030329423907463299", + "17301316944867831355470414388420250906247821380560618462329913428602672908525", + "19139125176792761113369565771916762091089412261263410641074341972472699592037", + "8186463001964086803315373078973607488567538876768905527322257145549601226661", + "19715283945499391078117757449557157262014864431503022516493444981357377102136", + "10201366877793384824708227219959809605313335011896439133665539069386849213406", + "18657679796594390529926518390837962343392692362549805385222541270238612706361", + "7486580570539115306934569904905950241452751461260355433571179343632374451808", + "13210602081373832317780583229140785143149759155013988676929972636959898239126", + "20547921916591862189543062064340935912295194861078724580978244369580188659785", + "11184938862747662895633149920437248716375494917732149572183883382335006977362", + "4564430184172465843641043220857544376847031874739611967386619487659896927977", + "7141474497649513954000384074955704105249233034539438859110223132506810864380", + "18152904455695511183625765039917137650094202440231199346119983777378283365068", + "3538073603808733813419298816140509998806938194073503117538238879763400661830", + "9176198085009858977059589400831647890975463959467315677036348254379008625292", + "5358677810755468005042017406822742639656433122059352601335552810789858869197", + "14917263528903508585499167331159661105708948785920472586609175307188322712065", + "17459264445642522670023202416244479198596207282984954048459225794985333792860", + "18314375996391380435570814127239902609672007999779514985166492867417826496725", + "3831982114680501270333115239154594098561342624259756350309439921335535690506", + "20912918104665637113589191778450022009791755974254243256571842103252066396138", + "13641033990672188411010402475025484333293999311081344333460071084676167264579", + "11812251882211406110219542299092601278938747815723382992634003397593468524422", + "6831378526897417143208721431885442730179700977603214290972417120210221051272", + "20566372962271447276247738296560940562676849411310335464134428317792972599703", + "12645078398048087182293658191360551774451388858142913314124550234755654392800", + "18848512616065065931619133098070120448249278799586409723288680340437325332421", + "1336951976108001940844939305921535183133161033109848951359362159969984671656", + "12850569062942139371781102794220985236887099863147625303610933201225464388254", + "17095240610637692323679811976243261972135774635008876108449261858372552686880", + "9827905280236638995189439521379169431346954052078412963417337148237294494508", + "21756974284757687824674400821247092844224232050435881799264172836701664225928", + "21071024335098050648915070341467331164448998348673899538194227711074199728981", + "4575704980288845009798550678411618457862054601563658773482638217288811407473", + "17637889149961283902802970141414602882266203898461797433796173000208254839889", + "11333768795263093043465906246853631488076833683398258097056018834885708094795", + "13237413177387831469342322098638791101575804381099372225484902457329675766563", + "17644690723564191319649063794394358703071761592119981992193950976485565800738", + "4591566130221102246468298018361020201365534301234509687763578673293960293459", + "16880258892960147740975242226985692424894589139379261939284621634132328476631", + "10753253761433799332298845732798867046726308621524332340930656512278172577964", + "6294042736878992012448357827249736553756583459648169754872627240315677645950", + "2668606416345354198548309314080005930475082556427535177631964192773305378348", + "5244780336143933367304708103198860683485779489995095073384345019218674347056", + "6113177497707123341972721698332981926287006839555002718473535918066824223034", + "19824522867272770281143825792424101858356781501070734931688923418771980499872", + "16889524920861245550560790459946848535789402393200784095555799980201051324212", + "8007523897573727144887255293212203546407757295680344011669395834627039767919", + "10043972607564040581522896355091368769007227979993058004755493078808025405133", + "10815879623965899246220301442969866254505652264417667341661157537312485515831", + "11534947289183790267549825879293816175921818072299730180286203718992863665552", + "19282679238458671513808783870622522462539288436443040483594699323647255140729", + "20993973658899710060621174143488118082242133512002997296378188507484929417581", + "2207137584463635998515616548473102748156816296061395772266322132360447742245", + "1906176303891379788266254493945992658935732580384991589403254257107793504984", + "356009908103458769499047304270411564071705602811825215044685668712377389204", + "21267156990661889558161221297711049481880243497825013463587260785886036981575", + "9511026544995595131578865949819301816364113937202346971334793771967449171857", + "8732150772674776446232653795368043280414095192666412295836279503085501609742", + "10433912179719211724964521733928883750833304291050102060071171195374738464494", + "5892753211405353458072760353770523366305643800457149832130812257775605711230", + "6072173732058843459603530982418555383917328480859906190255818160437636798624", + "12537411810282601586400313857613201485446415283134353086651901233218273826014", + "6917382548294560607950289035591212885648538608975878502811670462230179895717", + "17522466317865452308300593635805699602531255301383258028599652149794243037329", + "13441087273853521452830121325700732493909228483089386934391461759499905593163", + "16343244966838333682425984150791963916204788641990311583878776392583665902296", + "5360331632046740140575498209972912123753748791093482084409464010367952817372", + "17326261745640411514384830391871497358293487167841563962966663074154000109605", + "11832463539058003103012764436368900007479300735896611859760466513560696030373", + "9332530307651641794919337618798260519292245685937263028043423079258661105173", + "18589656636963228136343540063542372097923688201290293330159927366465643313091", + "19867733544550615468612533273987508641098463295160374186223389748717034468502", + "21122779377039628476144200947919650885809091682970982371472379500808529828990", + "3027016623356326893238890601376138710903222026620502687697483362378227239102", + "18688538985571458464198537125324538836996766056814806096466271703920561848229", + "7011851562043637216927989978271187524190844597096440024970832115577672150682", + "6976276474543022394298383474157051715295086098335344328214084449502467982887", + "17332130117530488369551999111592288939240424248347612731261799228734373086235", + "11760005773828232229811117479200618747574322788890348748345009852749579147876", + "2298592572354833593457878362078773063587664198044761229360308644323231458063", + "17955258451898615415362730916130728340133607644716002859752428726933265234272", + "1495160066997898368260698151648234013994510168440470178901776412293213577673", + "9194083678217569822513593808499809262580238989709793956568701401108176409146", + "7873147134182176342443626581580817861100691419143183095128784103924898338758", + "16767569430250994260298195321407617265691776202802582359934917139510241475993", + "21740623993440608033243076692676917908105712281956015230238773795741552902992", + "13259811027098062609299383180292487555512077058811432839971137250443197786014", + "9862179315713982904488948286370860706178740748908626205136774943873439543978", + "5283798667794826693954690769969228006851703579605314207478989967594232871036", + "4252584733067990475653166725237187089775889157323429734580856783776820381431", + "12973205666610532230766585121029838349435114222222352682635156927179891214439", + "287633827640277544463301235265949941438188349560881553375976425107945733447", + "9088334958857736274159987824864641712847858830802240840003039491617952671684", + "2339929702478917712535010770935571285116447513742167345028949204167372785538", + "15676860121778371383024352289403909294835655990865877574625753945822204636877", + "12764603061737711341313014678756180651482961849974746341425597804386430732092", + "4838308895208597109198370123135942497394705098532245211834944708850927126449", + "15227615340505775109084051882530634970803647261111629470904659446755110863564", + "4983488923883229416538630982432842594678976476580011041728398828823305128910", + "13108944499697608875788753758764556629418014383923261351989967790696566041318", + "12840723598548611269818280989252209606886290717050913748780108061152527561849", + "2952676596403552231673795576822772308483388566436384169804788313391241403511", + "6122163114479319080164532464109940924328926458633830912986940513870140253539", + "10991285734105320972904604247873526149047475605919579896179431815938092849653", + "7998273930160782917435322581864589776803914924450929021174489205585585635343", + "18738565009620163104846733922742158284630011729404799909319718271414375079555", + "5267789578561581666385683546519898747246978052550117863765974145167441262779", + "11531529707082144080873135819545917882620969294873081450175882450957416920799", + "18780101368050367674291690806832757013309591034560713102040071432479406757422", + "4294785451272921756656022299749163922793391211928749628139961864310109196353", + "4709384663557124742915933403093691049837232917871836683405730215659929289723", + "14881387167977166163300411047605462807380624840482159906092434632182882848470", + "17882364021447094903093424534075826770336257800280425962604559742290433282224", + "11702502532561044172145178834042891352292518800414731965233576503757342967409", + "14059864978850405613608096166397211820819484772138676470000521070869797461865", + "1780174207952381531321288553792322300359882548955331030522024911690744446923", + "13028727766195703514931384985263026051594836628118028800883341509333550916528", + "7588265429164678210439639249095081332309245305288210445601269417147124081569", + "9642265589138009721420730439928969906364025440120910401773575492361904450076", + "10203823545087224726196594521548654230876294164502500177215475003344697986058", + "17120058099854629688232575694825768634386944759592366006492580522962871073389", + "4222192359475448381394699451673800507222765289015074154697111370954996368735", + "3993784121910007141124454385846036053674166308991223986620192089439929299772", + "8723933019744566416337803833347252328328807961776170035099333968332078001000", + "9712660217038548658606833881897330347907173853654574936296015219821374200265", + "2760535358459121107870901826259907500576486637522442431581134088651955908758", + "17117109873353435959712351313249763994000699552995926658366410602189225375298", + "15834046942685590805387820842211523319635967093317938586307927436446892526328", + "20540611330857822392080560199608407622162192943120548518785800532555099780387", + "859364761671967022958373408533303411107861007743219314752373993491065278500", + "2969887420026581030514962118165604753428498019600416703008438822193590952680", + "18165207804423071202274226128984095583162198441473954125845000361590859071975", + "1625906472120027348769657238152772240899619610263515830625917309020852034930", + "20463932955653127762144495520150037479624855783264043490725916287067071124695", + "4638144661708592747026214570394653618741348169520846615537958570570478926642", + "14161574596481971299443338101939032775184122775644932228990090697003591542529", + "8347184524978696917103428134030602422953969299144482352589164719698955992623", + "15813323300222999983430155647025925955486314051966513470055962106024932062990", + "15881789235120065904292616653574390818033995432226550640643889297228035707625", + "7140692095240485283381028349925581289679980854833888018152159900503732423858", + "19010917339674038277064587622527941116247281757743905062456743932291367865210", + "14626089726879708665184866329935404127909714172968102824599946119716141024551", + "7794590602415713436531570478653055404401179384350609462543106242181653823825", + "8762400452539506415642761970628528841241237486958209742944443338295503154358", + "8591771034219068368320608087757251879675617969654197927442982939795060041474", + "16722135923767200283514351262528880285637400101562656889998995533577538049598", + "89464124861540540773346410834052352014308242060847315373495379383140228595", + "527363371365063907312062782674442937761539145521639367736772902232593392996", + "2507841963726490485511335482108618130879932510673214677761709746737826243610", + "11600559113928855816564236457966654301430060930571013803772049573600205529037", + "4588632959705258135254026492226920833318427708514752831324568512946022675194", + "10614112216523109461118034753484116653637318222297437542653638803709000476069", + "9172525851971416839816439437260881435627775489982516326698553647792223169716", + "5792656644651436247861358501481981837063028644438334753333821264192324104118", + "12896881102412475846285309217744373816727588379892851016206737393174951411645", + "11468716910877986153680082696909131615615571055661580004775449060276352989554", + "16433370238306953119452573705529989067794419309147323079675422756276020408035", + "1273883504219371718563834088540759123243117439006904940363157254976913033897", + "12035946135822991823593467599431819071656367730183582372112230833767543617935", + "1584468415480349659495095652095228645182004993793756033988320959253925346826", + "21386287619427343417104905630296265178906342440158736945069239788114458023785", + "8353771053561995945612416527531464945642582086497086814556341372197660908215", + "21451387710023590786286131498774138351594763095518652036485484549943942198584", + "4310607037909191923700937557843586755810945477870372794480216273434853743125", + "14760194187040766562518106717503624683554510559335502353786749509033100485706", + "1989722256243159180961728174407914946336713030784288455577084756567680416269", + "6686508185527220254925691658356528598024140978521686081374828691583660936030", + "10702736220547282218129581824426150350875608542279410979052446031034395032616", + "21518832429688884430739158604898893220375510075322761868526168806092202700739", + "18894734518217824473490018310535147336620281698236505678307171602214420149474", + "13651080497325379255207286313267854150042736096310351308026009382931418587349", + "13005423795701931110183481387065874846108794433756894029607220148510576563022", + "1791508640954698127256430696076954377556671221508186631495000025000560314469", + "17328036510202475587667192203250772802218778208191122529787186719212302087427", + "10657963758634548274685968417226435837089760791121929723402922305566484150027", + "1373906129582260565717689440357805911187492936689152530374097510483815842229", + "9959127778329368795108284764279846598110110516049484774588901738715030294501", + "7658768549089819420025961609972525260083323240153758777076357709438863924071", + "8556349016311563259984530239150734383111823917689615136867121162886430935013", + "5584784611907644257624218172047384219563403421449130896517357173082649535408", + "12250428484720929053394094480089037225116943346244386549438429776642627577081", + "5894587027805929865241808030013307622768224687737099108946198448930484926182", + "4640000227377695114780725548825120725107463526354871525420448370293105443156", + "14209260856334030476503172714481690115491571124367768551485878619193949022436", + "12847259932859893012278918973069680996469229489435970735462165583338364177587", + "14707765228045361126133465815432967736466274565508518646993164305646449611538", + "4776938221827642494595066454007024055266353658953900973539209110395754289252", + "17345634507638246813894504405651157443245008745673515073520154967327741083655", + "14030342049076255140305545268617582878430218358427444316024303212302433090888", + "3081608613732784391792246085705209806228642369232320349344206761814264266822", + "6925544598968002128460287121334907968171640408686960604018975554503413545297", + "6436833790683001261207201071187060041301666725391276179040664384301147754533", + "15822971282077757697408895884235910303980603368062126288859779292088533186609", + "11405645516905544384081084440311050207481018746793339445931815864373601814301", + "8057851956466271394801907096296448157702512819801554261185443997708792484686", + "13400701029177845728937105456192536667124279186738602373189177143094323643048", + "11966218129646969536507242899486947493941404691279766045602150839476320695158", + "15426703084090770508053125497176086377457196612492405232875849008237608103107", + "6284964429736232174040445851307654679317453722810844133660225254133335862235", + "13541475439682330895175095901646773164410091796597408681295206023344696136380", + "746760486363018018017386520506969904420399625886684141218702464564311095236", + "17524104887381990279039312517306518062132617046713819525042298049738730617133", + "879502104476554315787832344079612181105511927448955207253764010183827781938", + "3322243116889956217287455917347322211093649776443788544812848110324752380511", + "20993304704177227988946248236539217504266305909163005794546179470620336655896", + "15297086470600095823350435092749336605284701364464412627268330863173424318784", + "7926831990131610326614433341787624222916431629609577848917665290693634271603", + "11271157869866761687706729926953398656059815012440629723619426315368733378302", + "18299023753364987381538199358983670915973737470621191699559419975990005285294", + "1896523269277706381575521315908503178186583134996425770080392278759498041496", + "12890346501512276297101448381578516979954988837373044432656264176509301317397", + "50683999778726139626379750772467319774169558910797110829251191014869406584", + "2535823474764747710030290051647541950275171691698903262059516064562837569538", + "21244438525273542723000364561332886617309030482024380299212725538173747919525", + "3566180332124074953578668480009215478053830658040437750684892555496819182968", + "6934760873335280553519652185111971021084408206212600990256329557702647231767", + "10716990663016621229729175818785901525044168020825517922453745625674725718755", + "16032906457960033408967366361214250817346739568272864358714497113973437241307", + "3843556041176221664914001975628278428195138883854078534543734996192939783081", + "20159201956050700213417267403145919082229292739510798606395981692137742005549", + "3946206250066677142194595031646387588831888396304269420593204783498093935566", + "15041638172488186356886629449548027800133537204416329580391498341162500701165", + "13278796648404195845011313500265526847654531008699937318834233691653233844557", + "9401997027308433525669054020953469816624994577441846092561461184007344721828", + "1983197599992175511555068756140439953159901969155075046465287261273690782516", + "14404434816783701517710626513536590424905462755924351795276920360393132910619", + "2265153992995968786485646516094566778663253373238301922539677847420824091645", + "7566790081073938501935204486802755123563765476651717380300659543531475311797", + "847895502208273199247564103189534214890423186204714047221696858073193176165", + "11963011786171849258296957535441472428283852585041548938428326288746833247421", + "17377294274187023009074658259347356248383537938503682836124988411002248431249", + "1025753579901801011233785198665030697958075722777337374303401815648687864152", + "19284019504590857558072823196945292661333776228606049953803221551974077538854", + "314204118013777455817026750462293710777754680076389729833422020056750157783", + "16480262479960754021966845575947830901794064422051876558808623512389290214607", + "1118467174052506904085279606913979573425427098904935496893365844271017524128", + "19632743231294128529717484081406317899334378150630214776880617163102648968680", + "3911642624469919820429547144355740104724495930390962678347147942124333228884", + "2066832981312040153658964981292230050110396574171753029116180129049784719869", + "5311750082320962006044746418239249402583149931726835813032955695199748985964", + "1668605805291951132468779303736499626803321838797652736089353191224211818512", + "8117527083300107176240321998574781132203045054266787492339353711594335529709", + "21295747743511951700871264160352432803897824342737595930859857743511472313518", + "17388383598447322131131146498858701344049179581377651662282122447439867066027", + "1285164961547283134680842635704675169007050470102043475645519044978941760131", + "1875066966449664224570600546742926101175136253576702799078476168727336032193", + "376316574400845651365366460471492295014146006765806307181242245707469972823", + "17926797393698382320151787394969682377223530524132422415508830165925306730854", + "12888413344274698384267384086384474622307363694087246755565655858542934044367", + "2287154516202749380541196057272317720805230156010471100500251268302509398358", + "12091269896021030725381711946583875149737687962883250402694805482865888072651", + "2866048333839936509265230844807967492604533527765757660355779329791008604324", + "11835071699154512268334373994146252361488263767766913426957050581680705629365", + "9769574961167512396467538163460983111263497516872198932597594846643533678886", + "6652717430998307400653769850757364796566010885765190753303419969578998970914", + "11706514210298927940240806568375915039663039872151275540599047371226868127844", + "14503173259289644850389467422758670421081762433800521230764199189580041755978", + "14819563269715549434612532555018280611140077716865566327825448288943759458075", + "10680481968851597237106707337987338182186447633463836689709242917734021556532", + "8842568676211857695295830062491586931539601201165478151045194686251206282625", + "6530738090493870852939715092085577161577833016969257865187421674974986108366", + "9122348442271830670856465114634608231502719005088669868106730029655164877153", + "8276880496499930549062062890222235677345093568048001523633692507246467514288", + "9159103567267771525632277936018480854652194329966882107551346987942837974086", + "16469319105211987147868896414457254521940280033150431057117354850784171354412", + "10187807714948737954868581824072203418416253898435396377923197796615888421106", + "12487902950231724077418777903531512931204649041424531773792238730349062186046", + "7128847500406995361903929050204217572789701023482188856789540128660376992648", + "5624482939513897521205456066520453513748417048856589163079298385117683428424", + "16435310041815433976313715464222273283215148709695464992270777828213079073600", + "6053110243546717824144224394047966869215089006720239359415188827006018953287", + "12155283178966050547567835509058470201630806787546132608678364857190533906654", + "4516299433052637321210501303761417706907638446979735686067715866937355560218", + "12667848710309960989666753249292981950689410172688589690222261363826904222200", + "20798966719534261926649504156624517814254561351583702314533431478871413942185", + "17967549743799112209110259394081841952094330269294500558315036929658897218889", + "17847714150935110939206476281446907230585782511584357788270839909827513843593", + "3706525735092193828297046649401002937097518714707649753675691741717374375329", + "7951431498272893618049118070591089643051946670270891223821638082032777246372", + "18050610739452223409884731462410705437134574403721907246909018802102148878228", + "7681233452521913704953218921671929208806506209990716853575264423980840711485", + "13423126358538883907022095116894303361057277664724853411599423630968340874618", + "16385186307753207860551232886321416660506143479955163989130433021552655688751", + "19863338799254785908021006319182666048802363286601429063342266271260238637645", + "18613864443384979831007688916611349052439959929170133474546815634162799183324", + "16332951432721718166552572222119667287478083212745997662304261644978474988848", + "15183520838042840868796366239500461619005160337097541115133209726620419190272", + "21819632461581352219365791577295628387565956152415171439862191463144627141459", + "14048533271709057229957508911818231901369646548751751133058494379648714713155", + "5460165509823151384714546779805746551465260311624889230527298343216031522426", + "7812320479950772901428223193019468171803323319794359571259026602925413892220", + "6861047298949697363524436975701264276161947671796912946484193048676968364570", + "15350000814702190667768044439440847568690389883802239839819456575900015807805", + "13617689242559757166326885110516025083265117478902533337635065578646035372109", + "7476843340092386505769477537028758806323421556263090744578424892783190404262", + "14826737006932111183364733677544376863485041173382717893595766527131815613201", + "20482222533304950354756700764919164516648372491559583778492129756055561547902", + "20761958166613639518991371846609568602964716408676516216766187562459779452764", + "383428479364004198529582849470440881390404766297544454256885030893768964772", + "9096063532469724072461386558496798312147772678120608720218640484115240695555", + "2933312980053872879818024429044461919397766967639471518371949595510364515880", + "9299316327986512295931957414766538459714522358165090755549540858707887390215", + "13488092390166418062347006407529577052576958127764741552594028975338262414671", + "9829077383468426688376344724031102291718825262406301642537010429132676001524", + "17306252922949843274941351200908184305715966839608017699204279919732909328171", + "17087445274779483487397521683084452362124400111143021068068404568736590545834", + "12957176730411938817539171430465916443660534484629425102659921020718336935547", + "13051137677735706323786222675600013609665436923061132301167672971485926193799", + "16896405620483797393236904159048703206424672638297382666760526590725313874095", + "12982786219003483259026043754729673677479461289605569386777999422861331902406", + "2025152781178874327274493576789397778291707054468278801142821085671743579422", + "4335304794121497318666085856101737871981186359433585080678838732369068576376", + "12639022425423716913754007933194900468141465623346480681305462334218095484056", + "8623058240535559764777469232729047628411050024996927445391922152785990079007", + "20506335897603554545414833361572976187621941529253485759521266317325651663673", + "21253532477517846630911098846446871983813752932337294199438073014278982612265", + "7690372912700906813961714562821752274841425123411432854046237798188463759714", + "14774079281706150157728885377093724231164512116594840467791057304501073046227", + "2057509476014278951878531863305791034496952436217061173216277825372715694262", + "11541539364361827516114507593054831030438985642093836719960774810015976254752", + "14751271529818502394785288765886130704541730104426205431367858892918636267768", + "20653824984831671829709191706456216192511770845470322444515326861038843106056", + "21794617070379980226628233360507465028625654800811478227502718633923944312665", + "12337675699660313500286885345145964244870355316351529815248466118884457457726", + "9527268832683847687152279087478212995292048665053951255936397859316414854388", + "9676848840550815858798680133955006115514366150476209999729932493584446713554", + "13718457801302749437654397628557435190188493872576865462727587887532950355038", + "3867324761996955514268635801392015956546058763053808698121442586705196957126", + "3945177530905850250597694151686052963152292050981415927393741981018273529029", + "9473309264240097344589730948390594137445381539328377904021534848676986947654", + "9996385364578703060792470002743943020203968343080025005448261317627854389642", + "7671875350824730767796781844941080563527207835942241721783016221076158519589", + "21342545963270813418079341151020475012992255268798567166496112378940512106806", + "8273987785742417777035293384288140933989540189974521462819168552306151314447", + "16162516432221515902182136237589464594279404001688534734264317844425059661177", + "13403805360231306331901242144909690435939614369536490494604700225511328976179", + "21640586272648741017978258285249302214133507217427529405059807093199643534960", + "13103298902142682492657114828016226525668797790480257241873358498200705227711", + "3251016042668618943397347852790038985788901898321438389540422820491143534512", + "19418047092207786422594959190763286166909227118034848590779428639908706128141", + "16018739283901993654877226905623763753431466873170287728134253742237701259452", + "17444946939314191179654576411859454283526068144165928707555552999432295774923", + "15128585121813842824984220733706899232093493608422847549831681212432769497258", + "14256042951767483060181875165067417249801798477941578288282791927486641413650", + "9120441102041865153472829977920901798404277796873323854759847010789551358565", + "16824614118285494743762017938800453590083305489658290570438237922163546634147", + "14066296536773839458459021526010711790088172526749593960873828093107983908643", + "5017173601281838065126812757441844223954524936921765951283764327160567691674", + "6254306109691187702602819001106221686689064495376117914248886700342291435542", + "8093845266500847743481398069264511597137596242374064050252920004891985410254", + "3578536483838573103029984288079029549393340013685219142070711310306738904812", + "4046636520929111297180341957015914921052723918845140326762981717454102872515", + "7446649718318072281388998859356555024817100796345520325890349758135889404482", + "12366828085438268177090003236704251656102820345668679675414643578247762288715", + "10235336658636336826692093860668421345161445948384101191460476320469211290719", + "21557699385719674753050624572282725191612933706864216121110471118396873804204", + "21676195031234643974566056999169564975565168161106308063972653296222128822558", + "6363029841115916180506080615867336124807912331702908898766344258887335068638", + "6363363442473598630315975560083028488315295047134858188348763022659100540644", + "7124701104304155953181957655778532711129611550814127577450223681003954918096", + "7205717562822389401795306034882449236003182581929449060008168502546885140420", + "9228704321577313703028591075278114440418729713968708821922150367010520752433", + "17614180549151511016628006398127365390131305608457060951973438257438000114647", + "6418032200333926158639440620980173724897942384057810379437154014285875236793", + "1563831431103246736895130173427149853201118983353993792302858411456255839836", + "2319462743404521965297213055024756354349733992588917297296444679195296432311", + "11927767606932195981021511932625975307755048477176557643420944859867328059951", + "11544836785666122785129617591037772824479186137515525949187438698705551844116", + "1594554937757396474339277849284988438779469013126014780880063013190163371374", + "3090898925598297656723114627648156566177591433413115455417582215942083585019", + "7446365483911748580722671015415226813450613606623816089630076567220802142731", + "7277804562221458254100595374565579800145724793164291138831756170012315181874", + "6742114513180059066582114839865181272182587124666919323239785847603969045455", + "17639336822454434815461281360929380680585323524008927548062809039584978130493", + "3577053914395256679157728351997326335158820293078866565158939674077090010647", + "8416461669288393104752370629542582785060946946477447413022986748926853429341", + "6094400991411029253990297530870616276561743402531435382960598226029406844554", + "17249210115827920255165876773266699947215322191164909559927557290769226533383", + "16910579881016588643870584852395328514859173042128957721312044020554328803878", + "18548800605828674358041671058553674062230830447893195908258772241250469878618", + "19911311709285615075760278233929935358167599770457743440215721586291252049005", + "14163239340563250030474254441824385465013759375574504142110478434407678615583", + "11636512441693145656185679602762396225011813780067642639202962721478584613773", + "11627821975451263242823912745820712501746551642630006051017450144021728526893", + "8744830043459757570443313311577350804214757169018319227421153827794333111861", + "15502529014760684785001315229904504412899268461167235130234930235025949266727", + "6349631474781311552829280885666605465500111601027794362415725063684145078154", + "3750521632595755853919734934063554601358504982902984744970328457148877834110", + "9151149071511054371049219579896119997746835784236581257692741291133486546793", + "19272083712610290647942715418077844472245445971738771938657138000646231164194", + "4825691749471936225587218745193692386291702673577201485716323799193545312215", + "10104595857457718843210330892798628518507052980455210862700838136878095844947", + "583353789674136864282067863249996585561603923757420881823548159264798915805", + "9605601189839871334439279312434848410060547509366999421152290140420275791851", + "9086947882810130237770476626970553738390827239675874433366363671998428155733", + "939087130792625935525433768373221635016459152936104283115879791761930303865", + "13281505022430256926767514868008519612680654933479762886734630854898956588159", + "8791789091182070262897704714134448615861594471173394864103714557845783501440", + "21362425094620759937169033441239641099917726266745789893288044988022041089124", + "21264794594588373773536904588090499011630449220310853635095227724956212914745", + "2201440000983888343103152416697093803247262395826184450099145084240341640621", + "3661470436482399872770855708635287053510507688269721514323020960038319367739", + "7839180633039164608733079650881737341586893235460147432870429877862925246133", + "1364292691308802542355455613317294540368840799230835218243676354771769346816", + "8772467089802087196594680904948784186594877728663145042664601336273257169460", + "3528294282612889297228918585517392070857581849271784732463382671241778115171", + "12283613789492092234060914364373118974353698674396863245366831728069561564466", + "12820604492590938203463369747918352644874868843295488782427665387357902190399", + "13019897240405241197543377542947534699610589548844172163916774096781016951470", + "8978439745720039208900766235834036199032761881062736449080983584518864263026", + "15222275515593239598230012498885809744566950744378381699594010392927659453864", + "6158846143100676033784762660398310184837175038752344358512599894306514737286", + "3419255917977463022603617504775890366430819682320515293245827217078337799273", + "2797549320616484645720845216321636133654549511963540737715630452964584943931", + "17033753202496389008484483700445909344644255293271694371709019653557282454651", + "1896525136564670388001069429586407694373044886658459111231294687089652643180", + "15410846104953506982390647924353051056630524372570695181992786623509940504512", + "19568185152800187670153137856814273221696851955003399523563214963248234462015", + "20371827999905064832491002071821973934784290275145413746617942892257828998608", + "18823477734276348993184895526705908983521278925070561827518170646437136680627", + "5656115226652970780235535706189807810471572029095698537591078819723656151288", + "6421434687984511183440563950015895899135677057679953590513947822215985604920", + "12040384754225464077155439050798210419160821091649797103441177013046869869449", + "9772259825341200622705640733478002328903138705997041039987261797557503104066", + "16498280031288829288227785307302736352936199535492502196962915104633784174443", + "2797879572297199909334218711222177900854374704477138347081058961121300793309", + "15644078107885262244699428484967291897698559437568086329631330880220396182101", + "1929505350484341295824323699861178332578728141996333839839142429658318709684", + "19829107623275996909068882503976730773632786622439634235897400991781002387336", + "2349581104996259830058120951667460730076264470159293978617685139254844279099", + "9982268711644224005105745225708318829304834159499232155579405472268549361372", + "9283048909915207444384413611285315401509676836116090349272606584736947471535", + "7228184586853275989616881380719765868918305938029647325846170897121335348738", + "9356148801854782728189493667017091537583121935960987886599900693915567464857", + "505609318575290577159607039016980344147219758564644283699477849237669899416", + "14366218774993226370408163695258733389122646477999733966996434517776361579764", + "2089359639878444205205504625611416181841134778729917955490118311877471215733", + "698820948911402576486200349924367867353277614409335325450207885100392818369", + "17294754169238631079500422194295778880256675645147530605338890302947026045725", + "5743114444764763990137499217919738961538814043960695215081370978081114004215", + "1532354676442440269809361487929394117850339080897231885482935144216545001511", + "15429279362464933048379761813318395642886047028548664371898579661267949218379", + "3996365200571187062769515782559269970838089444839642643284597375210723401466", + "13855942579438265547807447657820171102227439902714241541267837936207338677600", + "10017315263017624310653373895363026608166903346797759979504062819071927130663", + "16907630432341625239068562338272519243551636457245225084107387534876995927261", + "7499064872525146201613148795250282369576850162788310832273877734938523830020", + "18958126705503391332983508022395142836904315587480202621370522508346095401093", + "10592492611778631944134585106195825750734295091365114316628335289401976557048", + "10233935978161235645487498670591630814869863266947595645533111837358567006403", + "18003113120454128964459787917100973688362112412222897499908177070949705432002", + "7039143063746813662581342159908917130120555794319120640254054115394750527325", + "14642639620523941644124538953496946557379420056235185193901717503194398478844", + "12510354962778923417991098874785395513418703200631409704677335762559702597729", + "10937907264762102220987756825649855260366448774314976509103469790406549413612", + "2856291402269285412222070625188683697884675330846580808282552440813379388545", + "975737765008679829063246253813268073237541742979444038400325932865440884821", + "10846579585900798888776933082578183338805087990458930175500622018769094956268", + "4529602228982157635664617353676370544979061743349920696434925695574883870240", + "3217171861525061655884750653752887679288235310048470832136609603512214131719", + "8115945363448342140068934999604399115922267391140037880996539055087195710388", + "17017061429975823256838374218603998280878588780557395344098357759667769523464", + "17414822882733297737417491176979790219384604825369331340721407024843872424842", + "21674124478965998545524545297025636759207453169144537816299040483190680515948", + "17404327139726954519140759696696303110669221199013129437266401728134593481209", + "17114525865368445983838697023323950751616885090116888636158517909348665004808", + "13606067029568271979635008642466621607360271211611257253834134991337929444625", + "12697011972510852002753203688496604009044404157472710768958968780456921052232", + "17908262237776925120663573891641823998363270265606050465713306950786509533013", + "21456469759562487171462776687926242591840822996019886989101706511495101340835", + "266521013932216168881283771008004557613060760037591295825839278412991410595", + "4426122336489578598096667658844019947877597098504167195068107491300030650784", + "9386708946433085177945274757444606300245243689157314090008872819375610588441", + "17571201661176038894845217669278055388543910674470132087585433795958011317108", + "4455879691406517778738600662496288227132258098615032267607735047373372289231", + "10411615872931007756022633910690379435607807745769276655537160609832149769392", + "1369325193519585971093564667957731115918550810109208821335573114054160355015", + "11701493479673417478812558973813785951698004134589804881992366063053267216767", + "1604976076096057025943679983359889701146704427744088265030663068037609417365", + "5807894190026658662778129602314598491833803649976558289016319277596337255402", + "6604568830557716159440870492208510177395633789687151427836556682055398194130", + "13221322798326908033948171538573182873220915914806870794442015701313412462981", + "4276423994177015753526554880283981182675757973382385661312000468093685717116", + "20731982721228405909675906960993136550102478961136398510514645316644217252635", + "5084416110782735943752807643199425478022977025123417839387489101289418017943", + "2080632875247898509655097068576655654491657659787279629928499240720334125890", + ], + vec![ + "8798508051216852101945770298446195263426534955832706109793971883081428107277", + "18986509933027080134736570007084643366993581436980149915398754460582000677690", + "12888632176077676513526604615863975427335143923557716212154194444095746278696", + "15218363940991075171925464923999816479227567707705088260324253815128900522726", + "5123856245344699442960347063644568841985144075867098178729206123344695866632", + "937497109650566529304426914695525196119182564119552807475810542139513078711", + "824338985948318627675352935105995425917124279032809525354560876904860400681", + "13942203133811236390194976449250445722833065335401645546668049734024419803027", + "21193497547768556525501812324063541319364865851059424372272833186043647143451", + "8250588221665279725951753271334754148372733354841465281007604695074534688729", + "19810263445128123914159130235504848033923366950322026683325764129239721093372", + "14320576994914109414332501339118128158228930675887122896979269439627163060693", + "18889264041663920880871940494605753485014632588652805059026615325416030193719", + "10698608730721598729809918763148392473410663742558667693804099019738511427166", + "5471531298285601691838160103499608876767872950664004448938449413930813358696", + "11457601248269622750970644898105156673192281665198367584690238105651871243849", + "16992951642443963917535033612483493956841253647152989134657936764458589935104", + "10681874111209657199770620844475073359855652721773538207614365548304774934508", + "21875342192304323235337862160226992419479798345905340775869689347883470787957", + "18783598503862573040343207522848147282351537545213737188311758281500392127423", + "1221270316640374234025430293653174054626512367600614548099335037611485538579", + "3803127350594514565431185919859613836470412459545124433755604579955078714169", + "4692704173297526575662787527414813729052368393667564364621548376076502682045", + "14877344233698668087821753402566363996983618742746012792982725192235615274582", + "1054560579819817802724755404438987869385528807680314510667741074193700268397", + "8052216208184446695555642950254618937388238814298100142455645263386380520432", + "21528486310986712871728288619461268100617012373791428855787397091733571140849", + "9607239927604256097021258716815750648977424271874860033430637795556811442682", + "2196312812082021938532541315765264710074289763312450521728804241715253452502", + "6605540160838083938636248853297421723407665107595785929587574408377531474397", + "6525948153406525772960169117380395975817023461160134354401655738067058124631", + "1003556227519998429556476568497227440137917634405973503866888411893650518666", + "13677584968475474622689223355399150668790874783709262452797580070344541448836", + "4272686670447940608576804106249107479440735969672981187306042096242258850880", + "7723948150633857131095670967217469617626942590283045283879017721699420758313", + "9563761958679910727099148022742805150896356950128100201760652748527446140573", + "2850052690445041465388681891454371728435601558220304706587137488583335087257", + "8526775100524058290507772716277462650712450825299014127801740914862834880076", + "3867865860920444582361195032750323847757212456942796852256870663055781206979", + "9531131437985240947539412881613144640386246585015365913532093261866651903759", + "7876176264763636659141490167245054739857019306622806711043600468363729864093", + "19195073274099628437757763039411307254419435216466391625117296911023053159082", + "17201596318516267959242478674525331020962456681235714852429128354797936423512", + "16429987001981270427843548313178399452962937303668954688438246688799503164984", + "2808058398896238113910841463946229560728543614115874664163904810633100174930", + "14219106904819518684382581834179422938681605045169559176622588393807041033595", + "10530037691301443797595179975755234137332257307745168342967468344289118325757", + "1780683171090951191330938815635375996828930714110381590102230999415067289139", + "20631152509228411005601100836698224543066495368069041690921190101674287477942", + "808499207021654020396580110067573161997188131641925849629551231827774305643", + "16396331554632517617174441423319546296247483740125085437207362257874071846324", + "2856734177282633594896606301173852733142847026457749184584827572766646232552", + "10322006004350928347565262203595059371944943723449117022023179276501731876345", + "2683049508597401695548071522846046195699870016352617057472448981851954812059", + "16247545910658018105089170383534659574306111291405960552997108542031333797235", + "18622054704352443244328095600847746501599243235049513145116519278941866455272", + "8702183185743408572844482710294629749653378107594727106707156268893318308842", + "14401120539669001367195063486710670290450638416936122540739824928865783084126", + "1008932491940705147356558882115440120351684984366727805937095853000783157110", + "3335415470820584035672268458205991064638866247863327497697585974180788121327", + "675348271572506248948949205284720732296364868854507020989147277054109697307", + "11425495584918585085965114263893597096866227224211705734884180990929134229634", + "3139501819004172358132939651256683854267531704642601593201346365873114559764", + "5783084359807455756426365693604321435940832494660634548089377362001475784943", + "12095094864547001070709219304829411865589880746021553931719922191437710414601", + "16318907049539057156624360879403805284297767691522365017367114160528018468654", + "11395679267999229912686944592292906403252965050428182621076890662342583575672", + "20304144520028193526915712162937805381528012861129116050582705669151951550558", + "9782367134866186358061353221055410602027546275400836771195060684844149613708", + "5028029607389470804476265609647401798747012470860555590083631854016382301797", + "9007627713847325367341162188681367076476205669132463414398773746849014673910", + "14471089911822534831111187815987523323244485794708545360218598163622346282781", + "8019180100611273479652907195647951337613619920735853449223048779220663542855", + "9047131412613791119405208650892730556330287685760678509615107996866748231916", + "7335839265467743759482091707230237155828204454352010285192894893585057443442", + "14787708665825803366954624175778735065630831061644057898061768895034788739773", + "13527353131634051756987040962797036674382517083826397597671775590484363794989", + "14976182354818370036095296869648510633049821903988384882639150664375161429327", + "1560099560219605560187324067315095140041097722845226997637592687804174779694", + "571671177230396783003670900588907847431348620829409362554250135027808522430", + "3595401819266532411007886403698316446251107730632935527816690692561072394769", + "5582619801223860759886119158956613012355932421337001876528290847176002785551", + "12913958465964733555039885816821695149723050623118481194340346951472209298707", + "10229385924925018504492473674441213223237935733123654864337438778499472034702", + "21343876046925805512584981384457719270702482935633311830189677174062117124219", + "6420204451041321645976980917151646516083600244123365393849746698818033299571", + "19251614427061141498566572096097506725955838624383486128732046911906166384020", + "3637855341628865891325364423447146770285076487178203925892266081818756628695", + "6291095057555542758591776864498618016939082736178179913313186141723218066258", + "15680673126007380386463552533962308522676179674235002556809204723523731273305", + "14161910492383069106925371061927425194676913565753916851706224000847740857190", + "8408124204639665996401588312942126836254203358943885876199057731364731921137", + "1799578340300310412035304211591366593871976523584701800579066126447600019902", + "3622312705549913151631696033404711371424834689912295490477655370864706883384", + "13273792131373119117124844835198348538764494606049066494384531598904652565002", + "14270260908863510838028225519201826231421616414346395482851862560529215543207", + "1633715375341396582749269086363023314520014551113162582725277839347569228786", + "3306641014838747329624593360740422499925312234577578401365800985267347686108", + "14198045292969051397674853108255956449504264447127690313478218267366467132592", + "13392638089393029927126006202520304645547980480174653070691229667854016527907", + "3343885948493512216041748082192584170148231918609106413514016808164860398278", + "3168199878854830552224332084447744849594328418779455928665560385861883941432", + "4414580242526682670231711868212166617171432599055299074136917305689841663873", + "14102753845056293060191802617344737652392043747319090694003879675100249630273", + "5573924339361534820906966230551252047468623512376332682801232194633308271653", + "21326161716444219551593862645873877150197335577674154159730974795774063715301", + "19432958264517639868400987651848393946587739437911153002798497064389336859842", + "11213890749343283806487445619338898013466071000086191642490563684623068539710", + "9198922780305686612592947154769134303077110139729181291466776593119643796878", + "21136183246673473125620223552691909911094171966517655547561646692807715461191", + "18418245895226184084223713341727403858051315526021187444511237652982687814864", + "10761950212602122725874752124635327020166823895511275020048089638533400314021", + "16715137911831586771799460729625653907150059087921720918100590730689273071536", + "17773351327415330719066508685011039352345666357995827941409702750841801825772", + "20231347041576378765333233596636479502524461869780149044300194060543432934519", + "18064563634590190884918686050639690971635922850408462075670660991277444012424", + "19311806793959939929201104461555154688516767798907269687984909834335608414545", + "18574604846458382436863152415585348247597412723601050266815439019897542533749", + "6791419133329459189167506884324613003818238896866734783035998091675242101498", + "16020026112470750192482231650248429937269643957555877460849721131766422051297", + "20044512180053459577124670295358045421070313597307221323295226934357969810703", + "5766192039785553259974801912149788259566859976619902528741727877731329189756", + "13160650100556144411626475539530712035286115503483655434606927361569861225444", + "9256036311849117781394603817644061414251138927392105895934210116699839233747", + "16660304826343536533933296919943639532544710122612011090406376521894383168856", + "5613106871918486982198177086366936520094704188389198685078718794779139126942", + "13070598684216243718425316519583985756848433332087820965201044383296972346897", + "20442537178749694119236982549472062379434941056035907413284316764767638577672", + "7934380525369255820244941077363404413659578389361986061643146925957595190009", + "5098727584136148023264970031064585917675686576590855834683443649082028079965", + "20311250985440103383589841574737981968195820548330595923330987127317084128947", + "3768224286214159313341476585351274256214081884717440852909749729584659454712", + "9851045187544813632080431293737874643968516290829960553238754661188963821885", + "19015242154372799267961042586541854827581444440949327264389997835941454171864", + "6579883332160451787803375748174162900180016921849643588581107525271529605849", + "10040045688615204420748720492172111994988850765670088109590569954563466338788", + "16200830095429004437461800470410149972585288873073724430176128378316485348605", + "9682955393234868764418991570718636989945366768432593131049879027562290804128", + "12304247432606946020923001398973669839540045070461170795482951827192644001957", + "18191542513141047176662091981681722742011120542435182371090664849144982674881", + "18914155310347961884616925389217412880576183372588965807237661684331120845382", + "13251661686687775186900604006618374427674252707179991219741046747323389941232", + "10249194086135063113459170280632696947988284060709952681203426883826751049011", + "18372233147890747575375422462203968154682646712463764047424428288714397527619", + "4638790386282413677458315728120268440302827185471341027696814407017634332517", + "16623961311962310335126734990913554770362581939583424145026358913546809927380", + "17860493200690068167535851968852986582339867469465298666834410487621188113531", + "4608305735853858774877121807982873005510358307902418229099062852681969399389", + "14245817054597951763417586258404021745844024655622942045401677661648532977993", + "3809843434538253198074703856325693344260532607506586917570357443895551048805", + "17962207143381407459791220803798424686492359980872541932770670422523978330935", + "328196272784453082510222579442282995329426913454628381427614217629272010096", + "12374354866281475555079168690683958365929973901084398491477273797832999248789", + "20853802547446175043916531515983184048009878116903616041233975407782898112824", + "21496110961478435785328603969876614135441859248001892605282920516413194792470", + "174344306580108774551764089189043165870298462272157912012996952342994211137", + "20687536797191141044727224925607387673330130224876076220260820047611716395831", + "13067331728561732140381851790951434625007152955086246816336518249186949048391", + "3797862935019829095677036741096081889651388634128316641681020782687008662828", + "19718547173056417343715166978970272483152981364164960220358919266690668222316", + "4038867288048886379019053981446145278427073511478003014108759946240227146792", + "18486919751583655613568544119169758176904901075587096135301780773087898879007", + "9808503221335286135961820380426080374193561918865479543141400875074697503967", + "11673653729232546119337900700609058880494248359777926756321171038104786463073", + "2206576012107962093523647385331312771747616647783007209109500521090968991064", + "9800772269959998996051474306860888030671933506518907174943285018516216530078", + "704115937219213713489981656324169840669771632134921090864597729550810437103", + "10450936455424589171986477572900171091143445830786569605988162504754224051029", + "21102186642636060890935221995324710172830713161820423345683707273376266063905", + "9163879187976750746407679763920281609583516506018439539723656773309855786163", + "3472157821801145643950882966615731480318387993084591537527672102896556538908", + "2411890225861629547000508300507629335095483162292985158748687911181232049540", + "4985409929001444812993021607654361988376208034496482520498705351994820408485", + "11553789937761176964063895958945223002657928340200203811287735666719305693830", + "16847788791386791842258653027481339013349340413294800029138566625971691859716", + "6760556724223230789549789607828387138865070021837886343220335025271850431529", + "20596400847159894247975659733452116044170283916549483164302854789226390584120", + "11672317719239435686809215238371249803784157167042393847476181444969645566102", + "2540677976918908199177572390470632080272842549139729131369041579508211107531", + "19442658692908544356400723297250992586408893464353224580638700020103731410947", + "3126219492402213962620193562481318950501969435505738692018385930122987610651", + "13815812651475874136168661258439176421344570120756240838952907916838907109528", + "21443943680756083274641262528830913057368026549878765925197792130996882062057", + "4605307168758134905354332635309004486671872776946937049460665298426311628483", + "7482893834680785986692353891953868933021236845332400077427554963067657007377", + "5511796194740668281350270549653399801893104530256753635073935873703864854017", + "1743641818114051150153510266165400817966589635697948934570080374390326493276", + "479348932723256576178997677888058436058269610751399398192779646687149113652", + "2911895727864385123299618342188487304466499987531177084686132082340794352256", + "20721945554748282229818069151690746976633856763939126384250406858494706697945", + "12250582445106986808691543043877193096050336861542243284061992098674816799798", + "1203513568724767846410309911297210537295690041996158208540636591896498697618", + "6015583439542775167098811213988699848659623500530189193065070507681443523926", + "13090526755326389175310761634465981673176179379933796187486632857997253599596", + "5204691423542830100481358117753845481374238423707185894207602712512441617128", + "13451357406880550276974168929055560555273701366887507611491312211347374906677", + "10327523031922710495308957226255708193968398139079389167803483310323608563088", + "20154372727310541088852354530646786495003018189623626400646862775892232254942", + "14022574434398251358742711545518515409780772767696241502841372748111287365393", + "5800935164580219886597276061890276866350374777469717717325353972942679889986", + "4950159996548574497193804912590478284182513481419060390699450490223901282265", + "16651189959199821925513089100199135327590269582473005780223712025001916349248", + "21313574815160763657406207917526347065428582824748947465014119238740065134827", + "16527537328830884258876707902602749401809299353104838028680907493128406403510", + "15328203752181180061659863584748718494669846163715366299567183721088123843121", + "12748724793783078481516963303490468110393403014501561235873124284244901317221", + "18960625031156828010763136389916953653374660277691326636541170359289051172470", + "3539001622988573864365704884620979405364663891195701665878843924015974631139", + "19440492503123228668247641573804742990539424862427319298139890001019307139951", + "20663734806319981969735713814960326046259899097186434280597673603867647826563", + "5638550801924521462873676353658824547611149604620661155399127974706744652941", + "1371302213304057480201653073728712066696195910046203705054614806040591336203", + "14916746318031473743643312292935459967335724866678950897137588157969538011797", + "21398978398848411648231431125400371920346497858046605440294787662089399525957", + "17030308547789363149594169656019066171879481623126106541463663868095060483032", + "2440921987343876776494963936103708492610319137255329185550543355589457647052", + "16578274606037635679209783094809437790602872464993592428997022911117833097149", + "584917957795662537423624049408930838570931949382380283787668885015699442922", + "16787159358764578324620871006477408253726184555269443751955596568136636185295", + "16078611438600534298861481344414944861682463507987217038328914463538066716267", + "8692607842423869778858860521189757647588004328790444839011233818764128397786", + "17461551965098847063794186994739508584146822190403534677972847044656722703432", + "19452713388671907333636730760656181158378071792518077405629847148635099895953", + "12121230247359921951208053896624893871654915559955364031951409301929413070034", + "4704830575919764561517254527427722789804729564629801789022427396957683932024", + "10670972751746137966064978863033768730585193577203300636726301560193269271720", + "8049285218762936069773906017628569610476710004139648882735854791085139873871", + "5327956364112241273910968805653529609896670219677653687154759819173833984314", + "16209531049562245939203780811684066382629831507349840609244051677227948603148", + "2041493598600414785071850826176044493717208172684229753087779307523403234108", + "14983712813504746225033809615975227528832540720868897893292242774973221269350", + "12085999002734552992271490964670175347983721486216238101789957598273374406404", + "2010148192415347724117376912318888220341164166588569584654147279107677185092", + "14204865408877079652583508111640133693635228399739312350971609944706493769468", + "13330601146337713429471908542961289712020817519764634531830442337284933922809", + "9363311761287060295640718461317428792455498134298183595944737677775311452049", + "326899109513011756995862753231193478723114246336082392308214181273112126881", + "21599711748797254989207108046977874436425859822146104148381410251216892766416", + "4801349866375335173289265243677780019445351052028447809305464229839535867723", + "14155733033291624452674783678844450106798515225633669031829757876654937709468", + "6249525168453913775215814309255487077884826362528424439922890888603955052499", + "14928369633463338040897134982481546746234350670771618196847518086862393490357", + "9125617238450534926549876296505645845116172794938106232962454586773357787390", + "17103886312678741706528259762965004480595318892735191450742885850881411200483", + "9561133527164819548073730465187187729026229121272078865756229410363525806403", + "15499339092812475393717971205752228601033972883632736148845868837711619810573", + "4039978125105304479934956398755842410107811106124175538862554473225969256475", + "2947887467809254352800319275622693352512539235808226814612313636217910816213", + "10793550355337981917672616521499626144068251539193270238994640132315408061844", + "15282024117559604646251556024222379207458577842775127240432856222129525583388", + "4938487600404790095807201685235688647996095712925228362099985579653367819830", + "1580271313232748704254579894100134003454608977989565849293374431242287188203", + "17650488790850180925611249978112046323146336603695505846749648092705166179072", + "6318477650409317961441518371381185077182540555690253948041195660104038462403", + "18703841587534276582593528858657361438697750302064291203982535124189673569022", + "6570410039872146139634976314211122538651252189045191357367613723647837080131", + "4058984348953256905202616995215664252962770887032362374636631606975462596559", + "18730155671005907941866324013560951043352315199408210078231145351355402093830", + "9651860366009425828519962206873795166909640005109793700260660519169015873934", + "5838396248515026677336009419348618624164637668061855829375740686597759055073", + "15333954343347884216807246400300286008899152705372200767215516907035196412750", + "1930765848863686695612705389177613542562429368163669004940380022708446841540", + "10766617427881894379670242247746203663519351900247145805786260703840625869300", + "5568751333625760749025074267385171935854368145626703295693077672484816860148", + "1572988267140272358245681202814159120843671145631424724491020423275325461878", + "19938390788588115516825752214441323822601991108943527563767657270216212171610", + "7571912702211887911260059806577378242621772456912160075153794388926572849145", + "6858979093205494695976875629144179789647553123886814202229119872013338208712", + "18762692183810081055439753242004382629435200839335768813270546391733006575124", + "15741259924712306779754554541398522471185852133913466875986860727321229948852", + "2627808396704584386154002253183040546217470699174068260518444240974395718442", + "13588659892026426409480708338634242111974891480475426278869635762077927444692", + "19520457627758833811699878500944809253730386938893290068023237193482219846683", + "8924178241223608091232956607418048641173985923478293687667819226283386788940", + "5816806026738575389886097663948769844875803508574710698349454181988557080269", + "12475579687915690911104520027833630083645170013159764349224529153441972577879", + "21056333315327274333873056478119184274531121536034759580035646721078602460263", + "21444457911856423029054975409869505918084415765420838103204937942386934191806", + "9510785855264774762445687543927870120017463057252636764104600528992946593471", + "20924833468200564542464376523632289762564405387275694375761127017107713239560", + "10520571364539530696429244627292574117914912315372596265076914837029323332385", + "15676633242665585964368692080238475248556973102970746891067091503318954352189", + "7605218463440663468653884707661331637891252539306862971462289235362996643878", + "8655416175027898012639173297596079731611447754405890380300192905812736625807", + "6587158966606269464624627411770696301475420343587060761712532930272301692115", + "17855802086555955087208003626983743721607218545075932831175321330674668519051", + "19637270878895908891611772385398729322367589125936403809351999767233932966110", + "13844120079506591315671522711954211929776840478156307979285069853392230439385", + "3896487627666829488959793133071741228529962458688538373863209568407375861949", + "8072922412250331052234441827200394762964253395032633720559799911487619573310", + "3446650687448682504274462997312106041057536787701884723175991150707212663201", + "6750980474265223706441237350209360446038939446132826129894534048737231433466", + "7932667749655660682554204871450377554998925079055538597319130615505233358592", + "4551937123821223485620220711817547511116227596903370212234130807711068597972", + "8450248183513826743946014093205824327880033986070570398677443659142729011179", + "20523087403588105156975104084680617581362696346833272310988747947340344564064", + "8021873326844086700417206574915335220587232800373998588094532336448721297757", + "21537680614486477925570839538957839593006098192503694567393749587557940631967", + "16568393458463797316294547173419555682646841229029462217197639056287054602566", + "16910235738263410812877183305130636228751042299094737782744154576712268208807", + "5629150734321853465674510845327410940323442617216962413835214171701329559576", + "12765131184498380847448550948920304867469527623961001350816744753387093810315", + "9954645632746218155245325585480173993199044803581756137160936155060542951690", + "4353999640943599221118281386228426498583991413938542575297776232303344359940", + "4598711079993417664489400987736110506328223791894077517963275447468098340703", + "17317745377506102303500052440899062192892945727209124468437255966617200532771", + "12259326473392165107331141130100680225887121989921120777667514143912156322366", + "11811238683014115897858309619999599808008425203222607881921631505596453270838", + "16699081706307776306233318220897168744889069844294482997417168581249408879966", + "2568026780472621467236485312283731374848886964214142251868040165224695316461", + "14887991441574434999687627633546581501365901473545173785249018184685706196387", + "3569299155477721143892535842178855295807355615071744617918410766174933059043", + "5498879700681283951662042539400107058426136148099967700430316029080607629654", + "11559660278391175834668360323261696294263059777402960440249595574565141656556", + "2245933817469402341452987887837905070237745132811239554297372991710914298182", + "16951354954717164970902473060335333600574402706601527686301478774700332367102", + "21515931335312240603168050753263038826093559960430063520103206567658032925825", + "1249411708644964091210440756030782120444589186855809089574669034358018078687", + "5918980335509160299664261285796224662727132279493574691223062837411060350013", + "17739377184579332650035245294019601185834503109963479023132769460626331642282", + "18469744224495747473457470133545294362819142862108342977835066995529981406258", + "5759336781416534390511113561800934668877971293662332789437681884454072500101", + "21332416097583521698710421619829192185814871724795352151990455290564854827164", + "14991738373834450996520664429440490206770501447625984036209559286781489862494", + "2292383959319987392245961291693765909376521855421393945872334290076611679644", + "20271880109317422113691100242542434637543023179088091376781918851828907851136", + "16343203714510839250939280610780086672320399980775100100207359519193914733737", + "19668001496569040779289443981105684833630116796777138243208746501411413314400", + "14867270521039301446053304216390047301289545979306959364422905455339336587211", + "9929001722154986846461251622116577110986506194975595510541659282347340459331", + "2420696236635890839197290329114608036709859071844599545644710485458818798726", + "7023164250260724184662962208964026963022579890290101367655364067452762770181", + "20508512038053113727358039673385440054337319672353371627416928672143778575477", + "824002554707189532054522614675201805472052085843409216867120989167259938133", + "8081396930643908204119214488991799751072819763127464506132047127093449268743", + "6146669896192112367311424975035875525640347544666981144388229137148737996133", + "13917552221424458749711502489369248582964839439204214559672563587245770000377", + "8550914481815010035465313609214308578203171728075688232687655725801893823141", + "17861710896808118014581828397113186358973121215643160735097781787683890541230", + "15595160929818874035046864313228963482705740989418337036962890306288699599497", + "19810339910854592376336564454416808551332919752503671392907063850461349060479", + "14234414635213293332305234819580453743707554476430770368421971402668862484872", + "19388187253394163585379147543203559718098061800153070411989058669962446974654", + "9996031022330018431773704931033232677865134703871368350999928908636869707277", + "4533799599412452199761684722747577946145532223581271248962115254510905734009", + "21793143524581931493773122340799146504825838409926910431529124937257399233338", + "19692292712401787423885461139555179726227035221831860547833110141089023723875", + "15361825934066824966062130821388513267446230286103312548685290096230989843672", + "5736434899097417592114701714539404395501559559582922276628268708302331297718", + "6034516841645751575815362526363553327142008775019507199148571280847313939846", + "3103941851061425456578524836013350351780973108926423482048781831843642166611", + "5899337062497322191697133509006899741055733585263214548357752956989422491317", + "963781557317112122222004641921550021210279319264222273713987285679221730138", + "12218612067667826360750451807845242059538814081271178077944945859470451709133", + "19859087159769083790343803575983864397266266537354870798907672197319357964101", + "19984410602577911276019354715470427122599274838994470055478829965861962241047", + "1510088699001180548764185585999030426586790568209473093795384481408826277110", + "6626530934788897049551186952232009297818099583639020036000874279734503731588", + "11102385732315753875246033828526944990963999730005798544082045825035822583016", + "6109966799003077547022556221879889867437672084424732190493586606121191686895", + "11639465666095459063122039730377449150155515188121884615987948657973378713177", + "5087119226269603720517452201720024842953062937909041658414079638720935374157", + "14200979596305023031605438052846373683912540635435718213758112152603438068044", + "10504614528473632996392119937661213820553616805799536317962705212982659337252", + "16896136248461578519387122861681641687612480673542507251813953270071486348436", + "19381803511891750827107737252264239897475475490344583112691529084617905175082", + "17541407330179013144706644068775388402691308134663811736351559302382670708984", + "15072973642203756087665519422382641458207399650896006837784917038035882610771", + "2308847250281515017414251485377760361489324048295236605725148595795546323946", + "12235376578863551481515043248404435233298457594750687771966106520323367004722", + "234919702386651406701334351738513931283772159856053034152613436560637774413", + "21637694258900941342752268794989465303386552780774074413553118735507317693719", + "5017784917192017182377763628730148212610872485218540677293490321169201123948", + "770314504054605850178900177028157853527192178178763005605945816624700149604", + "15876814891128030074112970202145286137873841691080700504603122203177789175573", + "21396093758862368540558980838454280107203592525118989209906020509719986520353", + "12395505038782995420136281017345429633379095201006284425785781752730355509942", + "4615582568807690433357570528319145785065741006112040062899881545600179737110", + "8043772689074175830138340191606864001269151441770005593654367646112660385954", + "5087060495541107066427394344208368671085864351635929517190622637786924485857", + "16943670806889779731197043466545390303516518769717829999301840370920339407796", + "13534112488771797914884729261168139500575711545907958816183168317604824618336", + "16825197446319806977233945546803116869802796446301133858223973227155555550786", + "415637162126135168159032709770391274308945193836031409779140830879628784155", + "18387406758235678040900363524694503366739497074863830200933011303909731885356", + "11179137042211084753827842203552443809484306307318317082624519139125401844623", + "21558283039234113122805760097265638181763687038555764258857715920818106215523", + "984886258318300688046776785673289560458722425831829175079944141959971496951", + "15742677322520864401961943379313620949320295584851281667782848443614715444083", + "4674404119733957791400958869998857022224647524150794463860851329191601384751", + "8650727403827795422786989886519743572356271096745868930429292580249174286422", + "13805664248894834838953946033892670782284990791974158822573815009987148935892", + "16425836039758852245186956621689031634149287919733928973102442742483370034636", + "12636984265967190523588079564146349074168180793368546716527682276529007569774", + "6817261026014072560057398041777830163991050944713581458081292224492038152943", + "3842591846766588833800550804121369117907947886204778461433916219752157723658", + "37271592202861207450496704231110333036724082963271323982767766566562691532", + "12329580473492550135339911865680237906360631219143722403158320079104416996484", + "15059957190605121115530324002634619045808465757564252411076061916764353063726", + "11049964099753534691591813062197785153610766318641253048434615460367998657091", + "9547664187984679827610628603629867733891345475510185082362431432235944303887", + "18137012162384412674879864487567137486356542869085283721914855801046173331814", + "3685098687651674532509991642879131752314328195366675630043049707942891170584", + "4350994188192128309646975341689829464702598370274816402210557114155641708487", + "6257821888636845714306847817710237763041012260573089876542080703522920377274", + "13253018959425522927774577647502632317700972755867567550168937147898302735178", + "16128520328840705715994832968486859989808820923410546017533359121760378044520", + "20170678152633918405966535017048153387865751946705242558406886703664743352398", + "3126527212972403378701842254033672681067914451311377332339121677604578433846", + "6867262232134903047018643171960682024396916574079628095990181177262447593546", + "5158367668931323144529189475506903329651812153505452886267986731006143844385", + "12754662355373887343223103245500264953264637968818954284520990187567577818296", + "8184207275666143481387081482876989547621596168672026673494737134509515879012", + "18182047594483210481213043235431614943690478827150601132558952379296218497290", + "4111619186005075315994626077421177613466749589414703176717884282581714875444", + "12594743600504910896656839099899310633582995354714016930508253088263104106919", + "5906863249972407611468323572776947701049556100204019241509444413033282677489", + "1980080210708070252092652836439362225685565242001269004929621280778029319218", + "5317272650834519781155258400716302959016815255066834148961703371077671280690", + "6755929511172704567967900822149236127789264783942356076752317952971695408598", + "756653592358533438118443361825151465623048518178327516109550024774438883797", + "13279387228067311574007940426672455425799739197632963751860641037826906383836", + "3438061374000905227745499451129047661964429059615559246017344409320261233525", + "7182178722730387940200728260680152279805701386434851756285719594136478079342", + "3232238101879637288089008409532896629862152604458430213480076264229233742462", + "18349073713456068979069801924492847615265826078935260207982474961526062084683", + "14669461622305417414928378093274931180941168738663334898025953986981156308555", + "21025953377099738424497295026970813014051167806216418684116056037559447904210", + "5255626714680656571286256248936450375168592101301691959500945926924371301668", + "17282802977887473307860913184523745285865757781571388182716814513918008763083", + "7631811346302144382630250446520799917692672405169780636309223495193617534466", + "20646156492067995141068212601070346054539051558428492870963989969028947901818", + "11672162857509134152068238052735772663152403666766041363264045356497052787977", + "11887096806532260110007600390059506485935624620297229185953255478078857108029", + "21264877166054737412301473554803422700628127592263555002579170780541880711583", + "17943121804479032447858025131006451946994591698842739992603829945304217132668", + "21741868983463662771047103688885133076855201341036000119862339617136906339944", + "1382607011220387511006322153920014038613273342046755883486188937618436917353", + "15178143370568504520122235741397126257210602740650018201900729283546561696689", + "19508797361068986472532319429763120919434246449052564653746851758275251767862", + "15432472447501574952637182729640656917161000067956855273526749406835661136043", + "3646314932117173966129769917469131878046956851972292537742853525040261895364", + "9954239280150263233476434487622548184763162539776975088510280448547072413987", + "2860206851873890237457963710655623849107446413141590367626845970849894602577", + "7624884329556925103103971646513913063945080531848229875878001163429377892391", + "13360943796731806773064110741074091445121635972973177327949717322801106153527", + "11667836424651042501953164038576384835169183507720986280095771344954386965055", + "11905856768069261907772799745883705412557691028383268959241049562161180720782", + "12186322648958524087383458213507970038354441682650936942717890758775537576715", + "6206377886698888214976033056004148608870783801657981445534961772175420895794", + "9985786843211942401460306610504559890644549482837388550821870421722527522129", + "7131871091468632512858311810874313071133138864883788963707243539301333044473", + "6863753977467122978046292703800221264317404999280683794261458513920582107611", + "21254007028585610870255249088819596192746568962023826736493046170403367390748", + "19316740566828302369845437096994220205932229807972164794086423967490376053120", + "20911390901671963410235703071566058542087894960862283015326592608742412435513", + "10947283094344459246570251013404575174415295611564471102942451430110207789270", + "6629514866202977686466275098623310374411361176607669574816969946802287210730", + "4306637640746831336889157874035984930432037257905593217438853767758187627966", + "17842812026941818985973284751293083233650807309923063938909281923223690155081", + "20979787799837328650256681706033358558090809594843147876018416522952145532570", + "1084395234163143750754914936597532036526030294466367212427999310133490427432", + "16411000398229165199635990982959651490150157098065257264356189234661735382064", + "19529434083761568271396183578711196610141016284281861529889071952129275189455", + "16011589790708451889651677332030836112945970875991060135355201890489173794391", + "18538965510307116327958097310749618403759736800399477577603041239573656036369", + "575597941676167484590243546673541695594364334533047994047106268896055691965", + "10154888807896331879146339491538875786991737788606023861857914666322797287434", + "5751458975032524671409758081174846089867075271579936974413090425599016414105", + "20537352507069134091732836326103935751238399876923560688100837864640768370820", + "388393267636951339744357828936678047569934289925965154807382118853267759467", + "7988929055663996471299857775851374803891818939607048669296465149104280329338", + "15854279006908524023292733986043025770694447645646628114187722686173514956837", + "4521251106518907970739816189092928174098228189505033700492425014567434676545", + "8157530011801905607623371429913769514135441595931542848447134013030997901186", + "17210220909122096186649472888037140871466614174061205406900504999283153448361", + "8320732794514386532143557744115700882386234810376915665505736773284988176468", + "18545875500168811775790253714678031231209184655369087385271022571392488988409", + "1254781372250935292066700779746601577560528849791669968836092329802026798977", + "15937651643466826506099692353730922248216886908526960483039790489122416783291", + "19652922102341829730840072437940487297445121681514373922080785529489772301904", + "10503757973376634172224417598657275807288376059467419568957007645015644121173", + "21061128242218898797612547848348324784465891245956046422267179077655910293944", + "10184102990558905165359578703213338644155257878926023646496853865036973561949", + "8666994074867894594122739436332358585611317775525945925668413909058593367375", + "6295777974744736354234904948599345763309384248069989076851179466032501025536", + "20085880035576919555482594174603593248431976403050445801147514535176924689286", + "13336325268431575611445366940808804882241012554243123490613520755178670444338", + "2851570355537839451958385805591947257368741486463662868962800334058987150319", + "15338540229139367100976188303076834527818508966890772601613851240301217961568", + "10371461591548028790292642751110580057135152343433828303350260803216047518940", + "4721084162843564631441880187545375946421625038671651491284453281351611614059", + "3995968148066851603072141668595964652983129138292929197582737382184727007080", + "7098475965261931921667649758515107427024701354618287208328785191069896296466", + "4781012573672976409656547624587641549313089733225902702392506095387529662756", + "20670752440000061451737406274881546918677944716345491651236710839944182745380", + "12418063571138285842036790076814486174694060062447109012153384823149675212111", + "7811816758498775303698763826175925041786332617584902402713486064657610670887", + "12183449593956360154917192849776155473122126272381798975678273623416489913308", + "16618893942934404572687811463808390124523121286530811532642072424179325845074", + "19406638405969722482660214331214972298000686566522726077456272338753715959695", + "10114896891602590148908922343663289384078633766105057337614271468528428689648", + "12530180531394196901972330325311958484582015641092775027610123114239686805374", + "11041683014697540482690315932778449428117122302594146671576370088141482310955", + "1320027017053531867758788220662625751339386035447221928720928792758652779021", + "13527787960362675982060947767740337401799422304150087254060335221227857899395", + "13729174130954201937892395283664312766703232538508820386345658917013576288760", + "17930242209772558948222336463641867165312462566025913611385142785331060524930", + "271824668681816275326818116439977879809479607030794905583278884369947027319", + "21830554400118502077887728598392792929421142621825963621109394022313090676569", + "6549136256809735363529860847857612644334750418268339758975670928910634751983", + "7685854228210998769567354902455601859064733599194469796921674884534065104568", + "10199783250519025166562439623829544304874659364288345176426181874053651581987", + "5943875072296398061174787119165901172801385563744445220331957391085927545285", + "13636089974665970650510341064071559084615387545694695884611938887433039781695", + "15691183714733597776429523227229000727289026713809002490626629956876436864306", + "8559680887315082801378048339294171503207432568538176257628851229613536726966", + "18821447832687547445675145256777518497433117070692725937727249438327468662992", + "6902270693879104513901555672223877604634815519768564032457887408714154308149", + "12608804561676097764962511762420917859780577008987930524021637882085147011561", + "7174750477556160125005376833627217199860110410544187422988321767638233689286", + "8781965602133662570225157578692327961234407570869748187793896100695809894931", + "2495257954047729673944010345252038964921244093254482708244520480856454194795", + "12653575930477027537985334989917636556832984698125835912664116078189272484883", + "19470590483773048893847572401709923514063082100887826438398963400593333077944", + "11678017778870321267772215799288011478356485408686518093768970488464471570815", + "9301784115496434107640350077213193580405719087632828834385703690626291479546", + "16099421215741601628246289398699744194733547679841291314995675269636375173366", + "4867605962743281143953362108297759970476738545503236589613425112307423983682", + "4859206625232481008184446590986037965722621081800881620559019195768715084241", + "16443855645256733949926481287606183123363410685496841842812427755007713532892", + "9353805991413463049534222956121131872491808501219007024034024595326412518624", + "14757310122557726344690376086282772240920466622515316103858910465445116386412", + "16114284659120061956470765697027372797086020387576070056735297826889023849274", + "18127578981196629851526283391389653885301579188814495702848892722544020055239", + "19887508599212070022669423370158309019634146887428772891372609912344825709907", + "17077080577854056476313617926548386910187074435097123438936357029443634140037", + "13226301328255541197539849574625779242079524439809722670248005223174137129917", + "4960598616057280250789993806465640165902417481299684068727179165412382990160", + "1556369617946500605910052041338863524761596681612901076288655800401759143728", + "8895728155072279486251055328673751534060735340135019245331916382281698263288", + "2289316141803713796617375788451106287296998047295030310234564594074457471782", + "5743949466604344050156379807720583796608463915463812355649877415948657877907", + "4559156913695113135073666675680811432586708455776982064075705161369076248306", + "15885688417651643378493200422346595912547116850227590423936072108251702846077", + "21139883658951849592430718453383511736537035608453172046329191674046781461328", + "13189533415954149093943176775514655876533454488327933935436293535694805743518", + "17844001788757965004299951292259913492254300676101367510089343929865197748634", + "14359892033284780014175740986504899257072848573639227540808851637993574775227", + "6889876198036781721490463051636227217181360455045088258864933221139868422058", + "4553935378945711471651589030479778870996380701114996688086418055402491525866", + "21810472237273957206786186837441232294905360772841197216403531161190353859134", + "9053152935239668672905478856994179206897589996100634932367989982680043213185", + "7903591118665286176079138425128951407213501136276774569998580497121699548452", + "3172076359801796733031209099819054888498110723937314354878294115265190182330", + "20407097360746745587552307442773353270033615342704398250066232913190814364080", + "7972160291863108260254701271534596191348694866685225653124288422099219831356", + "2512979638327596184144169725891221385374685508088897591186666227523755823449", + "12288114406943148383409449156486826621388266177895423682705260002640229785204", + "2564780208026103504658010005943517057775957652807715289383367743075323562762", + "1819044074894043026843741029300477751989386054356309111356865205713103547767", + "15212165170979376853314159201892286112393022743512259361106527770911103031833", + "14546339564581115494538806968483958415473632518920533358183015375037245948160", + "16595063968058690402196826920205083730698910363019110917303832709685137640608", + "15141874678776355759677532828036793885858184118820760885539425739465598163481", + "18904695587436094037528024957965408339655627593105121455062940021234808627517", + "19691835186381553427610210595631576698057108693742599090126967830113381498354", + "8924094782966746617987215970302687574282302360164926405994916025579749820763", + "19703754039872652879247596753980834118500205932499483040527802680246732547089", + "1222369520366776525212393255592594259431640497623436777492426726914294313696", + "3172344047869282929514752164510333501174713324035401216632890990510873753170", + "20343327187307675920101255252384731549311614062918830229591450503470004905005", + "21822953127524319865522817898285572788301109254914611303940997016471607290917", + "4119200650145180459943542547991468255860361677520024595215679941381226516262", + "884147971363709313208000703986053560492302821976778288962675801741886201394", + "14179192339259619376051698338290832703239802203346051877647263334899616811424", + "6257894125748014033621520751032796530871364895580315426488126143829369988797", + "17601756798422918594467038792255913560794153830062518652267418453154739852356", + "2915639491551461190644833247357672612074490352906156209159755564104341441334", + "3231102949049971084860869512445280179160209744399934744399854930563348405672", + "13021414206859086129077179016730508855909534243359809624497206694614763740073", + "19605385510680022189244399663099114503798708854480688481468264949015383978657", + "17021346162472827600023529413773560471771827295900312703532075252918830714763", + "797420759229039341104668808766016498233266139304135256309887013677831743527", + "2664903618363391534009727112222679446988960947334573306133164042707563086517", + "3385549618192271440433411525547058485954511711526716925876581944420956285378", + "1363918352372003902477247159358100870270143261694504161661979865477181878601", + "17725129391688775312434400553484246750421349715293800612810825705415551685950", + "5565167518043825254697387383458520114240098359236753821784350172714709788630", + "12992626143189731743865280272360549263209967124441767673953882659571766635538", + "11778225061486552005541072536540594809710403539663018251279263069564781285228", + "14855802626429861561613008610208237167206379805668816510881008293269978954622", + "4625126357862179281586979391899300109486628847801168774082540966299465334987", + "6276441096446918387723860737716070503136385106381280295004924708881687527278", + "1795411699207968753627657631153296652726915050129212264930465577194539027180", + "3713335398598470745490569816543380122933539387356971485299483223125101783622", + "8168117481656071903083355331291793306622574934522412245021942135108094609781", + "2572110912790333345146174163319527254651486901580412685997510630243717870169", + "7025592394229454054105021012166569277499787182283497117950324822835039311263", + "4277841334216388876550672363276475272389275617444687843049115977026804420380", + "13307361877516070836117482544809649307840244674059174145753388549462990581425", + "3541353704173386321602971434547681828071166901335602064587889348895191485268", + "7930538155879758019336102161941128485659185437630747910453735785539584502699", + "16450196550849346986145420593545138121140944184099182530791513972233505276989", + "20317647049317277971067996601837330680914292615460278222929651175763284855258", + "12350794170306113031197271161768360871903372891508108500893141893703359009096", + "3619108225491731892480788907918892224372271737626523316019551923666189881560", + "7777524276793695474644184635794903798228263960698425657257115554422141857963", + "13186962355302544705310483262369096768297692231774754772442065918802639434148", + "3194922763633786447595049582526939577788731446948460263029416154575517633713", + "21764951733983707370163229447076318279945301269175491715317016754083795809766", + "16974123712053830964644120202072593533882217585039161631414357628477067270637", + "7898037946204257594215947941255236785530939710112474014338432350690918260891", + "13624131700578417700359325726622999876995826287578399131977467236788609909029", + "711696429159123395134741628515974061981015372797792603239801873522576934606", + "4454694656802154477610657384658122890655367951456133773797632953453271645583", + "11258512209244601689743240316900203988033840864814099786180897714348264963892", + "17104789493255338246571119977680210285205025930099647162805883642403493155704", + "2453935444829235217884190831569908545427042660161097975703593935054598308172", + "14865321440470518031331143407868649683664573698762400527582797926467679386433", + "2136979677653477082590579842429661891149048368379361009535231454875783700576", + "4168503404348819959713764969732410335826536398112246387116198899646877476352", + "14962916637001251079646555121263487095246900845890500033998976380566908488027", + "17784806976263484298477702017969482877962979780736193065620735094916915015057", + "5811232683701857296108715612406368550641241305997590112572736833619623657335", + "1137391750177492513773516911880446733365510948924761786959001414998578780190", + "10377533661461362184186134231677823404558478220398261395966741229154302153880", + "18289640374707184240721457180013244890344288557498104400868875166742835064845", + "9860550380532355283228261241815983394260110595913388936133793178666677861361", + "4874241362571018447675014656968369345960496639223360836208429603461250621707", + "16865415500549523957415217905648921092860879005547743663493860402980518775170", + "18108918097362824701832555936428153547583210042204293837516231255476913995307", + "5814882735302537469013996470647050035634690283351899637246825700230993102653", + "5547108529079575186420571231950116618134926722630598104799502651040507258925", + "15206849009490203249915056590647669409740170384956300636367240071539934234123", + "1640644832819090575801198338202018591671247888384450305015978486631872758131", + "7653538136953954504326423293731449069773903668694073045541918594328126765475", + "15742666466329712178554069131786945235650635594806638864788722339397338233904", + "11117991054142148551955400250530241420008368948211075786946321189997485480110", + "17233487593470788370048183367208371204821743424889641470669677410605695176177", + "1026146833779113517033720464553035587620506307190537032842523110750653300409", + "10367733177218458884804949015952210383318098385156812709591442491050289560766", + "19795952047370883108661392932328291359892331001341014799939338429402797554384", + "280679929395977649114582242142346138466205172264485418126097892277002431011", + "11242092785741474644852794535567939603118987148698147008638503870866024069513", + "5042585848515676287159684547630780418802525904631814404423696800729724702441", + "18076295265515176256373769387621576799326851284582393083567912446445089657195", + "7379637951216509909219158222610656534687563904425133806818053082443647546922", + "3558112975941340025714332950698945379582897448619066846171473836063116876320", + "9573479360636272045463430387538379484130343682411115582933078720270296582700", + "15319039730033276973173680817870390182683166144884901717164880903880948070156", + "12614337451840522588925552004159363860236857822744920028925848657320885223697", + "11264872143423037953370674414336573063122101340016831919048747444897009600345", + "63551039484071672399844495086043200468124594386399597718753671627443264469", + "16482682562437246084957175194240509231216838776265462897558195414149416246757", + "13173166853778783824789219649923900522843999506901247221151336885046420684780", + "1129677032059045391430942335190974518204360360119509444502890845544005628775", + "20501934327919041700769005911882447290880962332107224642437572131655999551570", + "8568499318929533224876840771639984749494220751421895884374508523238084517848", + "21259500369117112858046793730986192593905655365067722159200063822227414197523", + "18511737784245858621248028192284641888665848600116211193811323135518967443130", + "18603594203971848110309624617834986072777858306337940642153570206399896731227", + "10817810567854821052648176407774626914880746517118466269332776843576340211709", + "11799868341887426863553231699803195039814149532556595741528976577115279703638", + "3757945008672794110380903983621818494776340526769633536295923729698796873418", + "21147309772231799704776665377393022398575359474581992532654566514687692622381", + "10106161080097685505341186856462439849936096425798398803226308955853233801088", + "14262263816750661321610690116851316864336319623922717953366014185440110799541", + "15141933436196205178645622716666344645155868155385407285733185900575537844179", + "2528094772114073897461542081006497820213677180486542945691028610950494870091", + "5348148742466995347556247741747876445951253226718284728036059196493410775291", + "9450763449774399387985728640759709076413273047954552646207186077905960887466", + "4298191617478880606290362740003112985908172107645583722035275913358222519724", + "17030410720819419348097350980058866817562528502379090451415524440163140111041", + "20216724013881673832814480585345314476760112405406761404693215284600396014822", + "3030458477787500523997196317647453871345579139634715247165773460115609582330", + "4498462169050723804654682081938858063245557243640516301148855502903911071559", + "21824371776439248570562107317467644300343374167209593758174011062336014366712", + "203060629973198497909844961226448148781283822023116446785885526153889141133", + "13138719392503582101372758211337939905779727766832919837180755391232674501632", + "20854865022095468190800800251894006373048202378274232848293926367900444699099", + "18588694216199791340977948229034824338778108765317256872571104367383806683819", + "2107723674718153039822163382990954569558924075626979445723435572951885590282", + "17271751087973139804430243764301653129405836972234862722312699991367221547648", + "6601353498913454241063626951167220829716071681800808284181512008975791453478", + "12008446685921630692928691914657961114819560167122558958661337441533504934249", + "2546793791363939452366278657165405700949349144309147725354170056455546924821", + "7509639228703028871971491982924543490428017835786144030628769546327315651842", + "7823420836979374535855612407590511724416995784427817183396908887631615569374", + "14440328435891567217327191606342183091806515070572157964854472183381142306857", + "13108790694241576486381404587677845524627865147145072471473988738194261674445", + "19983383938241398968439231728950534655853676209193309061102635732967764422018", + "11284194381233971884183176274626185331731276627680969047259362251065411330490", + "1897088360814614813239622717000987185543144416227464749796311263447835372290", + "5857538086726776983838909617047765193294143035705320425608254315461849915283", + "4535962484854275896801499258204616949002112470323390523101255172552516276853", + "11469688959565470671946358524828946654780293319597759366277869041848383938506", + "20012499472065515722935879215306365340460493343044867272369823908813586319215", + "7237913775106599492643101364689422933623029044428357142837972864389129948204", + "4449045505867908852965142075471111990333999619831208332535528566178225482875", + "18979580728127588847832634342765381189070401746541099544183581604411319882119", + "19208895793797113211677254952138771238229741398313608749033216609457932026240", + "5693339887541566707818870620263679026120058867908674300592248504295030161683", + "5766336473322649734565794453161873006745293312886382597938223884039108263098", + "10170500372500319676592379791726967782477062446940064561124188934689788907641", + "10715178415744481025577257316838846623444784908902638764026977772991007652177", + "9619234464729169347469055561718306819745671419829947117176160764784203967441", + "1725396226859654685724455004555068750501182150139117204170589152838896682582", + "12812488682187532465982035305360477706619015575668642434536603051988822585780", + "11634913038840687277143479351580381035995147077852960651195662158592298943782", + "590921624537670966145684975359593307845422616174883518035926979611039297697", + "6994357700776589034911446516222866144704328090940819982199063011389928815878", + "3578735612848960352693685408184960756564585180098599373883079061082850989193", + "21635405933646037549623279995086014983969914199701848464885184930399308788578", + "12427020649229929152974948764411072254994310665316587507041988661972823471907", + "5659276116329803541059701770846868827421187991242679567541795719989019960482", + "14409569205409757172710837837486699395207656272569912916147975142886221411048", + "20174498258690846561506592709929532887311794985051466436061305284714705004116", + "16144749571419779339987554753326186342500618892721832987727063682036648217899", + "5806868382318732909919594488299463205875390466419224655308941273678069453955", + "10943981499006299439884803446608501609107021429051016441936415463311572940454", + "1924938839701254827227113595273674646757106690922839787536830436278569286096", + "13979276902289154914577571664895855335838520340557113744304695510562836235170", + "6432081587087260245919599999151100148827877257649626745290270317469081484560", + "5063153002404552050282559105432952932908381495673902142745313078991883601735", + "10740439837861405332126185761433228439796897508030224612484767505999462329793", + "12737167379130609027705740172196108812439282784347836729589408028420120550933", + "9849845512381592257963507051167559787679646439786540183276617129759373853388", + "16005888832870175950940829700448047001850581165998249926419521156267014986701", + "14353647838770412975928759605442634240665383526900174470441397150591603642336", + "9246400563934815769990941385821129793696094365581285133233487333862515377594", + "15148965960125250145435338272790355289745702742252704183388935133186551786499", + "16453015856957375440870560801879892220374643048047546023962049108638908959772", + "19594591292469468407344408128396176069613863801953800169935974455228391704047", + "4786494574332708919915792733222077450535137127349578261762663721149074161698", + "11960730258074073655703739602687794653921577208052039888289111813676118677358", + "9848013027466807250590439150605527564079804116846510943688041755058752584380", + "12899034273953092771018315472337883592076632199623658827592500124277160375343", + "7444799755957099892747756300128576168091670485463138298855357993349282405924", + "12078602067619785815908569606330383217651816461769668980367782310218465279082", + "13207091244585343533434026539671489949734093160191356902826819065281696899279", + "15052325250252549646358568907141836154046676521102037138442805194847473405285", + "2221581370746975227443137026410298234625504939466881398515488592571828181681", + "20243663867674839549278772384366563405687275170339456055149452630358919741102", + "9989690042997457961300135390803031791688603090074435089369924996763771804683", + "2394175383139107454721858241476296570939299158552117381451586030928104650195", + "14935488700038770608988697394320688627203362240444723637257364275046157727507", + "12264662514829291661352518974189445073203160920355111833291657311513159477694", + "3827639321249325764386581723986872585672536887010319153929792264348424272953", + "13487908627465024716967075008462681337662334712641104635432980395748705243220", + "2271300450003775887579228062020983806396606091928055215698274988642377017880", + "9536464905154879502929074042077088011040150301676217212058440880221802373843", + "11224187363394886568032176392622806663752975492652881881608898287407285044670", + "16348011463839183311989740909923102224397330137023072134870626410011917574109", + "658746784212845073728972419644775580738462236799285816112006815020578863053", + "10913847351958014923157235635013414182776322060119409210360083568773647202922", + "5174660898410477334415120015192903322111803813558785977142572971088703464181", + "13435625677277740540867428279095038525759637068783477185816475988654675258528", + "16042236961096516425577672868221946711334425239903980281947225696871186016946", + "5966732498522491800452631630164751678119619125003570554878083612603498334850", + "19244421524004466175382168721538493986709062021717633087544245374056859990844", + "8953835349510092921386508744116096000868233729683707705475555286120350297772", + "19400107730527891751069598685513048198266948717144299472180340676627124394816", + "1788315965311520067508595535605409766732846405132796308898593684888230118195", + "4155306741635339863500551353079678816173576578036039224848730508326156410064", + "314333752297483020587573946457568012126281776266668278461087690408622762890", + "5814056308990522321998868808930979798909264311720790843253044589964499450995", + "8139572664280730177398240130505806903517588262678422575082094265546418213115", + "5891945033023051894996849367995027817716659752927558196235762187145542665778", + "15816119508706283096011330636590931848201515685282376441014894443298875354927", + "19765585883129509218113831432898646175337020355613337867993568030797990428267", + "7571142440759701899321724284276618755088451471808734385481644938761653631281", + "21372154727662886563674173359368281518527052830463392775221052936073944196548", + "7081252182490962865977081179238366944226264513969472284114001831030270956045", + "5223967788855971504613125877205268444815856778995847146009869071113923642838", + "7616031404430100022715089975212311635761004286094499406826744277117238450802", + "2964922410519663416704982602737862878081135021433460716313695716253990013571", + "21452022130413843576926752262576843465698254258090353961686699256674273446998", + "5615506565720477707126907662373732333382367798591588442255590186949548315516", + "13758529852543878424689721858680184284389257236387722027067085472062441696813", + "12270911407050929770266474860904788952698196744336477194920983584641315683723", + "2263765921105974400584982144019036516750696376273595921030243162454245412438", + "3726743207790008961875115608784686494039367610419333613620227882409630379219", + "12237143845448219572451550465877077742264329541226110387544727976984528388742", + "2409964261853228751087973651622025781333933822306168735290950339250464395333", + "10085433407143766997440158468408095154887290417940533218330090781308733416929", + "21228510717137782368419571997756416328932321564657530623869061270948157027291", + "12056471592273332515153939599576024781202771932636795778229482480420755693571", + "18213366556788088673353762707270651486693693110301565439057413547158475404035", + "16502444929714671396753943873426599559613041594477504659253173973027014569781", + "15099656057998038622782214961934296168421711158711759920714280998215172598701", + "20662687648270300297638887955756931826210498273982273406811895752232434295545", + "11319823310823640550774639562916849455005127799420683680222546170719181512525", + "343967214752520057864245186069476394037815047607811439097329864410341714737", + "17503305564468603693734885462989691651193248463782636796950758256530838277067", + "12741605036457271400687978857670758064474033476970216981099556950125969853613", + "20739683061558313403494347679816765721522415874620086168947803143944678465016", + "7946584883804172227025447539224245968128890222556746649628342784345139347190", + "8360187202053456670989734732945943173170474770371603015342370151451116337951", + "20059356712109588518115933733238896878411826141623495434229710888297572857371", + "8908929255369499016159063161703140212756115979036668550222341666828086389886", + "17260316215848220480068274186000229981635360232751196604952216075987952224195", + "16051483806631795891066047812303438046492064609198644392699337542232076970683", + "13616797129917979734082711158569544985901822934952385632710806021914842733604", + "7121878885265063724099916056725320671644022545379534508159519935129387437912", + "5095784041111849236518098036393508072376638346067943869740820917637881991288", + "15064740101319510049989912367011238454044423307266600930402588789041306100213", + "12407265211081220177754043474825255990635653794940031741483370307852381609406", + "20223426484470923566833281385864037127075416246760538371032215131656571722149", + "3668052915108225265616930005001596789890471435407321351170819088999432868806", + "11366073886283256473381607209905269811061951337531274662130606966429881340996", + "12582247379355857288799702955077607346019480970920005735329811307693949234935", + "20186938619235157734865577521404397515633405422805778974853873925656656294650", + "16122019959033821849412382360062366364664833933984337294691025029563985515365", + "254648902211450148074737989547563835748091091484232032343713819397130138530", + "12172833228273710344765296926585753189586602769025493553315361303084014018635", + "19945409419975886341220734130071717017479702410716315294907303154809664173135", + "20712004789058289094102947689666173023011192678139675809444116843756511650735", + "21105077263104009643989508074340105423304108979860049556255519287288188396634", + "3538342015671194745411221642090452794460666099501316339752121561502241774127", + "16008085602703591565147288064897579335322875565262127586367715180903703479852", + "21422197449727241817827580893411034314307602976542729347805156844487333432241", + "18799547353759539084890273894754702756999055145524208124647385295339036997359", + "6376647829380850860365386439681035038162788714588766405462355210239582784337", + "15847703763893026451216792359491847622491103863033823028942752373064363683711", + "21753518314824757010443592444509359716445873322887601064788806456493419038035", + "8018616956493930393966420225569393035642655431019891986498475494315186954398", + "11747316959744110931059298678334515105505609504722662598929370282308351440074", + "17893257331206244838570586905501874457956496735362457086282197258342214145307", + "15961328802051806619901962582575367866289226289028087772591680471434203677570", + "3236169926687880505076444874746358996739587258202752103445199991661738621601", + "187795190351727293099714304116924667408668969503996281039583636956966649638", + "239392318624502435385014551926381415338676314268675338353695671324466753801", + "18674319341781941734600473869568608233805776945980535084119278717005726916471", + "2771345443147472606857365655976656180452504182686204076714773790025740827296", + "19450913042313320002652706987083488807755986380163327474873550819278969177372", + "17088122609555961904069874590098938791545854926952758736324719542173158272235", + "4614324608780439388145100049836115973615823562529414178724078049067318464093", + "480346578559945500918475024651677711916332481019644166207062710283884336501", + "3976896258432286534710425248577923525874780501683135711905396303214796569813", + "19747713021879142821191045416534012039092734284665942138998895512844748934520", + "18114341948852128544591474427791645861453096798290403362024577582905309063343", + "16389740922636415377645046847550552757683160597807953014971200028725848855677", + "14347956677754622309732029695580580261895229653511993172444407254733241454730", + "7001790022045736128714608604018732713668075078108360908557371520612055210303", + "19272993806385013542500911534969336370461053778032527920746797814743961064937", + "20666992739220376856615766377753030050985727426420972006419425641580077380709", + "18907720165776367637548948232402401955322000052328805042740522159109944714138", + "9414327783699575006459158047005978347088459439117502202158387157394567126641", + "1092342932834424845294743018087259301897007735031966382725140810717192908054", + "3953337326499755715834998572085254989073834902724154050737740470058759118498", + "11743581671122680453195477167432558941219274023697487318378655108983631999472", + "14292519320039108746758578387893135567048390166844266988895150640926606231575", + "3463895766707893138928153619402823425980920627031760477180165727285868840115", + "17329024693549080975670914737054013479227561926835421032215803061920086593805", + "17069029917639740020306921281456148921331852897276386771126788265397483239836", + "17757973687563632162101087414879272203562112761746273122681647748208587693311", + "4657037101807059847480820087972588696422739806756490960821623277361176723008", + "10031688077390763868641078069309072895683953752120759377432369407780311740458", + "13372959422785941027234359900894463458148714364727687916236363488102034358213", + "21074689968655856473305620806477766182958744184789493409758269023421704332636", + "19863757339575916461434905195916835719746715041076078424686010055572742030617", + "20973060471220514134365115793881078818914475917880454352814198678201263612788", + "20786322802664930407040804724442246307149058272537433665345242730163006184858", + "13503324543441706240017837835235888103455201530371938269103987765298019164241", + "21516545371414182695629550949358554432241582789246093981854557932438611855051", + "4189468076924692882857105215398697213714749255613940842113064700527656187139", + "6356916718613787191898160559615069566270314091650855868585425220261360364619", + "5420879043826588690498755027108627480358930425000012254678542105050717051191", + "20559290756493460657385989162478253178529811977588548661414171937311774738356", + "7472237964286313816282734103247675024752524054147218881654824853569171740182", + "5587656354563280475935968622322500135733558246449238814064790207486002634312", + "10477445403396666334274248654801801931117602962284736619479124362799824273546", + "6964581565574090633894249931196779138063582556737680018364077690424381812379", + "14818621060919997284977287223747030674994127751231587714382341838934955054844", + "1561884120897562502024552266455149126373072574485245753929487036177604271779", + "15924114719216774839217247278498830109576711552882853826759218581616445364187", + "4632899269214938328686734061038562662617634605056083586217293196683107383226", + "414275447940334199421265067114189311498845927325050140106659496782723706629", + "5919841635132642392689439793932385370460582843320887853171556097049171723480", + "18213825499960993231734509662843099396992046367870190109129172304011496568015", + "19071949566664135927732333412944575018103341781608323568493744120181505633727", + "8055738556659889630969832748361502052460816679489752687851823555653740856922", + "18552532582629910542384644188750599556440125083583835015670173118025699825513", + "2484657787081400262201491424080522833403834349414361745080712757081157295905", + "16983418852456608800545535696543676988540233741050842886180695807863040864765", + "4238493546779457743228884918170815223308340385056120983013226844661472349292", + "3630132677030524902934720712211822367613329466140887879132884750998038269473", + "21054939309368014542663397737839771438999660373085660928983975055849174262524", + "7764728564558131555197022370274162477498111431299751237388301945333560774986", + "3593305607441900907267751550709584072658973999555174092879673804077111387503", + "932359123290353753331737736031582956463161520044366983625790109891741693526", + "4731952008769040870131753442142911445224559732127188801247458162044777478911", + "1306090977867005427161468095288389390649620350907397989639122170049060845154", + "7759081335204598570892984361955322222987825766180300022358547686895179745422", + "6447993445251075592811527795404536687284747599271434406060192746881971850885", + "8266912047004162765439491557705745929139857757706428454484671294796825044391", + "1314461175505921794571050454800604608649221187723852105188152934159567388084", + "5074821468464653205102869421665358795805465509804176663850666382476895922210", + "587081217806702661903500809062925367993834792468594461022841500167739579474", + "5264606314717935678144297576598053656417231843504500779254542039497862460981", + "1236480134248818593225404950925034920588295884010411301784531216110810413323", + "13089489778236095768305861425107967360517148121020346060932975978601131790499", + "17291786821946523371971061686693758035121148041300868933078085040228288669056", + "18124176342257558638062889896829524322479803409217207498687844328613679520644", + "9905839015283285144616603221521153361618378103985458187286841556656656429741", + "11809535677454857598311615002421831170743476213662971184893106000202355262469", + "4105258996829645758179809917480600473288889890938687299484408634005613929027", + "7249994723657380623014328438319457303659016324967581867420756005957067258456", + "8317023308476962783876206275099298475926201657427120954368652120829272222159", + "2011843005377857984465704450777581623363347938947142463422784260490016214095", + "6478487501062645568595261797056495837204909062128557523543545066559983302854", + "11332891765024246297067848612322823673574497640669814572890785705324624377152", + "11310396674827683007586339726668223579107272179969446205517750064367092175748", + "11099104200525710724155767594487158698174345291601467682384866473391802992487", + "9363361473795780293736671173763300702046469200956940247194666073284271734887", + "15151887186592767507545683753579108698447339021705506097120199743211891524973", + "19881265730819081878858384565138117903272592569639633426872725304622695029688", + "3011117599368717267651471428189462533336275598139751114483084233022831296797", + "17520576180525374756578417994075832591962992432186234756248866458711765589626", + "6155276852486738773749976144225301808688416984253808800735523464178476071704", + "8631372484444450448190767419844298467817852912545286035361602469665228507964", + "12205507917633391792796810613135648610406161967483463808645931187075958213927", + "18222453239521787308656394705559544583576244681888667325435264246411012699229", + "9033412577366915161372037999993563962295812571996632039862860993305238914757", + "19454897503553988644403623432258520403053811767663131188695520064462224816016", + "19817199370883464197796219716426529872878349643708961034403389904486407134637", + "21290720498988312226623568214384902017696056682729297309424737295532449054922", + "5006872489582777310304924776769064242968147807589802114955067857036564413999", + "16420397542367588392786684585727906891797023280517827697299749514608736021404", + "1300345640934139074405647472243803688216465663235066735522675025627248393466", + "15474333493788166084607018352361187159147026284793436327548632778313351493399", + "5141280817333171025837036045163967613491344199994520722703718097693724060240", + "1674845241197502896336080529694883486542569529162942594482168089081833468174", + "20749587232360151357799983517636847191215950040853109011833662933435613635469", + "21065338667581575565163875505871743203827212418043845343534420193848874866739", + "7051564661861006096495144384640210161011647325580302475305699820188085915761", + "1121065721208670659965039607998179107433568481023836429952089959263844401629", + "2114003185799450303041425285829091463889299614202766352631616657722513595953", + "3334382524507526203206024024777692800878664806770692329489928846721311223692", + "5349561335050661854855918228516028812586933810356904077294751460675531266141", + "5703041280392778021418588942391165300974701557007394123618062308100870196445", + "13673663050707034371520553032876769213055293448602317144467901970892454938354", + "5483873888673148302254721546416819014852587382013956934541598037319090821435", + "19318734450985860065269203041456593881321456849029001758521815811241052123018", + "12851330354839827372437628165464795441114428848058858241484775351172304561256", + "10041542640844175943995712334828870579034783871076347036534323366252583734600", + "3589445341963638025665117050103495399260947312205835568650192524332423143081", + "6240962307810325966231999724200767949498419326824465195783823947519631917688", + ], + vec![ + "21845584790817078371458083471368949437776490472877850604640045078191512294989", + "19653529167194186573342031346879012675435131167180408423801998487681049609228", + "2161640783454164110262374377277313793192503897274785966059544028153063342839", + "3054385704838408049711788708109646820127990212588286684954516786776077717445", + "16635301713639076283966918721405743045341739008997361549904617279107633739991", + "16225725689449395070421553385264743934675104858051374243666267106604469686859", + "13459300344588917210133884568970491767131781128923804903594902942358152425193", + "18076808066595657160589765822638228194586496301618971676220813553508533309824", + "15694780501519741286439086116053845024521602672078716577385749258673935540935", + "16872540725652861460604107748085417998883467929955001131816309200004825208678", + "18265717256656085201140362928095712147159090935193139243454994794524622317396", + "19947609676398163035598483882491861002323351300468831661031717096486749401185", + "7065348755377637300800426777670517297442798705186719592553630280930183590981", + "5932961695686545421777788171001317503890223201383043783424823453778021729657", + "2576876576710667081195577161905871971928185892200731156106299121736713352612", + "12555802030075275558510564984903031995058560722557285963258561359487710166944", + "6675427211912119210966904017515062933064977336124153512189140864737663166184", + "12222599141329943348111473622063042423140762381594560767061296463113725630598", + "10362975561623981137760844569177506781739504467939943515494131756563631401384", + "12107531632347826132438108083855485290921771214734424618157420540758495466114", + "3236413362865617508850894632024597913345632839215458268170009274560894755059", + "13269640842689962370480760671727240164372687082286848502921603339956981268889", + "8634391395282326489812410144806386699066840792624899435283359752045476380023", + "14222253145252965302168372301361324351891663598874510374220732501857922860417", + "8638897321585802770244834010345336579513350450350318876059595307827518698264", + "3865974821285567306249300995778666703191077355251395536574998983854299535502", + "7110975263857442529682465175399830853738223819847928136560110618272170902664", + "20747849667914457283564964533975989346418433637631755372433299771504842519646", + "8525337218586373689263383636693181730826089466845186214607593322372086164902", + "15284698092379128147447314807096025894174546974949762301780223877793581148749", + "7697267363768037767923915437621109821518467158489394234232803683407232938777", + "18552464418403713636184903318257896949762751716606049583572368219578636617127", + "8197992130246671682417102475937137101180310399693221498504232752936385287840", + "6267215711691005252092821645736755217101102985763928035625443919819600833817", + "17433952956528062441211440388577119958754746388457390005635829394680376947181", + "4412646415700345908595327060988016573431087490581498127967913815901104779675", + "15833191543444816612091389727640172975373200401937212078659643034429446372420", + "2496738022051529758808536908421531340554055955151436808600608028881270179985", + "18865821309368781007158439319264225124435320863391412688953283839208730853556", + "17356853444859379852104523062654303386446700475095103588258687890090805160214", + "13809314487709569674040696128771324530575306163394456992422515709961741509179", + "16441057642509466688507318755613056920894191930223829210993196564779122458374", + "13126203992288988176378067141418363395032818736472538500506274256104409609416", + "13787967697762688988712839398243982920760030565931489906532854488857802399817", + "19656786571615920765259702874045834039087950126970888730192726308970074475638", + "9496155930249199891836650339371004045437843955429376625371983436016490755144", + "6133650980214690439646563353939486183333374330790371938934927663849630407389", + "9878750392407472855744714788091164958447986838940220983459727015586370325700", + "17172636845539329981401043696407061375416986816086343858560846660524543673690", + "18266068074968659293646594793202575012585251834459743250538629833034512472364", + "88170009072279647351671114053985696295758726185186407584170034409102883821", + "7161623553009701438320582200845261728475099875569530553253147102879319777702", + "19053465421328592764143131116469165876378776722378567877265112443326967288533", + "15787821054928042708896412640384007326676625326396861263135967977164294783653", + "9615173323505112477217305395762776033870692647990635021315350642536385774258", + "10748585844981412663149047472971001536312431184916168605042111548221680655573", + "17193496554920138070905215774356694517155445370515924892481894322048517125340", + "20981027561373479728773182418686452188471940655764396684028110979140369006827", + "21262972686125563821794309741130556914165641373895499794098515843451753652777", + "17107658081493676403630365275304097003600155220274082934263833389505162130032", + "12511894931761241561787052333055670047472612011302194769826693935710455626001", + "17806912269440585736864672280987816575618315620498245554921738316327046304192", + "19545292022072695979212345737390709562681030627834519269858193519314537426533", + "7543800958185166098093959246645025070235714806654195385000743554473922936618", + "4625475082534149232161405731224600013881237737740742465433231001161153655617", + "12763413547514960206069967971684559703789391875445961922711624474020658766608", + "16881857439631059221437594346198587121133192812269921863116602807689099485795", + "3231850141984038920375478271531925025564375094627983241106994584163478821676", + "12025284448956248150398233143375971306100458475218939512492496426861431663478", + "4525425011555084029555870990647344303529266577387030581756537915893006804174", + "3795501990414375556011654275060518399449630146003978757203023617760680325709", + "4509128642188781738213513757207125341975604363824265606323571895455672910764", + "12203047758734592203615462366516348191118610129553686354997732038970187121007", + "13638687018405787761639420673973367506339916347486774445588648879776248875396", + "1480604348496719441038523415355764543336234934845679094037807499653490493865", + "10692361717579001228187212442602435054487474561573499974105521910665132275515", + "5007773285184019093586454921139763432640822738583548849737728483623941935472", + "14779176361271780821074929551122175132746249520990325894754727749064980218318", + "8810869743928256631039877155210471039332035226261305285283609913565228857800", + "18154173501970140404154140565370264376529820426626464552253141823874364956900", + "11656303509442573507998921894257944851336988233800378817636452696829680890350", + "17658875741559155615021995850723408238216088494443352771306394733637591342379", + "18902160612986281748775835015982844003483334222891067179969353562662106908838", + "21595310045201809412620701470963174488544609749637202383626402540041734306075", + "19479000691333638193560008307308022198954460138615126342769742031420251871629", + "2972632723219534905306782557604159867920608086253824361540409985645334537267", + "3847529854347283694984727631990010016411937091308711649053729266492176961919", + "2403423343103741792664345548178046472942690163193710191494177026621927723840", + "4715026270007766325068951713831542483223564562870257986931331836552507312912", + "10050946066792704139911540686518561899625455529845988837175998569612056291645", + "8462612443675205626907647847435181314299724037672159352834910195653278990554", + "21536131862603746518459731430650379927614037990254564979711500405913555717860", + "7888269140704212528047592848167567446827917489655456773861487833453406017069", + "1170377169572693438349285053961454675716678619265656860173330864613871015536", + "19621259602533287127007734174330694952187330430513568066156633937834027643682", + "17165866032840109673438683878903959007172818091757219456373859826178202458170", + "14933333727688891927411002006378277183547380244506194877231532901665762194033", + "9343867619319423527260818064767777717418825720619434299636538864535443951928", + "20583768764298760141290708372295636534035063275069820261065362331153347542719", + "2577125135040205550039517386386446603255535410845714513971957864613256569227", + "17000415305135911202592785659979381300200707282766529883690542305214226820231", + "12511346220893686853445962138128902612419766727072608028194026193211924059518", + "4149764657828794758957335209849218835702975200988138041342768571619211624011", + "12689460200478357229673533402655824055278729189265502524126586766684281271735", + "13400421547966647260602415862775725767930791927979420926402318903131836007467", + "2276424802663141757392692926366037451925020546827329479674513290273559843227", + "13207120510498253902527141512742067250437249796266587317279641215901655830896", + "11305234940211349140158920206630802129159533495623653407204084399910372957174", + "5497774303468738593952657049388763226915569613134333653497976925327612433620", + "11780989050042171707300156320134237383624870460000896361633114513125178671303", + "11197132624111031475729914540831613691695800675640925983729890209473799714664", + "16140443794881450163624886684327741887016098106725788249967592676372285999349", + "11051595327889397185166361039119529941213436445931880650633610124485963060123", + "4836646605031570157308209197698105249544981108702254887271797808619270080413", + "8209009069949005083422618473679185090070432230901987251869909206753231145136", + "16474909562767173375575972470108350369290532718799369728226238753027802729614", + "6086055204212098936385823679317209054285543683998660974885049732319143968166", + "15845663692001601094665565765687773803894441337616861842355695214969875896066", + "9098420601018427903226168857535773321796962623728010568581252061114961655465", + "14398020486027915166775907825392652502550084557499300430668649177321914768934", + "2529766650486869899750453189656713618464482405989854109458777379339220142554", + "10340604539765718682878802989600110179317791699890691229388614321680034249914", + "9878876288226000720310995235539201725902546228232202248134844052052896121876", + "15598631334601739991411156353640870142866768421111507060679644747315412727160", + "12476036027414150699365888926628033468852849122092016651897900659667567319806", + "20803031063635652861008057675598133287087428947752503544588637173888166669892", + "11219667600899420706469792543049361323110081262796605270588885844619718041942", + "9239500483618882938511561535687911499489200513580468310964041871852656042420", + "2295137860333409753273134561401486593645236761709753752653034489900637997862", + "513840239484316074257070195372896343613221099656421936676995152626965728304", + "1240423160571920455132480263739570027604064696559298170495781456216075158172", + "1000335770452092111597579881696386094005166181014081250146819592415429840281", + "17732477784640275643871498532120858657597895452427536145089468999578047484919", + "17170981021801009209909418054936322243367033572422755593175460758882664580508", + "10474002915893131225108722048498342055539813455822038310171605686332057287523", + "9603348396520941909404735719689357385027896452682306755794683717883589365434", + "13997990766251226080324180880591113480591220558468819674906322487254600879864", + "19165322589470665586312376362321121865643126447966933590462565164041476345514", + "15889877351963901365648141054999234691357421706029208812358207119735767519856", + "8668047067682657740038874191537478915165931784511538119786089297082841482372", + "17366185630903586492716760756481097015828466883331247688174482412238176387717", + "21876355395221655909209577718688727663428003322801196411166438189091863032706", + "8342495812890419318878301820827026193204690451839354912098079931173365213850", + "15887225707174335160711915570149252929623026695369026542224074924735308390993", + "6378295267974387238182583304654614405910401210077434367173120406371155400542", + "8599288341856208016511446109829802753279910611437057243892303163654271528710", + "14384569526991087242726852106274677884712683003324629101047489219988189168985", + "12554858483255821944447983588851327925753928086067377749529759729841684476442", + "1244202115364291386279329790002693224358694897412189477392486275482043163127", + "12995340746860271768506969399635216407185990298275348495956441603189500195767", + "183027008509741755078232756367286076025735908110463758323021771971495606238", + "3573731114015522988150416514182944755210001235963017910935079689853918043877", + "18230391763740278339288441222957881377176531304894832542129957275399074045651", + "5937391935832132177003018978899438941930145516233683431615177125757010459652", + "11430996404641585372503695535042106445550893936697962891622779166741655729488", + "9708207568505790825432073778606679121879367766370067169784170835562004694648", + "13398805456168802594406839007653458669253514721606724093311019328402863953525", + "9509172607193998955864433140854270981598209332315830561489225794322679022459", + "15502257451151630587420754221500874210427552449899109970701467342791400645333", + "11123898636843146818131986172543146864729611142704598768652657993190010179131", + "14756654073235850387277128827870550186598788932163678015197111219905127222330", + "2775596743802877046549055877116659535653734622828894792515801349479916697007", + "19393614735747455293764838818808226619563895886462373669050764399041257455003", + "1249320178045456927170274664240781660345447736835400684416240818258732622074", + "12796406917637014666646024992328239080230785967810042823382614274279812889313", + "8731150020101451449969760761271583792743252060005019647239509560664328018351", + "9933789898048906634037638211430912333233899173340437080629891912049447301727", + "7466451925704968193666093494894304477671721132981190905063657961063858961172", + "18149794038935586919422942907608353967008376245075544434132167909292547581560", + "2645338086907790474420268058095037943265764190369965623902938950146047558570", + "3805226260777608297922168382052882356808083423152211373837998107098065055539", + "4989302370880302660583716899846990066057960576662320219898456979014043515025", + "1070415851697739963236557454136444292508409566097266743684211383600964969141", + "12944245506579810779814853939016758644439439209107032516878032396119045414701", + "11769349237256342071683275569967616595926207710668472449278925821680308524365", + "7515880964846644263997052091312985911975830135506678004303761824155773875060", + "12464357909913670578721898201968110981078170975300784494985401212355213230335", + "12531063240134560397069746994123636136169642575111678588073390651101761449521", + "6147041690306761331612194490775813268707261569782473045839636103273693189609", + "20058953556654404269207947758850631052629168082562724690664696238258819343333", + "10671449076032051862717464872993019906670729457438083279869852502398951441572", + "9263778898906682528709315203073828182663073896201474787696895934306219116039", + "4280018790033654530253273135477384827165889895493311470077828964783579313988", + "830995672310831856642518343627405480722960393571135174568745694822266602592", + "12314576340884680561277987296413286687270775984122709242612931854296075085360", + "17095784374018350334250759671947431499861842886424783004809423482855754115377", + "1870276341686143971262732849057691846357227120913088159474346497974038463590", + "13105414947588023527779026549450388391878972150198998416931943855651155797800", + "18101033009026370452679604491367700242633788731529564744613454397646795133212", + "19518878118392884244142849835491751668891129028130325012169949275103156284312", + "10048097099868399020473369161831917580618232227587941412911792567651718843249", + "13720988503976110065971074438615366180970893755318530444813194189426744566454", + "10206920761042395073417518236713913313307032364045319534823111708069826397746", + "18034670825630502903409981952109964720282628088881306395156166316305807778803", + "17265902307488235822005808880948915593987424296023174321440226533612013329935", + "9429365481099850064016032865663594803605999180077296169535937496741805848481", + "13186685927810765291293578499657740344232117785406437983769041709812502541933", + "8033401834359804746763731113146503141828920003868357417085510169143014612168", + "14829873372988191912376824090708426813704721449621613864198115299064092181833", + "18455257181054398358097306328798734574318231150508108527392947186444436439740", + "8119199559569330746396633117116309013908934582593556748077373019932279318500", + "1284108314616459045915004998457007728060914233392140668856369685125999999332", + "21852625948025981910963631951406283302114607467722317806583142816175293668265", + "14294796340840469579766310516350659401625921390409030932793069064155351769891", + "1783113620816999591947201004404230259494066685648885624939940386561651976668", + "20631226309571056417714477834545747594141696200863258945898766619654143617824", + "6903938062054591003542771080232078653298889568458433305746325082721608484955", + "8256881116864939888001716449324731552833717991541507741291129726788047573071", + "13687405621147199886679388919812090637070670174751017085656416653029285459311", + "3996906960213710686419471713152378445913261990655942335471489495797584984773", + "18609485914058202995712970621084391939086418713703752883448366703199989106805", + "4737790485362149715518348725962346663474900881645708435962411601476490671749", + "2822552925802124863166593828171280409095683790486058849977885272116463701928", + "10894109234909999803847798036461479359595641981247612273970502633226141682614", + "7246294570777241116302579516225659482637719855779307083700855528941826872713", + "9013198024264523556163293154624511496427558116561774530941327330691750043628", + "15151960056770776873319338589377108700463507419234056013408936730718825997019", + "13896307757522598026854039348754398062744662686124720657491498342048635150631", + "936098917227958663269717535799277732372546413929626514061262842640907378836", + "5762347306349503820330412402395950955095460299470544346332901816556543923381", + "9011672463961728692091882997147124758454879881989902775354620290305441817434", + "8298508790377315029478690089877957774356278876814712068800423484382883105746", + "18441738918640842202469737660313781809854248733890462980130113721522272925935", + "11674356714078179732189659380227960024612632400322071192164520398757529418670", + "21741531861742185590228910897294372846694047325677774428196013372184305103642", + "10726909710822683151420187237143914110905744739798587383554354069582246136039", + "14605794533892313551961292244462849563801666394421863533658628423573613615452", + "18252321089326369077368015604893296999452816437445326292408407276685442204248", + "16489511737082127400599277690755867907347415222776413612685047279770378853014", + "12335271216576477339942530570019671580774683415225712107993157387028894905764", + "4626127015007086021549442631728304324061443778286284381465764558652325702889", + "20204422163930758830873934092037602825061261159909688022442254278786267559979", + "5908008139766198991903649413759936674892226062609391695798412118889649830013", + "18949218162516421406624855541340518738013110700902674485216824630035967277648", + "7857158354961323527996104954036841386964344142685428573605787682122921808752", + "18862506387045373228977985979058776771998946696427211846227485792071994347569", + "21130307920872379374988363214010414716464915978170248808030666261671221223543", + "4313228149429751211745340097430041420420928800665815874510443032063502322102", + "14718887479978402714517595897896626933964355973039392802299204272000024809808", + "6557683321264859885031038170253446373377122179252187766556430383002360480784", + "17122476831292693338874176268140351589680349774087615644242938775777697017452", + "1742427015172593656128486448061422456944242303531295475988475807736737942042", + "2027235762831193006217486738647428392424417413253628143597055373587736173882", + "18820467606179165158872620834655197843967670286762404094202648563691406576741", + "10125524296683464483537740904779830909043887085914486254166411012113004643542", + "449309305485238804235855079592488366640797157061432847068620096879828248038", + "18174298857888178621780055946769726501913338858930582293820343672195281946232", + "6524685458133323533884653748284163312203275737781993034758692071803006590911", + "5779446108310889204396522202292098396120321905868746440329327547028173740638", + "12117601207346032264472777912492513317230650895345305236204051403325746076935", + "17386891799362994472985052445984141822367941805998642899269245566076967495748", + "9179366996073356039318771265789433069240332535719540885945532359919512410546", + "17951430600208154118507690771734790328820535928178248368783575740656844500941", + "14192271756367781523935569988212364655718978403224403387301537958961554173399", + "8221174165933793163901377098818684602634389528051583218569555199418881843300", + "619524678975534727395248661178123212036053322038080027161284774894885656968", + "6811391538547034359716390364062047260775039349151599816482953672829058524341", + "10339322550348888691122766885623110168053574406341544663827975995639398303045", + "834547622517043358034390288436661677632262995429052976763390684889069201500", + "4521430246419400790694482286290497928487157243703675820424059696776489816307", + "2856429439451475378239016597030439586695051951861405539943990631405466607827", + "4111906549409128541352401705521383327041723912730932911918947847640475304547", + "21238392279368838153073998702772069142756942255081903718049634748881681359750", + "8024413919212120225608654701439440497293912481641002166919294547045993866155", + "19638917754035941400580825054915831416618623037514650566052024405861982044782", + "6363298127640737755043533904928034878703559551572444680730376201407773738099", + "5951378579926778764731263132308899303911912211097125509228135617058018449106", + "4299191983632622048727922852687899517860127872286225781380066638217198421795", + "13147530014153459600370443470203975351218206668086180214214011567772265521187", + "8932462500427500118784677946351185252169486521981702322459979960456999825085", + "12898236202423618599592389067167172325929052486002381527830813712396261626227", + "11097514049007489440587570256998525432340163981998515135891661207289091581098", + "16939217257331433664860194883658557949066598882598231827843396489027582239493", + "13558314929316884214321653422030897165706985165664325794343497050086242614930", + "19068785933927002693740188802713137005358154768592984493993019480794959714772", + "16219047234078325455733500620647043268680743772219676241027699492382953851822", + "11566125486619880337971321232314420701391596877779136632592874470668332390604", + "20247803830618639726625840441081484205981495541890152476410337155981008644211", + "10982561928418184138823352638412764796110898816926174525705905870653768875109", + "13865455597687551061085338688013943905732507438297014744008229213490729171094", + "4623686187146061526075222395870304599606839445854872221666055672567414423759", + "1297323969860517810025547983969849541225259454470688019030850877270479215579", + "14722215188887952104786572716523684038024407798912988920497316253897978502603", + "6270780574886929570568937279666637132374218041131318249843841984676427785096", + "19252799885324088942740034016032302070594496616562387546044018090542659494091", + "18789886326443791197255838067795128702043473536108855579944353350374719120963", + "4004428942869607083699086726311786949460607919907288923307322356602295441411", + "2877506877897472797549134443444956093653579146599656174810841010891875571228", + "17100820986561348145097462952844272816935030845535472396118435485954197036467", + "1347748684215721199150368750223253727950390142032926135229664962610534785585", + "4154005697105794859947043472401749393077233408100643568245878899626874345951", + "20933456016305992700551258430315019036248529816811141758791937748005878705139", + "13670472427221544431486503737474464655536253995920989690199387492221273597238", + "4887586768965099882782231950154450807371608927535862225573402423957578253712", + "20873520765554306935202238707923195971241799663989834594965009759362455236319", + "835408880898587261190035308896108471998627156220026699783039947254106997118", + "1168560772528590466033559747490971813513190425644816736321133758228053063362", + "11336620716299236865855310989061343228509583886619209006261263862998075759368", + "12980812954661261543443724949390081395650693161075132555819949729859873154552", + "10084252406967656001546402499122907140953995723236718543311202294822930374906", + "1644532730355076490850165587814950390528959259229216666472798276024619697665", + "9132885938811460827145905853169583367514769405887568204387077749084430489477", + "2725900975136309543580364211869546121021875237274249313229081305044972484552", + "16649132526365476017376435851279563056385888284228253635122650167497125722498", + "12731917506454877589272897239554773638029036473865906141458475592969608419975", + "13594653727945200481903485136384279897657772670755085103508581365171774040719", + "113624989360858461940510511528457240403880397732971520793552365714387680115", + "7789436153009366426158912863312519977840172895511546817589361831513864987768", + "16143950714560148477045714466178426422461079160482754992311521791041688103078", + "1313437798365489562563299651704767522651128839986029835665434483203980839176", + "11252213995691856633725287186457035931029344732702134439407400361778220541650", + "17736157138183214282785525992210357080431726331346127883418866302441793685861", + "7180555369115773227093283745784562042441101566557650242391581159039035173198", + "12210449409908576791549312007483796989239766997007433768188337654528776461829", + "21645736522624670721457131423612680680560891552619001261475935027688037968464", + "5181231859976513481992166491356437447372643837921293039933901630631480168455", + "1822647984377309820943781894578040991064004363022862403681677456868041924061", + "18871375493748399832446064841374255973869421566131394074253151764055941485971", + "17104418810613244184376069439022653413672092602368197196666088607272531673120", + "21352793177578730013875622823471064860889253282644816974785905687738185801553", + "9232438288408252188083609458343687653050330220889343945216702072572457878290", + "10304159048240945355136802455474936548590756836618851032143486546904634881690", + "20884395191144673183897559585241012685606665510456998263218110825947409467914", + "2819516448715556874313717913942313640504691377816634987702668983716292161632", + "7032608084905515886212514778954491987158299018684745883187663518324250619807", + "7559036428305013706113865872782652760220550823937161831466421604635377603666", + "6166475941379369323404906159647871547076193215494151224037609592313271326716", + "16084803679651600781285997577643662084204923480676236051120275962952234677286", + "6658815199061181195201720843092877884603511322340036305618980989430727251871", + "11532335040368550811455379206918215244397070466594500713220916970398105300183", + "223243445248411375033016341241378810903532891138952541245228108341484828711", + "3833279990355432746436294779672706393587026552206068860301259597964955244359", + "20021860409670140006280261770552932742716715786145482153861376747693162890815", + "3960940475385499730462877864983553000107482077213680397288242993303568324972", + "15345391775733994458108231909936015494312151716517317512597014646307002937890", + "18277195779471824870812914706668217603589292191686932445872231693455894425796", + "12683998657212817923655738438553698764065257310760896868569072930043411914592", + "2381616850898069714423289625050293940364468416728632275660762167225224591308", + "17069254001556064617313013226218540738464402615134272312196301018778835133248", + "18389457738365086195717208767239120166429330517506018082718782715649157736034", + "5051258247116083013584227503078370155132486498229823799712010421955209135014", + "7997986980169935581373258514853533781209293632678320920663489466999553296266", + "9084231611273069170288134842362168520424117219722297893241580415854843050029", + "9612017102514059830687104062100896777017998502712927457146148255553769995330", + "9213917869163068338076473790268314749980273391311658654819685979854193078147", + "3968414534544698110694188177667553264094402034823447016934487565301236025995", + "13588240166210590726886944410340082403890007139576685347416857458181479170063", + "8425770643762906660570072207190993414304346471106950840911695090319487814275", + "1652806391920335323990555627698612547647520442841733871570123598479115999627", + "18130776043151518739068856550215769502964647168112043888178493846726550417660", + "19135684176515473484108881204420762325009779099777199113513850601885029049659", + "18523926306415003163998391622948236629256503699057039444767412461271077678701", + "14918281748682691271882204320979112338671695483566718123583225923120856316295", + "8780852767944315665594165432479024772720494001116664689088446074574987494813", + "12668508386943347180515022360355291044387148272127255261058463414454846963242", + "4925095646155669413280350202274427260281996843455607837164490899877054944846", + "2595801235413574965831438899756848851934934001108314616806171013774086568322", + "16016207465062828688275342866097975914741628027802243675066228993942777558633", + "15024416797683381415563755573423733835281624847950439607885361353822729812986", + "13470695612540254635863734898909669181168896043111281127113964919743317383261", + "16896649112088097145823038767205812267673142507502911459577638240816340032813", + "5645009976160313260833270091943535119457478455011072475922688828021639421410", + "602871159134715892643983949134724748180211299390344137568222174867411670803", + "16865933848430240952665445021880291168087114172384742393439371745277930120747", + "10638616947682848797128584610899807071800790542581123346366834113610995491100", + "15823119882352004895965266205059246906297215947121418230976223923682971872516", + "6335662959372125109139397987508104273775067107064186843021683240893850916670", + "9015302195224176847832179354591500534302983921972567063156768309852422127379", + "2916208839246568972516202976435804092919863447720049244313355052730101892832", + "12462097677706957512887764105458513125712391543206668564860335255817545411462", + "12645432056886268747459912808478608940565989560801243474226148714998374680219", + "3180920336675161838114354449885404230480750260525222632193238650778186030194", + "2765038069658052652090069059291472962961753315554068900506936144102952443412", + "5456153930594691794518876425254629839890061712982880399455001410106283524009", + "475588857464770407073340860667255085025964024669275489020055454066130988320", + "11604422213771358649337761367286746573670774367844043829963235653833716835011", + "21672531595983328080827235954964353440581013778240609331813180834517858151965", + "4158282767336475980124978163165153479336138216933325437750412278000398054990", + "6032343652765967766200639763117076693275022773598878447445516751911914770612", + "1408994971542022766817088410277637989937031937486427645416181643240579694602", + "5675369397167644827707774427966283386689036453227097867563588663607826158481", + "16553836408556819911384314376537283029998074714786222283151724244687848945589", + "11305817545614916257748042736988000193121142053044277161651567885557438654074", + "830935697282120891923075627410843569046784310505888414612692179620161520408", + "7111327705324010951262975966073430392141084274376586856008212260205185475707", + "6041014280799995292240499899142298082182090482839684923821947404991902712715", + "6861532079489296739625909197765090537384733717891476126939216899495278356435", + "19512767336722762932902171703888917915267449700217444230295060094846152793374", + "11362087145491820831916999481856548088963000118526088967383804499026380829346", + "5345785713105818128869449775136443413167434948951799284901802489769456439786", + "17034353050546517551433657764343123751855407033689772581554238132654775360523", + "20948587704598096549680941899688868509854524167514075706787714294359604474171", + "4994911941995400553330254818898448719600721576253446166237206475949959408151", + "9688152172628114951713346942216519356583583295750612146456768853572234580639", + "1343745797764784294443121474436370243518251011725658365765145682550385976553", + "14125032499992691719199426991191077310874247595141214711018898761632184485555", + "7693434862282992683488101124262547552730705787109948156284399632991566403920", + "358969526543359888045815665915036908949414956460937733680920722686744813444", + "10388303602140838746049100800433273910870825475060431768126678575590491651119", + "12003019672927505670536349874007900046436859031431459357691867861903891807068", + "100475008966885612365204906854412018822648141035087921833385587863034960276", + "4380976634270985228665957813264807511324931231158992383372104805973515660993", + "6796890817241810905532067210297629305992402701618394901609217064231507595098", + "7688772779168713577464553940881893522916379475003769246647902913600123216803", + "3719641128095581959416223705616297841752773711170097329183166123897200928969", + "5811339040244843745049016703193592081836868671814750017107506365287109556605", + "10595470132919677811136446867941153163237789139416696690218064678877242827885", + "13030722908918648575860840375066614839148197698661025042088986261543919080554", + "14270313844057453712442736904892342369114041625795108985761645871570953543978", + "20755955200977796735614094726104970512145122846293966132203844248531587786651", + "9582579815411229200777590264696860160165980649555432144848137253789895405534", + "4350662320089661964064338788392477540031840065706369837322029959874552780000", + "11294656075067466938178599864610454390092206885966775647004601601555888026051", + "18946972646213006149468901853070557711933198234858050136328420076856760929327", + "6183788518442229735210652665497651321434896307527846329693517674734369795163", + "4357012315121006561105620778754114894493832281520086713987988030701496525309", + "4220425144490786998849301484441980495606132822919030749888073325247349169938", + "14847262709636261703845309954203315918152776098063861666522433996841734492983", + "2207604061881398535333278399637137320820424466179707349350037157354962490429", + "10374520449793714488752224568044645973292278262497536584844249765683309087900", + "10046752763001031505421631811000499551831682948464981948135908582555522139635", + "10191830759680421095919984376117799343794470779618993576052513294297834150862", + "15076222662591944075232357720469485509899269012588377631779056491168825321779", + "10030346249770809877262359992756272056670319300684833869196768465826414079904", + "4720507975531560789365265597577186025064384475474978173798769571327267599028", + "17191621856092434134985786932980111138837305571579695662259528942970338620884", + "20148399372131987633026319910847242205929076170415419364579318442517450329463", + "18536741510173922435024204045457609239829288683624474544615917164289358647693", + "13631750264342742049519923217689863850040711017202360015936348405918551837067", + "15610854494548438731317902472235239790464071411103741562289565846725908998069", + "18387668285066173974072893371855420071639764562065930624890442086525580978084", + "14766673420520500288514312076124802867192062521660406237863986898959550205282", + "3732185864446238105520935485353063605521423641525603230547743875428671598696", + "6726861976047081116380559824755952195618930495454092484512720173680677582718", + "14230102015194545129058653592673168907799074203765469344837164009883877641547", + "923698051441061755360657704655014798009775419003226945193621553062258046271", + "9689434574353223411824004165283477169808920117596652474458537007050145695959", + "6653548670473374668472111797166160911158340899061222339537692495508721251614", + "3795538039750942962828904073106200577850807348658267681985654384336620251059", + "16992880538370345570685975897913090022139738512471371596260168908478239467806", + "2201111019550353407862043052634082471477202486461462021878536956251970423986", + "10288260758300652435946350416864664136108249309736639494191503136475372654927", + "15709483617520776431567199768118570957603227217270596124343406544848127051229", + "15072326085023560939831375504206736581668538451241556883193631319058350825383", + "12561979699882391671048614617301093740097194439650447103774288376923816448076", + "11578577676104716528266269909528660737784973170422409028333858070522660907599", + "4774024940257712349371248845501840009544530180895035663519273410524858053238", + "6492684254039247711120616647406430763803059236762636509335603649550553435616", + "20771468823570726361366818215861608649059576818091620623157713556101748134372", + "11770234809483645852438195876591109251904813195909801267796013610714277347278", + "10322220982623441869990996687272667519839773221084466704263092761447901512117", + "3873750796549479014998049182061589742243147534079044128452565125163635863792", + "16822068107147748367260830510353037256008422122115738671496285709779217814945", + "9894626898191884524351933214321095257519558205219922050393534754827614996074", + "14601192892171927905999982540260020693712306290426245380657926166256138073598", + "9507456803001734658737641235710642159379435011566715643921196640676158132603", + "17204767985326745166438450937743889339302038750836189001173941240117259581627", + "11493735704785585407432943012768068237407868899310349385901453142043105992145", + "20264601365705944529765978188292560353562052194559042151183990689436087045415", + "6396166643103201291451232462310280514789516631380296812005611744416636341945", + "6058445133237719937803819124490281802427048168421128127070586670707895911082", + "17832742609350217271111001369998668554917153176201832135065834598001176606174", + "8301910681660121964370976371283430908357731729231997961142961954342095329645", + "21200700180783276860226125147359033530111487784446376587831447494082008760372", + "1364486141742658225769231963526281625713690163326935801558529383187840699159", + "20160669267302086336804098028492246933121636960809421351182280337233197662342", + "3635162620064198915033858334726014494627531534027138539712906873727339940152", + "20185829971410353373403938384712968683319708682735072330111840928607967762630", + "201523690073703194002962504757428126542763652704293724447838128821998746350", + "9709386469732131146744455888595822333747765095732359649526137736669486544832", + "6214797208590500165345122859363723824928963832472111818012074756679462353515", + "9545179136572857559578932159310632305901168870225039498707457861463081350889", + "7958214991370581593237224161079745627463630298171564909746677637838740804837", + "10143975143960280812282386246733660505472918014880729933237691446362785576312", + "19887571710409013601609612720342170573208042935750400481652798519320490462147", + "4385901431531790517574018221866017216283585679251714390188554453215701245125", + "1664624586830909279573419685895566313699996183243836877427547144869129575305", + "15793134038802395204513915871355486670799044444942914383804421551073411566881", + "20470704207635104884647349860077097804311221255557839038451274311052027499926", + "6142526726838860239230170135812194898945683787933736938595250804972260353985", + "13855192186192101570267811921410903075943095341965742420598451678343592386178", + "21061758735696246985536203700046768078820850320825204373370639318620908053680", + "5662817483820503797666808429029051672943117302178352551614788456216271483237", + "10333519634297417737172450445440333857302089078097476871967805971949123871529", + "8218569982501149814702324407474792474686368395700170296571212557818282461359", + "20233400137285640555195780437569385053497789288081872387339896466294226099158", + "10072372834150094335098617649200237176564672558260325152023334458902878530776", + "9266800412877476308026297272156162694485705323044163059710847355278349659379", + "5276337117659173276438760052296857124207008171563166875174912047683077401125", + "2006436301001583347899849869571017812498189722949517889639315185888688453745", + "21001242218121797019239763758294108685115914209711313091446808028690842184156", + "15200074016374430224281445993551091543367930754541238817021042732526880610544", + "19710826528876999823124699885521051879572010811534557471867248186884736123929", + "21404362987802009741223312847298906544768900296657310719715972255986007016585", + "7600530036229891939971232581797836974827849142680304648314541550980439417795", + "21632454463616985503979878539576013805183337895553881618120668190150301665261", + "6334758595723856085036854188165101506598081801208405745986881361560891199193", + "8057222251861033664666134852961391247267479839150238989503146436301385103200", + "3219721852432286392418844864881031568045047266727931843416507933961433025545", + "15429997317679838542619650717630685653076454689042566593207301547187192181410", + "329174031237742757022307048272693803097641581155976690924186132266202912753", + "21732746139483704151357074738923965870601454140619898689390165872304758524581", + "12807082000874685484816248695921308340943213652025179667821051958845707861874", + "16064026146032729000070008033632737632876654216683451632905581465015365908257", + "4212217153278443796283906098959531995688364954974810176542537190766858609818", + "21143229289970553639173591837823586981543332391397328546878889800049585920625", + "16608191574158019592113901126750079565651977188938492362618874182536574927398", + "3624421885419003645925287958934125046517213705659854889615838255824651468218", + "19316501828231774431815118527212477451661840620435061360743197812130426231605", + "7662891999266634580053960517366506438335835205004858023405036760628949585740", + "16083409929948531376998108923041427957606534473459279085237388567102877584234", + "13084239861882397209044914415955882241492175271640738785828432132564815850793", + "18210156525345343590423422394059177051429214768712959878778772626339164549874", + "12315464041324428320313158873511378501430493994363943547122434404767709664853", + "8954605304811330146055184939317681861245665333018873540562258152334326318605", + "17293224339343743174562117843833611404589728024045173960633854068798646969854", + "12077428955835955218060944701333382577662880272982277398053344529073555194830", + "7126046228531607392073289758329125358329379287853920330519927955077178144953", + "18588044234272060286987286081803360761513524944191766041826466047510554640918", + "20890448514466943340126201065304171306189507157689256667534257974304306634091", + "6801003349507087476371788107799511762780253146305342273491215439215969413940", + "3780619510354109448305575837112860323918556596060836509041441555683227828678", + "8767334354313558924867811651574408725653000725545478833889044301516199439630", + "21066572358677074507410523123848261256731407535120503516033231013762098795269", + "18362039042064137510549303809539961459419339855353944845069477034687076489851", + "8913523920256755688178316396983509800293437764919338700779034854771483564854", + "11723401432613346160205532396432709544892024270048469362382924649893252868073", + "13215697753311268652932970590975269015978051881025604765698398517094385751294", + "10096875802507022627888049762027565166660383010058121573194339315127497644823", + "20585340774134656767573027722172296226739825364200221949739798500696627689159", + "10445154974790139558211972190334915738383718443406895551366524953208899973439", + "21673116720904254079937605482525822519756033862602805679958950491098633276310", + "8625969092860470813380520419082444422545844964279894335272441710185243798934", + "4025288875907887520103326512414690750293134922246866469493778161136380894049", + "14323499257030290650454481578106573336673758956871892054979745929234879010775", + "4477626471847050821212591107628903165841822822191648560679737237549532746098", + "6035678895480961290473069135353807694173152744259585744720200702817852056059", + "13087537929005319145430419950489154179166101298384003566794942619862071759110", + "15034538492744821867836124336381708186593112293438604485661643830336837149153", + "8805139564894882006885168301537536158944953788019925854273090624783308357258", + "19958581387726270611337524069699729934757503443234146496516617463929755531372", + "18594586877352581063978277344172832910008313781358399221576815775414535759101", + "20126420557250610569978010728469817957691099256920991551072367148797364737827", + "12608220343122929299383466116607513455913710378844501818574872277345002049133", + "7472029840435729707246144983643315764441672074448478483499047549570431985698", + "9145534859649655987690711448922451001707059796425112511085875363972462746054", + "14833791973699407961392823324214593517418186311389016446279089810253909982772", + "5890565022258491346280610728283677536409667465411457717498759331136098626193", + "6036941096143250281821883413338948223454138251490770618188682101941802166158", + "21282043678033183106352077009071810571452663281954166213888935238324321673748", + "20333804372144772829649652869275200527604963503726633269029046116798625871599", + "588131164750999180590569033490334261814498911261696634224331209454245047082", + "6825251444721740074952317618082720927334521807162055931163012547596328197449", + "917697824543986394290655655205290161739195186499427989467675782006019774097", + "15041830455925245428849291972925354368991606611607025955853683450026323915411", + "18474239974098280549955893651580150846097530768719853315252027744284466692200", + "3611784158748153035104121136455977264222066374809674800505557964617331443457", + "20604659450393945231663570065906647078596881678092078709858521111095167311757", + "12029452301550033145724326108003255082656089254479215038003174967331098163936", + "15356676148621236051968257733981998213914051180019702757440018429006515803587", + "9423362269266211501814985604120446961293044110825100766698681717935266136618", + "15899728330782424719479421593102373102438201721567285551304437858855478298992", + "19106020154064303782722594063821106692950347246115176981502414167189733529368", + "18908465093637028691441981127932774442154173676388632144231302290143899401470", + "14007866203893293106212925571168282959988090650409909185874688109550330526342", + "5342742216767912627176491444663860490435717482395442556665323768598286007506", + "3597106827456013501397704575480537495681742041904755766922490829038770978602", + "19345954862705630389044258042054882168728404897041130532396992253851595567599", + "13651761202893618441816264801125692678934609890284167560926428043317180108703", + "16448172308101926626190311626973854215995348130429072972101942893358814042334", + "13856649049195496934480457183055513754814884703875171340785294070612325977764", + "2593658379576055879381789234288074898757591156526450196693707683508079496462", + "12697568363447920404231218962893478531573733618972364303216707079428387821529", + "10578645587798138343532931014102095372709438567484299904261443385326645475306", + "9492492460728662705158180596118275120458955222134204696298182307017420905508", + "18064023256112871749609279367679203109309609541901431681842430343172099602354", + "1989944422169611668560419735240024090899518972063746001231995750158992709746", + "19903230879435744155012664241474498197586597172440005182506995303093565641777", + "1728511243862152479724441453437511013527085523030423049007411340644871969509", + "1750200860549110325737825369011951368084185262869489413254703181129282667828", + "8859957468047988361338455823958226995655820770262073750796277641227321341998", + "19127783638542055071733839851815229696558338746338070032734486927449049698521", + "7078877955496438548183194474726026189811269821062629263278508622456589680639", + "3091324818623570240229136118759236075549426086908228304466341498471627762399", + "14195346783292343393569267444162421134560117165562018311694222203790784872224", + "7366930408724527902650425878366319531313526362168392830194685421619273052822", + "2217598702761121052299380093973147900304006951260118283287015270774119856107", + "16027808241528674736324615318588531063352235936452195394658431080548186455840", + "9737799828204615060867766665537725835381601825573025977613959705161843611093", + "8064501393540602388259218046920616332801811052858376733153856073004571475196", + "16842422805430821078995618361206787780503480464556310995070028960079907202166", + "11112062472802799468234830097050518793604563281810316763737206541428998286081", + "3996143098194824093843968965659132847407504849137530967999278126450907191255", + "6307499143062236655628471047117923013144505466650278288900215043429516667827", + "13925586587992763438435497293527949989397459231522640308463502932206077961500", + "13087452945182453051277972085750711303320428980713041081211383304385877763691", + "18093207370226721487749634577199906992299418255969574006908138736154443387826", + "14272048411789712231464337625432600879032064592923947963806042930999866142049", + "5112973508688401012277318169584325529641020499005098236869086381676918059371", + "15127813438826152618698293752642344087924814601034550461410899877754994198299", + "6969695649962440087033894050377257471647257275605050327543911409064993144574", + "6755033946723836072389613036793975461823169166252828563832361834388266522342", + "6630309846049050707531890910192358661458908514573775713066783149977348075866", + "19770918646745678079472470109308561511682083548143260940369403377403283034557", + "21433670531093667302664653834628387344084043216006808509497422477800438816334", + "20400712430451351419962326556923150417233487338363092310732550512855900177990", + "9914702749825526925254257687000920413318621895298404563035360292451257098124", + "18640006733688503648022700222053193091432820833842731658823766601630552120045", + "15001143407594668782401370718438100322710708950874705625981291998887962398836", + "6239670443845313966789296359213657096108058977356600364820415786936148776478", + "6433425223024186602967246363501689243341949458306873394092764835636608100956", + "4675918067976678709774913862522295500806856576135412363070396552169178386308", + "1601751749870408670839362316137379218159388455643443723425257645986433854434", + "13458041123361531838745263080315252882353509187267791623642428828275334206638", + "14471699013899259577738777309533960354293333303365529990782321200494073324178", + "20280430398960027135010448240285550337237252858424335652593355698129656795752", + "15301671314764260006262782923235826735016067425075232061024349010859210176138", + "8527420415370243636986575303113397012724035052720519440118106033441076019119", + "3475125085974928986675306749785419160190213748540322213576708845513558192234", + "9006980194944928107206620529900294492273459999862240882500316250867368209534", + "18341113199274904243447557429147408702772610985345439625451614852727142466679", + "641303854841744162878167226844505402377828908784963225549380412498130669293", + "12717068536550964634894133707393353175533641253913906785707227145457684209533", + "4743152264042462778433711542894756531279965736412696362852105777475691147133", + "12538011691198347241319721961633309700824171196141123297965193643240835576405", + "20609816220088637782952524444771775704801169004700347625707989982325840582078", + "5706720205331708334089980420369782946367580993809969730038974418250776704373", + "13670952207260779576827977242585356546757059123105172869720468020067882252702", + "14767430839071230390516499921530329576551075490453331584132978354378461913602", + "13855121278897572089789093806573448194721330823581341784260637700156610112500", + "9029464346382645337824607466955710618425900404147532427117006888589723750841", + "1522014999882036268928376276435422913665212355063956230967744832498304066925", + "8291362624704304963260873050727236420693946064959013721544766852407674345583", + "13589063181500587026605394799486087482543530017803239994475549538732438667645", + "13329949252386676079710645426263377053183751810973538969788279784055444085091", + "12386680681590613307772862225908657100001403625719832791304530216719729923003", + "7313059443635334631417408104276385788845981785748211548782869561833456731323", + "20041885136971069417608157269779303040508951822068411540615824115716811017904", + "6497376869042504752008054895287149835408180730990917088183191265348284326357", + "11125724561218240201117500197186012921479012541837342663628667709300377769139", + "19153359808996709649541642396803885814514927865816858283729145733607372609049", + "20152572433538554395328147373104228881714506304708579989936661727209606561409", + "20016439558639474267285355593250644884337484988031314831332037478976434317958", + "7527238505813249238885718653381005755459117986453125478349742303052560976989", + "18157976047185465548629298047288220777638494790360987385974875362640599836871", + "12215475598068312355286440209098941716275384959997573662132780937926913300161", + "19661498481048830903134453807971238540013636804700867840177613880955309016673", + "16552339415724980921932277403793066165528259484794112971750640492538556458696", + "18694143444126088750994041983752049518157493949000498621268553485531912882317", + "3713967579039675465490867111467075244841382142654006118952820645091137343179", + "18003791572957152311824638498878311682370695010264579557670846595111585019742", + "12786965212577099174577804313633357821910340940882518052929431837084369088642", + "19196303109560878004701565248872597636081713248916827960361832879728708100252", + "13503920737086542355495290621258674491187655992864087131383678759555676293479", + "11236070378728091455898747203990505205014449224981497050563648348504784872625", + "9626632821060958086537183012642203130268418644318548991569123722985663518084", + "13034637881184844942276438495251249937482750510182566475651230823087848537016", + "1332579251268852603948763724532278782861309157968811258504214239247723497919", + "4440487054089857105584789445239911365602192945489433191329897791642671641022", + "6061652828396333618822938589797622370923339089332057787863230635686741988906", + "20443625886285957158375952392918402164453450517610142032850159380049279019890", + "4971727988681610479349722318571442785499756930724120997617079739694258077982", + "18834174333023112536455562602096071615163100988222060601738058925300216483554", + "1418358707619290124642186511810240322979679442148132663647788839527968980321", + "9146563693745266063334532013679253366507504975079644933043489415067653903203", + "10198203189192787713857436708411760529883983417357336104059303759507359385362", + "13457105298809247477659188594503481428440666731107167805254859937557834208828", + "17541364687047908905500996158296679129819772711555398152345796866338919060112", + "20692063470613585148684100931411467587781915529223705941251811918651910411051", + "255059205539662129885859108675295842232143503986252525395037544865412535350", + "12717171726844166947240066436059787676718930218202178144871226850052045252628", + "11844159733516000729567466032644347431569093736490287481873540624836993897027", + "11002794037358979127166193862990494036532493412598623614028528989937231393875", + "74143635505641635571137692594773070124419429312664778822553090280375104361", + "7056329304173643667817989532223449288690091032171349984912618184745639839146", + "18641921263165235968711057500989010664480104039807002554029677125998810936539", + "19559632820551845243777081617723524038257569278710484296878486836843940297771", + "20335178684657665532201643783226288715290471620876336715869115375508863124376", + "1400810679146237783184309652518065868576549410755675655514372408922313217181", + "4901107318137271229016627403293875571324832946427895930672961592355892796524", + "5432919409806696890084817096600220639163358481346859637851564223110298016918", + "7553857716186244958951458648858814979749280269320630962042771757992327513590", + "10889701053782808013047326782283414392744894366555627960860238324337962809504", + "10225055313049541990073049693496605844127702734102449597528239569584063842673", + "3178201789995579607967020188792297279206559603024986232709441132816492873170", + "6847656471793158091195364320441056206778429470543211654532315995128613054310", + "12528583474708786099486823217911492959125739967840882229222854187982855300696", + "18467266119817551899238434875437425808022051394845724810256998883759435014686", + "17038264911128891077018547486438046001433165723713308233430847345626729200927", + "17955218916742955831569749120296633004126823963586826720707041154002710061824", + "7211241300282304354221867200910811631523632613327223837945134059614958044309", + "3903314564827641199204912578257298318982395101598969445634590319788688787892", + "5807166989004370646148664081075213577472290526426314941919217927313093625705", + "7286215868775919967580841436085988310805057373157718787975640918960675793864", + "1250176112708058341117534856693109443612022505613546634776485361294747168622", + "16240306074762036443870399577875028338427695244117010393369806321281281115890", + "15136410716022250493730454911117704953380153308032786787731835907574927894490", + "12835091061815802274496704101037812141879397401714459083078081237987781157602", + "9740091907879287748866588073726349058132835900960520906530105112062664428632", + "15914692134543071914048151066306389736053927516189539093172532429297748396169", + "981367411385768085119476192577825808403597700860420619441932576179905250934", + "8146729957224132449602418119478334118295844780357577983658167000941734233326", + "590349410629703152398401018217258970865749864711821880028353966569788201764", + "1825395473256187220041087977011184605194426952605089376835233620262931194993", + "7123515738169356759148725471278134181610254795201025187792320024480691382570", + "17726785796913877143757425784904469412799726913909454284181133920507167220504", + "11651205611193223879329620496932918885123654427491270580240367578782038527170", + "7363492115511936228845261039013774575631247230570693094937015313770023603570", + "12933273009260754826631125313953911983930122727552157672205237418903525642215", + "4587914992471995247205971137457571771256946895956563575187244174461900917940", + "10792746122808647351065474080470836119851772052088452562229191086431179404978", + "20854485826587742461285159604615271614646978291370447131740817759213177014870", + "7837325030066353684135714390699866228186086140255598480265046489057880448954", + "6126605304840233971990826423459339578353618021565536707601222973624714560789", + "9552503931384803960142614388346661043921110897228435044165354206374121160883", + "21548322368276531554717543098918449676251611754505041151177909568762524391378", + "18180071753020516412865055548290459200005267908156340472690024449103604081545", + "19794881883035632088168728687250887611858393833912902865301935760311201163703", + "12697056234954492550471667283339416001528754790033934829512770385731960713685", + "18997188462081688420104936253788181208943789361069483606382840563484861418437", + "13583525090048988441168973253797491422796978202781056749054729098883924623495", + "19314654753949754551488116156913608959581776089474885903850748881648064831000", + "15181859580303507964634708303997342165949140724201743603210372837522352052588", + "1716462370658876925282526879979978257325560447381441363811430134855582914078", + "8712634103130722740728459133380535370865755065924597276965974996780521350960", + "9765286726648838325814219419835139491993130621932376855733750920135287306908", + "19656947946994771960907781244127562602401277628142459052853670194718812445557", + "19486837510931007596539998551154014974137134735704825357816939421451262185625", + "21628438018144169767837932394788626973405404712219671990762156320628259145217", + "3756950750264795710121609861402232041406397600142239597456522141772347776528", + "17539873562638205978340064500452614593864489286304276949397837992418594034919", + "31501567535731664761828271772320938243617735864979347171792246363428922702", + "20352331732176385362929127748957145775981304217223745596870640808444167485233", + "11226695452056490225554147366326688917799653401898260586559601210633144658136", + "11279669284613566548129429232553360604072423151872075897074160621145515173607", + "18292000567925132069216498991188575797602397842406377969706321176845302551280", + "17394537715319668724138949078062966852069669620345676386188677668125466782838", + "1758531732991926253426465239898570102024009352558916489602014827893071642025", + "10665213752467842898072683993424618781459586563812993734884914172018996230127", + "8324794334508227576619756931916312729743681044831168054976090310260143855664", + "6775442988166121274859488523805155937302608291295720635827623408019663108145", + "18295585939863028658565671525942083548149809167848494003118620027469243247255", + "12098041580596728911973293152187391806099106269046962124832995425376587592750", + "4179756701368801644640767039230959196272720402682759516084041748778250510583", + "16793512481702225401381949294778305375341554886405623120613660547710034551886", + "4048682207452656355407948755890074205160404299490847582459375283758637453365", + "1909268909139397440485048370655601811806256012192941212480683118923705439669", + "3957160465110711873678443805553768764193925226448354732024034759529771356073", + "19248605214573594176390251265821595013690814611654024253657271349217548577373", + "13868854211319335141393401333112190211632180475309484073606978199113030773403", + "18603198177495186944736198329095228547417364118472010561530819889899131849965", + "14961608796326843943228062129500114917120869339277918579779470648489101516583", + "1868951368661473960034964936590962790214375788389753455318330338723533775732", + "10905586386180037341368454391941851073795645267274288454955833628477189437397", + "14954127679800529819463733123869358237687206843820983026443645382142721727317", + "100097327222806530673180018653982439008319453432490738486899052539918122124", + "12805546034879808469495394895280673159114129337420886322224562831326122327785", + "14806980879080756440413940765209361196073245400503251970584575890653655885707", + "11244087337738788153622356037614703414595488262581651455100475566242231927775", + "18570222240753995928776550172488765352849447095675359684346868515783858763055", + "8341186767195379582987673341587963265518616797937499770780867790468554256976", + "16417432689254526830515766295056137071443518160358174458760640472715479776587", + "16841713253514960386433216886097940412703740575768017997853214356595383383598", + "14194887769957144867963380965988802472719946120213216012427494993012946567028", + "11529543378722012166333054004374317420377342192547947476057235546295927556027", + "6228288822288755015903485852969606389475962987032899088796179982251184963398", + "7936701363023944576389877378554772776727492414245244625252565794409904100031", + "15001498940712434912521276724772034272928752268882108797824422534795904619598", + "8473716056033059546731002019964120133827043541589774095605930332153697155158", + "13622250811616358253729853546023741257702106070523773564774458974873057917325", + "365025468139420802765331768400644334625920629446545823780682161731304140845", + "15188301566744221387195339021364877229016833910188161414607699674936046087814", + "15485783106434451702559510093123052549288846753530302451778527951586674987922", + "16738591797575541545215307991580378005049794467812864864257667302719418546088", + "20925739023580534811148616300343740428924012857265956692833219002712597286911", + "14889383841375932440118953385212403650477118619024418302909728838111026909639", + "16907126208352189929083708812165010150781216847422378013750129578871272492354", + "14806337329187045580963626107721698864963698880842972656340333617747451702084", + "18421538430347165869364634373319132341572867349320823968976066555816366184444", + "2434665826886017086044423893890240566257398976888986717506547657107156268130", + "4107084864210868857776853415457685723648054900688044144581857773829680966286", + "9975696437638488842544898875508262421180359453753428380941136617917797565651", + "4271657746853939228219168189957401961257189278944783942462379137544482211389", + "6197095881644784733476508213210037292053663537272178396466755799876037787454", + "17213367299854554180584426411972899951945067477706586927352113350447914118348", + "459213126097844409580498104618008133837044548373643874721876534610892189686", + "11543212578280368772068695265607222577889093375221336525779600349460584250291", + "6403298899310300874478654413460079479003477532791552465502800475489780616607", + "9679879153779101961935393514698788441597495345714510688032433497970373876200", + "13406313792037016685976311954559553063553089970578743589839464948184425020319", + "18447061183141116334003130470774130153225311547501637266696790170481921881877", + "8380490825353548292894683756629385493171585978110314915970595197861650821468", + "17748778220767931278266669246252235981422317813726374848817938354712043425250", + "6989443852838917282085440504075239616539844445576232297589557657622451430824", + "7831657729066776489302369169030303662771324770284845700052063314128105065459", + "3925294941359174220766529276974428294409483857727579665373968233976340302182", + "11937917292063962829330707841648838486196775641195800632090436249316243167473", + "5653419633240940595644007985875227652581749358539968324306529520430709397246", + "4710671638294627998538116427765044043262338916893456876128991289569569324348", + "71394869385825610742630406624465024289788832054180269745498390791493509963", + "14738615985593994376179875742690333041302941042023229128451420345640432224466", + "19352351801479363044593690690009745314348194116715421753626607893015433391861", + "7828134540699329284695760683671979636145431779072416908240193138816504514982", + "21767328407325385326066972839469738803639297445302836419167176746643393964398", + "4363185783182535592354777041764733165968243966270266866378133278599205816107", + "12861900092547198665663242905083918119082751367916515401033164113207531942792", + "26199715195773805806030726371679979491296157888969354080702618784507347327", + "11422842882875515086151723214834881230789142279246505109137919711737652087050", + "19051762302341786952522177542948673906514656868374502102797859778503069987555", + "15304419135175746829806105353267450572438302765436283477928256874309497427510", + "15459263896362250252603436487314027681146892842462223021544635764438917687246", + "8022722450368098005612162808615173120915189731064159685566153653273958491689", + "9933514811147109956084664025371824141534792260321581906034445537159964992688", + "13658822996647839872436185744737341749492205026854185105317636224609004876375", + "14379624233209822191260559290771588358188218543089774948098229868966603288924", + "14958992313261503520770373701642009455846990471215730792533739030356906680013", + "3008264124109355458910031641850139041159853342729069847393839537381972950880", + "19920038730043462715603813734444323019432755215636179923851277692610637123174", + "17230906594400326225968287949357928337332875589057677202822764136401667097576", + "3295851897757873055813703602696670024935942454512523388333117755329662151138", + "18768678356443319065659286382395610390856779982946155969362775884999359596659", + "12460586127165955570640740026112067337902936125125513451212701690418329829958", + "11058259665604247832957658651506896706861484197660414347806317812760432481190", + "4480738127714472007170345890289828985073762836671874831610164101698497828459", + "20356672216023774813369271811683185179666462848912908217024611254147608738543", + "14909200607508800723484308159953932832836734953149954532962622450689109093081", + "9061041843468229886389838095513813426084716371809563990186852970500432288083", + "13877210447577198749973239837374936528445414390167357430100753821987322195433", + "2839635391670662085450211408709683689698694308308101424896263880864913513894", + "446790459594546823193048947973948688374393610819268956164912891701746906791", + "15513394297485200475424313247005293190116598898090270540649465364671255026149", + "6430544300458423909335482367339522552006494240640365398487065900428380674587", + "167620735842959596421416387102879695919480795342009064535989276983300514975", + "7851629689216713462310956055612887013872895546158054432042649792702892211944", + "6972603886636382162328373670318167574093559853635999968924151410796861460213", + "19413944499150555955013296242054320685906330193520693124525832782341915610104", + "12263527706889748735493918123122221596983902069097405802497958581677957096038", + "12724987466750360537318099905062339029588038359925927031456282032606443592484", + "9708897601683631082524518294366690107466919479336384437075715215088985624241", + "5574496517333770677326807465934080003942242224011251056548046091202080747952", + "4426233947499799157064891373345188337862104712594055992042177154581455374210", + "3323616387049914826284182817146044206680302487334156840960948301224727078983", + "13004254604656434940963009501076991894817629784556574456240824509876544606284", + "7301157702835275823143922645275544869236677259284614641634323459896004519527", + "18085948818621221598774302236513376768745135801526414290158313790799455691975", + "15187850571325688566534378765892972581891242830408971491252049503437712864152", + "1246313402425855943486273052355580345666640430821848725745627960892819218740", + "8647394846748193532697036206738902082890058434940110730560542269988727795912", + "10064655809228901737773717896104022245084200167358447082271876992404069509689", + "11849936299337845059630533008021049942767799074160683892846518986534992566533", + "17222503330227123082665055850287821041983218187459530901865330120583332963245", + "13182290359799776528759669559625168410983932493170206108456280901111876076502", + "16922308846046171347608544335458702314243928203269931669473214292617484140503", + "7558805163644194610710740916145749972491144028571940176012011742150030513578", + "19569775351485108268007779638227959360722563519500120339858146797114197471682", + "11059423706111256170971735544260170713544645580527143674901672982061741530101", + "14932750633257527497920398771292456029356930315768552640257901217840963910603", + "3437896142924792262479946438539259423504563537021031548773393821349707014872", + "14782805101152549038431586973278748014002447400847124060642259960939628565044", + "19682001999640336579725059393603666122104885151774112167088565361216155864092", + "4233558995266469322360257198354042357488781625226686110373130567271844168385", + "4047511689246902987779521780711143086427724115291088073014684434358317932158", + "13856430748589477860039479213633534029749590309123560510004500567115861827367", + "5679747763871928801801426015291106236767446876847749477902392536633742028903", + "2480123750122829773963967496725275864472046134363280592972001159541781284867", + "3193376214066985989527250356837102042223952356102254301113166141443841024511", + "8062756153672663466999843325461563174537500405375937887043564985230465866772", + "20934273497132536703003386629581299436206618333301538059074736379428757199398", + "3964142000339408965627671968349646710437601305543271274636785761452376263382", + "17659047756049778260030257809618419752271933594271518827815853540916989127582", + "3930343349615664221386794926953117177573248229077177174315534154624751347076", + "2895341264817391965072938270159088942930942041694844772295944189135688863196", + "20818043348799096204572140288297522915577162783223193328931006646915252532953", + "2323581855503968054101786162741712103392782241966098143187644164748998373979", + "21506950445835751487883729097676565482258136522526260378635240810473639421131", + "15652663761688777314836638604018575636259220826467294056546736904699739444415", + "7055942973426557227578535789272026034619140718369524980726263182702440802766", + "4949575918974841751734514119081067078445927926837555007268000255590820633720", + "1398399621038450203083960309132739969264364773648996881599178794373813964423", + "15732506799197618296258053128654220838812930643001991164136863850944185860296", + "7794835596508268056707656540537636605902268233816181487738953353424162592877", + "19334780957038992630028385332334147629399375592719839985802296503565556738324", + "21635034093671076768880953665214862813027411650977124864184274112296716574632", + "10688534301651495143056852052149424865722511689194196231759927113549978532269", + "976280778878149721615236526300424224199708100054560296745736876703945737879", + "1661236337347680899528966953581439111854379099437324147973193626090712244045", + "376684649999303144466214973033408609742031466036082108742020038605665915381", + "4455377013377822379614998251281676782235647079572422444530523356359416320717", + "19050227778954804843017265242388770579299436899390433258601701002663268793950", + "20176738847900667540339144241305449384029623393968373234965844794399275414945", + "6563336600400724498009526486444642892816244088883489205001024055715188696046", + "1774742053125969896553337470644410955775448576794083561882186570750312466523", + "4720344938456070076793371724100707050168913253766155392188169516296487837219", + "12386484928350266729292976320659720907387619673269670145583838638028478942370", + "16511156064543308562970376025636430728255148453048880933972883964686852788569", + "20161060548546289109867983393573712303980348945862267966490524939511877278515", + "15745678416495620522776570951840736496696200297848371457414809276602866061937", + "4371269787269411959190919691547618186773560770535442840395153562222650962400", + "9183286542027774648383851710226269089477011745654659545146528858483988667073", + "6831030131135399650979313302695351819580359371445002328037898607795789751628", + "13808316624446561665670975675845412570522644424965154154503596711464812129094", + "16573850887526809906244420164574513771138034770054149931125695105829690192839", + "6536774143914522904090235450413350153861560318210355846585220439397199352760", + "7433401028165144185448409996814186253264882020047922839648723974949988749262", + "12023679188187515805015064799648457297092902074185758947196154639017034370941", + "11526239531876823273618354625960431640864995247037473959040869772406787371745", + "9965606134640358953439667616539308986324141554480312185321082780157059913160", + "3745993460581557715489390110730324720335274000085036229679909083358071037494", + "9383224303353982312273937680493563948228572509816601479265308820357851069284", + "1487827268845002359294235769079867448539095616058866371843794273898817464325", + "12752425410737476015270360130920506733622111261208379938979967899453342006543", + "8485480321269023262044616550897625372838041041299338618725089063696829309383", + "12576415359894007789769349543504370901641305511107563487651205088993508989632", + "21051289172896982928450490300579871201387152257916628019163266526462496896736", + "15867382033370376377605746630898769390447074387330276410404020451043720395429", + "19175636645506837972748760370147539503389959528500852183571848133179892449157", + "18562815464677471696203191443459870050160752363485379734113024945295929018010", + "10670914301723557472895334516073215554660627986142935452136687134270343499283", + "15711527071984806338686904487656233279759984782956970430068615997429454331060", + "8708497335606838864375996732302168404094513852034309829472484268061328157580", + "4188819471869628756655847772489988754984005896205326092058226221066145721122", + "6512127543122355053584585699891817324589817660150620823656474181624359941201", + "485283184789889690494624068272585257719678055879291431306025716514618916201", + "12469998319178098719636931437231251055837496888416524814745527432538031712785", + "1296020106178851400649855820617531046666668928599018437234450345456859444266", + "10011446468770184926016968173857732818096269728811257796162165899021103326404", + "21669153150071610384945525175896288044525929994331131233225247540220566590451", + "20224127309865911841696813826362911446819981503618978937382553360215894705096", + "11995994988481623386912855165099904216709109375061333173068533008232786187218", + "9410915142880940758336239494539529470909530692135279575732428340046078892946", + "540343796196110456420764600417592095932817965626261174892651237721778500283", + "13684306082150121243464309606855998092353075421168995445316517423697818489078", + "20162825761581699251737493230139692067729837621407892263730870777826880180708", + "5352686262532923758786328475456237662420216644156835779261605606151509572690", + "14736042040902670309572407869335525984156459843045648740121852458089457172710", + "15139196852186360494919007897486360521240977399849539996614669434222882428974", + "15545525411887550591483485994597179301368938856348279539852576272926020931130", + "11742635236612776978185392287408975566560283293946133146948657681925156152641", + "15933911044011218543142885674144914931062698638612248403425430247045038884929", + "11224528638969252327238392070525091272297579382723799722332333037066879094771", + "10619901685741876140226157641208788563882472537632692937793306998778377039845", + "735284898318336599638540292516453331642892791568249331436388578312138627149", + "12167882615164420400306427908818494367178873976878804005748498778042330871045", + "963476496798286039732969224933550470500612316061831761002103352026702296408", + "10589214229258115348033093903975219788029199245856576715398082842145004049938", + "21557152519616203688970824263287584036198859167308821872261472006356046725775", + "573869759526051245236872936984426432239686428333700586079723439581218874054", + "9487380087795664760223154980070289042545005448274508346993861027000032902237", + "15336219129184315874932697305233742095099896250996970622669888209373427981768", + "18404646237880969912286263998117686518695361809473583072241508209656556652987", + "11799938531163685220849832019747758716514224719376128562353011229084757783628", + "16344281677414470708413218213072185241641469290932113189992078158350700334823", + "13411067297619308137174262243170594092291209705703155674514006442224279302094", + "347096376483719141995221552155578565668868956459941108952060114777596679497", + "21711034316629345478518202673372708169627878437940325626238942704003376069559", + "18882050099612599842940192045274010067786778900079004241849918566254608017530", + "5764257238170917062706360501552002326820365975520365982521494644422134554879", + "15701229555594307124251301047127236083745198814231032790649389796695363681317", + "19380342180431843316217793484208165905833096992510614135124089140124740832734", + "5309407894979098314097225178362235237148427064335413702368413584568729847810", + "19819307748431076945425543888401840319829139172119377623119035071741874422686", + "20514761050842041997240240118048816505140382250318444479066954659053422537618", + "1344402086478653057873064952452423683387555289301580402150577440089615404706", + "16697255135945674012509919105064086681485448643989533271078867487484115301326", + "4621832835239804428359762201398927678345509964776233571546153039277467113103", + "3806403786653298341904285490244574263470519864399252904304315511448068846106", + "19829858960657679259830225387994355131769725454664502533894857362311545270016", + "14331370957097049770140547885384829422939088321033246508644491038102571773100", + "17602213870111183187455849162801944225604239824059691632957781727843794239813", + "13431951289066965496411295925849182623784324208488725900281691974104907065599", + "16717461480909222952301202387848079129664321734166452456973177865963036285419", + "5335304795187086185403562863303763030150108130150704291401586263249269328606", + "12084224077193103457678419187386990486069302392148214780322095375978824542075", + "16562074867094659170642419054272949287052074902139533680078784684856883275478", + "5593185214695460463728593774938986800789091570195563391333689785627694694435", + "20794081973744988874029976307272029218401016626938878812907621515041534590160", + "15290613354786940528909115982493729676786892068577902693057827852601851859953", + "12549551509495378488198674258192692896591847320322918116198744545244343099813", + "16172760618549958023639071988927160267123900859890153325976796899698706870529", + "21355970775695686114097146789571025790146162225961276367865670606869296144640", + "6758388446832091660422761046124378827605916325205674642673860154638138778023", + "14106404069959859167123546389809591376301394503370836987998148793984105405167", + "9246221316655556670219438263600949328330249756179668376432941216174575243170", + "17439153852461693097676073072037755599321185173017314957734642307684740219597", + "8081777382362242695298005068719699951526876053236775057946263871745968444089", + "5955062815471620144467538738332476050500085920379711183343040972831100802372", + "7135549743533376618652729621156592228493633259664287822661943632128030927327", + "6448789306286809743113676641229641365524354356867853498363388856986312333060", + "3836133206442752775823759632522089911744536837043185745585363415112795166600", + "8306967267195429229901513132397768469414281874455321140328179401973148164445", + "14279081291461540920232629360665447603436685365844514491245275283801357455033", + "18801535274021869273717064373621101183756544015062966551566128881569524508060", + "1290309525505162730469471418279301124342110934722264762505649909318202025429", + "3684482296351796270499952631629720483486993312250657634474107248508746062899", + "13174517099719760880623841117042663715711430443825712743356469456554740491052", + "12367323038661460523248093127080567074978912019587769246568174104058982359108", + "5328098381011440170293483375144450438184897394389341853376147620924621832373", + "12027556664769952184858265393953265399418219730267455116938121684665358512140", + "5729732888348277625941886883620484887709258694699060380279441089816970092500", + "4021085134780294168590418396176917282024838594185209785357282466818023080991", + "17212964584402772629081731052343755101208077509065176631705574779383125014657", + "20917432005010641713392920477403385909781374146458276502002720501978360592707", + "15295563898035514774486916635776497660635050791955975586488426545424778559212", + "1359821178683766445655942489230783986383452848368510940932965034076334706033", + "8110406013405532283463947127567634123149268608919736912581466809002624991926", + "827196241038734359771319428856617658913932049877272548875698342240161957065", + "3791462512735380195191512407306530846222290938359064542531485381855595890578", + "11406017533405938491480863229977030648871769070115386849200353035840595881771", + "520670302347263967262738466276891414776779776742458165836379179429124641366", + "2448606803226047006259184225386977543879941109635656602752172963011710994490", + "7191227529515483786577983572625758056228282372415415309332838080598142611412", + "3307446417204024568218448979093609311776086880103323372856728466529459088211", + "3813554883592508538818724202670630447381185344079357801330890767369937578758", + "5250709431012867357277423372041580897716232143432581463056922412233378167706", + "1091692079685509315891403580607856616782786079784896146193867325719999481531", + "4469622327160639333299363654867070539113198566013450831894562184457403911597", + "17323310137022557438196735285237348172608407585356043526322906169573029382454", + "16687301461250715912904355201855034952586622338354151885963080312175524252322", + "4918535113766539148632870060160447192025270821762409737556656897638575667317", + "11072593994523457387389747805751581908149754361901108358077132406445033545004", + "3195233728052289389067022539306995714028010328554486938319749354377057516714", + "20817686894891259203267112342163112292566908705837357461445233267117792429649", + "17690940439879640319699865226478735545090209049084370958835445823603146902951", + "21690628807014351230241926358993998569388931315165663025074689739408667261702", + "20459556268654252373755265495950372631044421643418312123931432417755203158692", + "2615012003869030558909061586486157199297754407476408867239954327608829725401", + "10416424720480840919038397124331362407722217483977166150169359209212504823727", + "21194909967788113390574471899389319930586662664636393856442773352403088570772", + "21522774899908415003330605964114671001565200771087582504208866633533540017562", + "5506611081865651016465481008237511873335242056816344474949867549242155650988", + "9546865422597752417260521115459137295056544614907437375816616393702205361356", + "21830596616035544007289279751950703469521180388685936491933709578982542912017", + "749611610802485176586202226352686769865522163389912514564999424571463284657", + "6755555316754154503813947597597343604907450943684878399336695170747270471709", + "12170672505455181293754012516713072944675179516356563083524964881029055628483", + "6707337549725648754250613641063009246814657413626673293152655855698987287596", + "10796498904992920132771232449170737749742455370471689413932089087977711623836", + "8377594495858973573128154823903039902710916666748285670520960751078778241055", + "3984683583649079079845275538974168947709880082512288559917193166572776389589", + "3342097912826432514400613460588054784328673911636756618761620185294261653370", + "16454683529696451672086473280821594992928717172228276559555553609303793416523", + "18807899744562842658522302889072060930222870278511178161869216361165074271071", + "15733467702619867688911165419464811721151813607792971238595067966297846247623", + "18142314765654743253383559257284245535624730148238939832089390410939642651454", + "11195224772751371350570884976842181779831961285896963666553011681145523971069", + "439244367736881667144534860370666344402105076566699968755250684892603338082", + "10704735720989025726743300184412677969903347430627186939154207946469729017738", + "18578876165452990292495920166540986834727225658030437088905164910953626259691", + "8557967377050572410782106944750290348752651270453684627569664713996263383548", + "8761045577121588487744533431678957572685193486431511842082771483510204390408", + "21449005117895748002614414579158497856671036353929407470614229969798846654314", + "8742763699897193075490808534988551410985191733407596422193467672281063172120", + "21640560187468057824325948244870722744182743184907610616373323268039154063822", + "20504827051323136179653341596769205909304116951166709098994304340550034816775", + "16172525553351370894318080522373536864524825253487998830365706514360525527841", + "3591685457927038924948528662301423116917211093679974227116322357454330018554", + "6023337410706762262272160833625601604408129024083079173527188974815598816732", + "18314718271070348604361238020618683829686900661152269809595508349472847942062", + "7836153641990744469550400020392942083885339413553995305082889896550143678297", + "17661458352757891434962464787581216134089171454741034624471153568868635718017", + "4122036760441574620764812242429576792598439550172741100479310420694208068906", + "20862235339890611718235387895311549206105487705288574136561783190763219344570", + "2850551701806552645458448511649317843914427882049290827414738885733429831896", + "11247005361958789340696615426808536553465247486357927152826112838641725799209", + "595377141566787974548956333113514797724094819448399289547808025689225222483", + "11650535249856393960142913145219442364845834591244773725262296147168383099202", + "20317269079309969728497469029861008772266846936951222269809633626856816105008", + "18373353028723033673212698815557995243796350917201491012576826029280066160567", + "7414281571887634589036890397094381209738607746338326059409587963803891852201", + "18038763738650749116346354096722212724532913209902202281075842225944189538168", + "1770786615956839194004148114013826935077292967352199469327501774219607260953", + "7488031997643483244135856650059587771856081877857609929648968340004445042854", + "8828420155416920637244885570572746512651260806059857940333819295380848667606", + "10713758486859145329962611447140189455100648474003892294431344231535672892839", + "19425964738010714594065721309197326935753724219070408633462182732050226443166", + "2074939531697630696938698501714595125993887544292881866150005180791766942998", + "12047170609336587447894029543834769407220306562179617939497216596360229783300", + "1264730939976742978058162525644425945405879597356760675420608373469615068174", + "16770820387947475117163540876143499701759349964098540413422664664028819497801", + "16280068293625117002805552395286584356701604835446863786447466051605766622630", + "5829399622833188992426267462479081456743106260845929463922917463933701539334", + "10637584899633814574790036401685386209425675304700886428980902763634911791837", + "9291782595793252587833322197337655894886134207930378095811922971339860144588", + "5951026341599354622946777675133435736866407426534732764305509667517377130324", + "4403580174404926097288523091529640188805282235669930524399146786861723458014", + "5003639966922553172252470768563093188889050306376650665702227782913343083764", + "6558197410800499965347594156873334155413890035105551024236266846011615264982", + "2475377503098365612622742300317283313185534384082772531168342518799898155594", + "13480086440294256226712366993542304396509909765502683907895525126405850150623", + "6847184584651376043889746562956674365958636593745423518578010394007380039425", + "834503921046130599339994952233856873876410737494970024102211605603428829597", + "3623466614124962325494185109684730979089103423795285554788413052641061197022", + ], + vec![ + "9296474750911444465025945061626611450573261102544117494435956219223872045013", + "5146180402642819236271333772846779841277266622562021651959982317806096554632", + "20454733758478774733902661862471466785458678414673417084919753466149262477949", + "16939720779646471039361700224425387363963401457766730187304254365590145685643", + "16508379613071589632225608856524646606497744838305343752126125339777944056893", + "20867355466989514329400908378893992018169546886162092188544040547127653338003", + "9562028189723224670918372808954372258890790835333923497839294908971703629044", + "9227509288281899178360094205033853851646604997619773877005168383222677033411", + "8509781355418257783679010460137433931646066572707591432255985024195888527301", + "16352397893201944000231474199631274335610857147594743875684031732171609392779", + "7168331327842901194795012403324475179802342440545189729818235304752196473490", + "6805437858781519809721294519096505646809998863249026857458359222740400480093", + "23666102285914319661214067066621928648019777016465806627627356483470384578", + "4937167589168346771422573562192746031838523475116047879790134471501476035621", + "1346691375815699628539641638232212515770545677194558930872887124097351576509", + "40983635009581820916284370715993074471281691288657861297464948812277259151", + "9682480346612414028382424944197316598030638601235308149341398931369789543950", + "20156146228109066705562831124708208402478981918458654302206305397911512087980", + "20244794515708180670563002449620617650597057411850557162891558214158122324521", + "5973431503164625202944413714022034366590666955289560873103517106326649624937", + "19003031440781649161524015602474761488168160816940423515211864494962159501828", + "20712605099727052887180337155696823289955789009114447705180663042338119444677", + "15751263674652110912724722781530878809312788917232502379399572977178318108528", + "9759440007076373606849230657528653877996372541705166313887529308971932175875", + "15753864581145946158736383142711883662973744817981456049085179548487345401534", + "18516736976984654236711834595195133682620758902795528251669085852778367276210", + "12505762035583653640932505661921159087471940695093437071026827168265805916842", + "17973475260212324625956540069233265735155253700466680406635575121618318752819", + "16893238145591341977099515648275086133943062918579997543738633084157810726656", + "9669071880586595648023284909288486812190820353718106940661900367937844527179", + "9349088318894477564190440283477178116641834248883927901328258581942583077569", + "12186865849936919100247208155624431297953689379595363409626510899600302936538", + "14191429059221279746000430832297028082244506830783856999765158986408198377932", + "180235525898780969912044806879591313131227292826139844018949863600387171682", + "10889092107911649889040150092427122550710450427668385404292705974881857473203", + "20693842198933957663269842304864226322478103663024796211607837700737760050747", + "19741631810531886646761927581354810838182866370317964412790883870153217103250", + "20514964832794580053019916730141871673725635044918093569735954402314586611172", + "1563081830952767432323468775999289294801679977848773475307184358241727189864", + "6541733180459084604825913391805383670644609126706479690307729028795470985900", + "14338950551652503213249338133071776308134322059752479422120853035176120166434", + "9445962403225070324948180958168278025259517118659455884585920056598191781467", + "17673503748974627902616087621827013509215108587044719385816919777868083778907", + "6529067669277048252246949093210874205656745103861744893697681349157159395382", + "18670351688014831561846153455584274335550086431574922181801742319576494275746", + "16087198812208315804697003049026004024678636407919712012630915190666161641979", + "5409244980912243970485734262038475969739470891565229610070736907935180643717", + "68998709875023468479905615300134369445692715997447916337587330860748485243", + "20797106660136416987264043187693969873379408007710762405000375236313842719688", + "5277839105793767851333321356647781091931078040812937205152067116052352239761", + "19813316014421099365974197500618281012606383357022846408656988057396247542705", + "14651854807736789020692970167659260203349703129364255901280500438993569147591", + "1953950121645869390891017290629473806985703435547819703015178261443018199466", + "16966986407661837074189113052135209905137771226341312735335483526986039302676", + "12196911666087491240035929989808617508758866763772938948559650992149525851273", + "6748262588722620715981149705241221174138004527637005241186672382866432164292", + "12351853389756326378242661122644604232955500481743248231924728979085806709527", + "2565243335980149108987604508873860765952308183381198225102084152967125103373", + "20241307878322245036836862464964995816180104231642798486998859049422772672116", + "6173912854438429518808824631217531662651777757438489861961683800252069642271", + "20373949892834246498138105881327221987245360841655169052122063615887220321147", + "13269719501466581754706990055797732063851220874637620573076979035861249715318", + "1578162066274870756439515512829351279665654675138074205960935197210851459902", + "15699466465478499203883101572116714566818501168342041974225130392829754730992", + "11504917391580472762574218883359632564098492996052059988389474392975779673931", + "2471534962918953214626354556158558932844702538697900698209059019370494276871", + "4461270721380837522838335428169036184773145514356202591842435276161887233701", + "17625308215993897091838888595388246859096597033404108848402595233466786865507", + "18815388073919190191562579690732647812407368396854637581401819367329270645091", + "18268550843300936597164339843045347137811481798420250960800057984676328312298", + "7226998309855583456700105258532413039112576746166962016437941756495852856370", + "8072980663193342911861442510877605529321700341477138509973424538392015970628", + "15269265747158306563417251524571764365372430081923021726955952481038826679058", + "19910037920320033458941731683391812599895690039363377502140416867160565960964", + "15486045363368901308969563040163325835584354680260407824152890548047474173382", + "16416166568440710996186902352749667794644450153896415669656858302452107263361", + "16719876352169334284151333613847626557780385036803676145001883066946186048592", + "21250242709366561537300491285945444276614074599553674495821079421382627519383", + "18996863118748910427791883574992010505069161233259708625680518449974859990560", + "17413984989888387572882804568722637770904232773299911698227583956354366272051", + "21597529235679499224130811468867862981087206894945208547265972184954721846149", + "17271950603399986802591192304636434671723720851969778588610595038101316019146", + "6798909530322911571363098835602980477334813891267210720952461019098407212259", + "15221754151466299785203667902143040752208351220550667002070154445706666401776", + "9969565572595685753856723561942014758757583006296150732797865871416014191612", + "213937728610177048236193694412457038661914578783162813372436128728852762482", + "15615646173777239619093550417838782753019556951599702936217300723011405507797", + "7718045694050546136660011535056217361530495049313202420611728185159583583910", + "6681562236645975908164269312121030538373320810986198141132181047805166475529", + "15406190007218505433124772738477886033924738791369244099805663445061334497251", + "12748925302440648174656014197639220978675653093966691038521528280766659388490", + "18792405480956246176786158899722364426273579869771820318487342148987615503627", + "21034833205180901867479986245412384531166379419487221053266758595893395608147", + "14993530305792055254503672111497655292586320227932876629369830030730566504041", + "9717186869050569007497148725820161576480205291215534893842038294586234260310", + "8846581556095542298416062056868302371695747263219967935160771313384250848220", + "5719380810982615524673837631402222949910527678512468701059039624789965209167", + "5973398204091658428913223841081738015584068771535532858878785900515770169284", + "390665721029373984714826019392824960041229454845430836402699997231854884676", + "16884099579377843869279635395084651641533249525144181522512029929860550566335", + "16716976662979247989662403288430439465273241484103184167374388250697744962395", + "1289338592939287230201589454150014946433268062090374613616251000166621302313", + "9317927644121595578754625372882467923006787730797841509740916536436754202554", + "9792346806272266839932159619375452292987210695578600955864989901266954094960", + "9296083977157792888817756474494818556822681079104304334773148774182988756476", + "10323608200914404656342379674401080164220099943588034731349775904877409752904", + "5665882510779783554356611639475035143817214951779938939820232711292028607543", + "312967658452369621468725894369965307895839161467077935727514890821777198625", + "20664282841391311519597819314930060269576136022608505709992590417893434920589", + "5323350315725158992622594066490821193659726275127554898433661812401256218478", + "16039351301369040724720782620886565139379163954982512295794534252600896786349", + "13820693026747418768344065399393852077420709727979822490883114289330249839237", + "13797176144228246839971555725332102191019905588045129521304130064480669479604", + "20861818286081952786814445160300163171950644955642439845329412070095760317081", + "6607366884537402504576829976217056754321721309944806800456553075345742381854", + "16676075047056109258708765855713030298752565264610707737757882684833916800885", + "2596872657894796835537858907147863451585796495210087845405329734139833282637", + "1129905770296794876904745792895109768657958745069004656310552795892948378584", + "3524768344101236852745306230236516385903870540974561871381448404874187920054", + "990706121628678949689364737717640674078492689689565457695471004362978678643", + "12808278123975447545284898374625872643451056414444411676912801184092083815084", + "6358161990036632946294642058872786712712883111056083194592676110308231876108", + "2793873016535929696420652383221830923887713214117784093571041985641508474546", + "17305928010614439499134847438771424617226147912488714899621343734884653872709", + "16284502064199759145361743401051151176267685561605421586130298595070638086967", + "16669378724978577155412758169912049188272082311653969294949527064226374258950", + "11861408925173541719238679231659983919027526756130925399544116580983984008351", + "20319862771317637561778652893808792643716731292949307597222212602977661607952", + "9965217723779805596104842963458526859730058546126612755023280528059812781678", + "2231229143040861060383699098560329742848948229177358362095200642518040448582", + "13286704465412914480712873676020914803973411257385854321890647189069199504571", + "10047635595882320884409798135378777636448641999630707194378323292740008960417", + "17087336000400458291414525340830964856800142468906625956701637877370905283650", + "13535594575282729223473509709844990145664370669908108705760692736046179136608", + "18619202345418036145538258744454149503028380077256559127312056952610301046510", + "17607804586369163727645967551963527279187781470886431384954240254070602283137", + "2633042556450301220705608140363996319867584411611510879359782399294296770849", + "21731768638998447189300033743436435314153248129574741734083353285598244080117", + "17469131737454037935821691482173830563221091395109883834897114256467877636669", + "7750519651616125729362402583651846123740462681349952291880562002377909054050", + "9447081032000164239615272903502339392629921187510175841323135270498903409976", + "21517411732531464267453023393592251500842566572268409532461770072252092958721", + "7876501141846244962862794902521772277174190799788868978106856756141641727971", + "112943796512817751182977688559740204117088697116147815915631198815244286561", + "21045605911504121416853713285261007893735116973950420994950288232723845218749", + "1753558144636632850096274509984476357404441186238175375676398948118672743832", + "15932527070583999576056453444162361416070384829011926782656187054064561647022", + "10670345925352776542283780467580832901477001176626927666485810080031890388634", + "7579612604695836258451031149594628860115515363868399672164640908835805063913", + "16678286807861813265032290142015890821080993558199809221760573633471452514219", + "15414078726286200869397977002633905619706559151321201886825291326757189172060", + "3948850363929702397926233515670425547474212215810847662989169477642088807390", + "16676527723244281555583733536047809454744760551541688199219131455695588765207", + "14087355065973222250918209290719451048172913300838805685888196087459492418503", + "8104074033209440421654249234822181338065658024406724406758136674393332631833", + "5187207728881418438225188748028865692950088102865770071392557429006545519499", + "10194509841193628413711183989804813746356025348148221750035788743075560349210", + "10011332996303549537072329954668024063758462809797094286213034989313201039795", + "16531650268844669358279021502930777186663937554425443224519161588787088219270", + "4198803426144178314296362723890875454161257236407666607766866723687553739691", + "4796265297638646381399181426481493643799772847333437062194249373663993441511", + "5547609802231005143723955844984958632609857658378828698100141356246667308579", + "9238958429509576319892727665041354560043563806656332888234436819654598656915", + "12517630133819614217261779870726755029108748195491643235440705119352058557308", + "10368014234449326131235994433740216752312468149182650354075154587397704894585", + "487465315883418182347663117280302929984519597673016955398438666336416216955", + "11185034244837678424376295011043645561088905841730131726788873681031338174455", + "7421225151165727634904994585688522807152162423870550118585658136113463984936", + "364806019968570676099566454292016788351689833960119434834370974516536828706", + "19587762041779243275917908822520467733740516572707471226884058208850887204874", + "17699580368555821903526305272862177569486615328343491839828472034082952960813", + "15739138573269259325517597876326746482937619260543240058947651429318524320399", + "17749815771695585990262895269645295514834869871993754550237121995617786628911", + "6001281843453332722738415535953496883454214144943230146026585272790933236244", + "12226248842279453247400486197034488006724059955941344491855600110495696624034", + "6471818050024319863197241387509891745688912297463370650154695351698691437030", + "17643944916136214612858153024594861226464689685432825152621939791565281052364", + "21110507073644152221308742247603861828087429176260377204494317652281698346306", + "5767681379026755049166284789191192306599058359643996830685583640018326835809", + "20268516002780303771030074402103352053711651542638490897887552979541377898692", + "12422024375924323315232423143442023050941283872688585715847426230444960244284", + "20694378016149655833849108581703458975143197158248183642690852771732423212333", + "3589864715711417186674798636588069952164879749159939425060725590030374075726", + "12536189236026623553502052145542282538682809966098904986394409008189339523570", + "2807680329090948893979159370041090163078264208853025987363628558807228757758", + "11134364423913486029994525311335222090667061028008118303028273833566959977738", + "17354950677485256631166408496835881692979370134492552889236570818914175381226", + "9148772489395197941519683034415731069796332771510468178434252005940900987586", + "11051248410353114396778661421385387052304377861539041695630551535039137025728", + "18136540266852326106685174083549032333515525540247442551401150755180487725743", + "3985310545130175559232554478662499499843818415947765870117105273186277940709", + "4596525943567680471287409788454878169502290977680316722474714256040545023213", + "21372340401058762695712005390221995267277180470546612925471076506446695116009", + "14075257312640062020412482491643121652025454294874360644194100265009640244905", + "16944503245314408069496787236107780704688926045771652862339257733069860638621", + "6654085263135548167634225627185378533095825854533316762555824971264586187651", + "14273015308464032668640083373269579252065688901233915918278293118708191497972", + "11764478817260526126925152191588101018315006712336605965222952598280968869260", + "18155813367404719470487615677791656111973118264369674303621800593085173024524", + "10850039649283761393985741586943649861203783935137056310000609328911733104269", + "14974871370837446170027589325430324426484756076474120128444445200816418916077", + "11027268992558661543645635853060250199670617750348905948352231500166030736735", + "7737561462151958609897925089803246494900406501278116203687665387696545068888", + "8536397585289585667363111427598616854125268561779225310999422087929379230845", + "20520653588911738970276129298340919743898256960050723343166349159335019506767", + "15573689478722985997422248150576705853901581704550704092699815959211941071233", + "14024637413191434115623282477558112970843649259330326803453616105375507215588", + "21353180477994165001466351039795610246389619571796579650797005446278678838787", + "10956420585038523642301267761059211443146357574323727078003385100699325814188", + "17634836995596798350536418601573649005517540866687768902898663209263471034753", + "9073831830223507407321206741538426673038288500939999264368323867070102600399", + "8100061233881358546546217363648928017848251671613674228091904606518338839516", + "14292884686436880002999028765738013651173249817687065086024117836878136072418", + "17843666610704256421074257091600372846189412242040711501888312601205476877610", + "7418496999733433074316279404200997784331208365418356982886646484553701153757", + "21292338796777812243292835631771215001169911232666037289555901315952974221584", + "21287440813442297789932443224883752220885368198719782335487617798315717278443", + "12316285862536720021079405901921917335504024672055930573734336005894401174699", + "3187192338760815459509556016254324490807541427929108750144803145054500486833", + "6482850190067117044880439000213252508905126459059393355671593783930481002065", + "8071947666795842917503687890154152458243669781913953337362618950188906690910", + "21450848111897538423936810899713904909897296879883982984541189476327391575319", + "10587193221429670115264727936502940314613396351335733485096445152378181351510", + "3385684482890050363671196710999686076700864071377274740326856556910758812375", + "15982506074704654515559890904595916307715088473006256644287900474899011899187", + "11051707205631537861946095917392475702553421314274237258592689190929368154151", + "9251268179161501251470629870144065342881530535654006637177099334228872748754", + "15384401424299601275458808814042231311961518546060835375991090955541715971658", + "15147611899621647169760029554894128666862161642594655274320073446753024250644", + "10615109639224170479859701634647953864795396211020891058926612120687182210257", + "14404478161927699835476596901422616937403414811611272602635749875651680921447", + "8066178271733489868262162784101440625233465103401108911752234818690246453789", + "20248276648316419325977215090702991722051292305169422329958075780094418699373", + "2029002457916171156303194520244672392499138634810303216935386602108547985314", + "21075731183134253416827200425853801562619807215475840771703429923133977728069", + "14328824218343127380036695796575765857116907766196272954596277912518546721093", + "19160580257616407097132379087560824295215411994049928358528355359904099586504", + "8132787339090119872084216324271073977022107784441826475259174173324397592845", + "13163912407679060956610455137901723175820157380216990622789851897632818074059", + "8592347632837509846508131492057017267103172209796052768156176559923311880083", + "7893378189384253642782385691967744125589477790209699483381677762080196748261", + "12191210041395050728454216483522186705806341251170673836903099334267999015601", + "2618630263994051322846776438484808085311498796047898764787894432257296575984", + "13304976328362334711292646669717074062694791647749224129724116074506061700957", + "624484185190294110172011007497433523891084548746061325634035014633317325140", + "15930533828823189720011923265223664488732840218774700941123034073028585645207", + "8694885217655511794794497743599831016837108207363203834593510913033381737488", + "17331704109224667609742217259848258607875799984699711250101367091564505664522", + "1143531962761362035993655799963451435028684354850849659611727546724143302608", + "5414384052493950126841753058585655621007207302558963578017856767058437816718", + "8343436020075567035126766344602793013516161248129384290738181959425998466132", + "4832334637017830367140676637457267590768883455902783371477346052893423021577", + "15960489327340978673041589758216206637417346222123069896632550487782527402630", + "4557633726568362237945959401789921266559833502098724828463753976542737136513", + "21292745345591415194683498267204047392092318996401128975083535124377610645118", + "9328286636803072400168705383927986130049573701928015781654594560657277940196", + "4380226305886799411237881027947999265683595948968607979382183326525427173817", + "9767464780410766464122903880954110687963200055038905098288212464855640106788", + "2341077008076389666838372736815646466482189988625828995627083487505977087946", + "20374148380136094638123722089889049817432074134077941767483383760377289749825", + "15787533442296590591714142770598935669897792586470392297628568666971956576563", + "7633568663576517885027652011215374332444473983000466204175445586239040766264", + "9580455424171239687884724329420941872151195359863514187490663550878551019919", + "19911295277809179559313541842789165346180998073715101124443882860854846201169", + "4696263765841909122685466774945153879000521574484303419094957852664345027123", + "6118063668634440692631158765198200090955204724365488531804099825202234531440", + "19475295610121478762637598544231725416556110773059271107863119783250115177307", + "20179584065699439977644558242108004135948300904465438207718184556293527131765", + "2676625519221951651755843575492662910087680586300055636532952929295968711540", + "13080027857034076796318609243033548218531614593023186061246772929628249264284", + "14263363493033688982783626695159053510832721506041125050282934376406154340703", + "2706925569052822828207630841519123914917406668054471879280093987418440726365", + "4296262245978655924075197707705805754837595446469608588294115404804858164512", + "18695068331082119185822574502658840301072706119995753204333012565779354028154", + "3337114200744822151016415017664070914837554273478224716426789950128003958134", + "6975962532267211837956893753783559781855104297873769130878094791004904433267", + "12231027575978562434100945363599501995871801149646690231633189894762835916126", + "3888650643207658707541674459822797638642380807202524073478543941467788883170", + "7676102615198465271172138409531332193754467889637067928466752449336805364120", + "9811623913757464238022803188199125269665959963552692281954397128646993550529", + "156972936087215783948417984577273879197745728180593700417440323304914519034", + "16588845615557743733989563376260327418375621586848888397570715079613783522187", + "12011819284668339582414804793555969540908484357893010282713633444914261107919", + "9658635959610321892309182692375199095125363721825304507540533137281497868500", + "12870566947850007704602286722292111587887779596594529150836676091488336717955", + "17017505534531720639069672825866463960388881234646040969078396172375695830933", + "12828756987874340466657656310127299330830014385503837959876241551509225608029", + "18359630725137047619220866091928132852289131876343072040435717392635728807670", + "17863140285101027979634946030001422306163257009614315954049905801373677640874", + "3360582341611046517265570944669154454984314353967466888538655993528259823694", + "17502670755424560054495200659249586316206934247721147538443383457515937914644", + "13927649797430421409818392324255621487749881718200898095569535249421816857631", + "7898469048097586242538236499785851298058905177690518852139435937277393454608", + "5393613856505501947177492775058221051864341377769606207857027894289988034452", + "3985540196927201732264077382523049411262602519666474163140081018404802939018", + "9933548682032172763206440650514545057762401680471287764841975167579530669418", + "4792769546077532311825527426101752293398958175332337087633556291257147047450", + "5156370681902535309417699137971512021677704826447998658592162481410036210325", + "4763178997526214364264420973622397594953864683634906055109407846288865926145", + "16580450694184328601228411647550657642835283837702883837525078295714435399937", + "18999059441252116518985471589622428967202991051386298987587330050320210739909", + "10924663926297817693040648165612355343542542868891379772060513577838006191064", + "21154439824594463741340124378173590149781737214921140238108168355994559155084", + "19866718036982650474956880892863081255204850747846301678102177541466640536845", + "5726341152794890743559900317356587749078768834368131432915420083753465739652", + "9721930072810562138700262351588760483759343649062887160202262013979665248772", + "8692713109320385702126858931428174471319167530336355188864897071149715822466", + "17412352102001079694372298819013833514973940827985696439109156982412245617083", + "12672821032755011921233434696998986247906307111868736700673800862103166163534", + "10172970004738576173270726006846527765711642326938611469845242801391711907951", + "9780618262465502284058891490165578338456400832996467543839344602761711940182", + "18851700024286130309776897830342991020297865786362943013731692845791157935866", + "1702470413617318930175864989944938294024268866839160834076264568335720361305", + "4126610465068493007303692923323412316073023198781919888394734000856090363586", + "18923463588257096056764527998950010226471775437259486940005784970583303111186", + "21839276475997615446044485384539051285181302015654907519320251876081314334359", + "8307810470154672938299109640101353533274474986026012646848648110658880568963", + "21681710504784331775159894287594944141623698915845714535863219742158877134446", + "13673546849110664891321911520052734162092211680871085198884137808051757614727", + "2216218889963359247084339208809391515747106874740680794343547186367655541588", + "19115757323666287625233094721549891816100455942516447718127879700062782999180", + "9695759088071708435257280035083149593819491025470776577904130348886983773393", + "14990538824992915759805383740971251128446161760292769615173978580109946105509", + "13500547160059033639084125020765777005399100253116035721012986936873938870871", + "11690620517343570003741441631732985155983668292416671376092598551135607742688", + "14092995167301878045390831717670181419253620142006537525508736966592448309458", + "3134074644668983555014847848317126775181820544161601574897784886291988720093", + "21356667096328346522478877399307107750543924879742810010071567516379232573327", + "19328894389922014017090671733282649341431509867352021154566219841026028128702", + "16777200051435195914695940482277275703598221309253917444691069340963118078548", + "12283150914371601398948839801032083610952821665268602559004246563482653048467", + "8031025780211541530328680242940535108474848337234033825435617391087509668168", + "11393488534594129202264782038673712630583567081414606145740976603672179543089", + "9489545274708587303435157546929129885054870357881034831999260754593859728111", + "6440297901700932642712459656137166095980435930130325599953289987347675780242", + "6894515864899267480052927589331916028154612433273964297048946097044117290367", + "16589536620737203892631819952021004148548871602361830198268389856564419047101", + "4583341011172551024562134025995013510576215116397573125685762514159294995879", + "5241434939346739917434576806032039711895865193494390109560604956906855912755", + "17826720085025179303670747265498956093868413968174402515352860124554701720680", + "14064177224800231170886754123172947484113558685092392153296947056267698509591", + "20746239761736290080585462212523994318855974409743295600262800987044075760592", + "9275091732796562047971474774056076192970912855497078395575768670699769126364", + "19100348980922843718890560618583044384034028895423544873772560921345167893474", + "8069571373226602742410885815839523915870737256484068502291195820379222033494", + "1467293981248465102656318727619114500592839521238995988554329217082570049573", + "6381288201275521270245376318098534380164014423572839901345374016424121324717", + "15155207472765568640645705040738739058676005958167290460723767903432317983809", + "11827307205908787524136950608324322915050519697651400085361964512106546953617", + "21374803923432823385981703420361272374739614104998515368780896432531799636069", + "1620198401197709963530631727016287708030541032398661971728351531077981225770", + "4800625217713746765755573372019630732124860961049092382553729057755156854314", + "16885045113746325978276736698359862381890909478720549186885416774857519433844", + "18940059701033384450370562570502818829119108154708321114250461189220553261490", + "17028163572961360646345264113167539623561504425952365941615928454393252072957", + "1611295667261368131094571297996490796385397691978293531693197200319130547745", + "12046456112369511110295802643603369841325461255354393474919590204243253663937", + "7754599975225661234551263660451457408477000193002987626530262268904609507135", + "2313209556333942391083901663566216617901599085931440197682535151404828238681", + "11201045085233852526555327068198185072847585214550933934267941732063511616826", + "4467724481011544137869960218540384367398804813150942792543111067523429032279", + "20757297420378962887523157926616026028995120570567878138398997747263606554197", + "17461435854008784993561933203163122288937104371480871856334630516397129102735", + "11233240529972088933066139644647717712375997842172826165553170491212908480221", + "13986517480527430903609790838030615892444640383875866009325809535938190376249", + "4301929714047907689515030408708811722641058401192285565408232097014641811166", + "17696794946098216231804098416293622660221918490072683908415671549432039016947", + "7439888160491058128389941744272690247182736763968209695016076283096704865863", + "18423890552826544443227868172047086037747632248290044990903922658938527547680", + "2138999949837278709489832079964510183830385901897653052233908704951853637094", + "8615970277754580973564280361114435711269905378483503993334701750963152744511", + "1245284434872653312507712347938909167594598148561528981150147522912318212857", + "16245768201990863935411700653063134435976966358871420800168843470345424885412", + "12879861318323580145511978223564804504159396722688932396568245995032194740594", + "2552284675231253239834976615340003107373525651900622595931449498227491766869", + "980488019139379194961142515231528163966929536082343598209628148732322981564", + "7264750621517252424008399274736151499285393886075664598878039391991523050881", + "2234522067987218377738399151771319350093309605278907663987720519875860528325", + "3115352127411243786318531509959426596747177553864136971519102170874744602976", + "3667866402502198123848250630765454744061857715778956702490214141676773902196", + "3070805472938376665214561241692318374677535766486562510422267606125416243825", + "7823349275852374866499481666710330223055954666864547234510846404777769619933", + "15260540996982618345416395328474127890176746670866447824367770359510137832585", + "16879450644311650077796590833984905697151358442225768059780947025899660370589", + "15320151525992649849875202875042133283365355535963553893454329179458534031485", + "14632268633016875179098944659717422356155019599115523094512078700042675723400", + "2897293850461343844445387032809649396366859437152990471719742534237008502809", + "19666002760225463497556206571085469154515092232825812732816997876615778032614", + "20118956923652349866364311940594053676005949829436315819799225245413961818420", + "11744985056755246878773405286931074634975698324846162530423833591918403445926", + "2015290434884472026423323399096281629968890595973845384920383969402450506434", + "18249544278720359760062826368546772272198884406461513288445757927068468076813", + "10696154943059697598572810332978032400281533074175542497867727183214332201316", + "3971341798054170372777083512695270701169903687966221904151853325481552612966", + "9959663659512617071119055590004415036736845473755952682208877124936249722622", + "2181868782404294694165345801562667214869325590275262047722759281472694906368", + "16543662218198449396015118334228119894116585978443535797616874635898860943302", + "56444853332991525451220607324577660725674378827134771417770990653696578708", + "18053264525785010356112278932118420278769989354317119094784720416230380388033", + "963511433856494437037779480692599956325036862396765985497581773445785537789", + "1640548195682821030419870544261428767973895477020340173398587128599119014650", + "15577232677357883687312806010171709394572550002708034453277797023283497421495", + "11090954381098620504472251563901051846520004004959525348540953956152044818938", + "17126684395012300883745178409829259734795520186865031009709416122834152378303", + "8422844186088908124243365558762687987341862957152073183459572023886741121702", + "14662184649744589649763530324217861015549859438835398957469773613387857845572", + "21031377022606130696364565229626602575982595290181000993536506695259062820250", + "12689389963301532909415546365757541009330035137990488344057816579888146178666", + "5214588312023400585366048036841380932988375130807938893042700215898846591858", + "15041893128824524382738883860992957588596383766546394405410998279035324015705", + "782192460855406809992878758154419200401389375934686194113667662665836876265", + "5661239444927590688224044135973292706791664398184824354673135332710484834774", + "3817944105257087067488946967989598283409314186886285679195995872866829761906", + "9462770371773357009169408492776891016388486549772557694482752113820123322232", + "15769763308905916572724877727092407815390795595917044619305377061254245212113", + "13771914451667791497863967930538877162560051760275863288476375824988661915333", + "706561967078473376761233253052150494577539018705821668938338502999740910843", + "12390235197745683286169097117092390888206044377209705969844343148646378449506", + "11145596728577531179888406424537808841248238586984730649700720979694309693930", + "15681641822349110677199695953283484509740812777386467296516920337242539284544", + "17574569459993920657262688380744386356573422289886331853177778938058648912158", + "5624326259006122381461763176192388804186780246412847832931645688163746289220", + "16496277716358307095107833912170230220700599576045238114071305799889738129888", + "13435082168481898917836725813624706153275101528359222531631402061384065427333", + "14145359265331851785705850315135126451460028716020850520657056103361268407457", + "7994845231841309191598369070742738315856499258678582728014902950258896103570", + "15231733338108258465034981184038200743349384534550555337079556783807466295081", + "7713361220902077511242971379188205561979775701167781811837114504665826686675", + "11242747039712276301478013037107867308448907318991409117791290960665848463140", + "578482125379746689637837359294794469152617864738083364508568444154322295070", + "10411717957746838375775334848320973308009407649021455865417509560443692302903", + "20227006425680272844667600313609218155469920109215388465037566152370252232679", + "4086233333215814731082706125141659248745981704236593522409792368006446650781", + "6808584534953180557531972017829075410964510413317063595166364533912498333198", + "14933356623681974917513408843614143743808832277364712291262158931793965369957", + "8361829936147528340154802497787058714748584629340813748839621641190595526650", + "5538387899076347863195504194335672966840748823754653039217054113809390157835", + "6615705984888160955628612086123920128735091346352058978084487503753552928718", + "4247091362085081761865598677360777173802067597672781739780149117241511260340", + "4974625254311074298909209418614844254599548567616598303359921500987075775722", + "9907284404283923304330882823688663208972219438730081750092058981162203620514", + "14238658152145851054995618234965786835935641311230999365757330392464542182773", + "5602036166343678358319941150088594172266643715315669628685676756102877898852", + "10315461382975117983285315435824656113503983463182219407091635205239799886780", + "18907680493658247637744313142676664986314600274326418373879671192300682190898", + "8553303723584937031207437681614026720261370015480962759264727133956998736136", + "6891145490942460969785177369488530687011218911690606251233112277697487049464", + "19170245246106596353570021916624717497160367167030242670159454715827568730304", + "12963872577905157066479007532642021260793201956955966146918319119859824768103", + "19825143672793576100800645640010743262329532693712002233459160547290155991184", + "122363237387596939334930000068508772338726942066663977131612051418977350004", + "14083010722716557573128541885186700095072789367734739290283132018427397490175", + "3438988943822218606847460625826294857914025511956848084069535393649532189446", + "10824463893276561180588773956898041497815337719354064658470380006885795713398", + "16647020853733827256761129360155419271528077519934494581063879760642045999108", + "14779736608400098952280783906738683105991809429340153405681057429405486938750", + "13142746404873014842415191205878004285381311757484122253939053617110681448928", + "1386333773150414920705543260472370744952980454893569383627231135209073588228", + "9697679119976816079822213749536923969219789272727871054723095487806154942217", + "3460404774244857416356250946884568630025797822298777944076755223444927083223", + "1247968706400267099989617117009880060043946421405967563604685657862139452642", + "4507768933023927635709805634829365165299253230159842263645571663212665854586", + "3426290614024232855381062903753364259178390841306198547519682507770097215868", + "14446229460062832266543880366376059431654246279317515826580297094759435628761", + "8067953446832743759173288639514778564060677449303509306198517269476636669111", + "21177512050925009490126830107933732327927737774182499659239090599165030659885", + "17012508948587701524178526490941665696519922093511307343255635334215277408110", + "13790566627669249053646494281027520203709518820977624221038904711079372230598", + "16958540834863372886175563802155893167203339755555003665356919890498736433754", + "13423323660143533006628485455163236538714121124914329148003611317540843114521", + "18732130441148222818743122719599795831305992743627249485606912380686722650328", + "21744582565522883116221789698750442373155722956313850154199652336110648496029", + "7144354002506963954801968243991190427536676772300009377345054067229788469802", + "546773555852952995236535448961524872583912665647152978722419200006698017228", + "4115449488659159484679292884434524602598250771770554945188450323754895822199", + "8595752591492411960378746550184866534422481915151040676780917721787338199480", + "10165757572338172851680092102888140824090130405358311565741520039277283108819", + "13881202481966783370628597357006999877307398877082297393247431527668438855111", + "164079380527758195225075822377759030452558671627014461867366308987961032431", + "16597854725561663920154725753244355279782548142174519652163898109297275062756", + "18782804026635015341133877400860675283426234307512052057983648925359584161851", + "11803457827110915157916889714293161979623605698803927824089144848270204757888", + "3790889121366006080676961526219702764983373811240106724685417109395959845261", + "547387322589169298813085629174571402766705427171260176930124272482922852550", + "2250336107342267953278191463235028062291289397936525878162948482155007182474", + "18878522248575655887331882357174227152771300904536167927922454904180276940063", + "5479817494658339363150524278522534672218076031607309533533517453567105458144", + "14471434214677769494999424343272645790653559928767779107202935041996962964627", + "15118605967190623209837537416237887934162874725496448474965882020979641133025", + "3039022034764509339398468046956573675942916248030956764556346100611315129267", + "11040960503243486479242227243433964824049773842453715686240136222246114618507", + "14522024554516641986547166200505804498300840654246791399797761270595590503741", + "6835224295711983166071915743041027338226822865794125690776093851440377194137", + "13366807550844486078755421216059218883003148232530961590657899207604510596943", + "13252007130485429909186723432146549270562877209239528962258894291232641470721", + "2492164358128252077612941728095518049849413853275094452844245158937134153493", + "17908308295682961911088181370570531617402259473536245650574431533231050717409", + "19598815799287079436414455405296166262841941910574843546435474727483962158191", + "12296683988787359527811189035096536832943622321600079901820428531954001883453", + "3034216468239708296411368036093482845790159680213461245275097466511477145032", + "21365662921308444671672644376862924257055009191312934218262773003828812482536", + "21643121605272677508602911313799693744649969093302740901187983246336863173757", + "17106474623853535335864151625226941722837229436558906235895607080504648969673", + "5170493063367583327862860118856811567748934103888623432970286709351028834594", + "16157297782580756629356992582192341437261969693717401640006420404649789675283", + "12726902817862860900369295542623896245980247290073629666117912397630392192361", + "3081548921497703421223514856379500960238907095191066190890406228882786538855", + "13383733165408518558908753036431726341720113406574723548828112868926423953299", + "17114711170811861625673949085444809223764181246137324935055609379301828432643", + "490084821539048617783395755779188347718107877537460289908857747116706971191", + "4649874458515161549974867873095987666703831126237318082002364917533053056940", + "18309757296672459101064597681764458207032523283974093139605613289699615669226", + "7819183041486966141608141659813055168335432042159899601871834502038946555307", + "21341796073041881721040729550176895226179046215340279859887156449076052673189", + "8964280440056181910087237574225882257648057952084687707991537684955336080915", + "17214415387533445163014526685896715822410886705201252936359885537015585673030", + "1103535976918892886566275197010540828604931300309949743647411661976344710321", + "18989472017473838846112035962614068658032619400049135145786394166114140582702", + "3261305106935504628452223922938937365963307399148885220969836911471709180672", + "8250352610228962368545929233808273614693022774196635878184474970985288333646", + "21336821559645974200167373849850832540612240140661136750527391104897925746090", + "4804442184264650022914507746660662354579855239722797010340948536245079163068", + "2980351069317208287298989743520302917458165906618872700838358045014403829821", + "20789178264137518066753395738491570400211130020259232167860189045958431732223", + "7043197173168479199982037485481873468680373055205806152875339535752299138160", + "8803416368756444354155108122527515347994446936702934474369040166131196644971", + "2327814593413519022021694520242495352706688146726587158472403609475455845031", + "21198136442842149822575509914524766455809483419897291889042050133491478146813", + "5588816308782619790412052393435292678862962083038610001710149574381906419148", + "18457707371647662280814248200286355752809748069618488571669726734664943098742", + "1234389524319480772210519595012254096434562205385972935754568629194134383384", + "8590188161561261795686801611365857510200794054668578839168287669047410512276", + "14470989978325106127256991312163042779416463931400090968073878504946069484989", + "2305522070968512786738458204005001050714630746016184992510479809638463479749", + "7477355783744938536562522733347415235458953622739577251175967178186753572312", + "567290291622042941074701939710650764088062581452752653943609540087956251460", + "20440460641466928749670992266608077799893623138336747959135603955102479614007", + "3054829023148086310176268593952124817160009906490401089445995945337990758835", + "1115018683950178281685995685874075286310060333362422341896901389981346771770", + "7809307874649635295815564328714298840313171873184814252455880392757245438416", + "16435322760021026161995603943756578712245360106977256514516858926570158830261", + "15538054347747268689904146479533221617920707373984233068744782064536586402847", + "2145106610221843472170037420099674539983626911224263405264737836509031499186", + "10469489855508967606640238771767546316388755621910047798817316247787439887327", + "19269976274347330455450094587958438145203987980029244301223712026832424496030", + "9442647357194564700611387347788116150552532746010343621293769302924097756012", + "3958820742734683830021295040986048520026707752457985546687457778678735761219", + "11348329600459394107897118896385152488024741286593365288318995787678872184581", + "7994061748163511046803584801099079098965771882190345699910054751589174660915", + "17839452077827445141859404251925903822746019560954563061323642101356666431414", + "13232228834563301156710808377438125900543901439977087615805079133929315161755", + "21820445178921591403441486524597609508081666751352389500190809234730066099269", + "16335255581063466649418326314739202718270800342509998411094897137707475468574", + "7815038267931398026175910302031438514210779836695664391140597883647619726660", + "6108907775060665614604453427927916450888778767561273091208488690292223394553", + "18731401306874205485033288380603219954710608893214981010860304692443381676445", + "9207310842136026530277150017022352541117999932757777916196896007342718304978", + "4275597059348294910195928059046438407683127030809544814087898068951365707578", + "8551726143850685533914504884506052366269066663000473253249997846823470852089", + "17722307737167433007678801800007589919417323324870850217087785924251047414732", + "9659885913999670803985648240505723928144853579243576606650908903914665975845", + "4127785260298795455679482228123141201810011802311941172182140342819621401490", + "7995480315864311476694461046721076190059098585527103653430045699541205743090", + "2710887853573837837653751249029686223333938865050270571041154550753948687821", + "10929954836518904033304553904442567770321295457957205208591304372724905918438", + "14001950425766109615209637768509276336684867788731325954527529665290504740308", + "13093798171633818149701610236482430519636222108426384974269506295925166461929", + "341112534319506600537441322030652722098845095671561271148940215817004993097", + "6110906587902719841743444555887325466851146812889558891609843725163499179004", + "4611067237252812652698946201052371234192768537459773069641551009583406296376", + "8813661389433335471770742946393259278020908342551057181562786643750538648664", + "4082028201221928661179738646263379819458232996637786410627338568216272942842", + "4387150015663192481675842540873436578480016784260152864928968972841893485475", + "5798957359608013690581519427700262504660783802132038228115867574470007647157", + "19722104754281068600204006779633412991974614044671884281702255273995426048636", + "13237763289640918787304198678609438981723281080085860502804175876747302592942", + "10350397375768871942356366001436797697061286173475393119069375716517495164748", + "9716754658986776864790426519095473979615270133917036668138857377100462313944", + "12559455792963077442707649745319068600669837985026401838048238001273610719876", + "15691474792343664499590886820783843178573436351948842211318848415073250926238", + "2315152971409777702150694033027032394728963326020928261979764797562368859984", + "10145932773746660365948684949555749309408495540108698054181994778319619682499", + "21031755674184251231918386922772885560228556184297650283520145773416227622020", + "9656774539408247026483766906298154647226870877463506520381115258572281833777", + "3703366867036538119931629591865173960052419475390100010069369247148720449735", + "1155849517605989105668895794996696646805146181003961935923384046079365333956", + "9462523438649504157500459081869061592673258626587962773726459717365228540892", + "14558942402093706312345858485376818615887511613771478694966109228129293547963", + "2812048253376149161843484904554248272181353897695109556171864471465530141300", + "14581264237688674105789045795632866727938915214983870169917226308316644895751", + "11806517668379902968824386871470726201210807458248501270142903146174354419162", + "4072157532402496076820064418241903939352389786658517709744366379045220383162", + "21813972253527564887362886309776329116642260196272043100875592141144150622785", + "10464853353887659405357329005361733216328104382848677769669050984745487501147", + "14772015460668233451710325522019255336227111235340236488781640750731630746977", + "21527357780259989210243319716428302865642384867695769975035672624351025254966", + "10891794486798293092627071927690327494090905691269827842959180201330098409394", + "13485855904336418644657500553650073084861569474830727752625752553358760580285", + "11448242815253167183767068865945471000243774132210813929164325622036544013989", + "19410155802742110833632454245227392555968304439001009443806761608484053045554", + "12167659128474886745250741538637209499739823457162062821474270919941304684088", + "16680628007927224771777485144832808896272748488695838488671868152342742322186", + "21298757047923195531118553955836039383942072424271519371368119907422148509278", + "11697718923718927022148851233178802389523673168156063462791132046990360699116", + "14786267704709019791824267590492332247783919098705756794174245591027365669638", + "4029431706248165284072638415134780930697313346853706588481402470852714029894", + "6637339357364931518321345115064554926275905427738668939829923099637974821930", + "11721089735875799137502005413616822380279134029969641544449026524015093316862", + "11258510956066696357188198767462611223354755428568008829233602610737417570759", + "17382216798452684990847332797566093767764854060615116426813871855967998298795", + "4497813725838018324398390685637602656336499793658559967801659260213189483769", + "9309905740467289615895980718346712749846725019185323382202916800724200146653", + "4554312255934480823406477691403023661425250519363902231000470326223736059080", + "15877126774677139396238817617140527789790929268045936819000883506734809330678", + "102909811737053415440204213495606488273727867104784554516589930311835745189", + "18412616692627375517300170963764173086100899052204830988805458281556342306704", + "12497849254798953635808071778933029738229621492383212989583296055326390275927", + "13190130371739872388747884175792586030658495147350847435106581404654633998344", + "6569505978975360946878354767391913708682729333577071120385232557177773967150", + "5486573030999616702165020120135398562758060949059349810688840632469582165448", + "10402649247177704342444720212899468852439313211834653468379224661013914061054", + "14870393688688048179476829039887867662050219694351765548412705799226912185902", + "11112866336990864101289111553915677602536611363742637349719791431991672470238", + "786378775702052024749700197105312354581130448431768994347811552323325137023", + "12804314666740390639363966758718513558509859637020806917779321368800352250093", + "16383777838797313001717025761299072170493145903921192845224827276088079299324", + "18390795790658866542478563024059495583921996400061610405032233720404354578517", + "19071180375782447479569450482330188708754447860024817674265020413221587566028", + "7064459298524756483115092315588548572944660746058573142372140457074172044435", + "1201661337668100759364810191918525473246105501963149603200893010746984240574", + "14673821426225418930674597108599685172091690120026694257549676255194170791868", + "8007695637892306475030605880993450528464588921978475145792244443873714795074", + "11523933430814198704411556653252358930965476928606503642553530463689321317157", + "4720685254208822524727003349181010163122046826828742211508555904133729568685", + "2704641256375089357490975523544121554540568505171014265704664461404637160537", + "17873735287572402838142305036318020439254672746974064930437541429239252592118", + "15591377870113101853150486245422804312550411754131695747717894157544182932395", + "18680866424621452161410252746147706712971801673312117262770403991597018010533", + "351092121232997110902065296627489736041463573095030601146795248738327912247", + "21410776897919290439576321311168524383878404907590335964810760611175870803022", + "17236852113726644484641871544732171570702656662638441976539579805457648241354", + "5141902767347064892821277441749408218256386923351945667768202586451461154007", + "9061206488410388460545711706154817066096529615910172728152676288649487389209", + "21501744386281091461333207234319069661329384520296829009605344252699881602491", + "20523123786355828261901087089746676928050070859811577818342254696196216070331", + "16340183952833650334331728750144828293293213803155672739442287164371494962264", + "11997165266626958619141537683193751516111129514708339075256579474097934990898", + "11727998419969202419125826890516046584560800158309390774599325003825426052070", + "13931457202894182485995482691171342703522733597260457019434686547274942752168", + "8889288417892697124945054364222718721845070552969370183001562339292498026982", + "10607636906736209971474676586549274600168449611294688931553643349980364319662", + "13373379279879419696628639312899105244563309886546920506727138704477895635504", + "7516778707927565776230701116353902556324173125006482617300170811322359880287", + "284142816263687923446544408203711951081978657997111022490562722442340431026", + "1663629018772009800050577108421747444431944008366135531327269967377988698730", + "15976560170935104892839671978479711290979780560451333565745657902528940986567", + "2821894717706045749560970435026664943807315523436547166205412842765540126279", + "16411046577927712325274395387891881155718376469810123282180259561336053360599", + "14830500017171075678309056171812981524309710840633235720674153550980163992149", + "18516862946535092410308127384088576733043708186179828736204273213102857123131", + "2803122828384011132142130003641446021361083629354222582787564441368260233535", + "8655048519095208179618171351501333519098495288987579151859877773818991560313", + "17628029087309631764673769418575149062296127129914718449980855676793923700717", + "12213182221565572417730092495989703548687597794044608925789870740387528958423", + "1942254992896992114200957837548346988692238147738540593160350563013662461747", + "18572481120445885888145197091838633506611989952111678544191205873056195137330", + "18140911659901689098303870986888083953843757583911874535981587625576530534701", + "12576912117641358754786901787127955567685279522839676706223096592944048067439", + "9853587546273100154686512094544697531675085181100931274409412440600306885014", + "11051022304629047704897656757884328402546597879242426643246383517726104682373", + "21747178377575326127773834076417831630856635794535286757990250257220185876652", + "14802894612148412188667842094308733856318572638297904757997514236587913861527", + "20978447371728675031404263158195920974895558458780873769079890388209356430130", + "1037699465155917084450585874080268028561047537346921243992399961945112783290", + "4796870784617170576045350520159043022811420003073563826183620782718648038813", + "9853767424749529094226213721882427217388134769321854800041359789143412725618", + "16909978741728448404835572592895383783360498936047937910269991412415349672326", + "1843438491269241815751499591631260690521017848626075859779071605413804154431", + "14341379518602865584962107623594010671519157088756134035711400970326861508492", + "11148607079771922951721552848779822101435560243853139254657574581631328105418", + "7236118376476006500577604441648338380683405215283131664289729852364085763863", + "9771089868728917573774866709686459919517030662395798431632764214674312680212", + "9110797416046523350769719273137039416172041255824880845510758575776777500007", + "11171998782921300624880315291878283252073139909993544537205045086249176031551", + "6662646470172779612845827572259867913830316914285246080650610642251248472832", + "7840073244312824502623215399534211251667887906747521505446844849673459134791", + "15746172297311038934003440308705797271829102199583540526113736537482577060229", + "6886137335014489748489631206590121074634704468637741127875111216297167474235", + "420232306382434242751186173486850411467398307214919587427625546445400284482", + "6101917029417345450869344197624899835171925047771043819872045680173320199082", + "20902767593677591005062278004159629853556955206212143592781424915847484793984", + "5806682782059166443158221425741828463380368530625835045262822570023351074794", + "8937322067898730475133772449174500828509823386740428196387523130412301822446", + "10698423376034838319080023911266285836831986186258448454885030311257173631094", + "3804139705083664873950903601295520892698549383396840546300663481183626370753", + "11666167980086510761582909817125709232688171970969608229444060852628732414641", + "5195343484230074513500630640199601466733948553952258905990513870281939709899", + "14624340714306078897305540751958284706578556105002276099158477226484579202503", + "10083361130687068583126496521090418135813124339806220406205408201612392141304", + "18641596433875997766126569678124500204213295416321224520910179376654463020142", + "2202590858941069122312246576796422760143586439968023643572584733807707875591", + "5606778593839139538330184356292709713321311150529135965207704575468867770974", + "11958475164655758519149540613838246197985233378525766327961909142873639847913", + "9229670488942629146704143920529444712626724835075235979345002293458105678408", + "16754443145923358894066339463409997111280948017357151500387305969742481068301", + "2409255870410101963458063337813762581436752424874011147061097403491760442109", + "2214559337316973031881614971177447231501212859777889339656681156270831720504", + "11421110362488121690592793129931919017457696830596130693048382951666066696299", + "3820500999703948691966833683611482557851819710346178343790665741738753374219", + "8756218158739871072278901807217627680176358846778830959237385752221505342071", + "8032449730250468861487267430306584116120245106718506069817646852031479757007", + "10243677923364935391432160448413375676421376200851541463326287529268288890040", + "1128776597481264636069298358213640667665677523022374620075432951501260575292", + "5644093261057489381910165706940112111858706948653266534656144218172488885132", + "10992382177616530304259484530083164550434687278050566643026419033635199094809", + "14561508845841116001383562169823893923516132174944052932403904968433057227748", + "21863964650894297432572505174186286520067123468863642727441839125002713095277", + "20755119936203820147240015392257516486599536773168698212709082762309828651450", + "16959073226608628398387152299601201172109169744065562346871992262472923761717", + "1422360831209405989940170583665509252269399522601915800432845527860741426172", + "17389326678043835536716857792606285368419240597293609647618693076258681847452", + "12197527885708217940863852882450902665816552534167940448166754267717839462635", + "21611570070424770005490607477701523898795002037965850794497143400504853790221", + "11892102040110397810197867975938039639353004723546075702397206087388005784781", + "13516538003340091563836438322533954338394185445401173280530387106662595790317", + "12048467357966566407092445451263285920234083860460644072449020638723740218202", + "1735010081751908190348908571270511873519447755491670766716880879623393561967", + "1975466263323070433866371621575002630840361531361829342799564009137157551290", + "14332158763257273099367529977375112575029271371581919959093592722516585473205", + "18308662877208906527685104306067008785578317983243580533749074382175572194649", + "16147771244577038318738675557955640363954546932826136022515936117397152662906", + "12310104474053287506280911462776789511537301762185944649254713583392295220302", + "20727834941236374148190412755081722896905078541838912474132444343774737989102", + "4772017368444066833412562265277526529104319024388995968178984274657250179860", + "21049615822069603562632099674853063708639208121642147875791882100914627258965", + "17646394174446098039184464463379581654623553955171175600685924254263103033801", + "20405917523260600357692281918105892289710334792700216851356175227972968907413", + "1288067623955526969302061242482178260544140652671589048188723078863398511616", + "10835537730223027316050378066698794099751744792059501849218931290020119106372", + "20990157274288749983727934109087848093794137769592917583326461140632177148526", + "16941875865072358419938961334635058647868180482918222959682613586029647175353", + "9843778843793690986119532637057920745140536160016368781021998854678847780413", + "5125414792982533413337556654533863770640044560799521974799727390524971858377", + "10864462495296760172304401051361158670010031482061392973919136670275578530070", + "18638188379508145413237672170551928898223721010749214505292285199256581752296", + "128198311352192300389214509562427846527025583978725552204209143056794270869", + "8639617857907165397429617535993768106671328412853872156360019116822694247239", + "4844530255382539675437452182943895677920405337347260379412255490567182702620", + "1804675521808388615789572941859899805904819249465788091888167545049898256219", + "13789062391664555041422570123657413036572356127853659660401072142070681096201", + "2984776938673077398183780839702246034953572367406345432704517332443032892459", + "2992847031807357662780885550148860874749067596604232667894089534007015158636", + "8223481330716908812358677489080309112433589978061949842348101802357147464280", + "15829423985005178435297810317464595131483457001231013788201382741845473393508", + "7862158982782368203916129371016962734683904219117743973675651114828548094092", + "19398173801438973209233005992391884365223581634877055780725266290648936529417", + "19275863963890569296158744143112092383404704340976692571347641477470540348192", + "21372102182460094800056358406250397703306525384763761377034855645794765423371", + "9476173056510831081934271835896053957562178504127106649888600367232767217909", + "8945631126280639679924915282277004291625109402912694487894772245410534789081", + "7926253519938744933656970287399447078338275573508348380139787090085253922642", + "16018716520675458445608001155996902645263605619338294478505090713237417816972", + "14921856253793536148329746401088158240205455851010569917169181161371242017185", + "2079875574141510421000322245042248069972426430967618609676296915817312672160", + "15980599742048633141868186018745285129739756803812956666022183903444182047036", + "12114893033109318668956482804227784987572764113979211644064098174620745412136", + "2810098426330816525728669143855005497849959012191227510766066867001705905451", + "9142041039259596869436365631928849454803241725030479248178020744616036193428", + "16789255887716308252460957605463144609726855240455194269099382954389067176728", + "17736208027338616948877595063010911429975090558603409155923157365536120955065", + "21150410646727639080649942919157548722144769190804322567561458114897439673110", + "8728923715723554965990413741235509264041126517176940864777942728557354521757", + "18877975508697261368601618378333048287851497514619873601021983336084282573042", + "5857216433172498779920090709564798696432088771454963449283671260189720263346", + "3416739349758310085403544797458080484340996684307665591910516201053743952382", + "10014661157797313244292934148350131996657869525790562708237180274791925878615", + "5349492492153439871560702687440086188179846024931646961141799958661743380684", + "8090802326500729500530853058367718173141097881651767619458686010109346379147", + "3243876699925510348842975998823895571182658963945930929780026879935610333017", + "2417624030466093278001094443901143647464035143208058634414228940495675339286", + "14707208083442648370683763592077614356382972898797034092783713393639907619177", + "17545631002841426592730923010822053419499562660641460363423698482744533869073", + "4421380624161160840991891701912641613710893511150975452841445166075745805974", + "1077414817249103950943875081715965937853608110732127257676522759590623460183", + "3507723951294024188735232556852951953031271591466929388169161213367649583178", + "20744267413157655820488615250021371239675627876287191610069053435816486296093", + "10030806611757571510773710000844469375387967668887810533790132098599140714696", + "4098608919187988291739821341638774871917086915024686655297087774191912756808", + "13453755776490865531134267856063521315028666076529776333450382526888445047611", + "11760020934758140446049369723964305600159936563536726075225660675360331528465", + "6406037247037697473727755924858735296546535018055390677906442691851004797953", + "11557358458236767995494355298696159281191676229524038284238319440638237580594", + "6743825309135636487078170799646071187521226570701598888088674184356446519660", + "1363740300261508449387087660891142217813794297057216573859174333622397381039", + "17353086088993821287882776856791148032337098217763977250246938079060857079815", + "6718938715458951426350417166499489427024335443629489544367851434423278337209", + "18987489742261748676564017446964953975327326154943753293417429206546308211028", + "15965659332352377592570514074534026676650570619443318860049459797446297666148", + "20815651494112396184410166336624878644932077115689590904142342335838514032225", + "13289193671002988855733226768851953818541013880219936597636372756289364866355", + "1567979574094562858336626709833690822884595003609499722973068728155414218656", + "1406894286237293229723971624858421702390230552459261102967091748375073005174", + "127524353461789027170460839609791116742773867221485647945877046573898816494", + "14964917196913210912898635537202273294898388149888129789323384554911752584731", + "17573975090037837489354042024755208350546900760352759486497415097145199425437", + "2810800768573675011848063715305835214048305201677436448513685242208560656239", + "3182831596404920556846849906787256417421227529749874859977287400581732004348", + "9293221288281284622603029762317683176118521399756060307438914930508616154161", + "16673727443492180846335195490607282587311771952172084861120865668023189607968", + "14861970206393540357193848383493197595010751639867769363872113104941368881368", + "1947459730453714728047065931026988640356317164613412029204943819757651786269", + "19307336986855330171250472129691969885469727663168817962206758878226019668925", + "16272723820736869927531258455696258295545428585773733795358621236250129636598", + "14067203273048816019998838866277520003916774532401938198162316693809632760951", + "21551507147108044169777874975479534770240991315165807000112720115356653530622", + "17717640130827927258645965421731152649890280820567693269781156985346197796607", + "8341245955737785666220035421009659068228682392298228242003714027037157516189", + "12339617302318828762816142250616108419519769797732290739230041883942137188888", + "10123566056273217296763559440410478584111931737336670797432668142672222468278", + "100330409846079023411270961296323123363585075447874304748480232510662674144", + "1571586856190083814591643193451371280998279878174710717174319810741950319455", + "17626078717574459956178559042223066518589738318146553446930321898524763562145", + "12597474837573442277568310997313425097295312228965354157636545560783225415194", + "9282629691296360927786998265863490172450342562246145699272852196309154676715", + "11475383910279033220892799115018315595968658540404734297367799982184306742405", + "21207578382911046461925166339581302823631975619749313031737447832273859578217", + "9867737209512713742156966231095908977298144995685201344042106615506717185970", + "5419250263664842635521293741086549956576183663718321466133029062700646217820", + "10680301618473120824196964202055452643700003562180874183620820959381512387087", + "11734118782551011491731695279474438578347930162244424307495336916011158044578", + "15017496989515336959243556328206095618035482039354824183597442359483266217611", + "6511621188986288868363472995938291798169517601112511039955221592826262879815", + "1057116630043531259822644333647831844583791045276219751332477616072560117378", + "19059685203310882657000346272623187407133972415131525465827340360192915270217", + "658459778905143381055609790895794611242407110015004801647654573954369450993", + "7603036257465538034144194526422841628761243007297872008772468055256213693455", + "9990634061622229590998343828576831787715708492431159246049355339866257946620", + "8811452869339089802509557934124104823648284438116748217266488878838078556311", + "377338624779519383654026004940027827544698613282452894117899417005371283013", + "20372432760811032237009833207612531537192479064270437032142982696970398716892", + "15755624168218886509358985223476988622172061232118179707766784427029774962558", + "813530157019364022188179508608879306640863329215682533796638454834580544088", + "15366777101659035236493629475299055460750095122762878608882821037262385854171", + "9412569363133467481819948072214644683803929543842857451635373713673797937906", + "7663229432381596357590875498997196481050744300865119408024986926994876708428", + "2802277205489381760400127515311144092806348374683690687945106801827615715524", + "10398607437116928120233501860786387490329760704107357815670770315190035281298", + "7713454417232694103114115606745926964297583014900008700978733395172058088330", + "13765632281005573885638376819890884715413389187071206345092080625293363780493", + "8481595129822383153686510359174155430289248263706955785322350737378030164791", + "19662013748902527903033807785062252860528102610990787703983459073558867314734", + "9308675917577065974819002737905225232234719968566022906777214056034139366532", + "4460305046275724592205653945612957908431797179457871442468403547092050276501", + "15300682822970503133550740797435695997154332692415846288727432330759835456273", + "12237959719178772655779639362705631668446778143915144512652426042298606318280", + "9074337685905972785113091085216241647906400276520026931456332814507320753649", + "5631451392609103370493346239448329080866515797549576094657011047227839672541", + "2121343968626452536232091590081231792044261748288461026059952209827486505534", + "13428337287072393077290174792209446111049614088462784414150825648173933048712", + "7637923455564736402006004688931010233604652911202725935144306827988683195798", + "14145144407093909228652602933032447693975357132368479264731012546112843610158", + "12996083206893173697199261663271430611160188106624571072102983887472126762111", + "1731425456500536573020772566007405873501250425959888611809221924317821607399", + "7235256019731839713165664289644294928953374624035695945735560280325779220974", + "21068041929715170328271489788020516757451181357080748023363808822374772951544", + "2613269578304019608168678260820703130619030694547890166073793773931717299431", + "2895580764674798551230549071717806800560472156999393716124982187189744328131", + "18080627279556321451131957341924578248984242962783250736655220087867816491510", + "8541787229490752355605354050088489559660583814306921152210039891158051673167", + "4773003619955976464416147076099271361363813479523212833233541104584120420092", + "3902657294907605469046100206491238707374466860318674919042657295835038516976", + "3278680356861257827773728996810819308957995332730291009303523122858553038927", + "15799387696541061708257049935405397874115977721965461912710489016029411671536", + "772127417921361022785917422978769290675101599783616547948775836973315286693", + "21172675246800560416431972802840350117631380023487771635657330436402785697771", + "18058055216124783386618232874069776997923635894599900180049394490069349321671", + "6486774126469831729812548493701084245613732338682698890925717889323571075377", + "15523424894706974280109344562353257665535312014690869100282355992032362528753", + "1155165761749577539253357611425533199963683430668786603835581376097524220748", + "12293270303409235416382105881403663503297523019464344830582632347870203818941", + "3805029697086536368150132668072389131584837710357108954351676850002928826418", + "10383737378445903520223858424352769490012472500810730319338019642336472424460", + "19139905240360031959084644666653677709382597275601060683474709422388012451876", + "20662040367334915413974593999171397527205617639639561319218396170856657836909", + "20693045501044506792047932972050932132614012706885392044610670760209701329210", + "7646436833143149025181986338139180317049527836176583246163126009131421429218", + "18468267029773286403821867293367277456399346317458918979624725373649687804739", + "3368837325920673645463134045719391515049969019513957645401010913338888270435", + "11009184090818836540140614853735105475441340244881441725231380311734117124613", + "16438249098211375676141540117467319174575385934122099955146653152842543524308", + "1978426318655034633621003481179913733408584009919893346861360079137199026039", + "10835870076129494328875329193612835430557328436367520958854318265497818180707", + "9238585128656275231406470048000584932169168279280345637986485301554767537943", + "9860408784513424998732752702463731273076404557148376009384338221275998841902", + "6200534253629734756957567067039457925613934220422888818001227120423772581272", + "17839095320044387599555680620747734440255270476109368494374200849742690805825", + "15852210333828297391427169949742706715097259872699655846272917384634556986629", + "13333830495117301018203298033441593118871576320662915411592512406905971557482", + "20141868252044007123768212581882815770873248742867175012988635705853879924105", + "19536412434762756561256835516560484981006774488160067264157868466806483409550", + "13376474825075395326396381198361278687546895119831914117080307993251668968861", + "5426793384935877497416931155195289044246814775306615779818726668069304816143", + "7377826504693724659923090551901604172560455391003832805477022207542742841455", + "15304023433512090811722731808458537014494291201252876199903945357536893662723", + "21332460757344630529450409218029849205820804076582364819572498755186176235236", + "10123770219692666599208924625777509883271312561577690589112346574716432563379", + "19563297971101084260099820862783813929179580711197283960855071977068075400435", + "4447207254069026895839688542596519844298864167018271339727580848327164733569", + "10805247891957676953966507705079087855877568284903068495618773980630496028625", + "15247455859749071900237435930523136345408272002648820316650110622790580875976", + "1523513713815340967949299977561986680730112913862622151113511170812079722460", + "2250092345142769832690429177076582432571233932766644284160212961505086786198", + "5502205194489637815685308301009607192191278776537698439488907603617260091996", + "12376110094727246736838305034851207905481280418572145688559541407100489476563", + "10967543165217223191795950135818653456591208931427429972754586323384063916713", + "3007127915385490247377746617881910295130312971235615226220093403044166435816", + "15039810425747682043693978030807314591772830040893968588297240388685740832440", + "21282434502237090849892927101680045504469095017581606642683944529102929897154", + "17820554077495649709432871866725766383400924076526622095222498536082233385393", + "3238921346058569633798159055732162989904755716515207404910193961449538091755", + "6963065779232897395043653410311694992252845745677523471496668662716409139923", + "12741150889158293058202855298380167280366511627706735086836055155215291856874", + "8505231440570036863755136868680092759740858472921139738784962359970555463386", + "16263867309272856871859017360735124501630350380225439505739588230939592341511", + "11994652030543012675378700484156120788799454178056174639173766735729691200407", + "7531001745062176388176369578077819605743320864253593427909699809569190244306", + "11827863847264026226445842677102655786795007713756694062525124054010199531855", + "16129429107591815909860445595042156146087129962390514833959473605760944146527", + "7516787161495467824155321560594800913116855117833255279107222188682607365695", + "10052162714097814491117037623656731155747350728656529965818461926126557689689", + "15866126693591846474201863966897712396582450897559972801925967203045783070614", + "1769345590280238074854062499047542732649300047644326060581629862863392048630", + "6419881722518831944067972549598430355215508824227908646199374367237336336567", + "8427762909619307952658968866443552584787988597438819510120993141703552873807", + "7893311334904009120458996652611823451343891633360441850908461624396886564456", + "19760139770663625588230394835227131962944058142185140281511805786245566094372", + "3986819882418057034478817109485859706183862449050678809809350743539886112292", + "19462740190201175689471975116541495793256811137828607475310915853573746549315", + "4950984269438746319161544135494005780273536398471035822969257463380210776783", + "5114126436371649572151778297196722433397981560175541938915777654399517384867", + "6500502433233986724406965295441070598123907669991330544723786166137230830713", + "16317287950659298477752416750967064455139776512193467637272228586615836234506", + "14644311768591599882243015624322844079095287900058309581805861693953854143586", + "5280400910054229241086158902425292691428494311972092134978890627089874392610", + "15127218399002910266114392708998449241113801821878209170134753716497261629315", + "2711401246560501813405727886361637939228317090729002412066290100904319360960", + "1913027325164607464956755298437679573731669261937548387089448543475389709293", + "19048913840687946111515885036078245399510860136071611921573959765837451269059", + "21295287720552550910280526966903203926240851680963634134437049744624969307301", + "3797109693086078196558789257647252246485873371501397666934942661912968057995", + "17220092189283987679009565165189257352830222471797888201205665583060198133070", + "15728859045813610297052814756440978974533041326711446421367132340721185641530", + "7915246674314292718027357038683169057328569313936589479968179748005116348962", + "3168535062320575750000050980968432832479836571078965478747377498891053785750", + "13803986818738311305292789973880566948405947108749390476554600214529398575121", + "2887021549045614886550633658248390500136948561362661868354602793719521054017", + "9835777853770722919097370759265493857673816349027354889969484370501195735082", + "9162920843634529872148328448437467777954760966007230180656824492469148201817", + "1074954035830520777949184022573483523978030205622574039670230048399504082838", + "14573949395382273725648387764764104587706358354270169802238874779976052312087", + "392719645589691148855449884443988672799862378880367658864925364810308158541", + "3685551641667332817505970777889874263257498648047179005679069858878239338060", + "21636266924388678043670779518381645484139129597308274177295703055588816929542", + "7321567536895702720774368439707249290671186165402244403568878177007380798611", + "7172839196695686167303608986523055739039297465612557351529643226329584487820", + "4229778574282653726990227569322645489471840372440828936529243607112035640074", + "18782302953492985194605877986375464862209789031757664619583780308051670003641", + "11974809482173143458078984920442199204778548823433238304966088658895546634996", + "16243115558222486864600123441049281534776025041710213515085053285162975382052", + "20774412501254836125508172987964523733402936236671082985700605339729723682856", + "1483065919525318072073144044234229344901017930590205131905224416619628808251", + "13859608645215082985012618178187462696738961393768893322969190913266642570277", + "21405376459105682082984005097612235541120033931778677874212817450507078023807", + "11689238963312530686999514700594656275688886785400717773550428094425955677451", + "13770805346049970815658755939543097628223982878203541747699103196190562329538", + "13464128750778834946158208517080192694313764854534278881787962107045396572111", + "21407849640224904790247752730042846775377573219483807581870525715728151019912", + "17742435015936027530371893290930447550842976399042348699434701387859868436168", + "21607472280994630036571403820711131618277491312399185275464826427174795496015", + "7688464458545967396781600592854525549649369419708847302997939388491317131965", + "4387376978957625118504779199367262576455322502411234315349687321331690532595", + "18931911591990162605728772083755015441650830148575725789586998382906047952930", + "14640568984073443762298448827081280142493018130989596534711086636304928257387", + "13306842042380077440486698326492089142513016713060879132515526658677539077869", + "16831808713587057769987931635351931409992316524094756901264732606403438287007", + "11322415449116068033081427912158622347193126836157199640557951056169543153666", + "6851604032522439802523441319645962614365864202922586227207366934548805743971", + "7865033453112245503939716349145002950003125074081779764874079104952011815860", + "7859039670086457402270651853161690366745490673814388503748678622683637617076", + "12915205729177842184089675224634811499690953326168778547490092950902372657871", + "20937773388247481346344394224147944853257697507105144044681818248765914256516", + "13287060897761790924722969858390853273555324655965292728828260759103061260482", + "13306896346810583848301553492224587956204219709116827141735317644044595737290", + "18219814232296473414944129594782177430971511097498319923644038792152844524438", + "5428298390273304248312869576101694361963883992477060046151268450358678474516", + "15201216935560530575994837331432805679558316705524948725894686934721622162910", + "9185979018761703837993382762881735970994413889163208925197647077666234876915", + "19181785293325954761013200262201782189994371972312628530578184844339518606203", + "16637687071791710254394571978230957592057586799407792249481371375691006025241", + "7540695380854477789623159801158526233798259867148336812702557598270412992232", + "21033749924623312349444484016552328468392604073844480133610758629121621931608", + "9900738449713019488539657454744856913719757496206137183076543026413680378482", + "20521005306019974539700555774138941983710853964949502636832851583991666071090", + "9148625417956423696904186924742393962087070575705980963607554918018064302410", + "21162567363216498523188025354796572574708404245885103426215436531517848841283", + "516078530341213545969683556809078278712251743628535410360059529914040404316", + "16846240853341179628895683480146570801780199580812523539736983428470139888117", + "3725063466997152760713869763783030250548722164672702170123853642540240150907", + "15613553480222544404649584760559934580548305353382956847869893563076098726977", + "20351109682633578989341194704546173168875553988784930480177729322649037322556", + "11996883326331293630396983616262966081550223706386102455796773922602029237495", + "7467763103586466278784854382537524995001493410600869109792768087664508057830", + "2017508073008218056990628353468704346479637577205333604607959225275229259220", + "1314798328573144515884513072855778523099366140621231925682355151505185465849", + "8723657373526005784062072282873485835867170661363188128978957400998918352651", + "17008566456391889354408264184115222893038736754092176958021304795161250142258", + "1277201481182954066723110290486484624236238076832533331201564897838632505678", + "2883326282329572573598657327001707359250291449257261775578634065330832194673", + "4435817386812736743435792142021329255563452933485604716406076651024269234049", + "12698961373404268899870565736817085990987024732021219796534551825706597317720", + ], + vec![ + "8089493102530595468824649860529717181797071865148765611726566631095271469313", + "14191702863884040950201894968554909828474263688190658890761244249722339089253", + "7127251756910107506817428481560230656411897313679770455026102671367474097624", + "4637045655841785226199626823170615348821917492997807409130873179711115857270", + "20694397780982417522377524687614391225351058648522092200738043379276991211973", + "7370528537006777008458800981771544164650999525791518443407240929647301337224", + "8357863226135085648491488089966537213596680483394798064376015085804610201240", + "20367087512494301090653054692863377975501664994817680661442168333644299005261", + "1950307616347822794878104597377932622958317394806719432040871827549672571148", + "19534568412595886801081532478416580190048212177563706092280027206347120417736", + "3526428150493332211163778868665379218281231008068537115657136020226387337771", + "8661888879209475483716403816709663500534119170711151152467249807886559994385", + "2374871949454649266019269203973683966955509927334059254254180194157352943840", + "2602346264611026079459352146265308073912201263350931622963181149514761751618", + "16750875216633927741061710170647391823629779494283192027015930006045661350833", + "17325348607596842041611786882495470980592459865615213806942169413086586278610", + "19257833407854296241609506861086921463964253377452883026082737974007723285939", + "16875536222414380047765946704936299627494679557426090013440678117262080229388", + "2035577529925145134060996791483051399276402053645795728801937468290487364296", + "14222296831200170749164428995066771764920247405996747821740895709606052517407", + "19708208883712347371628256596476366883171584832295648266624355950215220127904", + "9765600454835189412776212142789582666145342479104764891694616693066517922502", + "13365055082376018935548592209736650793571432301565333849832704476237136996118", + "12420692692663472732723794387493491467146971343430969855362995088112286983728", + "17844493444787722109223680249951335211927705850925719012603471955916755628715", + "11924944537382281343613401541176014853361783437608625866798343540969055542140", + "11538333989403053525558050588509973706031711021450280471202165095037142068477", + "18764881783775503232423409005005138632447539466481045749407270569758537393398", + "883162740610443285913150132085694648635519837269866659825930623017971541006", + "10171610390436513861069093903522467940290613868370765425375996220687957422386", + "3782996878040749700177878799895260702330488343333700969514291046490113056911", + "2239298968343190621001798397134314102896115970272480212453695048745962826317", + "8391302051404015178833807081994898536482484463022532956140929200199667853077", + "18096164030411129129794470313655227930799185448547884977984818798794318221345", + "14613424916575212836238688482051323957035101724778773648452919665593660234946", + "21828842930708391060823304507355770719075227415675853536112390374449711667078", + "16155169369395425892836659730715232159396910561858841286007416017756724971516", + "6878543234699575736262375462702866780772252779651204219697567141737826275015", + "6515580357485419559928692633356133128461299871887195169242750902403019378404", + "3124270150531482035695013416051086970123461406854560487654035672981879561715", + "10574698281815682641771693421115734396172155905702803455639975437772362072107", + "16383053320907906491543185419013182425229207444535577699313377451249772804551", + "14128602818455692582904557734609240140547347183347545360942329621911511704432", + "5010441108136365108046592406551529565385874487432431586303802326844966531017", + "20105162467673383983751690623903949493335895059047083944279780871549558030082", + "4243524359837792598965046978953117623831146922720880550516255054678204683627", + "13992943040313469850370025986460260524555943628212884466234808367632688288666", + "1356223459509978352432345061666791804860823828908318470584528377749655994659", + "18723939192823222870283999271398340959482157197116460943968917507878394278385", + "20636603031793247786862933945150382157149390912061952007323929980504212222032", + "2128636310217902240014588202116301452804441854659460379597999718252532068242", + "8892458127594737495267008183431736534386964959413452688074230438040504386190", + "11063574691797903196312547816101464620325790434381460261930676459857164737407", + "6204567085759054728130072959301910137692879386674785283047171198023995380593", + "801138962072186678791979363551434811728526970692377261272697294596118718403", + "12941641588837981062781447688458784558606932072335320068724403816548547438675", + "1341967686547656677059175660053506857201298028878352128737987225407679621418", + "11183207447266717668611438117401741351804062326702937903525908319309155043524", + "18507917680426998547390822933408085624123062783706353845158832700169805897057", + "17600956758590554476691669608345000941959084040124470813766683278150335958657", + "483394656899715242498310209793599026850663551066988094136788591643990355221", + "10090827432001200203094010206359607863114405903353400294360808239534902160627", + "10039403020393871677252553778177538625214464462052976366251977746523421324197", + "1924712848258707645798108847678093621275398467857399987976700805356929290674", + "2167923809975069342404582706442301809782773089534518796665536897555762931998", + "17151337466618795643803903749019481111634005237742283518609358703199930418386", + "4693404918498880046514671012411195415185134287680728307646808116832211396470", + "4839381186041991439202094011010050618021148651243083039175474529769659591768", + "6368336559448535344096548979708211013055912139451892726345028976601375052582", + "1969826462127986113899121152613324197819709993940588880171966228829834184618", + "10949071784553227115382687140318153702912633728202525040498248461299029092720", + "14575837988956266060370685891330921140979730144767405243152428616625585430364", + "19025750374860322288379311751788635906611708349625974065695544669443137256255", + "8764838805814072278932908632105809429351124473407135322177352737762640822858", + "9508966145895699172941574119083482387827406291145211775810415653335356563307", + "1499853062814132179278896768948580432185360181707926223121987796423000161587", + "6748895423937754323870965728722563272366114856617067613970193226138372983547", + "9814536604142267489967579335173323116472525708739068285104384748406479290252", + "18898551978119284539473648820403307265793266184829523824179430658011490726286", + "13332891294455702171134399009213907075208764727059236543259960129130320074982", + "5806223588823614408610900761814632517803554600662169829453323047489266087405", + "8600992771060584427141790133616651912076186875693672268259185811464115092188", + "2345229032656719135417406942532115442859563039531904661440827899574284256939", + "3389225209359511603097670682835778418062727662626674404140526378611375444627", + "4001034682434006987902788179906586121095610380401857294704332109514659937637", + "13067063794999809131589470979742146742674772176859338210659998590141023560073", + "6021149641876662294720012642501582990883570287510418620500730995186581678990", + "19744062936660555217694711756418639275110313106982456779211457821487189038259", + "4280146833782122185864346406516267200729946534205141990397627632307276252746", + "461380210352497258096433274264553487092816458993207056498455795007735775326", + "9185904966475190600688426658264723956468287249470549941528026771035049026029", + "14362213733702712122544208087232387435453213772974406963783416068708716342186", + "3376133122839395926880247692021311631985267298172444834121553500975764354590", + "15430636928872496244042298024957854104479533547499980110816885404855993587926", + "10066678820787654667318707571747478964216410231002799394324814978870300697084", + "13679726663800139966289976616317518761749708307387522908283736372782010246091", + "14452498713182028708607687209189129972318024710956800636750706657647839477841", + "4665977443169087186016514814881141858109411469723890078365751966690257156734", + "20673947333628935106924449469424554002781432367358546714606202194020160454893", + "8371937803667063739943392730412639954872585103736021824547232324141910768530", + "4915642891224254203187535229956007243890165147322145197624420790022741880987", + "17737894427474715513464524059598818432164911920893615068415915800842574129123", + "21257751286440468433003251296883236318376753833102432675015194790356307947025", + "11831044910484530710733100158936923549935832556815349526083442021617595246222", + "6362553671302097483758288321671356788227750730995074141338726755028234269753", + "14935971406087488699083625022278942628959200513244202282294495763807242526556", + "15337281352851760799121170871115742187805714822038335053341937333897883894609", + "11913020597445264316110942608419581486071629740611054234626537590474050938474", + "1838104841451540707239841220222372684744879960533787766800248740162155353463", + "12200586110950172266226854658183951607066336178441918240404611233042731023944", + "19022187774400544497696484163376638844589760125070799280660843859892595613745", + "20574219232807646025576258258887918895888511977194786423008507430088227970769", + "16786939539299167614623107235117810634408742454195124075763115939760135086779", + "17293110551721019748567259052064171353712124247596873005371071440209356535788", + "3515336831584582569659665150343000056186787768627351931657274076732504326799", + "281425181255898711371985357453012506419817930424882315501470435479210893648", + "12703632225346671660598644961986122293501524448004046573092229475506828991982", + "5589259102510829346047060861494427710966525350274659545392525201677772096380", + "16136155264962057601674035851031539132207654054954939479993843931937787809008", + "6577810342827559587628942717478127045802616172145914985109615391025970118111", + "21163359977438641650165237544426961690819476598192610702649950529921750524674", + "20111680006656824813833529237249851680178501017371275377838319189183351852836", + "5575615948519348213741695691025005079345478514823636124237182535409145360452", + "5523844323060926872300411712160500242292621601876678751811292002367512597282", + "2341781247790586645587607723874752210647545627417738353111026163429313125329", + "6287726121450538785847268284295299220404766172163996260292255850387839422364", + "7510648235102286772333427364079209113816404370140168905255311267436378725194", + "5010598474035699846534727472507206499428871255705467310762876793528248455251", + "5700900579731011250748267725185425351062102227041063523439252105791254824347", + "260864497479086430816275699586473497971665832148788274905912958670548982986", + "789172560806161139006535038197594038879692565830598745604163919464033838458", + "8100205286609553283468855217617464988341806863414698413875768149192804914582", + "8832923720458983936387697888604823914542155000760959167380458346468815941677", + "16408716740290439442219096309603613006830415688534254451854294128560591562449", + "1113287770802944863484309232492725673552460311886837538428140710794437752025", + "6321319205351235108330320300049882062942831936257890309503365991814791003082", + "18560922321672258596191688202021423732168869299915307979899958586924038420673", + "5189180998718572459539043290302679421565915950138990634526371489122263353689", + "21059088895950142731136323564720383671175925416797251043903234558355128937274", + "1758538453070760465213341124871446098960577889968251388551632606564361922354", + "8880106936008308891697048583874212287093823544613405494775675377028797786924", + "478113991762053058066048308336221551443374933771727184756201865704929054005", + "5364027562586142278013801938849728210749918309705526248720112356632858758221", + "16060418035757996187280816105829974246762721308664137780198420107462005497738", + "5211176330971465153824216149376981285606706263050338982115099875409328929990", + "10368007546243825628853187421535635929255384415227635572356066208437184727920", + "11427684168459596442778160390157786957054817508127224050241732612892526145073", + "18949700777601180659579150208396846544227381511915556752893455904600581402034", + "7164876529024763696100437397763470424696261670104386888341279210050743231742", + "11672893202716354350665939605724566655297144836947407230492353459173601370992", + "3909710158111676258105703555994764863745260060728195069107924779522169147903", + "11345007057187618276350650167405783488453459256756441881422153715183450077456", + "16177820285119478894470005926103825065477859050875380004945625842748711696023", + "14605787997931757094644238801452595674783310674883843033832086542610678460710", + "8394271758834499906719701243007064560791869846306715272114566194508664069904", + "21873434283102736245937985212570921154785039540401524103800440576512828034687", + "5288693737755970825903341313388382553570352630888453317445067182115774973600", + "21527468641133089700262079461319550104586512157305923587305104390806741900810", + "20906707665998407830558869509347677772600060055286961495556134628147066213175", + "12592377229521260472205372896527756013482774884841906928184642093380092134349", + "12910817347876296654185371831758099341950752668436921762585644650086702363745", + "19707023277054651202681442144426045379962145417802880101371794305270012080065", + "5370501568233094600905283140114160955385907390235753857797923590879732764547", + "4893525410028747500809250162311718717246192757157339358355279414251440821369", + "16933412769230696712087772684638356779344465843185712014276708361284654443016", + "14752252971762751211424871408209457845535321896357466404820315342528474475265", + "4381439374316418237204510331759065345075613480172639747277311241150560517970", + "18983302468109324889867853797358234303151484569217755559414917991855202421044", + "1720853637877748574561923069656227402993841601703014320322493127808042278354", + "18055674086054269831422192610284879350534759472987936156359168085840018213729", + "10022985435599924530950214242280707656465340100733875531414649379326713485700", + "19489289237398317489155396973411927208825921597467958674111652983018260376467", + "2483969152386321683533021854216836603663579724438750369420802837936459253247", + "7096495647820661985493920714559517131838710818830485847136203068929085317377", + "11239734991193991562092142618442979132467959527040707676033760692044595660477", + "13964689425465688308583323493745924709191744803740806305195114536185949582431", + "16765583167493792488003846249322412563932361325466895848165782639635509252698", + "9258699025821383775657130802030622351199780460158138938453769223645462201380", + "7261743362549790776698831974802523106349906457536556119083744106556343806039", + "12174595715224479314914773177369125156875875973781826642881907250708051936707", + "5012109434360646519756574765661145101042498088812514145017131935992653466441", + "4700224901573028234520633038757562359543812027452948633531739331172070339917", + "5524276305760203869547781419982228286567487292869238897177777816144717638402", + "17095081617164642751160867282346616888601375485714887290060713493809720024377", + "13598351826191942256399407492736185075239065075291047608049023984461266141081", + "17308136644455825036504551600136601372687794695239587014243640872267542984788", + "21730115551932424945388178787861491256026727823117641122401508483473017057216", + "5949879858200957394974414439063213931632579243992797429658708423363937192395", + "12803563373135008849577150591968062878999687541475931973931310610530915756774", + "6197313147432278847012935526443261694774265540021863115632496255704682355001", + "7028974783929794816060380650452873559926928309476428464943277081506765913122", + "4456589108827474318002287720505015907920793224049488679883557016295128273089", + "6100631380538490803600079371988603006023173019183128962118450543769518343550", + "20177888580254527519697427670797609876974132471313961205784103868094735572841", + "12073238358529645427878918495905605836088922482621503239707831646933770345610", + "21856100081180867115422179532992210187999850914786148325024530634866939637660", + "12466984235357303385071417632152615871825808908890287534009467031177378240877", + "21079839629488810269856967110699842674750899640941851601070908540874579869846", + "17874776547285892135748821889881943162098691701279199858985484844123833691703", + "1051310306073108765618056817409777616413695911463346454738615844650030082984", + "13201928900083471438265807470373218252839081683324776881761206414378175945385", + "10190119257010511211543154766347424644241552289850760573785222226686792626364", + "4688333485355359912766058497543573340825697092661609637162867722200016624599", + "17123765906835174464437643379916457993692257252235548439872663365295598699138", + "17134395901615480964750415429455088485278477136528521479550104193427850309670", + "17940167838269540610857156370913968688439335297994033024607831012271846654207", + "17211561414938780959438190369003172382648707317417933395371238331823656001285", + "16098871745352156970746489901084198750790375003919623885201193800062775011577", + "8110023901773238127710250492301336333009382423651067999842110155158638763822", + "2422126936887420595943345532312996428472865746519279257114791700143799243285", + "10404075183720133448708607844137643895914849868988851944394714021532771347787", + "15058460651933569411128043696753704901683095219148372416995175617698935925786", + "12723555146577954839266714779606964953587444931552430067661560518513484316738", + "5711657581065990142612711893585463369566607394626940266394184697079173482347", + "536257458004844094090200378771107142207864145916201798362001449936167413480", + "16904097338561724274235483260490381087656469057354151613747001642006805270380", + "5885951988825802528717928331501311151617037953699202264796404860914064325522", + "1638374036867203230684496314040773233229976276864977417441853704948079389600", + "12231982678049991867660964493898657015614690001085229646831798098083877705620", + "15427058040900308626278462505422407030810836290013997730209614367042825008816", + "8287021582226423932765127558352821849475385690410389396789209560743363809623", + "1082920048469231434960727235146664410555571531264546962637788898495946680112", + "12010985569823806398477426440616395624594456642130882649075614403521532359981", + "1296330560506042268524168200578272313263311415565810607634491211599523487141", + "13952994457760775342452243315330031022436205430079469228726234965837656704462", + "16985743548885988875181345488907967382109958231690477723834234297604193256890", + "18108965571078287240054765173491615799731924163046353815744437352944165909003", + "767530387704511846542067425779936904920481384673999726390798572580115466105", + "13028307645272598127894992332463015335938472044187733546491605798735426870634", + "7618140648066747223455845067208730203353985191563779819124185938438241329003", + "9331096408013670718143367691921833484100954507332698681105640867440874379095", + "18801244145798024592964955007270988394935375648640247134868164095028295260248", + "3795459656522732094044639001176736675357207553263371458375866920248726997086", + "837603424793724140470838171288512417218344963365692836088493443407197621528", + "5831962429370013799978251611601242499647911352287066127245255213245836916243", + "15608629818832866779793800587027419050315344573115273720682841552596629193016", + "1032806196152635164955947370516112750756471391006183599859124038948506281039", + "15696208732714216759620197747787990886188845785832889089576996959760026394301", + "7234583861372635173862436546128104054595325252312930586077823639855585372879", + "9351673222157837029929340587547626334173727344379333167413124993232252858910", + "9944025695384518607461067522154717153892207999526158631473359210163311199905", + "2388456762928315498284690717786606118379553818175612967295585468860359388241", + "8762894023280585818322989976434413098781364467068028456427186735232945062041", + "3982990592887978322236356963193527056120817698005386105106663667178275102339", + "15305580827228104504176089928458181616132990558748682555478070517971443343847", + "19329984412710376451608868772829323267202139442902035837598118892290482040500", + "16858720166203416564086563387111926247316950607110418622245689767918477559853", + "18241191751089003023961171787624834962373436019307905123520202159673396473314", + "4235718345809909430818933555490446039661741163040234575769526351800272747420", + "19336790216312697816897624746946849815032853517670504993859895524588720552146", + "5833407345693372936993877824926303626341316298366978224289402960052763586750", + "1246029211601050773151495439169819001283925818386531745942667315981536442422", + "15220086581176169769190817430254624676596374261069714496878816359393753960898", + "2365861900029834138601812494207710261363070950725532631535675557556177296586", + "11098939996500166020441603457997996414027684936264124308565274744828953147961", + "10188381420146390141161084654671015083379584925005132911919536024814384766817", + "4842017639583023386245773507388835267437650777401251470903076835565728725044", + "2473142702350888708640145449504461869356502285425231033191892981515210840933", + "3420689338060147901034254227618353913575873772273264928595432321920193621195", + "17283074258384994096612354354366039962078336488852681769982384814157770475001", + "21006196209784588036771700052971738964442512933084691689593009338899209077510", + "18493924441589584713280363204662484496255740376612784432044649586411869984552", + "18050342602178255577111253065667811034294368946566845729063425104069824407598", + "3678841436690736561960339537207788725774745841190361109044779271967419319179", + "7229032436003943468306271354423246592397907094971085338195794532946516086746", + "6074543407778673702938004547803408348112315194664133731027958879041743082105", + "20066840392762178519205386382693042859978931394221116082945207576871299356172", + "7392805501563984757154630589230967797392843859128971344647830779113836888313", + "12821992933916071670969878929371658252743368422895791718047075564423909142719", + "17668945380988406358182777882021562738916627352451654449781528301527115094220", + "11046977583853814151360987998476416244370762366051844251247672138778958746421", + "14002539550635338734484852844372585460419306414704948112807545053902011590061", + "6606166606298514036368338857611676551502463523513184670555953533985389963443", + "5446061818493011809543734117506203755719984305445968514525154959975352640311", + "1111668700238284277732413088411620500087954609586256178652323895010927817926", + "14149444834268176201304046807022441432518948094788616136522350328948362984806", + "11145589672768136991149928307436511325152474561287303838823870178226307903252", + "10735913608001838681702607049464645919999926391398426712273901727922068271016", + "21604506935173200936527132172076877500255612688310066661071635553990139487164", + "15839861321575777225084554553361389979179161218821903561853968278717519007256", + "4119757287481158134674144154651639875410119871143992982693366998676854632059", + "21215853876753845584435912754954004476252409742434691973232278809063267703513", + "6474112081529376586123095858950370103982143188298415134572081362206457634840", + "9652012486829416433331453480518336590399776148133427672040049807230079809918", + "15197188648271522366095502604900923401004235531330211517976306351199244466155", + "20653133196783868133525869637730316323485671920172550159454294692576016995406", + "5372382735415117884334788700701478755716540017619541377211078296573383620529", + "13207488856826369213621681118482759531513035177166234417284384049787214456366", + "9796874023172008376751307392327706745295558991768659529793122654595100420492", + "9923897870015737084413253850361127061692788482930375413255676958440886663490", + "20345695890485642585927456012849850866425595188379347054737827588286474285546", + "5970363931303429796131779726714445177344307738485323531135738898520018230730", + "11099832493605970375935052305980301651220466371839450598182845139430995541342", + "3984084259485258180085200952180050171170098877962423607492480207306084313759", + "14795772399510400766677766636479617776597353783628606580152075755214440944984", + "12411649494499018184602448007465543838785542392797557004957418343044512599298", + "16626394877225947777126043865023393002546807148362691512796749460115071596438", + "19056586788697785123807358806982924302021705802715675015657752728604200366151", + "4434453689868848221439283056960830923558217744100875597646474729523600908085", + "1558497076513757145941997689136111603376893591128645477322800957597462648163", + "19855312204158524284458047353907697917092904349885231039917644721609392348549", + "14296610840588714282305996857377052531476403374009704740496611471123591762688", + "4255702919775232787836264045412364184259731261431115977947396605020618214051", + "11933778709913818332041068411271656949772987367132405709674023277986614336789", + "17039721891026771364303633162265090865698196106396237296534502784700270974342", + "17677496806049413057414389850646660368467945835594987026827101037177591654389", + "870853693457310346529819971157542197768087609061398183617507613118675541833", + "18050709179661944189572532609164386192084249162773126990656248077533050260547", + "12509892200475964347152748879404468874956023169504780638942472032501158691943", + "21290469710465436947459252705329759527038443945558987181251205171276803887919", + "11697948989002333965655987240828667368730889495575710652080571936823918605037", + "8736925166569662118997397920658489847012314542439353474077461070832299486573", + "15840706598368315931966990863663232282633707371020640698077565307266653295218", + "2336556619780315190172318504866216965057876522664932909981631800248874766723", + "3401386693708589750154291055903211427275255738949699968058464589080271508279", + "2985234144487193053560662812519604867522985647272968908108472491424983944847", + "4708870044417079288579972819522537183137753616055169595344370650267781985451", + "14922125937386550210569417108464732470846637538443952204254988396764974305556", + "21120247382250540544939703044577215089934389719849213503558017786742393072448", + "2316928219829771701890891437885406935408196453098584469128414556890718887397", + "6617231706636202699892427347447707304283374531129890683057423079735568483257", + "8090371166463272188656489380541987815472988984318384965972491395697937697839", + "15553944362864127106455863696894507934518908899701997904436263710171474812555", + "13969363969212770297664533823398202808376213044430873505018872984372178723135", + "12323663899898371993768411530695190245261583246438004058508426675150745422627", + "16566875439359417854141203050455423662432117146587478868034846190942245403701", + "2085197407488705803446596939115235993629808393250087488250514287409223581616", + "3353163139852271259915937989527822937141797275129253304946488349312180510876", + "12046433326685614994434242499247496702084910418498830651483913063626259071609", + "14532850787151304296314608701306827699237853461438425922459530673831764439726", + "1248026383149472348014634990743396120794718445584945878307644249641199424325", + "8057577408830637105543973735712037717868264099646638037329061041095961932706", + "483318248530006664922961695058460281946793595997210254862751288308569479187", + "7597115662868588435202039449596982590007976221501668730777779068799655592123", + "20576588045443131888269350588198092656950342341724106762422448997215666028156", + "1519447772833782137513870714676314005111021965782273965574223992106447841589", + "4564008647036378562957325007261730909909040333020122431007246472496053026801", + "20058604285923748821870861850977236730661592466138938301165874489677433369725", + "7444135345158592582936132362592519965410456021574373937334236087846829245911", + "2619748000882337075816263795535027848943303678661676628903586805250445194179", + "16416961968137667392446268131224700809614764673462182053193218154672694280838", + "11133666903754924307114887742321725054257211678992195923482419349863465176820", + "18185607668620497969429683073093259678523061297809671850245875139394070019601", + "21100277417778348195596070047101971906596351310455360764416675735903158404363", + "19242696527172349562445561603976204919773321047775511674132373901693664836452", + "17641599298698108341739444819055281386405281781490793437098263180756526877861", + "3867854105746657505538112984381791148258872175005817045777653312620913799165", + "13673929044343556285939637616797217757029992003977067790150536754605693560092", + "1413616068844936743999269099411394796998593026467324669628149625629672193659", + "17182247321635044788965517464433108044764735758956097220834338897775232927292", + "20369403412607032840251975012855741679474191692713337906759271231600952698270", + "3368021137971787382116663997287877185273428758197831072626886100000321343009", + "4058882993633327642712241699549337354407965426094339469485649412411970892252", + "16745738472558294852806571713586420783108275141805815749526145532281107769806", + "15581910313143599067008775890965264886765882549739040775187928885624726340064", + "18274240790635707268508029122006654280996256674828118427269328392146795445159", + "20233611060321484677112349983942832171860822463387331585688221516502467246411", + "9578794697709092641086862842633192064390680557390699768090648655701242260988", + "2852999879330450264744202807076238853213578558186322493583347517686662265691", + "10741465223456896033565854764716115079295016404042872162238148987621341827594", + "1287682441013790555075762279132093640356858755666376578858076731440259199594", + "2754348824392215081276565702993043505186786457070961060283939332925679390910", + "11228376276796390660691597656113154929593350154734497204665175991737933493193", + "3311568804745845654494413785473574358224291288129470978720234105131364795989", + "13909323234259677397453192122165186938471237491769110758142097116703508140857", + "16483726454860443352311561107200491233365512138292033674515348800113826861405", + "9812016698744294015002456058504358834959473085649393839832264042031387688048", + "15177982625372891489410897122382147270421146795964397363826406495667593673282", + "7519222254582187388553575935727848524972644886624855076224718541180666103816", + "8301393036521557606902463799168007719863879180990998631543603658427343679902", + "12294426767414989378173056202553334768408199886443392931845979330633289559578", + "6739869506728400044391551988623920236526787529007157619233939477743084008138", + "20069013437903411974438964103206724858007754851513756279456345172264534005155", + "2018834934981362435424318060070780595968114685660751661802811774334240763265", + "9403754976005906248280231838299490163038233707814936394634595857779528197369", + "10417979303761863711608825801177810340012849177958033395021985945544086842565", + "19604977682052360618680964990952175014659495782934855476845092758883928933035", + "2688418347826037364876739676610309530415711729219616027453603183128414252617", + "19429655781202385023906019671461539686080096105536288714975255299583443223945", + "21850552082723421744247018249567438591533518178485575560955887428084379635362", + "5617579950805240697000723938792084314286755653766678432489519653418680110671", + "9555670299297105865403034351288164766308791892391888668326102655956067266166", + "11495978801695516791606532228534536491719831441531647897999875880662918322774", + "13446240540987488159401062110915298027617715146895881354765875946092155869706", + "7830137135198409572038952404379496414181899227574329472045729197166487746395", + "9556039398803760338966955211123892534270670688829455928022562515996727400498", + "16536848921900120010270774925810022257466132951671306792158048247185847693295", + "14984883995702583492812943326719347992462648669814085270913355351041523830317", + "4449876409800178139287642958372279285293173800225271693328528758341654973266", + "7254404965814435397385340781449208987509307430022649779312503908065673947649", + "13482540945483896073831058930261724641277618328981766008722675404404347005009", + "8516464109813705017846673381161730340458008814885800650922822516855928737104", + "1123466447164703934328741246642448511199513706388932930170273400845584259512", + "3549658554379334242628536166107543119171319090515117171924404150785175614651", + "20050236656917680705173407104625075641049186986084540346810909246977321174260", + "4328179367990709150244102496965604541058014472966567986200766436334838205729", + "6523960484836646945629638483047198947455910731228954877131634689551005111678", + "840118507410487418552201986292140077062095264830249777356756239948365951505", + "9443485141542020716795178817254625558092596484849541439794346219916656780924", + "17517352113160950398700094980635300524550125065948318365273967900505416951637", + "3558475678500267728084169977682358432036940763329037251571517902892359350060", + "21782716253294940222641143651977099452381765047328512527623130468565364299843", + "5143600969269719315523014195013433247337519583796238248783742413790148311283", + "6937766932051718809641611511685721559694403467477888704545484121202675152929", + "10248511959409536383597760784458127936162061804351541810962726000050652155800", + "15584432188633520588792022977848834701354218910295071102828776215462904575092", + "16507813940325077551530806573175229924530686412372461197571308720671287449933", + "11975780799589036547299759597975704141323969091612997515060812893050562154894", + "2743143635303404960353780118079778350398309245035425997562746911685628540405", + "7772317651868959663361913464992926253491072635393117289337616002993612374782", + "2337519377771760840047685336751334655527732210909930380948789294151305059244", + "3616132500009609097754462360087761508553832847286785396472146776175233605533", + "16840763079152094997371697832566620838881567041180683145570810083272689914599", + "7660270111053834825889064071065415593147131275236956990950685283090480450184", + "20762611535627684584459315491847035257226740939101231132494468375819869523509", + "11042134071344142565200223013849882651956544247603198913312251335786248573941", + "1940414570916441943786503544322754456611678071701943345167834901237861815275", + "6726537219661359488596406444614225094882184675245355532878420949418407567309", + "13510096963519324808490741235975735288120771162631019837713476375721562862601", + "8622373819062603720895891234592129397052930901106318032071934400492518897707", + "17024729268332782126190150627072810510918979523772816301096433100167961982933", + "5587788522776741050743071285424100117576582212221222382824387609679897172811", + "12388474196602817840033287553175313493977358457560707192943603355479290048023", + "17628897462697931613283808657115398230150168968257584770836553363771557372104", + "14065018459890202233327759187460200256630019200670511082974394473420421694399", + "6104554150616525884927725557698817344144889522156367737688769378902924558634", + "10992664178398974993431947901729345793474931192615930318284939994040095999242", + "10969415364246753478074755753965479915045305330246521543663858633748866143603", + "1272956806332000540144317124032834499397723122931270496707464205344164793800", + "20231387145101186513751955054188659753720260135170026275339142463242692015712", + "13619345053559735757194629501334040876412094886252831860426351060385674007066", + "15232357465863047438256672278087920688704670526832495687820763524016520668185", + "398623536003273726220923501915643032345957170167431833298597360746684401150", + "7028250324917735970960317543369047790628992348836498053408852879988541935724", + "9906086796055827169135574765108677877733074061825927799032011921038506005373", + "12788056119136131846722253277450922603309904756259034915496788214657808474919", + "7651468821535297879836173382809170069017662802420683445433781610638854359553", + "783979512383179545035255083828374733462990002107251717097983319441159249905", + "8836457559777657917879541925866800908082149812458375523311279635635800064090", + "20144830911959238621340309337187081519944136818938895654338696747143855879203", + "6287181334311526693967500402732058645490470512478517679915786729496945390849", + "6578356433253304325301622313818326592018737710185433748824597250242226401957", + "7102838428799453179757741468552077315750505008228901893660362447987283707998", + "497820320926977947430162841325159818293818758853362781494155076005984229339", + "18160985608878840530944322708383120179552980243808985184923313895763861919637", + "13151612592624659285402557051397602661028781656351284997191435582230535568502", + "15780018535650817819214066689149640940245062275718550628416824107970066217991", + "20500218068755784102392504532520873969817687889455201735073738515957629646567", + "20888440956803193084788282136946318522770638138510716565517310266646640263708", + "15971618258529607882347998799169510722902529521092131094419433339204085498306", + "5293253007777884257810026986010586149314566166761521493811000336947093325852", + "11581497334099661755434309930999056492294889088823870215073663090290932016658", + "741799820113052677363038461398206547514107871854645629573511776865766479899", + "10132388802463968927185535273034278687094388163001210029432141519239006715163", + "9843127774781963908073388692741045845788815542021009420639678295559452765837", + "3807159091255176851037359514650776155078897682364934585802230436085278410633", + "6904224411392552889784909729922790171388456358295280077234569059475136886573", + "13434461271014860123956911179522881298853645897065359788401689426904150525428", + "12249944872255100022137726834287337969948262832177273992983186014370317983705", + "1080721436007830510323005297307130991703868335217850548555329006531295547187", + "20651452101643029862567543402727347872461377965899451538964773059299839803923", + "8902465483627533643127758766065785114055357770410218037441501029224645377694", + "17049203022284218301986830675304595858941437294636126244507847280421482250090", + "20389632733862984292955678575857173748595770609738193230360968914580393387194", + "2628553647311400613862969480533814764766703257834731382409245421165389763845", + "7113709286888238485244587172405174762331565517345483851543315956528264191390", + "21099219272139712501072896978936944264265953306877942445724732180674664269749", + "6196322429352603190460567397253889100476004214002852031233332452859780069595", + "8042719870001485176157425681827371545772290235839006373715151688719449512739", + "9109639854367609940132679558323551490721386060080938849664245212200893608513", + "20820097690315610819796383305043844702226083970185755192990081897048903995104", + "12474580713368057036057537615251118300654026141156267907684197425413737128906", + "4935701571378317615941939703137616736056472417588666676180454398865436202845", + "11284674041151323919882446027842742890041719161934493530658741778909469887490", + "10784274648620717180750449830334448050402020683452763192417352842268830091773", + "7221763500960709043106304906102942899855402476011030187016839441411503790134", + "21488573117797078819915291564603086854092528370673732237937703606783710747214", + "10368071846917543663295415889847910771342838450725996382692227125006143332582", + "7189971404170280285101021558651838178138415948558212834138150417852815291774", + "3622212247952623996680563730554546964978269732772060499110124228651174919309", + "4030261128316895271453652515658449745835613736325708089700420629607904984695", + "17917906020983172293093657775725231153822157764639429745264576611859524349990", + "7911943088433991265213669750138013059877768768674246542956611065207230165349", + "1237568201834766592374215633649772138875843120827112365624718270590862573855", + "3421335729151995408099494011827853754192179969298834320585486465552812589072", + "3983646153441614758977318714985842223356917025653336289250912061318144657309", + "11832501153279122995870584183546009144756312133876131903016034834496067810803", + "9642188977879773189558548598547584337663289943484049782260608599281971392829", + "17650631071515565052542834438104124084088724345481542312112093611903334892790", + "11727835841766435406263157822186528758001431234638936084294421464770985535272", + "4170985922866379778894675975982515174956777531610306941710536931798155932713", + "1904373901352853963433078121273558128713374926256562753718137883724136086536", + "20310106358538316988108567646970248789216107374650929380709349367764652307148", + "10755444294914746017826019531774644079659674520334374055753829758342372728308", + "21544150011748410796331015950886967191957797301800349750025078804307553228922", + "4791178272915634809747385261951447492552726497734131770971381971399880792451", + "21569911489317541997628510847711750299218484102264583013015022430206018097370", + "469129421958624587885163292532024178451414238938436764179429972880411747423", + "17178941568791193515971789991206572943108926053917999875254005411851993177716", + "10061493654971891913017572469769124056153763544567322059270144080123216592759", + "20809728888234709563099636671010468945654173909532666727272823672496239666493", + "13977154471274089663104412732631175732414148541501676926172952880637640768097", + "17159586220373273602393948660742324700378108883620196368910126875831365156676", + "4073500643742253412297370658761396932893392648826435730598979045413705716932", + "11493572320701213886088466735117685416116051720844612287863434228749232164029", + "20892362924238047571943713393658663337479326222564740924788211586758905169271", + "11301788649359616808987952401363629750830090004562424782094282760076674679757", + "5346827191385082048034578496490044229132766705726383391388695220005635473547", + "2201675309086116923924279562154152714268152257293936509978158351509848697027", + "17917826577478806664624583743441880347892085028222113450954395295616044284297", + "16998236939959525187887324821682683276592762127156629849525502305788028877451", + "4214391906402965555572230230924694640705243512659675242003943183722900957472", + "2247036556360539125313249919915213027481437766291950011195105972974928736865", + "9520057428546863347057860284023378728609842187323632161028631359500291204227", + "1828736612590741052604266070553266072363175828159047049110641125134408628099", + "18248580838532636162005188449054546706775958322552749296747411333541139803294", + "4834174634635006984667037697276171446677972706028785635301769650621697899268", + "489734793278913821067993383657373029590536750171301785048262915525334613888", + "20786356799510136039282916235428434827695977220581899018592633397684279594261", + "13145806261364716646031477788186247592609087183869974953048604633861380872823", + "3841420600164259772367211721293848988818647274121301867288590071853319905062", + "6882597113948243507685423253840830929482565588666222909972451758645869849656", + "18980943240416553858613600850285792319483905785062366023956546569017873987439", + "29028675420319059649770139934414847448931804950673695214332234580922091102", + "21775882073646833834016763184296217506960385126491507726769771477412306185790", + "21300410381086030882514625793664995316371660662503398686828472860934288345599", + "2472267536757789817746114566761390885333410401690592727164834695142144448445", + "9723880451630142367622302246353057781908243406397604481250639516011253801606", + "15313110769360181254868962440810453125247644871877064008660684649744823174300", + "20564192458187565149788272882595180521577855436987831222746293278781628416968", + "14590472970343049442795311527863765295112518097070620865372037933484660359574", + "17062841617700893799013325463153088719125540677385032193714935878731444635251", + "20200256413643364477818739581045874029732018697196252518589192345293202187361", + "4016942840923529049014357120480338974430876995693135820048221911362323816443", + "6537662900592412058939229458410964809681215707806173558553209350444735100542", + "18297886978176179234700005359672839811634650525194200352748308964228483504767", + "19662609243585750899960608765774063353658909677643282385185291970742157305960", + "10221731387204953046960523786878755517637874808703460048675288088446619398011", + "6359039963669314770815970957437041104980907769543152198211817790059980604175", + "12215821248736109157702052060566873526833550744650237478543432061962195037956", + "5935095671961849761918916493742868190941272209470285856382557274883130995501", + "4892952774759542491697203073862387895082272084344610213076129801679488176656", + "21229502683877666320987735203037721130704543292725579308736529207275811435612", + "17138707315635877064706472595294259087755028865414511496916808945331553578413", + "3064016632497858706665392042657089766401657752838410773325693629079632182414", + "10697546089228176531454125219656376659283555269092429548580998097316823780605", + "6383154332658396326745467904696030415502846256075951666613157084114882351628", + "15399057406934719483674477103950525850935787593222687850952111073065008222381", + "14222385230562109850723354194041721683341002968759594278414075630295191868997", + "4196055868873306164684774878036056827685013979028843775890547079994909550345", + "16495894724764636941708778916623546529990869478284583127943604032121307478877", + "16662872698072302151631604897467020278898785941962087730337008570271651661242", + "11474333637424192324648146148268767361869344542358721131204304533867910403346", + "12663733223747936066515430496850730759882234287115648507227477484368789774494", + "3278587449214209390499027872507714198695688159471276082957385919697290643338", + "19852281910336140665278848076045642033038867843956224684297984081107396007913", + "18119827693896204780441288678080897397841525584683046254519435612134656396725", + "3004914531848687259880590983112983929408762744461212501319599913078181196369", + "2744805266681634195002030539778050424843533661368265264531107280758966836574", + "12003425394929552979405575446174684244823087440054609540505332749485291543559", + "20899617298205776433505248799032591564097087832964850292073852661486959326400", + "18977355049070793830198782732221581680757588074059967640900502934882545605494", + "7774492678097446887356009465076901979542998304721485056654902284935411555748", + "6257979871454846095389581530427518297635929206624687597975380788548536091169", + "4200362970271656646831473686822497724241729322168501270846014047124987169639", + "9626555465339955137152373316361342798468143010897667050837558740100066479490", + "20599104767749131194316802432182162807569082153791773541255180345102031538229", + "263120164166236772856966508954885356163375871249262527569221312470198863328", + "14408635566922092915650756800314844499933046455992065014832556500390343919586", + "5183079049039149593555827045385122348972389627856098826226304101776790536649", + "9079663711634286747144802677527389482368428094888913737002695282424348199029", + "1730279784246934965982679327290069428428752739692892522465325889599043152257", + "19417355737429211343570897838176489391485942830255040228180844510907794134979", + "4688867852231614618639054238240140493597889866886829462162366294959927124611", + "9750344066229503722317800976404611879233170071789439067052923419204148303262", + "3998708829439769920633774213209304480109842139515896658207686741134489049438", + "21119879197425450902002580651023270363969638681856902851675391960298938692105", + "21081985423839377197813891376664505429739140831959287968556239547809632016084", + "2194830658993798006279037291585161216930179214066933009151541946587699367176", + "10072059773309529038163761158232080490764157196414798621723969165341603556957", + "12893922413945288356816723514764026149994443040839144958812668568890693761688", + "6289043885924508250801248626630354568142964747989700154772682955247795752635", + "7117847768519054206399668810694592559179837439189798231517777441723405148708", + "12250493458894268361669347775761796626700321541112455611623342396141245275173", + "7536889841233679602786965527644616779647633163370923759512908958092882343888", + "13743804807205248364239225685151790362682679734025326476864976250180416573459", + "15326756679387284645144696476114707028416084124671428061976908306742987298792", + "14138908940825881278249529554167499601250081601885817719517135886992016259170", + "18191604052705446018115707722428677617894390137039905732841218263472908863798", + "5747208788515494994202809520653945260017053266507158973974399964661798663161", + "16272405226087543462175411026937377018988783482980328154498443115982159189635", + "14959941590764331840350995267307957753388831891977493365286637018137237442649", + "17614662493206460042788564726025968337855721129414467376860164849857118120897", + "20540842142176422103053529661013282478418611089363263097515168740633056607687", + "3290501693077219671357645003459548779173001871326499393140572778475444534834", + "6447714071113870576284977914086213514251182728059734289291667058468678194763", + "10016099876948482641338204267737928588893338645093292975971465694121948536197", + "14390773887169232315205787249570222449199544947506512428178148864937891297988", + "14620241431433245619096116183667070956408821753296293274413828291589840475809", + "8494548643236049061832844399476487754775580533076308093638832054930352314493", + "13769276515160804060029880354652109198182914994347382081537158871751993099394", + "12260040442111865637116150785319893997124694704607680451569915655443058209529", + "18536763786390498498949547812325024712812297365266616445712766917775521176399", + "17646030323097974380890038898728697538005884509434748880882937861292172824089", + "20995211004588227271383296369921345208592928705280945008379701434887289620654", + "14012493030585128283500948776342859322003214361666347021120271800114480256613", + "13455652757462524273399933538052579123871086976307529744949349716824204294368", + "13176577891048443118691856747592745460758840755040242121263455031909886205386", + "10958007047406016650282891454669527247751542376915102729040783130554758505696", + "2403556896710211170900277969533691258363807287618829314859189083914528732150", + "21557822641920534343252006226462178185422073111762808253392360322675121740589", + "21301363144372514699996437466711759383396133417588035206347144265914876911832", + "21504297452761836117267872934293380498824936327520529664563583098264179167892", + "19008511347839951812168011659083529710470044770506456216838511009924048532294", + "20729557973386382250734811255901369475271445538588448251951105355722497057092", + "1596029835560146984478838415844959546370291207350745477127036146832708172428", + "18779043981021734310054761701946195503647990042042517453246401248591799960006", + "18389072889502391007861938373344479996746585336278814994866091596798460590651", + "11450018471721248431523978933304902015421867719856001119788032399031643640503", + "4695792303828705800181239521907223047109864872167868532243675764473118182293", + "7504424077032992561542388084424474665707766373549642837850671808747703476058", + "16201871852003230376980125294909568327837373609180822015372468013683148626476", + "9820880186139182810240320436271674897142093850866141441610372427566550592116", + "4474392152763162487463052318741100507628836016813487468299920576199966718180", + "6535313881166679884076402867701793095581869448631792643683900609540448349145", + "10375499075088306448884735241746141379659872937880333028048697275256343984198", + "3166175670215426596895103003450519990743126408554698027893417949729089445829", + "11825805020940873618060190367149910908253947573120883350031415196553790678909", + "15868728010683147011542066925511350470588043768845023267900379312401595633901", + "439641324715765398013368707995400811722128832670521930633684822154134655293", + "21389215620992100898484688007707226862245610434491939970737280409708735004882", + "13567457078921654178980424734811793190031829390199528822285370655562819201102", + "2491418221701715606532424215068729097730197896717397364135214058133617329024", + "2700199371443700220147927924846092239465972046042951758397024540313204379477", + "11101155530024798073181197117436499601132355735889219480985438157046671552075", + "7696323106369972761130328211405739772776004396041557644397285018363028133006", + "11874928928175576980576459276992229552831994515252269310033260164062026645644", + "240537705962136501448280118114493602675578232672944677099273394877211057455", + "2336277667844723086566433195865965121270861932965343039992167442067222380338", + "7139477698789264606031986148297940201890262913499702250627665080791275501502", + "5394022087396393768813205254315732819042275688988698297882925332496064046016", + "19793961339963600744392705441271116638543292070344579052218623579091649097618", + "15692138411890707768379631022903362931511371639119812810678572491600193150934", + "17870790093336984580535630746458834581867280473989239593391879854453602020534", + "8527221939827993709561548898140031570873635681631994323216682386420609693119", + "20583146985132338324328431878826670751588212915037908674977314222878838415115", + "18286401926708183610455794878977380145855167386311409319243563628128439897199", + "14883280595953108786791995875596640384464375470758397510182264364463199426941", + "15622372954112461900770387091989505548249197707826335911691325586886540655839", + "15015231518950399896087228957162542423583966819051318376374846686122344072726", + "4110275540712809298667287978052760900153083659165519222137609468305797552622", + "12194886690835058962976784720918154631659193272765999855977381550575603733993", + "15244557029932516875079143618219344257744782264536288508363832394149847400408", + "10234512862511661102613686672198745648772485307900923622631623670310818907316", + "11002446381083289255418443918954072583200871532274996806630154250111947858951", + "8253167315431388215871891033564848144784018068378784924459677347009078928353", + "12052362697319720881876615803891693831545089601220691511658506577522506606138", + "4222271910532283822428121153000170791277438320812055898378713943538215316712", + "5653799018158152396708984453701593562269544320974176828284977837083044089432", + "7882074107401771620456811688079120160013843021919844939348749959599330360070", + "16985024708206545567858733579435707605892308141313442111649869690900835499686", + "15657638292217617224447239244820122003415140104485558954475025681733455080516", + "5031435167133277726502623124488830505559857356049078624241295172338778604459", + "18251569826624635398451261785711619709466995337593606694180128347754947431611", + "13347210735949290753346060121453479592654490759925951960015474767685667320469", + "15097256163521186466089214691748103981791931847659339134237546471578704117651", + "18618539001972002803104792202843684224999903989910895364254642809781793542910", + "3535158924054577294148391849345768098132565619653646126038220164469413178376", + "5247111262643738028940705230194040190316748748116050300897903801701767549935", + "21069968641157288335927634486731267978865294883466175079455493856177243522705", + "15182016439888624540835624880056168611406902880254574867923247894452951108191", + "2598270152918575231168351721309733272482825217008498067779287914396446525010", + "5113774671804063464274403166444533180735260894306271253672198506848528131887", + "10007988864825946871589264454040608387449058007032979960058775715911078006740", + "6905160188004006948460048193173293195325586959399957154757620552653693466890", + "11995759573081381716106152146833656576924747390008060686555489446745383610128", + "3012863557306381401755965576258357584550751416148424411503270543269480674925", + "2913988303571063477501511529375194010078206270482236339308347176586704669764", + "5006524049092266462685266534385319119401827059140718482624293936686566174021", + "17563183357860154367150870160675168713982368687948283812578969167511639823963", + "17837755859790999437375156561325979429838685660428780384415700354505074279205", + "16080522246080742261793784524730583623229678427635608200910206239897175583035", + "2848708361765680705684254800195178864363439998055587286174501633177530616249", + "1557519954300916467422364113319270366979873515036760226798787393508368098341", + "11733665678441137100700293713589760125678167060800184611962879142675741739407", + "16521409005131685666434785453319000098069672876632224692360259274386316622759", + "18967967647390654785643258265157841586213408055603172849772769208320302959605", + "17571504476351312669488808692966809815779784230239825235217863108338926113527", + "1033277958139146991725614151292577955914352533347610456481561709576150765927", + "14781931979382308373625511201561097203707487976646566051328122813686985362864", + "4650875909473177450881505980066567106490273485086660264292847695230525365004", + "2914409799137239617504079923731151032417003482030433682771204258557926592318", + "1569377349856381614777306232175508373904011237210172681516586308749045834576", + "6819560317780627274403497421141083285449699366697573487561555149873327611188", + "16783037329427380826125478934695948949747971672927005004484739677562779828896", + "7015004192682971326660995855922915203604605225985220083215349611396572003775", + "4630816304408133216263172876471813378546980993666459834637527842126471866675", + "1048974869579541183196305195192354335945589066090693848404581740062134729282", + "18688715639285068183434963296396143793423259729912639999344372787920282768249", + "10934347243740746938446533383348729597078488045109074394137337392516949956248", + "6293725896350451546716316494602770048720703017891567394397586512386125658192", + "9703640866977553131835948007053717693480506246962404280815291341798629276781", + "7906707563931146558411066527524578790489630019846849753651156405406896838827", + "9702629288736663637774512920196886201521548938988112829178357919548773380071", + "11496918342981223624025423866080407628491859149911166113194854209867880853781", + "5310797284993667039758118840812749372556974855379167283523727209282978379416", + "4023078794142040206433592504682005395486039156676105856122688431286266944198", + "16871217006715623479558921653467262427043486550696934636603562460293483965032", + "11838323559167998464544738415089027103939009770214130070107400686110312526340", + "4980088349530490327691411848559646523716982917225546360214229685978505879808", + "9559603819596004088164413773616676054644268005451072511817132718244048934414", + "16706530320004737946238925506482163802145108867695620161891008305110107710231", + "17097818114876900788313405299390647115420321455669519337216918484593668351660", + "5849414403812965413267782406018277549067364089813096482998057955032613458546", + "15554882868930267918822925407791760045541474181510040631764755534058258253399", + "21580870201101672999738147681605702976639626554191473007622680366607482413326", + "6529597247071863795966038055163209598757897174702699285551712764342047434265", + "1034354038040835970585668649926410980243448725331655567931872752141342573332", + "6310767810288764607994771877877727315289627303796831154815613377794983946591", + "996939452759173758835198197713244238928300388619776170462989538225909183250", + "17830180799634516986244195887614846195714707335284590299432596686170229130983", + "19874559606908304758854510017033500134646556009065042866233430268619254302205", + "14009373839533951923879302153319163529100920268844053529575065501607218593395", + "14946211767155341356149843492542554767905660369447051530372801216288515919491", + "20201956319173972615406549564337979402376802300388863728690331165140287483581", + "10535506466358617363674252301599248223977286129433846317382254624662176433824", + "11029001794792043521930346330104687908171223556219538577009137251048931299365", + "8200934006947443074514571335915268415570710146769685554653690866413931711817", + "3756001813899409241012385101881052052933218317388650253688371184478299762463", + "18636887900618256435910622299263466888026971253061227337296887637280237818897", + "12062360063539460494176603336727957703003697981349882838776879968409682697224", + "11001722900962847730169711618381123657713397243841075174948041047383605406084", + "1100165499084337642558411348439001505815886538759724357694738775770474410180", + "17434145857282894864497601363005649089714522250566258141982190265575138829458", + "7528570688175530782083445771420581373161584322581902670613058236780353068011", + "19971690728399713343613282829324748110469462189895719072018362834001408037396", + "2720175852023799717892872520519566779572526301065275372226989199715421627391", + "14943825869290446747104357486851686014418770156528443888330443464181536442315", + "463946552619089332690398123288326517388219753658554785664250177816814153004", + "17828919314250532241077886046465359044175524922026640483099339343132288207680", + "17254663393643639301497528160788050107293708210389962463123967310041334977099", + "10548323428945380231342461328951126333180031707800802905121494905097297919778", + "15741600332199859123106892774234668638862408966232099592590755994226268019056", + "1447099980864195663747093395834509033779875532198378629216846242387465017398", + "5634271615965881595424665300014723762842669209816714518648909648355913896267", + "8004046094319510531556517659927356739393971820240935140962728964910152787977", + "20150098853172404856553856601505464455083744410516166414862502865711843962616", + "6051577504932496971373107947431966202921763803799244564057047344716078611429", + "11153752935200730615392163240542716924397740666674490478903681768299619893440", + "574571428841330767683871500343913695389489991910772848795148223306401258112", + "6644002840867033629815195671865575216742798076650013015371202918478434067981", + "10643887442409207306340562760946079189746204276290341516975302787467861819914", + "3310054989122793204488875713765468888781168322357480727671652094037000591815", + "14260109332138908810733885305730437910719800845345795697882239548319688811219", + "5210296637174697538908079595920299077484266890923778247313974722933789990659", + "12099525392201549319291916254076192583959301537918452056524775934199172994864", + "7553233508370030852973625898622143795815488816458055012305692281375143855601", + "338064484385145371035100049761904487152067475286477053744625247222287881704", + "21656711030424471443690125986754350631269722127039355499852011488517394872248", + "21372195548620232488593781254533859082570347959319967220919951808088029020212", + "6382011083971938503792804272844009960813722135917547320595901431805157825428", + "10487620314920598491955634712479265679552728563160570833716083687459951803271", + "12540875281457292616015016392478978686561298989814479837942710114246256185916", + "18617705893970874028060182711496372099359212095272496239846702650061090540602", + "18861927157583050522649066858336628481061253205783797036256319572504841854227", + "697040343546965749510304464460790931385381610135802696124987191773265224046", + "19957864832901242629222592391639674066674531543245225621817890196632976954948", + "18958366438463449522535881612753516577920408884030961917206372848340856779454", + "19038355323356709854907634385093529445778219247035572752290295596750121939785", + "1288546653652611126768551729241141142059005744057588910355805731786584613343", + "4046804685697550720337256987447438366138088525717758741922811410001913306096", + "1660762585827970516291367008365082875857712512262252287267067642443918638514", + "12490758580574114271593656499165833022285695011717771020275535753216014465968", + "16141486882419673588223773309048616384177430148674560859754337286781225436609", + "17480842754700647574286106752058337138867662945102069039800534716529718409113", + "15604353321749597155917847886619012355001132908396771273202434684314342259150", + "5617279871415371338336939332259796482400498338204339205308393954394249833452", + "15174696383871305992552314836076160250704499338484600692522408887766438439385", + "7427777880578061171924488290292477545896473049748950597878341286830693333925", + "14092813309756880555589883560674882809640120093304366339387019683168400944554", + "14371461943490927493590660203698012938705485668960202862586478499151043526062", + "15747628341829994869775701388730275581025993393892718204096081193836534027616", + "13069485962326240936812384345060376352182714448869348207061583108709995536141", + "12897613411832214271030930629934621444235734267985429117525716946550585934838", + "21009316561423875807053156778128985534726230082102006144117574738389765473006", + "1961079851137768143186691785724923358396590015729408078834852546188718166268", + "7449716401041984694438903080808992521397429308993548549788139074686598693961", + "541840132011603695915673487977337384196812668637554519620724199330714724824", + "8732237210312418481429872365007927003824155222103189850471564031658954501153", + "6523310024353124781137808005011914742907908537623530782692226224442022388987", + "21509127266455930277492767884139578463956043561699345583365079657386805307554", + "13989299184155011575724091657019750720502004610297338129834280607581254559697", + "13646882669283186383881254452527864262332184212165662411849024353857046450116", + "14437939637607347068422046603975325432039018873549816106341419990853530813605", + "12400256882351762977557053352624357859435580188305833994340851255855777961583", + "5318260629482404358266028277859623051836786599425915900288734688050650647740", + "1629695214770269012001751163254712973932233705878496747522731454404864982213", + "13712071936286520679632088394106925703538964875601961825262229735589116706613", + "16370398845138146853603171685418735096308178156853614168785529502102183447562", + "531316798023999736377588166858362632977098508125317800095882267717108741597", + "9318921203266238488822738977554047526587525733728386955697050423076330149397", + "270377449844572577022377874031006263208440602734811115345017690504339807539", + "9815014161182964374794581271513785279039355629218722105019385525592211310401", + "9645578731676628215511306357368922184828636697072609821617709363109131724528", + "8278125422456187544426337239756968442258418675393889722193805619331692372756", + "3793686014229600852890515574697744650225321239380634655110095131274614241795", + "11274706713173058310395599257524413726315092599580477329306442323879171602089", + "15700516289342200878818538157175110895267852686641088808116754074662814875793", + "14231470645515485158149500150154330504733538042275634884479799789708016096981", + "17009943350256143028237187628790018788978713833977098031809639804676372324573", + "11807744076512700514106955514318371416449053759940168158181473579522112561617", + "8941191247819458429052997300931331828693768320666304381154122720332624423159", + "20810756908118815132070882638097329621005628857845667418135716334205275433963", + "17633865705062992379853990460318358612898966723353031319355975229233791359833", + "20574714650596437874739546946725432737055645662464099228865520688481435554952", + "20753133214966494228304506683244546691191781338293295716113306511488052350935", + "20891917718961601440155839168193313007436009622881050810291426124657399756167", + "15254490709565398763344025189458873521593894682543200304507470388535826802423", + "1579686464441495454543935122179009252394402667945704420064352314351485765393", + "2776164910982632895181744444931014666522951510059312025217047160140701867676", + "18493452977704296940835401396385377366306134685072368153755232646737492155884", + "7466441893052199319529201615576158956429673118460829755667264030485444838721", + "4862779186474359727417788114204862127925883646628388801420770199523844825968", + "4332442906725686065471004321063349183397729160637280571390764069298441846158", + "6235595676847271156438843637266606946005787585155569320931268977334224113102", + "3283545972614629083851761609721595874215964445590540647737064482671122002155", + "20190238096841101806664255153033971438119127586536510897732203034569691981419", + "16218082928311959370464862694396129351602418127064911331498297863184968070057", + "18169106670538118432467974548733501686430842104311041161699612921427327878488", + "13082519725061669934177494520541983774227971959053999627907293338903728791646", + "17917738025521205167709067376626145668664963656058875474248539992479417821761", + "10201169720940960483107286532267011054369536208475708600788396458879352247717", + "10086018032281190838410153727159750412677882106214361975307419597102233105666", + "12682273581371325166244148831560984283003922721179649899812794401686084266959", + "21151848537444166847396763358911125604594195283585946282585966889014856464069", + "5870563280212708258714113395803290954804582727013499575940699343839714979459", + "15818574025355019546843656101475484151535156797083091329572001913076927497145", + "9172129818981348435701876676880219576808443896350696165457788920197063328446", + "10390962755465039363458687913467754632739357930439039623432597903165701965254", + "6161501669511652251380864592245214064026880951608726788784852344316145896868", + "5405539522259494292389572744962975583699928794990075330665720986459457361914", + "15953141686281883540154911071743713625324924225902448030996737734044456286469", + "21879157639189744211597108651045875700807085936267782759316146460177277605878", + "11434924404918060113007413962226874803102772070441693086168193464929290844877", + "20757082623598026102923542323531106955538082419998942072958829717667465557131", + "8919981096169474486495376362947226335482024821650926316923260800584787410595", + "4288509578096166644556335935101899777779885105511348520519380469688243082096", + "16046529059566280251436022453196743987059059184968007751447655603059461800273", + "11219038614950179129482943179862383597500934389713177845014944329948593838918", + "10043039951240572103842000677370211126438633625308559058041812947576435228523", + "13424594313385554045395046911081130962489696002268038176721598695954847052511", + "1211793291463193275930858215285948372240170625699602215748915241438580144093", + "13956919764638999174327326329058963982898576605238294264300483944344569472991", + "21763763972390992315030985535287866258485311664824948828240050483482084352503", + "10420983865433228040050251893025618324702726171912049836799135351770260802977", + "18753701818722627673883564699398410722354636353042388382508975546895568464372", + "3775364142286651074799331885877684616693199427012762917550076623916732710822", + "8292671711306889259828642403052383798091670542487370026886155070540857817510", + "12071789317828192902441324443833143078458416120447222512665882093850970086582", + "18221914904286916930821501101975619932383182494940702022220624561466550429056", + "1015894946220130503079847588005345557311861372219799708101258594371020452677", + "7497079366974677538814211796849030622236102734688468791057012961185250977217", + "10412524008150259624425778663311437889796006875864864836590446801100002463061", + "242804608586097049060214639927231617495599500538071474816862835383660136678", + "9327321863177171873474299501143270493456472132426279976071195256972553555122", + "20841963613720468677785103552893139903309688713322442693081971171914472255790", + "13630784939841089364059908940844732601072559390491244936534430865345773326547", + "20060990491599613171081634276027504616735657335613608029945430961773413795782", + "20369723769740268530808565104818084023349274297831884550854878783888535628782", + "15076862507709493588855118027827375721947856558107489434980647124128748591027", + "12996451838772518667606758612923003843581729895975567888341928977998771990237", + "4052235171895745508958823720790274122684550078188920081778152850440806616718", + "12335377703331511956642047444506386381049513479297082723690490432465187475758", + "19412573446052112260556809146936739541890274154067075795508039506436684757726", + "17815752693042999749244044082547565016456928313463444720511782669652296613554", + "15784264337580227630693723391508440881780776717973842946134335715743491257089", + "10667492170364941836778050228790234453197448653226319355770388144152747476935", + "211997855288770996034164566467801948520054169907247985981041869092209280055", + "4928982790134068590739975426823777812194464923471161503361037698280174981760", + "18608672135933853582317718913701178979379432491853388463545185599228146691207", + "2315480928424106999355320576364787114368100799067708928765166041722251581141", + "7132821772386644248930179957111951717051009389997169728630437453984113307524", + "11744909558588287567829975231377896922260739746243206347301263424478589809196", + "21821616737585515642213483301817094657757210129023396850436714925413476278715", + "11972412756334108055648790188313869962577071423570734765254546184728606861831", + "9898102092275580917130558353359107455579856499298488646821411779664420246304", + "9958879822047499292094876401302022972082946727826778952858218178060652972948", + "19871205375909775929744751330720905649873502681808501037344623586575605895174", + "16601345490108570384179778033128731955939874176242885190845545230306090545377", + "3600818319871189164836691793538369796689767756596935154198009735998848369707", + "20314694248383769870802453966233555256007670655653781360971318867730452026627", + "13418958906290175260633447769067612135267907574578622587604011162488451092514", + "14459952906281539694149485094281623760953141057796841403669604773900469687889", + "19448408956408494949564099234438127422205398424291589853947309097810118078185", + "7825443276535418239837092010081563810404777554695462770138005656816269166303", + "8463248112790565810949249352339633764856217758597371912588298951088604363676", + "9397106702637851943166369067733828452382029530464971824017078972309585633364", + "15452595095505449307828854722016355425252678164966267614739918073395150429984", + "10382687268437366227597120935808669117993505555024110738918156422833458968254", + "8525129123003317464420034009755418250374332671627293582800681623438541074422", + "2209915653341740331756848895690532824379055156318218590971248250386542567791", + "15183382625497370680223757887016738067273663916736248647060220264288252640054", + "5914882314939376011130904692287520473675802288813732481565058295269249787489", + "10737923811176739642308957871008944847331638141618843900584295941869359201136", + "1019349115878726003171044582547108836234898959299710235354611802499665438533", + "17364570285151724843778637821645803441762402239038594475632207111794332738860", + "1251558044831543718478805412133062543617572066062707552512150093969983011815", + "7568361578986094203490921683991770751640726490619033852251843934473195496119", + "15439738350303496845805351814211602783597897988159829928947802101119983398961", + "20009975853963282344191402380547695759759731502702993682892413834957351648692", + "2363424283223098643833999734510060612126929924822351279904900380971757668501", + "17136028473467909987260660923882066072229277631411461261810169503965426571985", + "21423452231832054119549543703585288464249234898851841557254723364015587266501", + "6300803647873111234660196693510491620063330061194984556803532776163457642510", + "2749674757601823156522337416483425720076662114029481936093706226193678544468", + "16123152544885237760040277581510833657110306240025009956733742940484347179299", + "1449335556475943566914615807167633374850907490355989852917815325720800540092", + "18225835808858885369557291110939124591374272404427656191824524491194015802997", + "10406157408365973197865488683230737937923502029339842530701446718978570586144", + "17998633938868470446795829948946241208954439598754402047898587965138352946507", + "17256506181869579387781206921456178119308959078547323103229058358574594315926", + "13094455817799190250176997937777121524540082751332502303810836528817463694222", + "773415265947842731444676861730775210907581945844672294668103420848288364110", + "19038336321288882240456993528476377501756672900320404015643432684581055112943", + "14760627809381104024315295117982862934682028410719221222838112174132134785643", + "2299176916578536045959722453832883315456156391111537255429863337814706171473", + "3669114713225196659381574151653298340387887549947282054635076450967251116153", + "18251972251689708305163349578105700140002711019536040700377516042131395885101", + "2208114007582253724814286240939815507122998650551224166265438176279104064289", + "5311319465851004438404228350963430011209528099234009157573275300632566893387", + "17704997085718018561575909495530243398580104458533121202802306468962737491818", + "1933762715500501610210207583856164878867609341004969983518458273086102828809", + "6386814998566871009542498039659511536698234159072885405476628256992102020495", + "18831772844239784973934592955595859276748324649808851586824036127112826604451", + "13462121128312374635146040270944207295588795209645130037644415451121036635451", + "19731805313375129918425060059406339849106971447864245585064948352741000760923", + "21643500371506858849424889544041572150599889621082729284012490052076449459481", + "138548710091390954908010216339657754049773930079521223071410504190290814535", + "6947102089761831011730597399319184690211329034898095828464106850135090631740", + "12831053427863630744244436108113801672008361468343188269856032816742671083134", + "4223577351003454708551493531516184634014386163092922955496011474432781253241", + "2714897164693927923639587351413494956248140707486375397510165870974510685388", + "20023038420823827383850598062203899779139064378489163672445486337197649825217", + "1767883277856872395041944981599210930967554162796692711247113543638244036456", + "11374943081906439317741616342767018365183355349301791743927619930324701508426", + "11803403776542021481872407152864894420411711895295228328072919482156044458427", + "10466014303238336135169608931533160584648879880459007777160264124745826740750", + "20569672017414729176046551969057922112780177375685900568749563089152585958033", + "17872595105302125548629012813042403567513885359499964690907253660570968601519", + "10903006438854654900289559455490687959429486945748385817337220540948365309048", + "18275515870643256842855966776500808668842291767076613550498342673701067299432", + "630933085628668840611776843471079145620019967645658920379584401715066362709", + "6825394902701793105668667323441283311921241346208501522910007054667207868452", + "6858750193485140252798450603380083764362623733369268015553477107387074944232", + "1478873465931112194691102753288035258894560238829532399713218315372158028033", + "20647986868364738274961741160207964168903320676158610371768611791255451415798", + "4340383424522509172928608655219336498337132315044301147894720301443278858359", + "15694054630954602584443160345828698433451692126398102396637062194669728150097", + "16587614091042345417694939817299154667821001841573634480871399767976428325370", + "6780948432583055051074963887359666213579607675322530873343441117551279310337", + "881888803549941181636901791599886290841557130000792317917044641982716656024", + "8375540908772391314073560695793592104950470672337969483097880419747173630602", + "10968989437172024632405943909737990264150382688586767944077705368389009715036", + "18851349698000339475263334762001556036662188445499369323276947028195614775701", + "17424154833179596191247217224032955577230090491464139783174467885567507995873", + "3084264395291045886600299855227253813661906050535885634611163481700929635296", + "9780424450121954867052166726264263906169948113675811543750657338499901472300", + "14927658638057710246989480138441311677749528914441518171301964877558977872737", + "9409069466927713011440733713350127030613235827582038407437204556786573082426", + "21532551006723685558182869738272976023905972040234419867623013049768952103538", + "5167833995989484123952079378988963389989994865716472465476503880641449880786", + "14740174761652743774118447006447618386992142680472177663315668117221175944698", + "10520805511348878943408706501985230943081177040800761729569633389778724896451", + "8700454790689589285537042584692084777365997167238651880195034227220137266589", + "2733945906594382609383183532639154621092632308934603150907320167864486314840", + "10291836929398020145429078280830166142519086643388813863997726059451399134380", + "1964652348248051415524467307507959105507630568171154193714989224874728277054", + "2594310934406347332341406086415178782930670052092905736460388995932291385927", + "14842121917468246033091527680370186171895171052114757236254597861059412933851", + "10375528532253513340592396399825408524430850232835146379883683152448199357827", + "12477762696438196028925893395417443678494787519078936487705085579706421333630", + "18021944163681185812898833787149788656465569272261580921039580457574363675422", + "14971348947199715425743490776577354350250241776207063239247262831298628671824", + "18527079575564336560853661036281436413609153640671180843997315618816477020062", + "10112969341623453459297605360048147871962444397321717541108011492952113746933", + "9306811905619197449152929816385830205919355838468334319731910917748600490999", + "3201856562784023690028197460260731000729676130502544364740684445045551547485", + "17677019524999624366971265277439539545709248668323859450511125252478150097491", + "13203760042423946863820551582066224159089369605713946028771025792976332967017", + "8225744798383097681411492868795146058284602972120901801159373206820642535790", + "1133207841388716114249120311196903646181388009397557241156806164775023041371", + "15623890151225925383841140893652872349082273871391477651993101123938000801867", + "21454879142557364834852736051259149378158105754952971451715419987896242909650", + "8531552648559366596105198828222595210930697829968414405502802286874489507133", + "9401758966490949657386555283103887925392012048184105735334446423864991206786", + "14182985100305261645378993603110572106752819147111838091043200594637885017186", + "3351125971378624693919014331249933776013465831551789721255791740304274394936", + "19684429419661111328145464896944065690801463972795522382446603218587092452167", + "10925858543362322055288327267322188904474484027644138316216578205314218206492", + "638388255012974167128675944413974318871770367985490338348509002020449680093", + "14959175299535994556786536841655834078592404933909341983568127492171858384391", + "4565657688930940961208733539150773567906556683309024875952853834684480507269", + "18262745015163208046754959923695809473174547423960055443621926543956602209348", + "20270410959376379064306739018970053272238947330997122046760265674383899359657", + "15290563044070434983378131412705775525253143318870138946525234035666015420725", + "584590168302279667271049654248756511695470228213252786062709717390671267095", + "4966088591187905712289854426727671159168968384675952400787560742388879645568", + "3319669368740731092651343449167365623382886973437878280133897523197651190312", + "9912174158284239213664392208740702249961859675813287499135373479592639861287", + "8516379350240514281945243250529128948244709428452350892659587420308554264613", + "2460558416671744640916958595519740745483455366236568201673238589517657340142", + "15249503582713331075672114681569135202331428122201669911203912573537116149514", + "5355701614078955989983290080356684040651137096346994307217952640790301753843", + "7986859541259474766804707773691600248831464381736783455743764933501866864285", + "20896597282789039779549640920767060676459830701472255011776479759676387046352", + "21156365340242937197411344791352838273101399835862399143303393482855843470763", + "8810320994466343375413166155559061722877903255339567630911647558329186883195", + "13305939854322882862383989397499916187143744662574072474260034250574401506438", + "14276510595076120373993498057833260625756300056428067994615344507361982835166", + "20071507901284477038407301846126798169150113895071357904039436046848822333309", + "8183811379732619835362931863732297053435925338898156873268534636771405892075", + "13219046823251102005239988390708288792968718105445890139009709283489860275155", + "9185773756453985715582986632685488321665392756676197265712130071752773976631", + "20421943269702844355893550089604182682047061852707721138511917444304707579860", + "12300280142885224975710767798713824153348765684179955650717019029210821361254", + "12007970010282235734724332615090869243055192449773846575955902036212263482679", + "6158352771477574748962005695592225162907260568470401385862937675095774244006", + "9907046449530603675289866399335586386847026415848055552734816021036571412645", + "20848733914096475328182569300389604774285326414256566622667108340302595094373", + "8365137332145458646854804122757179721555979085847877907343540983873210953635", + "5631007860876051233682685206319236038053360910127434722172168921859697775602", + "7724822014604490732390628840430579796440157358556500058829335597037618014759", + "369071834493409594945180455653375424679250473615867182702388739879310444614", + "16769246200562822457100153851476834038704115916651426939703296994708244449575", + "5761928395342052380070450997738075595651684639539927184355295101970822313162", + "5566206280191314323446398313438814776510866532854163164867370641136219947308", + "3342359366346342054674985507754083252076489241172458810297886110396010701777", + "20961070283557581225918432539907379409525514793918155863543775859703676727621", + "20556180232726542574747935614764094533414324377887922356987347326584809231233", + "15941149549798383978046697670090370142285790712496734802869937995562571324293", + "14600396724469636128403441949598983100001916970624980610808650856082650218424", + "8853454033412621833577484167285435511890615294361962242058729914818351640066", + "7796912448927288083851300561583091259511345752250157116939318925851741489961", + "3163019852372632897541834965385695185434873283151315355155397996458747882742", + "14952700133737822394693717249052150819987738575989807253015506109171868391432", + "18525964798774229541041472797217632579102334608286281048443267822115517194616", + "7102118124262431444884005767970969670970778150875473949502505015348122457394", + "14204638357887780388176917062053732214797428898508168337150295424689096270757", + "3277315675050465719399614805088484534242274431436504827247668714966713345731", + "8238377613232984055051747513217839877952472190522754887201501162730400770486", + "10224258402104106587652987351104010753816241645110952300303846844538654914570", + "15487805061491340966964538995368847025698196465175525562567846982560655044359", + "19219815971577427671261496058630992677146093954055100897228392314454716131964", + "20451783587558695494081025729566916635107391693056303514267562508131052495026", + "10604908883794901754591456082090038158328418399338332217230293938008589705164", + "12629655676673767414687101606277783347408094199429831144029123923860076780652", + "13709603387456116061265164612378749494975357559995793114409724336723134851988", + "12280342248736515373215500158719410978133041790040105888782814256839967443115", + "7016009627584978047738165231314996484413117067952510110423917440240605830479", + "1524894728322552104763656617099911162075578893415210522528939966083567287381", + "16110348090073067974052480411460325713852194746966461188536450049907379558864", + "15849314408692105099989833438461121938666945258532089314493985018340786241149", + "14526266680576776847324515988959661063035583100946967808594725417429124130409", + "12662059588246809623132277946460950856148161126345911747740066547195150214304", + "21784234245035153912497219470830935288918016717870099869682681847939205742526", + "9781991278293660355311618579950123622358901576863101735826839255817708999571", + "9734447579561113294373127302234593360683756540510409616709038385517649565283", + "15783703381085552443769424496547949342637297192593569766965137630433735196499", + "16818302710679242439066482280541233367708597536159643998239357880909455304", + "17208557330797764065799659085570688998141169399652780006230425322841317471944", + "68706297573456724111634550544331343558310761429949721000334906561427561646", + "5166796490382346553866700788131214421083284131608596259217301814881739273429", + "20336383765590527388425300334919391504612546166109544795528892908246473855987", + "3743358254907302851720282727384172290999978135762491123193685721554867920482", + "84015356866358900057683156333277329434974724445531256660202285630028495424", + "13076432415761967873214874574212608989827734997835707946240987502102677974919", + "674004304490160746369333425685153534516797008922146231179438460150958899661", + "18008401489523347421324064960257465802035658427821867761642737239891301877084", + "9230814159278735889507853746171683425354655931537527400639327580576056029011", + "2338224170787780983513724541155899891770286010849997183556172649088034621522", + "13774730216408957127941425099141817093498762972537953648152397183615811260761", + "2008226192472961561861571910859568903805945585734651871281309234451941696550", + "18191659524918356873059208424871952262892246019889299985115112751645849510652", + "9977051090514243658919274826700877766433577306278237326432737577914469740819", + "1382241145032463690710185532538145321402596788581319285825708537098818318411", + "19630880072807438067933226715597469053645950344003618599545076855182567392314", + "13804532717560570932337083609013921209558901545207945868049344755900793666387", + "19508550180350246129831873366824988420065599516069494466305637280501827380920", + "2848475116255698304240592397534148356674367429794174368229897070816851620326", + "12588734179864636951823212209185103123565413699799377322920024420368718083095", + "2232868200526350302935711180734463487873472319399673090914563494365441045552", + "21377055866142483679502571618984666212079397034684178104676086894866487789275", + "4635961124592421709613730717934803195170398911827834468836156717082833802089", + "4795610144270291375198683497266358163517248476702360287932565598454128564576", + "19878139464835077446055142241229890663517120197298970825225586650258704320634", + "9323502139000335770056400844753650839571196769328639117682123746249546059680", + "21112416038547244178847876677595343035216538411439215223028113590182490455841", + "12697374728966756322005607409702182672422756890620656219302331428706184232671", + "9995295835719608174333254715476035051015528223152237761898234348962139965339", + "19838681448410021391386343877373049070883481927354420971134124213644615857262", + "13348946731323604604321164467837298053616765723820806627202376009331748334141", + "14459243825598700354634855807582241585214330632597159841271530816381999251613", + "16398077966528830249699687699527475156225434078425955606570595942126461545256", + "7643106356234289086355359290357087474077139338168525601611444369470624871398", + "20959675452873599571224578970521717955557909237727928302612036851445583012450", + "4540025033646420810215611052662284909609074316113304153198697292213556037365", + "12027414908456226247222654846878068961735365399441671468269489072556154853636", + "1619579475293093356383780863588610629947769633032102520272612883476001600909", + "8181934427490631780501305508522146234029250148182651874753791841738732508561", + "15274797459753339681175428319112732573480605162611546476487133996977708752899", + "5881626303176748491435260832560365957494745248996859086310569735454431253109", + "3420994635070209394832291125346590627475632172750870826118213841463585026009", + "3253514739572615120245273590897551489662089732892213994698961442123844511104", + "20203053841592538933587679570153207252397020205630948336602455897993666135475", + "11921266577552501086897102705390311185747062744461377484820893183533643304437", + "13241907169609567850145071795854997578682645559619300976538988140768348089882", + "6151712987809690919701305472528460675037031217153195032569932714294427052374", + "12205705969228027397734509241211850240154931572324813086389133244191540704608", + "12945812038464520921512101569088203002779738300982254987224395885526111963420", + "11566504805689497712142963920462066842262053081516919575350242192944407040992", + "15723543550582708278977667347083710027075971342576647975064035406870923269719", + "7860258127934035634020846943939055662221372673596335233171159964609391837625", + "15528468237941422862373023290041270186925402725739650209357342065347651170444", + "11352800656251355849609307793804420136337526597168059373534052608892527331301", + "17897134085314321992998873273654112498897006369781950634488633467466113054350", + "17437455229098036757167276638155356442563492876806914963325540308515770959304", + "14997752382200324825750631040991638912810425809039371028733815341246302297900", + "14919207184372260640968465889336548904504385718633186760383678178843526009885", + "11844428225775333775773424762116332026943738109456526441415077427972318646084", + "15239467296659614730514306837963031027890655569818408146133916080687077630265", + "20117441496592956911595459290983302272515832294843762087476380541606326158806", + "11211331365407064571488620323378276965399956667340240900293979889578003659573", + "8791311092499361250396136430755948222248236194668427353488891370543849807047", + "1774021261549926243219732938834617869058292002083739109596586460663663531688", + "2787995130097988538722853640105055460288688373288517482894772682647739193296", + "14036419256752421574134832204020173449399727322774622383219518631065684283606", + "2503905040784637175494196915035325275253506707537902487189138102884611289404", + "21664450508754049721193573452150382260579289185348178882539067755355712577906", + "18957082022313129842427206117755534129197834418112547991189485282634468396440", + "16781909482475992329419834248503013105141202009836651280677498803323770600224", + "6643893904478082560922317503708920766922698054352006836803634579280954593309", + "20411224098851507032152776776680744497103387047587118749494718067214956146818", + "6932200046628136855984161612336282559188694975968887215970260451999517971798", + "13683745075914427134220228573435856137115339570721809234203113630305711234299", + "12049119081343437729871267418004147930387014906392381996118616615174663353079", + "2441975952742754201500338273078694079713769380080349023008653075072257968553", + "1011172201777323348203437837012280331103466286486119939185319004696667574496", + "4513858889726009970880526008944305706495472698013415303299122950266699858614", + "1829602352761774082971266699128478520319034089172917557099196106572588528973", + "20888913280392789424820640494940209099778028785108373950708163556643786717499", + "11546628016884748339883959858649314450404290142635813671623548341391668641333", + "21503514976315590685255962605196280426006590386762670744592186136529638021924", + ], + vec![ + "21579410516734741630578831791708254656585702717204712919233299001262271512412", + "8554993601136913148229849281645942416873068991157116548355045570766869071269", + "8349770263904395404819051886764727880530744217762197718931556224723090619132", + "3123463970516625956994178947134086868722089624251980030957656091366977385793", + "21442360932957798040744480141231788172382126494033577704060991460078536626315", + "10231325350034913697901001930461380417506010080725776869094346614943052057882", + "6920436402694617694727322082450000548200664649231576891284834027764418393590", + "12792717999817516574604019538349201413861750406724026925198874802923611904714", + "7319083527910098850218832163004092895955809799710817531274971443221833500573", + "13757426179233640966146754686419290630140910517321420779897314617147307309749", + "4049033549996591060740078431987567671358359797940903000648212935570542836589", + "18201423118137949240970920992151778204900119273029679711616513196892916845798", + "20625824460928171809204757749985517429359815439093046150315733891121610507133", + "10457729085307334834523167401466014435492132985358294006123747181337070073721", + "21561527744019186913993064335391813055903937050713577176254373319368609289121", + "5599728995155490107164072595052340911357670532131511292391179640158683770855", + "13966745298956307615009517188536529139238646569224392383446375189982202020807", + "17756603569040095098346793596909383204174838953876788800894937537311312048006", + "21742079076354402484587060728532755692106347543073105531119578054037775042874", + "11100784872920528132266123983509067070706469425630493971770997902694662926998", + "20400085312205960400585536190272432205634747302273829805331461533195763963464", + "20028967251238446138082148432746545470729859763361092299497853989733022321309", + "21646094126368547381762879012999402861347883442032865497835121981839683154574", + "277256790316883617863153728392861425598900309956876809085316502674092638050", + "829273940377701999291777589563653090200708284690056650568100074655963961702", + "4606908934947031763433560217361121304957410936748694859993455652227072492205", + "10769441872728289230396615620861141176949118733537017427393172917499470840245", + "19521824504454300285368889620047541794275889938757845035419559810899465345698", + "17161053048471962353174720811774420740284389196847515292313979813334039268748", + "7908822737820790247231631548479205241063360318010733129560952138908448461427", + "4877162162397125215823403409232508291458423909077159953565289381413423118030", + "8487393998302601588798118543133789294087935184558260165377494640490662085979", + "7454433584826937164880257351721993831542783218228578962943846432869272993591", + "12600486335574416961082984651671003440366178113351945406282261259087640562075", + "229943091042136639964977508364517877844589816262259724739584329059854831474", + "5964363464498190105797451630207382654570897906930358361814931706994649645813", + "15027885081212300130366181566116370954163923966760653842199145107431036749190", + "6389712846176883524184535452348872799769012323597964483555439005016828865357", + "13050625522428562689464418495099691361897297012535198348448952952830181214686", + "1457960163867278804802442802649716001232992897386781587117754753421449788143", + "19121642548533119996481133068671203033851078573250942970641264441950592334007", + "3319626593342830359906793887689227542493167081286725783452961782138075389498", + "10182025658554317340763807114890885589336807302908478511429803960136159439487", + "5258867553475471512860996445670851629850555214065072419972647507253648925387", + "17105844700483111456515253413030059462544811526461544189616915804056937372339", + "15389507448590279891790879860335127747331525679865083633840630125275096453854", + "8628144040598587326275852302297295030455205882673458629883629373821226515849", + "7225764039772127797033872800338173049227188735693607855118081892986058306767", + "20070937673840272071045130712690506696769042932336737261842298381743641619092", + "12139783026483217581244209544149124607538399031092603229603855979370010147969", + "17581810038009568123079980574064070648109195109589787948955203592875730952957", + "12141791671600953962785570868053442402210784762014326945761482080946083167280", + "10216251141439191088257104654134450392253712707713481968388586155680061818083", + "1414175852848441331935246181908753253333655328715371554777242869802352097003", + "12411223399258687363418284739063179467323133097416451119653175668156302546282", + "14163252864986479721057694562184281568622251449154036885135516034438034547025", + "18935280158362457804125825095786762216868621594409914695877661895590787449138", + "19612073572528301850608997760721508284827614275438129248352825723957284031526", + "19819295714156197944855748114967530774512172286810045467127912108030396642179", + "11371593776080642722788656520803479745110058361122399788254568568846349693622", + "4027805955664709942434150181718117928301673452282014923837288829996079949500", + "12539691854417510068939338882045915380674719248923282579976372900935687263702", + "21456335515466708235982252733061551106892811579323562996977622319059624115114", + "1466175641997386496752167837552521008018514071345728218669064866303097231258", + "16954396739281784813954958963214415095472216566673098897333193147120371509076", + "12708223137926559496125521072416503266378368566414170219615449248989766379947", + "8788739220646322755486256871812144068464402944468818647293944655221095435821", + "13058732292597055849703973806172477675203122319912563406670103404654094386664", + "8931344638882118593791237662384261193166536469680242356398517062367452395384", + "15456845400516927354313637168726345061971892967841823745636300923188629474327", + "5751588038559337581650296498368532807067353107651773867820816744681643949204", + "11549544825319477431118343561134281237789591414423676704396089395115754641434", + "19234147263577254818888926168924920479297919454657521855750553715796101778809", + "3648349134208466654728357812767145066715472797730454946149007751312314206222", + "7718151953117918461425809889893754434608769559584222279828239292761893621712", + "8845522739821256867897474373924647700071798803600128774472020272335057310062", + "12793577303328701474174653130332291657457728764837263636620978444987214166803", + "12567791764609503071525053111715537148465248715927771041171097136254310005533", + "14173284996087186652368776168561110401474338255050963923163796413857580470909", + "18034666979500281081740131331708674377786999775618310647791265825609322054725", + "21422354834639531449049641141105504766268284938752536446702823580190877745329", + "10861911722118463296713372205424749768917665229584553370962914232866310912045", + "1426840929949909140164228257293070123281693940796332643637029311310121856472", + "14301944441994042783232016477141675248310618781100688243801831318561916576546", + "8689261616262362847656173161257424730101884874532916838450695695508844076137", + "15123977840288488307479771803223205244132730982232338102604391529168092315901", + "14782587644869453236501780556963556761570896168324364501980524203741590116061", + "20171126664277707857959263654502050384578410237255325322075457593732181023858", + "5586442008782671473934242848395070351077466917106669778054075503048330770950", + "14893034316669944289540729978541666240683450933307479859464390524607307041597", + "16358386602267214062406516556279496593235072850353941542010428321612942609886", + "18848866854232312978702044457572917667782740587353338084332267136131275700603", + "1579215194993191651478809349088803658155969078580739214414910140585581589538", + "17033458213089087701892498495271710586197475793707993846597834001983636294290", + "12940326624292849673877504632305122955030021835426715254781235159065401203407", + "2093340797218797584680567638361507396244460243439847174481303012347581894177", + "5964973748129501579884254138099588668727348462189690734364404017042795728252", + "1674681106235348685135834192630054282175690835155947917214719741317698144031", + "6021317549494232079997036595203156655990507346855425821696978600367848015237", + "6518804338080390019586997346732962982860290823548982950371646893604360711024", + "15170463834922876947772409926040699970156014460508617331830728121385518919006", + "15398930479669448663557196733417026149527004779216987588229439497346738958046", + "2669700622596766237628533802450875322874330587389952384417956610466102910333", + "3127548363874797616403801375102757494200866522631068411037184158214286131549", + "6584403272373574724590091428656742867168271029343425772452216864199113551892", + "18683280795877134163038651063011198948877602385157504892093537654399764426518", + "12422086496748175124620724672115957665892586761203533990582978803368996339430", + "9745099390463439278844126903162955736019504616033755299630228960871294951628", + "6064302059807957253392579676216068692721552882853761726090911957467256977688", + "860534097291826421956520903118828583111860517568849548148819591113129410233", + "9809207437695386100460912579554305365027175459186390700555141956544839955242", + "6576375143489291749779792018893403099848704832143183847385791291045583986902", + "2551573667498115865454648920084921687986702958687913960418526064766186248697", + "13043550024569409591105305093191112805611412364703194793685224224072149855745", + "5369051621601119248797945023525768932797813569336410551989722329535217332717", + "10399989003670197520503648853627144005300436598931266893609225004624861627954", + "6159561484143246751423457452493034991227592994791307133044136210702400602726", + "19651431183851896182934111830326153107040303776630454129626690653306388341484", + "14970612719926241839940820046954288242553272322468930717244806728631485407526", + "20461999502486452961875044483247881758853878278954851693532423676388213697528", + "5016750536904085805050275769221233811927007383797241751325050175740220466319", + "17316427284462136919522043989265881044949832745678035885743571937214912552561", + "14932533665158850512241105212984927846164589888111067103835286341225240509742", + "16012484446855626574765806641361955141820105388650596409595164514899481874274", + "4863651915422513654068087402811690721104417928537042800794511645180712743925", + "9478941069339421252769300213729433894403874553023597073962166402867140590783", + "17529734771936454727002429801459948360484278991049231778922771896004721758963", + "12672015814840095133854330679674924244657276110030612294537194913437310163995", + "13442667219867515606432268873704321985951188504382080502019480975401891351960", + "9346556839116407181813364316149756946394621057020562307256030525707411763792", + "11720199480542613604905913885140886560194773593236018605042270421391171700142", + "17713550818981273796962302212731756472046580671829192490772244177376146261137", + "10658520565101402948486320613747540160084586467440232263820881394770094857487", + "19120553688581692745126354026518291549778059267410591682456431863134002720631", + "5837704130879353469974552270945063041776968090189866547252204737075618880582", + "10952573317837731274507039100853076769322123807364252392559268333440123751056", + "16175443191562457274813386127054957574917457114692631929042817125665307085782", + "15651399869272720599280980856510555798668301135962902383119739133368631494409", + "17982602271750585864051043003255537160144994845232276906099438195600610259340", + "15564417296959768207318803300620712620729991326343744282367518107640962243181", + "20488793123009381941807231432363887878967153580282107905075818200161452173728", + "20845615892337349138315927113904389806784179140299978993512007141180651572609", + "13259443846669565093311907999318849863250202720247601058242623542433998488480", + "19583450200980335366984605451914375573108173291577305129314361755545713207859", + "838397221216450052117952481963960818729311704107008458344946293696441980221", + "5011508169974056046810100610889953041631883487165044189687841384459345302746", + "11361142794005243853743618662384069287777450724025651283005645149554307240000", + "633456298666951303063125949977139107258301407861096110769739192555903857431", + "21529743295731761646584336858048296237991767869832124757149704140550994020630", + "658601336565148638150196750528474813469384561163113116358457661687263150766", + "7199686023207207605469992040453620774208316115852720699379826196410259893822", + "6694724393708237460096397340665472114749949954099504252044742926933353832323", + "16157341357004248687598290467887486980266976396840580002635620741183071441576", + "18735931046113570691341052792512856145472697573166865032702507242384749856515", + "6329726929169898271848965669873324332951781357803010027329026944351232247476", + "7061209522680426874403579559245042585450674594552752972115778072823155787614", + "8946282535333125111854282749852344921885511854306802144459174056051518348720", + "3988279129283542026399878866455129212655792613180690875708855315104446444211", + "19788373916759119069273555853960393438264058803290744373422102428664987314058", + "14781179276955000841116554151929609467906998220188278865550170013658249984549", + "14439714507608577761834821622197467839862763277392515730094487176490304118865", + "7462417821368326183154895363497223167855553631230374112323789393782682375855", + "14594890619141141626245598750050255728680683081531253962411791337998057959565", + "10297822643679438597162031819677962851770740929826506853838015287832878785074", + "4231562753232550403815225933022904310027433526532932589628179163940950572874", + "10646529230382575523755302352793337142051175018996981972379640368359926883275", + "12164083461947216214412634084378451605511487715584004827824972078192861740778", + "14686738730377226817976749475359230017849316512373192440082122302915229733394", + "1972065207953025646946682878392649299678417507238551179215236414492110157365", + "2596220810659736571653162812588827790612138851645327014072494893329877375848", + "19742890478753895876191378843357325113803569368242719397467948082842949716134", + "3057722811279760312017893583084211485332195649925192440822130571411021625062", + "5078380046721228959752000757775271056076152925648793679038634805597314364689", + "13994065550182407605627049394529818937411332791332501915425485445970019749196", + "8718903390300613451595895490522223543548941022555756021584328963874682051659", + "2830037047734434537263368457077478915382396457133799070168011318577509852518", + "6351328336589112831842317252922662854527642572646149728733839010100363641064", + "2326811025141337415486606567159001979990362270551911801543813258783748664928", + "20631048108966815289784074608382072458460940973738551134226168800345554951214", + "14721204648069833595280990040775556291988674304257774357769088964732410863991", + "4551815408348203166379129282299441425423743023821112768447969406023780214645", + "16626589364834731158131207695359287961392723773324953999720551575045565560017", + "2119119902895954746578148914775899257881351646176141505001582342610666449702", + "21198001320003994532825962721847645202213745138854311312804244693213734456020", + "16575653563112300802890760228610449333758690368857078853765813869752023855520", + "19662199829424784148957376290310955285339135428848477356788149061587904074636", + "14365866723679934269369638167309959664282416562097092385771370076826961535871", + "10462405794880410718710911820471224752218613463413073336296570316774568383223", + "2875852545895825315521599376020869827316570932962420930916494831426174036683", + "9365014190378730240070787324401488407601702337948470069729769089736757502613", + "10207664772554042762314615033378156185686480986853035052764356129216234339601", + "14593204638464636358074700677706356615788934459664487787695216859702024204802", + "16870253735699395936222032450057462746120274245691549241725232755997497777650", + "10403141045354931831897350467824057442824486714796947030202528195269765938299", + "13491630075210993306306680088269974619065901790274179689314972497025507972072", + "11737690900303251277784941365088697342741256105580987740031964012547987099246", + "6479411522140791199878732386964631711912096436445632282256505752750116503021", + "1083921069605939352705123162314489784481429719496507658938926140311574639372", + "17653617267480348306435879910355154811805166995916787026122631473598046826333", + "14432164328022071373295386637326904766549408251892516429892690428586807444784", + "7793671760657336901389781721891199068620856343884708391197481940646184551315", + "1959765449995198342923438542063212054673245344496347360855620191194506656856", + "13782621216902843666964879695291399503179812919290969771526164415604545126461", + "19078359557987218636232226316587656499460623053969287998311225512418446587303", + "15876205697805498189610174935234268016677320029636416200517433249256912037787", + "7722805406045443730324325528663888753917114626390901464015754094863680930900", + "19209717507699122245389693034814796437142853968464799877186934474171699195095", + "6585127313235216502111419023607202115168882276771320178943546160044534358599", + "20805733952846662054565520828206551321957145521190409450891077526078523041277", + "1584895259816785676773529464055176663163421450657396866598813628883854756221", + "20856003384184708896097189495372900159489733605505425206950257455550934589790", + "14069406225378546242129093232844103602751521581800986668621079503726397000027", + "1028001874294327945398022002342466649656159450229921471622913285892988310568", + "17966371882429795190944428324003030336630819228004846253694564940042988400820", + "12876427863944186509000750451848678588143362805691657085788824358176114653258", + "8715273966427022806434959651283926754916348745411538421378504642158804932403", + "4267431569502908019256597205760133122178817596876838981125845973819244098360", + "19262568227942313166139131845806786518421402326465887345846202580592913547380", + "4587852954486808043358798482712674466376898718708260090686361850306798447997", + "14015025676058610927837367157870446606501041323636097276737547710444897937611", + "1144137690247115846969300874102656726503285917182531654472086138598330367043", + "9454537148137071892124156670991734830383436460928166061331273469365959775909", + "13012777452486288707879402995033258068339583475193898659333632638157561913335", + "14224623168753818289919819482009713832024545924040193705962378465158371078837", + "9505762419233185123340587169990814384174703626434894051560218285882560747356", + "7019256137023476309554512440166531052657689673592456244254319500937647800006", + "17246363017424260106221670693985197925080671704985089438076796011281669775795", + "14408593968797438981684807585445491387554770474935530894938751288467685293766", + "11991202914737654500568163346559814604911312199759237827422720619371707311619", + "17485055588733729741263685618351826350652951158142561188142663313955733134315", + "12950471790443580303905847354051728755537901376411054363054627208333559704631", + "1323445558625272814455691764419102369727943978699511295257501714917998936833", + "8841255445674311239873770890653537908142822789956793926192649058263474173411", + "9401395313777449751102417028930156506880556083443899378760756340424905478877", + "21060472724780336112168263494706975132712741930000971588397970288258676527061", + "3812019230904757099892361572360806117962259446525402823615305574055615634484", + "3514498070156020200040973833201476402797883738073136493951314455793989266387", + "7030071313560321306345374157122385026218445152391153750375781343870025689321", + "5268144785716401601955218888231720448573921710587461252164696334890979118029", + "8300685363844078100354914067414753644670881295812529449763437785519065857313", + "18450162872081547013081002634376155990252513846297828484205311669445865332085", + "13292716648615315298838871484647252965100904015865352978197979561906010036270", + "21013686439245380148735850740480550290335132408628769676980938610161935118557", + "3221231898146718165495762474085749772444251029483710808533124131909521295435", + "21706362586702075336538820540433124172473413960581336734430968480142138077992", + "13486895089928308553329688303040674812803987395822848864346610815697956322679", + "17668589109420826004140047157134934003621500937594400640720194981334871115223", + "15183620307048155399117286900834263744557758459406645835780045985078670266986", + "3170561135789021599641212581208901692806457808161683895582450799937372092628", + "6919102281737620426489877909256066802544737782816026767549277126151765906518", + "4002850049662127756373199253004358198702226377235167238172929008366286605110", + "1107642403321371666617924914652619792767807515753221818405051786669061003368", + "11885648350895482809772026695774528865889321558031441531978106387676087338277", + "15378937381250173939485112486205353769964903768096281219667852296031194688940", + "16437477998115322080973717158007622249171727785394053923880768422172683727081", + "7621121366936849931681051136134866470312478335111295204625916349299382392728", + "21215912298727134138155623335764864420030241120133029649046764814328222738790", + "3170821186412794476815678730429053912378444748965057631248759273529827834502", + "16084650047636623354069916778426687798588694909600147172336375822549887134716", + "5100048383300431022278915674482647701788618482574130930551328380700470664477", + "6089313816847452477548960449234592795575689699536263376449482717087314881254", + "3168424144644268762342999941888553529072271091445061821545187264931478820334", + "10404448021076504176124328273829362151757942013323044839630548232003974036828", + "4252171300134965718003785947840070216898476595813167252439064205515819918152", + "6217524790069168495104329195931800727381161902791016429835385350530530741236", + "10144395323727769803680924125110392290775229805005263966394467735634758369184", + "16773588435110330580333921944382990185799235928388619755745278707444537536196", + "7377711139925591251943689121143870901330717424145420584097007639933333168762", + "21066973161927891686455166855433069549513160220938455527728499561969343776185", + "19501795117214672544349409001236794757366887214419994956397195381058548371627", + "2696597170314397939863800656320896858584168884088153464800095340021127302558", + "21168940252375267860138608985225319663694276566348965377356649424639627399939", + "8729578229953090469373121531954476034394661891580932672218135172268595941310", + "2843049930012752804094477290180353526348132895187059237802643422297864799516", + "11477013052507658297840246977078282722343354831202397750212752940967096033484", + "15309765532985207981165438737385487871403890172460978621511228072457639715462", + "5276795386880565031975868524294990841634011123906486763299115154863864095167", + "16891192769456289619320007723900774808412675144364121907391915236424354884923", + "16679134204463371830386366769161735700621394109825781706069839015605424451750", + "3726779668847121591477372195002524410424328772388206362047548845558525545594", + "309779746952337123192541883987405477861316061278735939472746602872146210577", + "6116943109304762420893019486121829026477809860415070409858407396285217706031", + "15461534026148460547793521829520247652146949380168641953893161519404620248399", + "17490188391720816485403388897026469756907238275881766262188942134609165349946", + "695497190921838164093269283587166536603898439348751059907333515445935240850", + "5740644431998005711645731796487090897088650307567273144862464339327188211037", + "2924287064221347495709747210800576855931727720487579410745268421394700507499", + "14573731858717233227103947986267826915706941233771169473071405909223613015343", + "7774646633424887132991406013236011457803238614262239840323638862678503960297", + "17118778781828713462818509847054627300883191299007086864997977171169360843500", + "1050282722198137586289457046966751947431030691327586256768002473254440863847", + "13445581272162801515105119436838273760359267729139949483205892441735924907588", + "18349340856764570254875357271690106769333653675997142444108297087440025433976", + "4652091796588614730462648254434910913694389428280196479944835477366269369125", + "131910217723821243570751713964244292677069024546597890404591990585681690631", + "21456499410534986907068306761035738313492308692998775099405282472250364294940", + "16716064024995806321979269360595144737028204641252901859053814928024784155019", + "20095956414904309942694457361888203543242910622115746869354406017074786974736", + "3757071258857910927294547413264306476593820051587638010209583502745249383710", + "10923680137512329262337058371790257353876483628009769758330988714085083694256", + "9956537089548622902535815248396999405593511084482117014020012399528161074693", + "20271486778333058297667394153786073312398256884133810048721290976749349792007", + "14016317906581503528126751971528140956503207448983448742275011042750601060387", + "8746591469817011275278863986926266284079779997046001490419468813462270883629", + "8984522535046539605932734670718817033319009310710809111062522425202730307709", + "2799492130108020790397631531338556641981343238572990117018166640120082230253", + "20327087348772938506861277218558621387616751140016505866350214286146319911488", + "16319897245400426733698423830406514849234661290508433522979200712395774573821", + "1519870284239742680329151132587900987246869312347047206488363104123425891937", + "16461017950418215698742181372949724919904570515241953684108936425007551365381", + "18543391801737989528567594217602323229839954429370908362237267818290566814608", + "8685602143546136106524472764079001485875727469672211204721272795643296788175", + "12069346074371335540240816613547917114412632205795651309433084773115960400274", + "11988670992502988905175891565316960155103243235237609851490650832292602385997", + "17403966780192169176887636449182981656483203656331951842717004987726351707328", + "11324032593816374026994927363702518223149146507370165210922763265919399924610", + "20234844998585751045105028410680389242420574978256032494303069254030260948453", + "6845765195018211653702320958640753289098798259762906597713727891164248375213", + "3889696987737574856084707743921432094490126858489993810406205011091688718490", + "18124922133262643422852054628088483763756251512543531233603218549062255836441", + "12631624196128994950514018157378748957581711189609992774676240830354853053921", + "16425963978111788432975031188568839119447517807863396285900192209489855884936", + "8953995026906183527591662774513923704717356851383827135468523305945599975444", + "19118152579552440466145418131293777218789512388294771840750929877489494176003", + "1815764556579131181044414049066036485535218062641438722387702702907845125991", + "879360492005214940756250098489982523077085264774860932709313739626061471725", + "6498879898701797309689806511256248775170834501358785166173840360873803298370", + "6056271365753495672454589488039784798700896703812263056079587620516360143438", + "4967400286944517048147291964513981345417368809842939145340090658371340301574", + "4566978800722351857193060210384689061165216230883853755194411631523409885319", + "1472717723310974984615849145251472221350601734805367368974791217038995119259", + "13776027174095858271746500087697263062688345981919975914318610607049564847265", + "8855093701782146194984545464090688949611436896016570549019701846352658653421", + "18811023873792469394695147052306776708450724591075344787347859872893669250403", + "7691358114878791244762289651247071530769998349760928484062499608910793916658", + "7225113154421014531794800873967433806904006446284346811024995482075131277430", + "4255179040498688460969978231175134372259939403539293652133247789357971307025", + "20794639690572618510879417372961642037150870482839234645523330418091682849183", + "8794944058569076073698664070073889624033307879863301731569984292406059326253", + "2823363224083068189197562122730561866372340074232470613435703914053034396662", + "2975786158778622849913792385919164957459418638496064741275725856836606581091", + "16980083616151411398660130004732794369729853408844917920819260677159874549034", + "10213122016673910048073131434217437693976054853300442236815045010440415530751", + "15622844733073950747464963822187537454489639825890383970141531456136711221220", + "18921846985235911245949818418983694297719932450371747402698247786766269226032", + "3046395690298904837024144793490039860680756832120703445515317729068809524596", + "2583060914190138727980083409436742233507882746342184052904895573386721270220", + "15629635543342892581496645526353345602210475132913669274084203765913418607483", + "12153931408209967834920681475366877980388294821029465748773772434628588757707", + "7196162362609954988171353261930756212243825869655325258155368337285953898704", + "10832344161051287447174100117756887153534049211780756324764320129746636797806", + "6499757948467889740913713634114407800462786362067580649690672122741467699071", + "7899568931631241171429470880810625833615306002278541085808972359443075433638", + "12736525266255297750005081634236953960899087644399368181751506194282329326346", + "3885354407428541945392073706505699854042913519198595640992547091062316682031", + "3816703467689192492336832188741146914005957253921702912680936907951936401119", + "20505128951308490293180094071215431973523299690572491020108425696662802268726", + "12432320732362421179661978984313902638822551634634152631489842715192622778201", + "5512525665270220248672390077644266875095263411830016769341860810913920051168", + "10270457412178462574290846807202840698511884913948623978547229481110915603115", + "17881266377985198177178319262577725460740518218103427901653715311091974197536", + "8510066829287194091329244743814121446186389458433991751573612039633575413794", + "9055280011331581456260576278219343217137015829507887846588161405525910242827", + "8463744395607465452751391868824103994906876103054045629692996934328842962296", + "13446532739903962714217041803396024505862416007402976354796893648172348836934", + "20461627446006946445871657481203161690018232261049944659088120713658680145761", + "13772437540389795965930455187657216773904696937414401755764626097076342530873", + "1466290965505206997895149562488255231958570328271915401528301574657737237351", + "458020438009477539046680120243558779131470015073376206673948106465783075724", + "1421211327829956939723172049232055433330521137466148179271043779757165996383", + "10974718981737058413203531348845889514701700275404265370241257111393906385203", + "16573626183656890049533788707333278060585059246627869841186891657544526527154", + "9919036431890005168544961022934926297421650894480789723772572215746478261369", + "16576030844958446931425212176715038836356393446209694437953952981269181564296", + "14994178560671337822305816896620048994236927709898591331458613992689693774863", + "14008584724223915404998855561309674162219693188120257826434623735246475372519", + "1069086166685137961564210887004146480746150199033946836704942515923278172866", + "4441018674700315637078726026786902627166868710369033622977939038672598925463", + "7640939046542807984747271754089880008702702616120100267707112408768750045699", + "8165588904763498143729494321532511422369875008004817175656306909794360343847", + "7474879615118088486232080639206966699381035482748779385536890548622822072536", + "9155173050525839883630603125759778497949178563635870467694197797566249638786", + "1792459779962272311746727109790955426562388793812453852666007819191763428793", + "20263099395174426853367767733535578420938395109027150658334981283108594115829", + "10303451485708370514931418998595531573075964003678715177508051557531947678705", + "20321308667229656744129683025590573929765537488045735596831342276888215355579", + "3624395650764060579161285692706624195562301326135878674105170566731046375182", + "13334418042222364794805341409419804498243524763983861307681793920401725352392", + "6303209034428307796195867505386756492498981454350686160404486917810670093803", + "13336041503866400337979868539402126587964669853045701517757148479437143265311", + "18767353303859794045974955054051240567712613481262860811042439117400294729243", + "17648775923900705033106796825075257671428721760143056038927896765118752472038", + "21205320334769131061393260976939399463360336322318482845795119858952799244444", + "9155233455417262996613263565710157090618649015115334735214563627053911364986", + "4147290460198895367036286052342502315935666580918696244195287512520682701639", + "20798839743961894523110712994056132446749297094165852697406325453288254761759", + "10967475255107274575063249329253351284200208982490877243231819333935797701403", + "11107733429142106765947338633972307528508245023783319424287268815241476152303", + "1684156923230048092780410733570635056170405885844154942542264956876312136441", + "6785232819930341498287206635949744381666087373588334711760162570781902812411", + "3481752771358613640419060374040695972756380958880755418404724590727014534662", + "6255654521236333133437711371709951475374611142503566953029069344699939884443", + "9785296768537417566104801168235697242332552358062255540417443962942437906303", + "932526381863697246577606288678833611354323840639105626154693740791708621269", + "9020085732775576234837702925603013416533345825301814972240093864457581450960", + "9671990085159642158315772309293609967281764349933520964615615069622307368396", + "19046031964146698646372035717767563096934497588033260517438574042056341692955", + "4697021545834663993102099542459528774847962616007459562129439303924850728783", + "834623291329335140949595387679815012162663877433757180177587164505466461752", + "20037517567993747767719709123741990248999315495577556924410214834773675677458", + "17745162106287481150568322325139792027305354960331855484108228857447789511536", + "15954503136290327680020013900783441236098225469294487261574644367048211928766", + "9447580075462399824000861225221012934395732074158377365412928734066137521046", + "17638109886139425399034325504572336884601102137123870982594354109676619973628", + "4210479489522190727435015049116453108500323090316045735249662201929219316543", + "774908475070259367041407977077109033779248383557848908386935310773126844186", + "18071521129238587956292632288468255723364769404447125651660575676226691230621", + "13782927851189257932376007280798546946814788900735661108027866834341111483921", + "9061904191092017185731693336948023564331336704118962360596629665269886564501", + "4646677737877430404232975108246717822854320420060743321121290725024507501530", + "248089340757097041959106969939801712104654938085655092524027449699183655736", + "1925061776519306799931873233357921480445138537754738082308417409427350959191", + "15090381222590604653751344079459745088601676165498775998808367167579158825796", + "1507946310710275058017347456880204243614713444138569740896198937197257762391", + "9047126832872244897061755443779135724439127934417426920025891305321906533199", + "13210467659674398263347498463769321394392811495810195742972914861526145024497", + "14930790949584540337435206846889685669928690545385782178172828133028677953780", + "16709614617820458913659268544942181680363927832511699782451755998512279824691", + "21741729565131743651162167923641181853909251404044798652854243082519505872026", + "485748276371306614511019734420369335387299906747036897161996666725324275885", + "113729363155019628451995418785166919308643202089193856958029953269497359518", + "17315235749721747007692514702872348378105966945192310104719562066051041365785", + "18164826565342651411070681557540176534582615273713551079309038721773735887418", + "619154088023795178917549465782795919604596935887112076630902791174323663727", + "6356343581175745844660675205642675571886993827862033572086056964311839166798", + "9925861911435596968816749828945917008180837850750226489783169376408872855250", + "20485137494818996958862809145264015810010636121731140334074571507470008401090", + "19656735537075233905125360479201796779994483024563540752004528779684256455735", + "15774243068028338132223253794279808721177740456197787086161475053638867039504", + "10497591647442850110427658608196767909160517521573199077258279280018098065029", + "210438711366620938094565498037172584426960275594120406278610962685482768128", + "14574298645311491089278146576548733364636851707576602363349001846285614576119", + "12543161131818467611229160618197160281328232851440846538778664249828945509460", + "5869885827840429160723685065960013290766384774919021040094074809404023704797", + "14800413279643792835835488664661954863340552091411990276270728475507101877386", + "8706244411264045072904148746698442560958145712983473320099851020229801141593", + "13670524729264788581176214636184652482954266319986131183163702474027069017797", + "6632699635952855355682293206130135801472538218093800086693644923578553649842", + "14292924690435752338909900819628889644248019746008463256978678218121438364347", + "17727807116656957204562694366530472131199058877798797418410969267673712196106", + "11223858699504492688371995874202967948461173433281557745471419331000190821973", + "15274518373659950909975149452889634174127158243424169830798483206460674313743", + "7047593141729299688704504157654237466438485917193869775780994636019451364555", + "3378912259124002728608820025874776626345774864595321854977438303831475863909", + "8837103908146248796259735965370584845236705198353666155001962958984824353698", + "11869977356793268256679742068396296621649101901864556682314737356997442919617", + "16469201342422734819465744813830056682872807194264521097865986969265941221776", + "12990791567002738838300315843749937126679083554067128201599773654099601117791", + "20519376488199491586810872596388233936561051835647732260479226405592285629272", + "13549175857035221960740890286176570298280920124622104651989532035707272553373", + "15234870385685844193215578943145814211167163612264546132211506983633757513134", + "18704889004070339618907065844757112006583041625995006884582590095948666509530", + "2234955996987396568560381823250866120960007674191266942270485492312904973151", + "5564977611394684319243720881013051542355462582947649518330549023416464959605", + "1112602741380454855327102347931753030221494100363029829630354546334828994329", + "9128209482091812367673670394219617423875730198454831896130112252113491505252", + "4376101007428143823621574836425643116618104664163736787280388345260726375856", + "17331301745157506574267466700454501468193891305005371065208065202603272248798", + "21846545094192300969525954249087973697025055955155275797969191218036594965229", + "4498927631211901890366201669629694821005085404418517058539528045609417501903", + "21785888954457119007377380145673667061898185873161711282742721281162112687992", + "10412875728643419025694818649503070798945684772972009054835016566542500457165", + "10759299704717838172704330861378107927462309935609553476471308013349659622009", + "20590357061487044454315237834494568787816431390448334652405889873515373283815", + "15673836157910318771949663697819073723405442238797105611030274826598578081102", + "21475838557209838850221160141181337897147127057878049055974104365046170025610", + "12207716311215040854533276425309298962214124105108870363296256769166507046674", + "11559647355273809434894669847822031984160367996613651160672893927347403624957", + "591243049503910187533030984285442752553334033673422383798814281778102029479", + "16149820605774446835537612705920133098873928503868848274855310057025837143826", + "17994206225397988293963936097869072606400130753097128779836685484696065715846", + "14255641384045583862403050464134422000560975124837558223693835399889249787677", + "17504545541397972120376845150557483982076571058727369435414053758625774050033", + "20262964605263856854671661755299361371513888427580858149435552591882491905348", + "12438123120680430355474353651690582027160630756728481836282192739044572633306", + "10986893609190710977332579571229244255566870443973548516403950419251545530801", + "16087745879258651861681909407049342984746351306967389910641236570806978994348", + "3161560484131968841565856280480697486595651138902139808256180482675228360792", + "13935262764632300233548760451251751405084774897832419843437366109926436448024", + "3163708356211087269300587340868486145250960085863061247671736451529273060199", + "2135858951319828747123196912541413689531634489616050528404576322173340406195", + "19499372732572987294622585729244698705235805453794292187854255591946466724248", + "17894089552733756400990786239277662075181623012822588150546768816557117698135", + "10627476289794518149581909173158184680927686574280550541626159986648732476852", + "5936760260909841348473330607703047527686233710292277373302498592584078811475", + "1671632573007285452120449241726645612097503185776127730816609206067570503177", + "3240964061357526102193296883771275932317464053465161060634703562592821382373", + "1379991033533041123683674223861213511881534224092884787544607760074673933288", + "16612309984678362724113323611405699676953754495433780645121123868554119586714", + "8990362216544353251183644843626621823440172244041771554179888258848070990408", + "7792126163077137553546721412284336099138469839853005420022151183726709890605", + "3411642164274869168109174406711447272755835383047387248320765695217678712087", + "20744964603175609148844959505361532818311810796853446841217756183414690636777", + "15406348836110379416850862929702053477202461331674247559909297027963274533036", + "6655070454278595774182716706613320667767771244472415371150701320921454970910", + "5387596765852619562692588945067153848362301378074547750716364254552830548618", + "11374645815567953400996409579523063654937913407852397185357281079289695498202", + "4637259464430266322534397972465849540585061569384580106712860758129812888983", + "11664424120893756026105365780051433965998344366144921839621845056675798876861", + "12683173829762047157652990138425355617601406763777942452461639149511855161467", + "13231456998217432692837253637279353598668867747754119281167569613817285339906", + "18515103011277984777089818507163076049947207220694092563937098383351447664230", + "12292599779221056615130747040145001893088895814628302035476053980079114062115", + "6616224505832681391261988520162269850555430131210843369761179293711760268991", + "9345928984249349577886491000914566117062182722884874880308419980252230631490", + "18529045286534814640266328796625676801335117782021569247528965805503339014374", + "9213994428894984896264727606602499546795637673535140817494171390234365346197", + "16046191804660661030536723745809610250792224521907784347921533311133924729200", + "20387305341543872348027149959300247251122586296441271309757521233850527145501", + "20660888328716295053746457587105952359847177180169600462778173036912653930309", + "20868619915262427287234582212448052350184310305114553346457821129256743588185", + "17663781345821195819131504897468846255222386958594579879767055754372925042002", + "18948627844717262137578097615546021495287533410031083974644721619152121684198", + "13155646636245265066188794529431453696019006721019099462642586385520674193264", + "11607002707400435612558884657345015071868104333677950253781252883531031962578", + "7814494031495579790510272464332992505237344345380518199394208941034262720849", + "1133679025909186037940532130396250706184367022550359228793807250960294591300", + "17684405674061959945309711765066024811535672808158415749778270434181980067051", + "12226477960064982944626820350420332900927073584585614331096659786290796181633", + "19811925349932047710573270972607617621205677733103349721011497772488325290731", + "8648978019377605720004678083600719374811142735403518791266825142192290428262", + "13576053523641184415871793911230224707049224969614290468646557972152185575110", + "19246597006093201923867388663361027928531131674594730473459152193253618076466", + "658606426123772934076319360192555383963003130831902899767201848799898493860", + "17290137813713243852250776166370982880777712118107986170022122607636402519519", + "5468484217427333109722188824068218191654858622412608074953511216209386470685", + "21574260030527757195923820887880669668169386788465310192452085714817280961577", + "16977301410295947721817774534383483730974509825154556215531376468755351549427", + "15733754299741726976786941703016488589821960074385924955118036049474131193882", + "673051665852885808394122319132734442090810198084101653348055105938368910407", + "13398071607416834058601862099131647257306816396251547336997555114713122083633", + "12550653745423625869263455159672489463891823157792786197798074997479171696837", + "9401077435832768325771683033269047231487705804464911158715103022642914069963", + "12470382814922435426465904555965877134678525017061716145587676176477156930917", + "4934832010550666003820836613445526232712748207490447572633148755378222021432", + "10147431980198881931337046775655000300780675339813128987464503437796530727819", + "568707585724749374908018432889236271799675619271430223486579915440515081761", + "7940313483819289305875198195901580599194224791864182697672727755313391315497", + "18743990138882019355059105644701125600589318429506940478381096888059645669064", + "21390103921503672356366200239425679587351838964225860732507169466542370471389", + "1162301008434626626179696713526875746106593765970497860274277780972785074172", + "20866648005214775989252883040721823770262915606193206494879341544251201195074", + "7345491533727875108206436501195735628498565230546589655556895625258093485858", + "7625514906338569732343456767807169396379912415318224530910677456500209942160", + "7862757427463847382674463970373593668082249748547169027835585420099101631793", + "10678296207725321824311910857643347417220081751912275071080081222106552722672", + "16952109495603736214033791235849594583684019147749856522239399814261672810874", + "7275820797336428291178396248364001448190236523398157638561627689896470220284", + "9969981466756203881447261853491208039919719371961809442805550510895150629471", + "2820683912350770819480104529177445624170795283688064543451455124015297123761", + "1768227783012842108298280205661549942041342510905211540896799241998425991810", + "12106377471628405436369258554037168031059303858931832122655790690193581259368", + "11133684149892568979034305171877692043755100938665306193308979862319584720202", + "17034299967559262110637856726685484180103963204901371145115468175393665761738", + "7846191388095544813700988786315012990125413238605101219369138067522789941990", + "18501907765236851484806470528611625980973567313044760445349490286993727971054", + "1249778578878632628279160684089277562912849600486367726058714364522238473984", + "12800296338215947544269523539435530627816725976238738793426232070819346748361", + "21158276531398412025848449677754681262986399643402199704435277598413275051402", + "3445704611858969368326297112584817848554583085326694642313172161045347990986", + "1096936495127696656709715702297708886712481387809916555366077657639639717937", + "2595620917275871104056107465860277106075411236679259253450463497473275008081", + "17133880510415980077665570077127522127719512648188691671645676431813033706096", + "5074434632642876807560017812171878490042102579785821263047865225182212462287", + "12326838696626858713891707574688276984801973627108664533453869827609207218879", + "12304708188533179803341734069046800825101691162690698708386871234713091258421", + "17039317314373515840113235553933676165005713953680758739139458602566292834442", + "17138392904367957911746841143250516587142345504139102606501472531272348644184", + "1667176916358419631869035157338470222219117704099667397276080580945958414759", + "15905657308104601519308683078473840880633544254678278144766436492794698882065", + "5818790161586099604498469370871887484543304527772047827828829241332373438952", + "12442306790659206506330372960358262675060765197848150572966156688729178055833", + "8830924073341698588202301965823165752475570241349344118304602842583809330430", + "1875325218295968167735653385555759668710537053646457950513379995102733934773", + "17881009017973237557824378556848686261064176014957336169110006388300690909574", + "6685909350747636031504999384308339032316756393531361646826148497177153343308", + "4784523754559868056092042886072700730690109555243230003862073871950864412709", + "3579228774281988929604104014107948733265891035249209872698544379599035221295", + "4279085918474431382642565261103862932684902464862097608738233691705350921017", + "1137759862158982763491809087349360013612105180026300214422560224275715429456", + "19720837769260646491270657488868445833170057293472427873975392955686128702328", + "1718964391395646738355239526986888311027176887298320241700031309916500343965", + "19881985451679395586972172156300827725375888727627109004411614649624414408826", + "12172287315747539949563617756773178635584674160408496477097950831147264075213", + "17818348202724817301996509561425729131915819248800408750587580377834731903089", + "9526094675919376961704973755217702642807170426879590367299173409422751261551", + "3828510101756167773639196204933352052436416699730184799283196091112205339599", + "15234684891802383017182920097366274346299756278272648689423306851279308385365", + "5259340948631483055118623587523845455777103002480150827336361752510452569472", + "7522204711834833179288206454714805063533565847207420606996829544233502085239", + "4461024416231372224773966846126492961855795819183621636555920813846035684924", + "5024379057555899833767820321243484415757741022843259764504133153673503667684", + "1944348388731771850836911827979470257687115271361319233348322098245989069259", + "15065306781743278475238637320889039722240861069687500843669623160807616263519", + "10185565710140214717926900268233420932083773824278146477403635012592608678058", + "633282989982188437228855410820528038963373266773393154835968536206352769131", + "15070609296388507673139787908428420573100959040320412658731328587817279331759", + "21412207865606943642342520185052032190311633739645180935143927525277916223829", + "7878150466166009547688919693656375135045159152200952621922018706527536944814", + "21647238538593110963647188691796027858369673773306895927659346354059471769993", + "499258196791436830394876102694379667868532135110557694409916330175138906869", + "12884932140229984175244344672594504633237231438569204938753218905028898420879", + "13897088195397438949124517043146998392030835253375096249186075371152838123957", + "17292635307267344947001814307009165392877577631472640481991264040854674668918", + "3402459730835246576414179745580422332982133349475000364518392993042878622965", + "16196872248846772839551997397431726113069640679308998300903092440097004592538", + "18016286200009868237596690430345509415593965676022902141045234608328285884800", + "7857847074246536045428962801424396151797565515320554961976852417962849298458", + "3893665144753462156875073379241733664547431241880239458489799597153819411492", + "13248007323269384117634056450668957554780628822533632623855150478480951625390", + "18276875079677833610517929467816562761552054119550676368999897123627796943528", + "5189710327122023109841696471286837143455102090557692433286249568240177726287", + "7945689534444199447942235389147404638251522098536584100372965245456120158597", + "5423767002711680999240727030908088708424949959926318146878189397264151455693", + "5995072902526586585223000514086044396450113354893476089124870631086600489121", + "15275396095782853076485751600594247065910139735226081476243182046971110416839", + "7337085477458019807945256166142271568824298087615645600806448794391563720590", + "672727225441339286039441508031715798485173015033624765579287288711179551652", + "18686118639158601820164163991883068337953517102808111440802394108699280438488", + "14028695600256037576881239065837481650658243799767033132853744776667874365505", + "58443191205451688703601063117164997697541381759347793811443271650169777861", + "21065693836733911343227308560913091721048742432913504195640605496691788221566", + "330731975523362608415899785414131718097488715216703281999950906065685546389", + "16761217887229483694018038191674783405871691887163059178481478503168342732832", + "3038029821773816605245101973977979223409779873144308602734440877027458504742", + "15321291577034359343843366677170820527712726038561116015047816977743924220386", + "13707411308735348097061010267850476217721836580681738128758120478182032058809", + "17436870236156178819421588659602200365388268058796067042132167176029472760360", + "6398050943215095842335686342334715469621392080870897191300696782676608765887", + "3437851705781701539278760214561262405409371984542409183492392158766597659391", + "7124479506211457523573057217353911508610466081033238660465711588737967142974", + "17234798882124088040334413616145917195326697085511927239835381731514314303940", + "7189678840883577982600011373449005624085144056595391210996212544957416984457", + "11759897219791977703855743039753523539327151517291958119140418872939095386327", + "20863399992661754827674386311991156323060622036945800022666816987897813665853", + "19303856056826570957071409328135004293560711503205766767776395391371667771674", + "20145537319102686898024411390314804436660254524742986363357188082440068405993", + "10703774427752668974576334932100051927133058205544953271144849898179475571339", + "18572949224433194996605971200517412011627412770605201537755920772491000856992", + "17216568647787248412779004183002114283399247525457054305327730013550616639101", + "1149230406252660804924057240581611320485721839789360487426995484240018883527", + "16555038770640675528229594153638806495397639088923421322231578669556920716448", + "4570242682115771574920314226681534421057130734296724983202350760375592356599", + "17057311432878064305365984063315754288324488570316135529616408791432610322138", + "10528094520692277398437810246572829940408932590689365643375030258637643836256", + "18372709972473962897678516007961361205643396632377488479769034609756086158014", + "21838679058944462510227588871439974934573578287277780576996692447397949481484", + "1580935194501439869947304184720525369376830253681649968786933642354687903995", + "20467445367185359735288490209436765649401864859115524728703996670394981839178", + "1991219687938782033642326751499030593324853839359574632972633310438247709458", + "1439755133435743273361732699887115117694558270034210455263872898360142260289", + "16300147327505011303454000556020917254890545519131742846543658162285928042977", + "20520490665047234670156871323008670381517271529350180242819417364083994994438", + "6542862810250661443960454367170533117465189617181697143331232138215407738369", + "1321343667823388542880641322895423041177577518845790583045290901719235409147", + "2442599361719607622459103501177302579953568947914600055748918886479950617614", + "5868547468478431065596263697373807107429411676393246849408309043501871198941", + "12236312006031079186182743334640941452854376343312535021115608217162266564748", + "10096437059927455034494932369876021874913717336999122002472353603141122745838", + "16855287129299048285700210681474924546365514190517193678115189183373112094664", + "11157210691115027557284750949314979990011151769293562411757900634452166569473", + "12647512288244490046752876853167515938997386483355090398954955982145642073003", + "14545106158760908532417185649648478400561191409850112377631214176889261943702", + "13380884028176250201501329354617948687842379239413597035170382200236519084210", + "1405533288610146305353614064658402594063683037599662723217460924638972391780", + "12520645345847038927033831419634817247041895425958103228961545058464030447700", + "5466316270148149873459535347452815877745317540692907701390798166221830387727", + "5692512917835452114275964699861010134159019192212203758647174343214228494998", + "20406430429993275527714460195190469680616300984772360022156779114506307005915", + "2464398587529067351284637471629204475741470377175139272463319164375422871700", + "14514168707742420576792107362849792246555009352726620152895701096554575857830", + "13270866810108509432782712956020266539382253503195894711776480924657007904548", + "9134846497886036320932877977667565061646780167819704730891157458029677347762", + "6968315929580902986583144026090679082271496835598861747834541738159673277903", + "7271494204378938515839411341192945686765403888626619615653078042877068436796", + "18286507248612017881101512297381359645934672218434256889911439358758424747545", + "11110097749119198784554144689049124335810208369471373426127558546444086832925", + "8247301320031025187145317669710241636727060646792731418249820159438470005156", + "14294937643948997192288252800043984341826315689719836039426003941357321500134", + "7348709417616598268612977306891011618520420209855159927526151677200518293152", + "8241665213979757536094384437357490949853796937135356315008833005380426051194", + "14613486093064180194908604682667542845871833534699460114586605109597063839130", + "9113009852475701814533040575255279924173382591876828814441237692300104301457", + "13165038554179369948431676356672208670169443113631826535771459184335356285593", + "16086269628133108266869931705626389777530735876369884384351431845165268738278", + "6087260580031589238539099192443153008156470383537608551794229727048294996340", + "20512862830064709642749702619534843169107182362836772285105007708471619038567", + "19533181397104762456673826441378799870077181112746023293729567449839481548356", + "14705683451830296925170674619865205995188883759493716060771015969186134607704", + "12605792817445608495860292975716815181045267213200470818664710066347176280047", + "3592996587655107072245474938139935892949344064921754274126873928977701118749", + "15294232235999070733030126460937359944041996136808334336982336855120910512334", + "1582309023481075306597300823293668340335902140969083485284345214470852671798", + "1088465469116422019323930771299807477223547422484605269302564104323452973509", + "8883047416031049757538663266985855517015256170002963846635310997205392683864", + "3176854208559033403336658900147847127925792493324423188639056424099958393072", + "13232382305984866276823393930594443402152224642505744090163285056748376747918", + "2245408257366834949733190872330311995971080118654860159924241594642495281059", + "2379830947280597194685159865267943843813010731722978284837340564719341924509", + "17826177593330561305441136255554046830158210141415356927118963102466292013052", + "8247294876117518524724460400399686295737179004092227538368916244669417581296", + "9784484010004736296495309204028701732510703011300894445280176432324640320289", + "5252332428538395620048044694806285484695976570037776918613895482295008833982", + "14121980677685920870338206469007772221567007585360563336746921691628879549127", + "6873280017888024918917070095341125311616790755139638467124027157089622101088", + "11318363160576645628856748485098328456894971803038601852118504122294284627221", + "4121152361595345093207401693369225144531013563993157593094962034269624651820", + "20683333802753484511610127216996129924370396812165897253170891149253939360760", + "18647670031404843711327708343249425853609227031502475411522973225042672187860", + "2086657429367670063332013344180770222302417569271803215009583482264097874504", + "19709435480590614483363007409253356879041585154641286906159427713982563792526", + "4258866914660942354120395242129829740747833749509017072799985182732656616800", + "9040566395371463976833369354842616182669127821598268274888838547664814843928", + "4116084355554837400529216189356527577376881089426150781634827262283154963048", + "21605169971906188704396331617487188526616554159276096155817564565239435978416", + "17937211187232154582564924643486965895957558838414375726168318393094228123633", + "1992558685702604567028071709121593075020313087150274357559040691997376317338", + "3218330818271934662263059558699096796852863135305095433439395639068666897513", + "9251019796910681440348368762961435892628247766190360978557679196269677702320", + "15836693249656382763970061319175857247542072239256868703809948219144542014793", + "15037961154776922819548802422798270596812938540093547487192133997609110330498", + "2832985667948889103643595801116542064299718867280064733138075131374461684249", + "17231308893316371049725716015653771498326104062757761825930828499226120649063", + "18440767123713815329857061224743112764715289422724359826699690594664366648275", + "19107308066370859685275861140608997220650596581264375407813390731366162034891", + "5404929079073337935336499214267301362161341750373615311934457105389796446473", + "20619481508117738469430272904911772560595466539395055218439600469328451867796", + "13952701312362872281963137538185820474584748980975982879243876933687953690941", + "249746714007340023576169446261897246896602417046451816160506088486861113993", + "2031064645897563637919423800257706696891919492795925079196751344512608989440", + "11565396752616415432819810596660051755078386394477458037668058318114060397110", + "986400357247356567494096182209394879745469890962659581282966363140769490357", + "4537710479751915891784323654735525989928281714716787626598475607721311119956", + "6473679789570545843051971615499250002895246840329033388322918048865214899581", + "9663160517547239942952324390296932496372339501369452594336052141919689254511", + "5816463053578002459222339447164819661176549623835281810359748779077848682107", + "15884891878740533639319804312855499125304552172182333174674400304788572220390", + "3033403576169643300191876532878569681892028128211422158671974606431741064057", + "10358010399523377550281291332476224381854765291561168350961812145251103430188", + "5609119676745360689177377631509255444635743595725402489628064332010648311979", + "9629834817212476647292649072966526100818069994746003213667948679343174132340", + "9902671572518009781416980720459757101464549561371827438607346753254097417791", + "7861900468190840021147507239605680877304969442537895993247780719118539599806", + "17965713539282108900380748546130491121922627970953515439952089259237956451418", + "11875127160859896409551848475414052588524539216162668112975117611722753563101", + "12036060586969767703747823124372554748937989587973573397651022172958180951726", + "9687479700009208904244134411901361698716242095445472067017865326177763818896", + "9417881715546662771138833677126201059337478279387740105578558474324645551658", + "1453393784429512178361095160478955627301424316545464923297558140633602643591", + "3605661850144345838926820161654200172773665263094741288943401786929181563752", + "9633343945573595088617177094944240138296472849064303543706399640795820973418", + "12473139325003262775761026452954333162901791070446569863302424457084077761149", + "12050383798910643577317544771125034193641466979797280393384224161250051391008", + "10819280347517551331483926007074671789351833709996171469616831904311265033949", + "13165812145639084020184122275986846677464323294523670942848342958951658208097", + "4349080070868874275277456883424617452669491031060808106496345174056753179120", + "10004465749978899491390807601888552616948704671794075232666191099858337042324", + "5250553500845345497570122559573167112673420661316457421274200097450990672373", + "12898588403041862218453963458103462644872308284833558427909835998108927951654", + "18081519381738296094081786403175972446703155704846706982096034153576188388497", + "17428269008435424731165207394539747495252057789950545989706433801022598432683", + "21363561515458498091299721959548254375350819182606817501876503845082368630248", + "7730068437198222255038306872157350083702057866362961468917603557490811496832", + "804393402354592729694369925125379986785009558185994901175413585942989446396", + "5734375191529745066389276413443500729878560514347145222515433157787509440061", + "12298550311942812907291709877922367696701304981384797706564000787234950045527", + "11599955784759432052811066625229516027776562566066732630526030964712154732575", + "19052852164576098666742966317699449063762547007283635113650074658720294958279", + "10025188726400272980943623464270412609902684461295237328964275116870569460545", + "6716809200457040320003933672999684025455855713745782618771058247491604111902", + "13265049252191301811995103374452481986951626617983097109447548540667223415855", + "3243273032455921996687884516398249181181318053856384035604616213401999420878", + "17596345835810824358133183122550505795231799288513594802190425260560699653345", + "14128892069525759858946235743223382009747348980906404699362919849705747120829", + "13560912558482649403704338887070267536467549681310240991684055262800855969142", + "5146650134021051734120451478394931677954544403196703024645198760974236051136", + "3656624380537215154312224820978463973302627823287220718508509926228536255064", + "17192240779422792861455260231600955507004716950247796731699861536149977973585", + "14505892053752720060006987522044578502315422621292564446333307406645448977523", + "897766293354199284998764120885006378362273185992111179631631299334090746025", + "9385522526111341509707107108914634969549440746118599228963287393277576591675", + "16755551931355332730912571473383446100229118084434859591641172409884703288623", + "7998487350537565460407312493288045720319128967533762889043801066609578748620", + "7253071994474199371350196978282275858691584350754099653147319975858840509065", + "1574915908528094850594155669399292110958198100218448518346743116412237429711", + "4964033462714392747475438670479181630637512997723146160177292638427948047795", + "448448106178274062085484969210407935775566171618153143848162702130236340948", + "10632678501409460480908899293916037077432376165397750836428181066894132950422", + "6560185425582299240893314836102079088239101938875583740502225690151903320396", + "1579188680045650467520863974543764324416915154559115370865175124462148613819", + "7512915739904886375944428372792517861202973027020854741625268080946313568103", + "11437215569201917203849322845056384272839597879584906569042314064918170663914", + "12242031850346916661228168797937142001106743366886274501414812437377823138597", + "20754147834828558255955521879849243373047193258439455093561468286224927742847", + "8071694345199003059727834592733443749021397716021823212294503054151589204390", + "20008195907609188950845942022048531038227320303695709133926612651814670959266", + "3407176450804539102225412244906714437508697739163709736953739213204054495282", + "7164733851792769372626784323196646242013517015794517414070184073240948375536", + "9905209321913745841790507726277960404981926942651589731149669818541827874214", + "6005284264922151317117707687482989323446281090296110762814732182741632133904", + "3429846891758468105169655789950721158959212737421209807144772069541192906919", + "8594924739933231799186811828034272621585362372014000894229076451226180774305", + "11871888849049325223331295756953912508046243621607006393548707001434995954238", + "5685905463286653736673250214945816154927032180553041236977187605699044205816", + "213743477607202689216486321834878291503247072102535716407202454507834205331", + "12562677380228777117621213265298559705423375836884092254836487933903100167894", + "8185089847800873546122723865396073717154949803733075710451409261160174437901", + "6833793650798095878312843740119765700866687688998823144083128641706792979819", + "4953313804596399497426456604424338320630850621290040554640752190475708172557", + "2236942430605502498740725704270029328474562664606378240692747298661887827319", + "1513449164658866312019182303051862147479160906256039744485216368678117608853", + "20317977663255757433651259494490740600408545133225161089258307793180016743554", + "2805473554735433677734689688066817081805362311169954998301659824970436339447", + "15815182380045621180846286591593553907538664337286124104922652024183257765519", + "8995040978147557956715534525198883385024370476405764975921649687446895470970", + "8204191497925877512228406532110351579276808609895204619986274589454615200331", + "9804350573365946552974871840565664742492437387015600083520724662514547605734", + "2670072936416198613788578252423721270352613415834375050844481006480844299140", + "18981033918047008332984286244333212532097768099085053122971946780791175897494", + "12954085820551020895974547504930170442441222377530978192526624489157895091072", + "9097838829535778653934125096834099047122481765699682650259018742771271485024", + "7412500154264631610614836174268215158855286123479543445207793653417339063427", + "4570719057023209933442917712353770885061956176422382707340131424665352082829", + "3764270938841013974016907794451240962927342721628880682930414663597308799660", + "3003259409352957401069823305356475477293574843963128589242837442372343327078", + "4364045643562272249326662669199826714126432097046293502341074915354885207241", + "7862497546139280137858115009924456872495405978857024048016201451567691552233", + "2320345330709275050815413684718297588549014329479521210951823856644277128291", + "3472052133118830373581093491758594658278444460214482406644025496494813391646", + "18719780395522132269892764976785744172160001291971824246311191396996341879998", + "2052034405003094013719516407189467871257070713148889132320853589752948812286", + "12668293034393175159240347623878811740389002104040561234210863028172486003814", + "3030226117016103704707119677479690730613220303512226016348578882444095217375", + "10328007796868265401669271360208572151985515933147061282836598786351719442924", + "2936234154384973501504058165728446155253408008794108135203900159696674018692", + "488196422923618399001126311361138933209773385094782255292621218871598725659", + "9986243106324062707533627601692123931503570667062976466271294044444369357821", + "16946417777163299571223971859384083494444080413698624920773661721819621003999", + "6290655646787769345150128237305014645896272983703662862175950979175390099996", + "21576354856650767064171440939276202866931509433119578951322323205119147402280", + "12396222895516500136715256668686614381644469516081823538030375243855459590807", + "18323538829312240204982678233417444895412920429922269434090001873145951634449", + "5312977696789603985280968610327711512128871567270265803635161870118441769141", + "1256303934933114233929368123369287749699533819478400217199836088113619997588", + "1766722289253438664291189751442574085464717822269757100835532731400395828058", + "20358149792139162776765514570327167438522971057031059964363017830738523560815", + "18792275959974477341072288096653531684536236050557537981692565367846354045353", + "11262334644528432796511003492639130680887823443747110676752140224527884546026", + "20501847923202184923710061886495102946632889060597711856226126913397710337656", + "2407267120907499137598716355969720653158717479075795831021615986085480804669", + "17307860167097742136268530831561503531461792239855909861554172148017416960805", + "2162289869674344221546800054490037354766673860343307342595970088710829183154", + "7028199420603561050998184473139307688291589649001033510888359073812068249126", + "20994672525924208572413211399438489393060949253402639946739540459305617910138", + "20173431861606460093483867873896693022082731481398426039971589468498814864556", + "9008871249428555602906292660739315591043104408371562099899839775533895523948", + "10700805877647067083283505504782153003756758200729717834117016178491024406477", + "21112465741764258732843126921665151348166174697732269978267747373163853108430", + "11434984188666323224207642407059759324684918143122828248101482207244887988138", + "19774670032646206729857931401475084640123741797887602999266543966674579660422", + "674655537444683637096570248236990032160746930820910298495859277351312061534", + "12399952541366504233794506479162333424641228812125959815028858786807335765308", + "10787188444435222346993386033929793480957373636649543232735691292731739491178", + "8444484958726309128422673453859105535823575309761203789528942642797742183861", + "6178443234860827296437957284319327879259579261423150811121652495400576061977", + "9312686778448920745396192252021125483491892057300805307510293202738266404216", + "21035346041382930907137468070148126300607151584874513632902588011146411628958", + "21595380874048139145422335028184290720358814546434544789176692636485866078352", + "18101046998013962303174610041325057852573934184601619434223015638490343790989", + "19667939085949665955991312921627801957163412888505151951175612729243786613781", + "6926779782333484660471017512018931263032231687078574887001518725808608895509", + "21080823663408874605869582733040113428551737099016002655485931862299065393278", + "3655825253274650356501864672127621389343134570773587805971056417535174536245", + "3388541056162402337902270805874665052329588330241925030058121260891155159271", + "21883983703980930327495083710303031860831358299523823198355219501906879066592", + "6926045735792789706902681099796161456533517354066439495586980016226331896111", + "4122959111197116982155867189740721062669675590322734927703841118527609239459", + "13219980757163558837707442934888299444190968070207889541780648207183773341011", + "13812897721847878024718349018307386755424010495939938584588468146497630813114", + "12798580293550179822728288481477643428051047081525754174406779865733869649777", + "19217125674525037886170888487423869066614323854468572412518413433041373346147", + "375553361556668826677041847695421482571990138873344010326810282960129792132", + "10834658340690112017927173678735250754641576226700757836412274044036729618775", + "4000963705080416713341998395751411942820883040862140582570351568343523301185", + "11715758996898666999645486245570559500678491132871745818362150491793495427655", + "4263507095725155156517595569654198316584673531155392198157637482244808941446", + "328008196666170836733724513867841384647787752809351062335576481522598738696", + "16052279110256413457891846976681654137774297241350913171330588402386482933504", + "8560435921497695081829647680343824474942212198090196568605135998993570233835", + "18716362840678189592322462186141719951790452060116008532478803871048621361376", + "6373296854260461347237798330630093524006414867838125038061282895929391886849", + "18914705717475623119982002205679946947799155688028604423250694242332863378659", + "3615848956195277523544974986464432491666056752600413462508649484050878259586", + "14319383609652049721947038362087013158818175249064317958973877909037224815373", + "16735322269478335929131611670089342135588205793924787907856943392431725411629", + "20487989084414161462431324456040544956671737924589348832484117290264531005303", + "991404779256099913569561460005735823176831315250109345694197087497778707447", + "12403152875035099961283368388852584749460932263482397452647736730447907363221", + "4086427505181709923565832636992346270489207870131792488930389136658523450334", + "6143243951533181757415269381412864770996360748004903845141664179532399602512", + "866706669878257575355607694505677029531447447184317717274975559227499614511", + "5892914572161311963309388543417806910338156401784367910536431408323821746054", + "17195629524346618476376551682847818577110341498528926796026110967915240955181", + "11821298882555096497181913149211502245650586243756443688232286290083613236253", + "9353931901221302781036617146700068445151424017933715326811471823048576997254", + "287161824097962028466164990607592105232453331778514498980389789122436840050", + "10649681231914156546306210447083574697745999931000675911245824305402757632471", + "234428462053245029707379734508145490630528735544251100489484083890623632434", + "18386986463595680658295944092336172488193344109864388929828691162200829447922", + "12209205038092046905635371865560616384451716418834791040178049545643031921053", + "14186020280018069417447809370772570171911004194015095921511996859327548729773", + "18113938321789369780471778880758786581581161378582151974602552514969078582931", + "4811662992940356526245596671631791612493389462608103550402208802794345444140", + "20758900083194181903559645045132621401748979651195063688583538188953422299252", + "9153554145073302417837255133650907646404668180089275208960151746312542076673", + "9140083548410620433186361969381763393513996980985547052071730395844456832878", + "1995008884754637182207447536267941537231422109677541855619755654197330974956", + "20815985241080261061330547616924867409496454481048128927799047536950736307626", + "3230373257763661238115338374579765087994728137593244037768237534083906441753", + "15848607284344292541615961379571084541204910796797596203678379270219514113553", + "10428395164296448020881569101995272889447042680020183589472054992027224827786", + "13680122146242354024351667942887798315658431983426300974494489056276061013513", + "4339724378247845795006138666633339576672603219988412146454211158778911139049", + "16957453138566211779676251195537106997166365265767483860476580167187603818641", + "6903442910536492004022094150099887848831560470459811862902118892324229883825", + "13517533794136732881120013247194703467846939834067648417739110803619549581956", + "8573259981507024845652388913624603863752296398651459450944134507080250987145", + "7184725885552680253794089893559736740786331382981862187745268057810849566021", + "7444911651670419666243138241908768267984541319117854062859415506699726860996", + "11938251205745649282918409002562222384447298563524098642560439931062370036028", + "18732676061737136378462265890132297759828778436681433094170064283098167411411", + "8846532794008556689131513011423108042165045871690949838768507118557843169852", + "18388218263536244281946085549244925864711296342518046885707040924859244937400", + "17560203902531872086160045342305935339585392467343746359739902020514592872929", + "13543101793457457855715055504451796018964110256417682942067062541530681224758", + "12729201216656193290459172785293440324005383463664790973551946761644249872265", + "20749632282565878390585307142178974866932241415051524225408429188255209021839", + "2939350463247023543160206627078350892997171197177918468376868549940855641486", + "479410521971742071578523736929989300479738063431591906751176641695551615616", + "1215960229051771956876212387168875875104433482328478370485649365955599472636", + "7395834689442865088318136274271999810879214824816761763663704696957588580019", + "3437039086902274758103248708959011309309143141844585728091733160570479897488", + "17467540498235313026126845934481902834360708027699640261573503748997917041831", + "8422995023428881457749354920047230520807267797593122026229940569066728153312", + "11738236614524316047928272298201726059224571806912522830504677268234776263625", + "12990187369429149609670218646295887927962536468837638994349699374218402630706", + "21623781561819578622543358003640431769369503776252057790027825149203611468091", + "5669501143149367774701636329186878874504568114693026656335516415399035236206", + "4575509333922357841125659935390034260822150782714631158836599383911958256934", + "6033679984514005206127292322842556662338038222728990090780027736088500900555", + "20960588060390074988596726655693601209728221976889320157850211914560680389602", + "13413928900186225435324599444732846219399870995843202836070995363431243049194", + "9234295907731818534748337816708817747432963728163044189490249482655118848141", + "8555123146188721627588124037374319613226378704908045460846666824116325453744", + "15273216586585654487893582395632825165015207795457148545076967758704213266502", + "11125068324382272646583837096728304098536045737064996999867399544054690011336", + "14959670405320615939216519873622952189488168539376564485090492806106125094875", + "2609137341445825321095931245531863029306734693698914386115461720635228617677", + "18022833118482437226280994646426462585862398739142688151319660825030833751162", + "10525185277608968809171389414591123336341871721390818817629448578893073864965", + "6744998464824276672348708743166802119889279164929133576466782672127996471038", + "9344118411856392638882345685982595534877291739896163576786468663773481537247", + "5834845743289993456669132331911158234826336724070643002101495844260807919180", + "640787484559876348086629339096900566749702582335998287167888457763777550412", + "3289778183958313592191132419001427890244410850048418852950969831934946260405", + "21884067909485911557708530514125998779898644250629017666973972309955096019929", + "12413233158576537989326032313779399359311922621054801366572548255508592334846", + "19326971287642001797155516864971431422568657490079056599164481456075851978783", + "9713216558784550226779073929454993288918740379425900055346553812422457613427", + "18939709206067618242082635502394826733708666259540151764313557087718564592235", + "16287201832008230557120811959387085081039691924582377369304872636500446900292", + "5278016450516276499641394140854299047658079220708153291463991663971826612725", + "8340962164398516487176161966485950102648589482540787401234013926762930809122", + "2189360335587469104898894044890322510567148239646828290042687811234738731248", + "3449789621053765306024986494635371148296184209757783340117745997173900013891", + "9143283285825049929933624722851126967075894848265558258882809634241528781890", + "1762589836333836268173539283261821177424666871790048223025892425442664744623", + "14999716003380172870846520006929664713498492291151583767005426828389694408867", + "6657396937759865997077915983426704746176142403322137472681086594905173286297", + "15931240944401174032343453067874387364523175128749141502399457399279513999466", + "1093656103569127166341414994548826968375416499363412936873802336598768367672", + "15311996490740753142335607256171022029850671542830487572556180935394970969084", + "2114569000427676164059607854200438792707180857430926937778356703166016436297", + "20765151929972334364703309580474623940346949760797265180189525857343032900699", + "15086899750477019230037863517768898777026828694611906648102458179274814888575", + "11989598054307650119711820896035556261218721126425285775266572489599541225098", + "9091334194223602201291135947382348087276953920280768131063598550602333641673", + "662205156672119277592919023943339579805630811299947870362049797370818219037", + "1644010308269285824046398201622466330980474102922491226041283891094107089659", + "10802230809760799055453358968022894649048726749105153336410430294944584338077", + "10002812375469387387638524822236342839480428168589080127597945114460807065506", + "19156323136144190554785957482371465262949638224644638616894263767724257422262", + "17733486484176040486420248003268701811107138651833773383126692059485133299226", + "11591816707957137858747879818244290349664729458236317322129399152472444934827", + "13438697403526660565724658068461816155647612966569784134628157461074851140504", + "13266011411738324637226437761946084145971285033245245813436082422574964132769", + "19496324867803620550902836425197207665281935127556215366411961309085032313784", + "17828723725738030742535695874826508863700363541225603578112437608777873288872", + "1354878734330830246945810749621035198088901780682128075198035721915088394677", + "14191386869116296861827703975696048379271311137936832987484810982707013486938", + "19738102036337682966068176606232821315534061860926048846327720022609950683611", + "10125898950023999329674512710082674945903794489998271114320266993547905724563", + "9735132529803303628278600229677357854336331158152745512812889827254017680646", + "11236813353178034372164750145200156935906967316633703292491531523808184114591", + "2838710343346183231321901296981007702601287106254090132583144723338172491341", + "2260966150439461282635555159610786965904582998424984888756770014321125334804", + "16205138689269860259863339330838066928731455712034665818609854024821608206800", + "14474351689504859217283250911440109599364797953678136799363008066531050767071", + "6800897037717406782446195419208951974623496109363697062923841346454038837657", + "12439223794583479313810611548866683769924970108158641553689074442900057207206", + "13368632268650760591616092601174213792332738038582508245973036690611922918115", + "13045024155077800673372198196114071407850396125448182263497388710529843778012", + "15909614634449771616261546064207953846549526793661176217246033322484959782377", + "6286523689254946058242241932237494136885909209872547435875613686442878101066", + "1349982286621373054175291479185807897612755726394394337821103602455947583575", + "1790249021131563196559147247422502568900570496057134946620667686190353467913", + "6402193114585552816271289059052503078472437339555969654050634927290142355144", + "16657876151292774412640987426284773353540623435906797018927318161786869839630", + "9323926757990898215781025566456682055829536111985821344881754566754550287464", + "333557759600743416321063171376142987411973146341256173569676328325670137868", + "2979415176549537735678518951412460315394554685744871595392830851604961695296", + "11399925948142490745007741431204138659570087052831458877959853228053991616097", + "17621136800256980786736718847997675507300992679800923101555538476888606832414", + "19796186386112600298425768110232392434623500274218805673491160537841238382774", + "6150633696896276954724869550196553826388538976047912638783098883173888551921", + "8007744165470722314410652720217502653722691054745133622163922368886561184511", + "9311054107030040402449841855464250035701299963653145080544526434268446648883", + "17483374709267556993216232945834980676370211318754373298278341962960548363667", + "10342541634151745634549333576310088998125069092773405335947539258498170319639", + "2491113909032842407846736301373377587232014330531326042787834409966784029431", + "2868273648562988738033854616949524236294200717479306399357880720258598168313", + "10742331131465347969746591645056052543770202432577403033214021867405353469410", + "11262784136416067912059431910504651513874071545823747299137490135956765416093", + "1202953198131460912225596542947265149450470358249744433218140619832526467659", + "1357188592392022798249752911997083133072840552839921198518049365021930318735", + "6860322969159072475760401518666168198209741930191210869338776131213742985903", + "17512830541972446751364043570597924188477065675882039340228337890464360413831", + "11068769874220100931580712510878176008480346856568608049014134908792656846759", + "174592415638141512586004221919684850728269107225502531102930877822615095893", + "4529660791853304207880649392489892958123653811385478713812028357153062637877", + "7261086657925858393339848092042570053113017792782297779091045392687309229931", + "15947797860109427499686809495296483548232719158897790339724183452147879327839", + "20792174987130011436800220305375988411204569143955960269071283382992617027310", + "16004359657196683674112642475201997234099915262640166308760622340887283269558", + "3052232100533123772344258509339894427157169209304015026294337193048877370052", + "6932731371388662052904698619255543785138918159081404052613363170137706724722", + "18786344120940971245053939784556033915582618306965577644860589607674568931598", + "5543910602266336221969634219610367731229996706190750207556121552771043245699", + "21500331075127237626915881392062922706776178350223005349901601754581763355631", + "1647168321391235121087005294677186408057439085818209785557656918589059596681", + "18530920602212288118571329897791681729275409540471839847360270409798512800049", + "4854705606288041012191490612688235100018679131692705525031856778474580243436", + "14030500314224264714821884320124695887543721243139555484376859209010937666224", + "2929002685096227153223014766825090983318157894872369622190343561822695490151", + "19571082362460435625048830465870659122288859631947561605202388130763965600724", + "16262018111979731901324396497332329657354718141076944178560644525915310954979", + "16511368307044025445048172352133100276074403358941934299584092446434550554652", + "753252068911531248849891296487019536968643055711963719939888051839316478907", + "4925743538740679971454033971243400511986874154138434310761553437631037517931", + "6674573928014195188134308196945556256425786164998594495377003561132663149662", + "12252972387729677079741673273643386252988421977551152663330085764982570989423", + "8132942533382570630447992711549276375854208836400139615573300103975003948893", + "1767955113430187982507552626731364143386403228830412651051530991601802225661", + "15911785581735751807295094148896874484829666426702209837871379520505512480322", + "8457495441274725464495320737396221038491121993793647195771335087939175598066", + "4450592062983808718489321963811761580153883581981811699755824744572598554379", + "17594374172823696288546149573800906143533062920680825959471396256808502015697", + "5396987646216038506498234734744679865090292329649749592797349235509038812800", + "21252439428941443609961710022512211297072223091751149596182317370399721579385", + "18205060096578922655953660066798909616473486532390705801648322522122587090830", + "18335844957174152986460129513698965339432209604680688295392195893700811299508", + "2642745947776207344581721189041440984169021288344823913353017838424039626428", + "12274412791221963394261975707650556785293993588861677826296117405653175236519", + "9027620387743934195363518529726678172699541005293960006772332651314467807053", + "447942484646789701542537528994314353531710489288574350580201677777950035282", + "8057692910194936390243001022339132476522458573171096947792809940102911406995", + "12466422220613642034159029765007116066052620609909566451840020754182208020143", + "1171876794208841082635913903308771131102729703148972430947313152931064171577", + "2996001803829960955342682545650059577915377668754838044698518610136674338212", + "12306305078198172670943701974214620978597606399214937108559926306737496310941", + "1710451046983264379967941386456520655992388623198157754427123889803480356000", + "17294040628260706127805165314917539522165501484257724022309899345383198007240", + "14850723644587717617416204055806811021029607124589054329504158261611106696194", + "8626653016235921835569469801636971931942277275560421125462026339476626883966", + "16134665167778000757091607171765139146858141948472867080489695707419285323252", + "11129502792062576191937938132554397380912998297589916298721102071015359559556", + "15130530042530114554524440015929780266039077867502338045121803478767735700077", + "5922013411157909464044985892976718792018167710191222879749916950629215559119", + "15641877241146443425426298971354708474362723075989298367558100488623078084763", + "19807467678520679976886734556492012503982987205100734773481397135264223200444", + "7230620319188569738319728589376800438996515892335609872222230868954870926930", + "18168775389925542038768548563310374943094173375522704828602237046711660513509", + "15879478673208122828337915995586151196586860000621630078538789187695874266640", + "6026559623764003366786032824563693874782053604114144074018595121889075259493", + "6581629708588609217727738860658907189729022916858514019350636298557029783381", + "4392179832866307866014828901921327571555384668846640428849164693147430204259", + "4039689077078382209094762982217352133778072152116592303105622250221872775182", + "9439756845261909878224812875899975078023923372686432160229876632562036997401", + "6300039613750170323909974701574854925454386098696929245502563775636617169329", + "10245787402060152709811414110506095522941754087902005711632016024561712242938", + "10770509446150307821311775909967816156602102352374955635502734154581919715219", + "4445806424060983011786548514585153091691541530320683355086806781784085761841", + "10891448460108394317032887254041302638257759566726100966329794645560947944086", + "9055121436695773704587898653339600198373789357537888127317084878411452883579", + "8149630563292186659644235715307853879418282762593116603286751824944805128957", + "10164520096412584664920364217937374178249615925628067827666302990156368241543", + "18787580258401627795053641123916277779446570183960070225650619813208411270515", + "5840281460603743032409236132633000232507414411373674275076564056089047616513", + "1156412247030909285380152844453068577291565904060426536020772600017567322066", + "13125262001118293895463954353229315406286474760130294037415093324929424537303", + "19341994820951858136925352932235917695982462478372266716377719180643995594202", + "14230192493251599368583155353256194379698225636722091587422432258409725791125", + "18604655597949661495485553681980778009433340166469812699886221824297364988905", + "9484517765495232191823212744512718095318306206191891691619884709082351623103", + "20661548256453489016691122417433244991048818711049327729621550642733467464794", + "17946084952153038878596350204495193827996043096722462577062358769356218083033", + "9008616567490400741620365097652579204686050477332773331876377443733844010527", + "11222501299614818564801113661500553859475257082250633539503337648966645140931", + "17547881514301195137575407746474668605213387222566272868597007270413523256918", + "5795058045621081034219295632641782062332989904715400020698296776847639194943", + "10503000549984486673912349445691696940798628902104169170719393589667267164117", + "20627605141977035823281920467011832985049476688278934213570130229801586759490", + "1617802179061215386952772461423280627948056362689193604176834379576303877113", + "6791812933391289387114968397366223795809410677008110102514189342693442788856", + "21469327667867855439208525645169470185070216384607993883382520539336879692857", + "6209704596259199225388050030516880246912805490686902979517644524792187929012", + "15048235302521180373501889249113906037936587642496276368753413449431797081949", + "18778185090591194140890220889049934755279881763207537060835789721322305845157", + "4164373610491096709440557803327678927854304626112734913682240155408254130319", + "6352957909818668217728163741226734988658723962520906766539822539894434836600", + "2081726858060934846688892186400729209835095311388667168398290314717411097500", + "18997085104017244551079822479039381301947270057658366559839643454880390097993", + "15381301300391534710642382148869618456973733474322247178000572705046719371489", + "4198258606721523455517040976251319538290332464337310822593109666080121166366", + "7557782631251063800473816565466881793101085796415715068491278248627266080710", + "18931480224318877255548108668163955495398356426693160573742850933557366286581", + "14006438920977933743471268674953904657230294434994593269165676508225740552815", + "10552613214353127913757671512246056403297131067811718291694487016254806821431", + "6942360360107439367031353171424554084301681329082198856946152988574077265518", + "4821893567676204037011511732637248253220700045205121424698817536976139720741", + "8570797921121743873772790445200803600261480452613730673514117912909339929304", + "10210191620579364785116101817818502747961980686320008627354511305745123505207", + "2219514545666614569412405614553938185242666345781569909039944438048257115280", + "9472494948236350938478699115530847822498160599193967472596054792264811505177", + "1966000492511706985369338139654568276174679894528461227404736596640963023833", + "20046698515808110863133254224236843582890061845803004799852246848232152965906", + "844879645041461183539563036099295737132271525297913466134251805988318847548", + "4731835924119595590183070349774829521463227171971888362743688018910258502055", + "6665591397442095781758927683212527568272080607916992672135848576259567872049", + "12479020936095094085154050050726399793348028251321297846621658033596298393726", + "13547094394131143768607425506026982562580191167096570425566382504500825930959", + "14726791597032654225590630927699963688874228760066722543952181168729825328904", + "16458751398904781219324882164741165137205147400663608606201428995139003250837", + "1382702744652547575130131869708589984736039127219433507919721371542416805658", + "14166947289061517490924648855242003709961143010494793848406604325534604905674", + "17345393385322406098467895186375277399629828208438881931258894959842597584446", + "12612093274589904544460621781003810044552285394822234432357810635329000095532", + "2278721075910399058699498270814807833560549835812826924195171790394865401759", + "1421362911034706266530649492401610048326109063529762443419685870164992649589", + "20384150845787594899080953437004222732830782572958598551146508153682280572403", + "3495056095843097816017033529053032886550694720911641681721955773137850234745", + "14487246717687560703169821216097612442592434246076605506691782211475316706576", + "13114661974362015466065924612631881453272278776220284208159815065535423486323", + "9628837478322926908639029641093928246719582225562091179037197080152788423316", + "16456984127855989467975376775709400558526389914848937751741445859284106536098", + "19656266549615253685970702218272816322599871270060998775752454696892588799707", + "16028536897482325114555541492282064621526855756620164892739323385311597784598", + "11146275353887579825261271116625263398084632057838305651534583557054398181584", + "1266798071261939757558459653520435752781168817699931045808536221140555755937", + "11242956579746912399423902926753108012060763899073974272480062541403588053076", + "14588608018127887593991920960165305144719061971763947578582110087376128309227", + "5393054051309402705329828859286427425185515439646193479342950065083063200985", + "18307950351265411595229078848795494559405008993794506472277342386767679169011", + "743926999062879465491123202608691059211244131659206478586545917792531513741", + "11450449580887323007201214040662031298427088361641716342102428346626191862079", + "8918057399138776974775397421552812822591030597414174436378830421562569121660", + "14007657148016840281780221954150751472316590653604019267269105557294795817454", + "8897431240575139049076571283304115052162507033543918057893215164198174868677", + "17409416377040437657574990618884772475255396933561856228823381810258648281132", + "16403607054571283311114350132750182990388190855449188101005849970173367695642", + "1508877263063909922036861471040526805004287450733006660015588614987220564178", + "2405929790914208591765690668430163058227989428739435027301989746453297508008", + "18415257845847977290620817418058909465150962144437291827522053905306094819516", + "20783625745588167215135121578855692267545194811392233146323762172638833678083", + "12583735518159929222168953087285648797218797099708802919538903595273472024870", + "15030113532753402263141105846533650021837620483920708638977418255212037916690", + "2044646201923266135898414814098969242685760821863709223961924291978394037140", + "9562505824238493762747890608580676752653265912034931437600706699047478680911", + "8576622443481230638247834729157921300954369512398151853927361194153863723577", + "13502467573105057302451195240442043465889307076796874707692282952243564124313", + "8659508751425384756294968991737225118186991099981336883558347987313410663071", + "992836427155144083079734949008912409782777055146977880211513548288277680936", + "14478698156814197173486553402886358323315401752422792440407576984439553283243", + "20204662700070586254342470347097589341087597032672938910846995633724257876133", + "1812172830570486768023198219726218583158255123460220955281515074543933097836", + "17992769749806193849727573532001735714323064233429371707200828907106131204931", + "11275304845104653478990825724663443324387792098049434796341439810037846570595", + "11105199526118828533245892738176913532701964584183761946009726630431598631704", + "11393903979182757061241357325556769026145343989318381225525091986823175945546", + "14383047179623652129287498422471395756755287245693820194038638652931729043624", + "20453515719997662355844823439261666280107449255435062001366805179715649416520", + "16342434030539357589118587629035849207895930777526269265833103191510088418049", + "18401618409669783606190734020469430253158741609682792710560527808266513994586", + "16076963378432439787360187815002671229026877629938245603309362816936414414606", + "11529521787481754741418171353792184686967806427253956770441456297160607170941", + "12602344479327416239042579290059415968931395895265775848606068378636646131638", + "7874996576706323538862472352643073872193797790899948188898578232811415974069", + "4845431324532575010258701269749667428252187973009639700566740844013627970107", + "14802018959157569593654049670448062053140035551074745737518084801052997376690", + "1438261891736096301511736944301645044858355530036359764344568183983865122024", + "9702483734495711444970258278431697259819553205295174290488141405714571120392", + "745629299152271704331537263378566091569916279264951187804590327433939503876", + "13647050656573274198980106604763314305257288237932552445752822394869548724758", + "16745795700152546519998532820179128558740146524138261377398336069302091938316", + "6511309643923082597828923519243281993300211181014429981003702021394673484309", + "3158509665257424804238893020268668038794684527943417360064521274731483365497", + "10106711021741632147292275661510721445094446856823798214773373487329113893162", + "19539597394622940270506324036474158048415508212083560312665281444636039358507", + "9075752841443178653052367723489194637305474480630925657941805297419704103107", + "10984322959292625191378844945459317193701661510910417025411449026843907121641", + "17927313671844804578171839390174936993766288170716470877087434657482712787254", + "18872143162724264635018175304456023676931184143071101308504884978404622981510", + "20515902079806118899516548385287144085761546545950360604606371922174253859996", + "909520465300399063286844098900959690198495601569624327409635184475032912958", + "20206446745684213293565932220432184473350758436589542174203682990821527627997", + "18202239467972118142408259480727588505962487821013411792329301914239859726481", + "7983919062477498484336722979137049758716865253938030483468589967847498836327", + "8325614337212122905531318376855865321332189692321777599447159536409656516919", + "8597163804726192574292212854626326634508890118939606311848139014738137868745", + "18500944130179290196885189330659070775829081695220678669482033354888226989090", + "7688562031300833340110739922365866810835026837265955101002957176624104705373", + "19947182975808967149585827952170169153114833389807259043148589247054925861923", + "21517453591126354047928769118216728006629501856431780724965733122370735013602", + "19724728051616532722905708549906983762154956430000563385110162693578183573835", + "12901041676897371025108379309395257314967524835524863357724200518477312324601", + "3552976975075178791886580855175573474759766023206417049453393296909032090255", + "19723727023156957738383690313848921568395238875690539785344406327140649751346", + "8448482122526118108012095036728031952881057181233719818597059954973230302598", + "19506723656402269183886569439436103718740054288352928129647596321989076586438", + "14170198227468034198358292107569967739463050831964193487443803219358410981401", + "2398884471809169728404698398912564280110318964918284340553363751754870608551", + "20316276154960569208855163430299959763482642890911503054443013025286320052982", + "16819346170274370820168489515108636849055213099894018965040750518138293949687", + "14032485862625099598391073907784424901699264655891124043486362510876557553033", + "3741512032866709198636578814340035900693212341083373891378285003365821212725", + "12320998007117681710156579111620440763582440787871319835484669927670822914066", + "18497785580008161471127317447391820533755559610828409772165480020067085485597", + "4405750113669275276872999085838121306688869906871946649397890860602053182664", + "9830919490764773329556696442544208406733862221424439787824742578837854955405", + "11656214840454358128291973754562337687978444406755233034850997851692380129929", + "16862314752433119612255838474361565358197526603416756657147704910780503202458", + "13994730783691699927566696508271362101008053907735972055086535421903219406757", + "1854398114607336170485701571991055833572643201188015258021784624866312103211", + "20069390379729391520654648717585246938403361904664791681209786618785720069963", + "19778444821535136400266636630030874919578160245360989612631440824622767847607", + "21076683052368294199461719450518198858527944040936974409849054794891242446768", + "20411961758852468040955165630870750226459296665790953169982230333559560296737", + "7502887992944485334895259919103098713153732704425367381733235650810817022601", + "8197671201190749689041918593081864258260291777801687985230863071067546597951", + "570474345973383626887611250305231463005632817815912456645561438458026430574", + "16187881277000098252637261715701961539204559080071010626416256497925074197451", + "11845760454453819227975628605163841650771493308562299599588237256809780809041", + "12496905116588812906791602937225630677262600876144492834414412499317258049345", + "4202178453449927253051431595142836159883278283876420191896732301089503127871", + "15280239602029688372093391224297422856227971384132785248484775299588777602819", + "7675624637796659741242134119256859966414372807758392029058215748145801821134", + "1558712828795805480069595730092542425736929845400776453853052297930907571419", + "8635050664405255712941235442916789795311088451605341529181390886210645594786", + "20012080883240845774134523050094772793782396855825781678689671532280266223297", + "5332665745663855702669515489737590813722712486482340264533181716182162216492", + "4485713577378561256572703202440374134284884194291407499970429041545518915674", + "11594166683437400908552833183389222213106302657616725421515671119008232951402", + "12334131761060442183744872783660449330900007808735685674075245978195977188916", + "6469473140282499287719023824549928080797880736382216700350093546124693991876", + "9636916035199580181413428196442500662713954920605937945590797926723030993514", + "16259404193045476674338459391599179316200568243819582010383092764410171324132", + "20780929014533211529148194875929589500835169316324843103846798105106103748435", + "19665958036420604957261288306620614439114405875604211377014353932489316681936", + "15722491897648578237100473323139351762887860215830601049261437931157637153597", + "20474814639824406443111360000192533367769367587690127965461453022108167666929", + "15306300298273142257702357120212730128497075786589008381550108606914393296015", + "19116371381269652319147699604019975103087973589614811479290794650138683901396", + ], + ]; + + let m_str: Vec>> = vec![ + vec![ + vec![ + "2910766817845651019878574839501801340070030115151021261302834310722729507541", + "19727366863391167538122140361473584127147630672623100827934084310230022599144", + ], + vec![ + "5776684794125549462448597414050232243778680302179439492664047328281728356345", + "8348174920934122550483593999453880006756108121341067172388445916328941978568", + ], + ], + vec![ + vec![ + "7511745149465107256748700652201246547602992235352608707588321460060273774987", + "10370080108974718697676803824769673834027675643658433702224577712625900127200", + "19705173408229649878903981084052839426532978878058043055305024233888854471533", + ], + vec![ + "18732019378264290557468133440468564866454307626475683536618613112504878618481", + "20870176810702568768751421378473869562658540583882454726129544628203806653987", + "7266061498423634438633389053804536045105766754026813321943009179476902321146", + ], + vec![ + "9131299761947733513298312097611845208338517739621853568979632113419485819303", + "10595341252162738537912664445405114076324478519622938027420701542910180337937", + "11597556804922396090267472882856054602429588299176362916247939723151043581408", + ], + ], + vec![ + vec![ + "16023668707004248971294664614290028914393192768609916554276071736843535714477", + "17849615858846139011678879517964683507928512741474025695659909954675835121177", + "1013663139540921998616312712475594638459213772728467613870351821911056489570", + "13211800058103802189838759488224684841774731021206389709687693993627918500545", + ], + vec![ + "19204974983793400699898444372535256207646557857575315905278218870961389967884", + "3722304780857845144568029505892077496425786544014166938942516810831732569870", + "11920634922168932145084219049241528148129057802067880076377897257847125830511", + "6085682566123812000257211683010755099394491689511511633947011263229442977967", + ], + vec![ + "14672613178263529785795301930884172260797190868602674472542654261498546023746", + "20850178060552184587113773087797340350525370429749200838012809627359404457643", + "7082289538076771741936674361200789891432311337766695368327626572220036527624", + "1787876543469562003404632310460227730887431311758627706450615128255538398187", + ], + vec![ + "21407770160218607278833379114951608489910182969042472165261557405353704846967", + "16058955581309173858487265533260133430557379878452348481750737813742488209262", + "593311177550138061601452020934455734040559402531605836278498327468203888086", + "341662423637860635938968460722645910313598807845686354625820505885069260074", + ], + ], + vec![ + vec![ + "16789463359527776692258765063233607350971630674230623383979223533600140787105", + "17179611066821656668705197789232102741366879862607190942874777813024566441829", + "18653277315487164762584377009009109585010878033606596417396490909822722930739", + "7373070639853668650581790286343199505413793790160702463077019294817051722180", + "4823864393442908763804841692709014014130031798360007432734996408628916373879", + ], + vec![ + "19196309854577132760746782449135315310664418272926255500908899397538686486585", + "18123132816088485879885148351452823314623055244145916622592591084094232513914", + "18436594886553181913092702411547018228276047601279727265790147051821171174455", + "15167500404313194506503404655898040457721633218143681920692711693000769735187", + "9437986152015460505719924283993842205604222075968464846270136901243896809793", + ], + vec![ + "21445376105821232747280055223032050399373725161014449207033808524504027971613", + "49684738714301073369749035791061182456037935161360748355432247732088942674", + "9826409059947591908303145327284336313371973037536805760095514429930589897515", + "8494798325496773219358794086647759478982958403252584257436898618394561204124", + "21251937175072447337747316555423152807036003235223125066270735279039060889959", + ], + vec![ + "5539100337780919206842837176908516952801756637410959104376645017856664270896", + "6297628909516159190915174165284309160976659474973668336571577778869958189934", + "12792263637464508665199868777503118105486490400267592501708855807938962470650", + "17254685306085558791725544672172906900581495686070720065168939143671412445514", + "3590396502942934679818900672232030233017710909687947858184099000783280809247", + ], + vec![ + "19055249881366445073616526879263250763682650596233071589085239500077496415637", + "7367697936402141224946246030743627391716576575953707640061577218995381577033", + "1322791522030759131093883057746095061798181102708855007233180025036972924046", + "20456741074925985565499300081580917471340328842103779922028754640077047587707", + "9059147312071680695674575245237100802111605600478121517359780850134328696420", + ], + ], + vec![ + vec![ + "8266021233794274332054729525918686051968756165685671155584565440479247355160", + "7947823415909040438587565055355894256799314737783432792935458921778371169026", + "16508811191852041977017821887204137955816331040385276110261643892701458724933", + "1804800467126006102677564831888710635194614232739335985819349312754063580223", + "11189892034806587650995829160516587240879881493093022855087765921356611070470", + "20567450145123179140729389574352706949280207113956641415022972885523439610844", + ], + vec![ + "4666756311257455192796774305229624459258864488677689058174087310651786875914", + "11389253665835451896363091846189307652796786468610595637047377864063404843117", + "18793736599347263150867965517898541872137378991464725717839931503944801692688", + "4206344588923325482680116848820594823631536459347642329098796888497153867720", + "1739462481670645248707834504605096139894257554120906850613041004917967456145", + "18514227342636266640333254638454588508118462110178719555586534011641424431745", + ], + vec![ + "17887039315911403193186866703775654467672391491657957999455462537283842145802", + "2824959020572825365047639014537190268717891749361604043531643698340708119767", + "12521547103713919592301476538318318223836047611311454785951907894055964264287", + "8658146183671258251984364885894342376430874614261222570603159082682815800788", + "154390145585284450772861151318029820117470958184878116158462181541183085587", + "7593705166056392393963956710828665339496927193740869686529339432486182720653", + ], + vec![ + "5529559239163081088908568555890212324771345012509269613465629182165427812002", + "3729910453162885538930719732708124491456460687048972152311428493400220125686", + "11942815243552870715777415109008273807076911177089425348095503288499102855779", + "498938524453430895689241565973888863905147713935369405079343247530256066618", + "3976257517234324421403708035200810671331954932478384823208414346189926720724", + "723540703523219510043977323240437576248315561543814629392162302024056718473", + ], + vec![ + "13306548824219676333032339487546407241767961556934015003605485324283250885682", + "7970147269291664639740298762956131361316495463191268382513594527221399186752", + "20633313939958767604804835838065337107615699351647541991788258289962727735454", + "17162090859520817529294904484646695645841022315617926715432606252643123848792", + "9181379842957190051440498041153333325098774266789773971685141362947015398641", + "7051606617662816798224904133351061549832959857069896192072217769241273559278", + ], + vec![ + "16619522548478824222688310091434959542211899852679631815023615875678448806029", + "14965311177811968100298579672135357167599499478246106482433786066289128683961", + "9792733250919070275775594069208673385381167169182805600474820364274865306108", + "2069253833779081039049908513863485270550301879399727430830923273191877809560", + "15847298987712771667136245955631872888473964330474501593909263901393348546986", + "12244443532166430060291409356011430759892629145539185535677568234713942157668", + ], + ], + vec![ + vec![ + "19332164824128329382868318451458022991369413618825711961282217322674570624669", + "12346323761995603285640868741615937712088302657627126374070962894016296466118", + "3913895681115272361294397190916803190924061797587910478563401817340941991811", + "7048322889096718105055545382948709082135086733564574465991576956878202831861", + "10375086910057323893637057154182902576957472442368661576421122036461645295833", + "12765622911241487148932810040772504127756393086809438933166282251044289864727", + "266900212758702307861826326591090138389415348463003233900705815890364224151", + ], + vec![ + "14435131616556129905356866638030823183270286404767286105643513738132789033353", + "5780976801287540146775934937953368730928109502001687434229528186520268917700", + "1618320442446662026869390273942730786145909339107736579759397243640902802126", + "3818399583522206096165108192531271582827953520684743806492664825009577810261", + "11764506724346386316602508039052965575734225646587104133777798242528580374987", + "2414215974836165993714858157462355581258152126063378817495129367240311967136", + "17609437036230923129211608175600293197801044251801590649435913902851695334081", + ], + vec![ + "363438080029711424794236047863047716381155074181485245036621530063262917196", + "535766679023716739184211613469394818313893958493710642899297971974381051070", + "5305068908469731303772738758164870877638068032868328180355958394150421214337", + "10807632568240507366657354568432178961148417327580695024415275247652313539292", + "15964415873358391713354948903242729080763777490509563223190335273158191600135", + "20700362719972015883260687302741075186857660623182772413609788566925949033885", + "10135127975676256977820296631533839366076919827597067890970660746228807376456", + ], + vec![ + "4251490167543116819728642817282216847143714366441358372252125244838181656331", + "7745587495915033527847242564710473705100826890903278244320948416581724663023", + "11741113129223221800185946819924457344647035336264986754437921049066977440806", + "11630296782890656599545188109639399768829653360050213193782325240600583381364", + "16861140446185941149398487176581839232380972247302922484807333229513905651035", + "365879246117123675211400356410703684399715291171114630107795112994207447819", + "21725607857580053522363567649763546934441685061337033780528788383243719579033", + ], + vec![ + "9222866548596464928765000608129177609426964853736257576074550520759533736918", + "10261578281201197531384003420612639018011405529775212563256392340336951230146", + "15644037447921591571869862919382888810859308861783088910843592577202362807673", + "12752004188139535619565478547449108772137477456363099481095747591698702436636", + "4205805109630387448825516813913983509046636797101589615147198457314360427718", + "21047095155106717901091873146599497621258071512562421967648909471775919992713", + "15624165295872926124160584750951090817255240214488120310950503163805737026315", + ], + vec![ + "15064589937731741958666763896598138037875460434244947486199623542160035749721", + "1801577872277160959016940766173040841160105238799805406938450020949902989173", + "2896766420608048344829901127120623317655260981420052771341833288256800199953", + "12828791469509204618898135640019714232831708508424682785876476343251730674999", + "21363471986981372923191391880511344708743312828234098289107697080824665183315", + "21372706354350795416381912271616633829725494570576895047490974943034914894898", + "16006531510217730955981102005088687858079561573088629102219485906666961331083", + ], + vec![ + "2389357602244845938251345005183369360523566673990464798041306722747500447645", + "15275955107196234672088664710679934029171843237458844492987233368659104714648", + "8038797517535218686870517662905230585331773059774130312418943649247287196930", + "17923922393436914864421862212181654800719733137689602673604754147078808030201", + "12890519745320143484176500044628647247549456778462652469313611980363507314914", + "8058516556024397257577081553178859094042894928866720408652077334516681924252", + "768425396034382182896247252731538808045254601036758108993106260984310129743", + ], + ], + vec![ + vec![ + "12051363189633051999486642007657476767332174247874678146882148540363198906151", + "6387692555402871022209406699166470377527846400909826148301704257996818597444", + "5501161701967897191598344153113501150221327945211106479845703139297020305204", + "11704372055359680530622226011526065512090721245437046184430227296826364812961", + "1448611482943320179763394986273491989368427112997509352702795612841455555221", + "11429145481524962708631235759094055797723504985787912972575745356597208940857", + "18021858528471759023192195347788820214752298716891162685115069036283008604659", + "19817577944622399780828745167469547332167999743980557486183403063955748437619", + ], + vec![ + "16868980302925985719076889965831700407328155411673408077166038059874616424216", + "14717432944340806781505761211058502775325970511884444497202848327581753493322", + "6273484270523289845253546319956998489830555038697388950038256377785540828355", + "7726043103954429233325852791166106732104332590864071922310309250010129731951", + "21052353119157611359715869265647287129868507410601603360127523286602350622783", + "14881796557136180514390287939887071460258251160875710427576954128871507002642", + "16341327439981153879863707938117355436152690262312411284193970279829974799334", + "10737675906107372302108775622264379258926415910493665638388971468924879578019", + ], + vec![ + "17652699767629314433191915267767147860052614073432922215674211498672835339113", + "7457854400138129895665591719907473144796504905294990100367501377050420942800", + "2136850802972823585140870808569264373787409642804109426616292140046700710743", + "14029467347298896610468190615212519453678316548442709087191045978401072380889", + "17927699952921266007590534383984238136710494507499176330493504416180410161683", + "1404719213830610030709583332543456268094679432456284386108188509031502237811", + "15774757292079018355173698870903422490868220545526384876021336136892926326596", + "13992040374687149195439840459922227749294794072303579532004750946306028893274", + ], + vec![ + "19895094843870397064274579657905921299619388074084417486420154568847155746891", + "943833985612967248618844364501030453998731991825395875139617731659343743483", + "18334641092245356682448009823797080853859186519922476229272838591594967878678", + "12440287044655505483131716236615633401781045711053210640202766768864619378050", + "19130942564098572936370308509908873069169152245172660555660369853346605570826", + "13687979327148217614616687417475244897906227789285703940171633508277844471062", + "16887921327479880141959363366262254722342925451159884082370074726344024008329", + "20378003125024698406589040864014894045124234695859352480989552885205935609512", + ], + vec![ + "9961553412530901953022991497331082655746860319830309417179972582392489275965", + "17755268665220780466271147660314410613992814315871705414495724015443459797439", + "15394131279964876131165951719955566821453162041574233072088124095626652523043", + "12668230348320365182085867728169435383987570924921845106243310905832768752125", + "14046812111383844816383347755263287603387502282980410255379630204396960343368", + "11590093969266595252327261214735156204516524792938909229175092594303424141199", + "4623517074925959322927421514289132524032863498392441375476410779446526502799", + "11550389531965919926150256242174358326491059727918559332939872696684299343135", + ], + vec![ + "408487396317981846281976563618407581852133413686169882346565860317912856432", + "10717757571561029382519744040791773994731123262749372629687813122941078154016", + "21323787615496251932181222397986048515693661833099659753170924658480548866921", + "20780799310067873093555276926357624414275975377319941015818682052081980020892", + "9948385944800296129032348634683354181546876394979291412116493575442898426065", + "4957033413111065858035065225611730571499258914257595411830870977545212164095", + "5227254936689728148737265263965107718869714128941995977191096572191110991079", + "3582814872786080867997255427740166393615552773099677831398251586195329933975", + ], + vec![ + "2136737803483410555580163900871515004623198990079556379647848364282254542316", + "2965752098571712086281180512370022839542603960309127077035724860894697782076", + "1478525086510042909660572998242949118476342047444968703549274608283885678547", + "3563375996604290844805064443647611841824012587505923250907062088840679700555", + "15461452581843517997080348781604020486994675070532901120353124746087231692278", + "20472517020063295821544268171575414161230806406668271887185150097779785573889", + "21058001005918321995459971112208002381460494177332965873048074199074929946172", + "15805746645980285645504697043988763170971539673993759868487715403982423015009", + ], + vec![ + "7141240965656437676130015766799708612940092856280620325870466265817008351948", + "21418010338098024788434337801477243267248314524079104488811186206038748626642", + "20272108634229595317682817969506273496034097230124371921628691470754475805838", + "16734095147399743907618148751687506877774623133599770145304816136018239803101", + "8439324632051181834455499457268557602816180314723268640869118054114888151316", + "4953900961796661020464968131122569974581908893169105485631905994366550928492", + "18071625983692455679240094911529791119099077429122520426399552756115503123111", + "19638917592063029281156873227053827678889868373299664608974791764751784473040", + ], + ], + vec![ + vec![ + "708458300293891745856425423607721463509413916954480913172999113933455141974", + "14271228280974236486906321420750465147409060481575418066139408902283524749997", + "15852878306984329426654933335929774834335684656381336212668681628835945610740", + "14650063533814858868677752931082459040894187001723054833238582599403791885108", + "5582010871038992135003913294240928881356211983701117708338786934614118892655", + "17817167707934144056061336113828482446323869140602919022203233163412357573520", + "16618894908063983272770489218670262360190849213687934219652137459014587794085", + "10883405878649359800090160909097238327402403049670067541357916315880123123342", + "7439184039942350631846254109167666628442833987137988596039526179738154790587", + ], + vec![ + "2727663760525187222746025175304386977552466570311228286110141668880678011929", + "16992375884417886634716738306539629570444547136030480542879886913528563834233", + "4178586893949624406750122665277033849762243490544460031634329370298105635905", + "2517914797385699886738929430037355069462619900197972886482360691236776726214", + "20164173810534657634631187494276970100735049909727379228976555863615716408280", + "19970958827248077001061220127605534603528515080207197493660642269195127427214", + "15606275977308968307194602612931727810866183872589808138812916593200446820753", + "12261436001550634140750381230737452634746867040398895669545077774504957433511", + "10405309809257831434323731445544896504541938387524726028487604098725193737428", + ], + vec![ + "13408856444092113657034337770571899796129642125690066226794939383190876435468", + "19768080898957882918527124226120459667739640387901357739011662191034806046251", + "16749889646056241484852997428132695501278739424507088920371060969471495213919", + "12331609790192161246735870679870317366088443875784324655482358218146673901073", + "15769331739277556832196167201116801527901089923090632364403958141614820528626", + "5227172275505968397128736045169568430462701766148126842874241545343535393924", + "919073378344729780131814412541912290691661039815032069498359347682919854836", + "17858725475505870077023114050620337312678855554361132257763133392017321111169", + "21805188450184460363143840112266872832328782034569970452376470141743078343745", + ], + vec![ + "15808413311863154368918155104905222670782553225279887458053980771135357021692", + "12828907214414139667587331812274388831051429093098655261887619166452245292431", + "19323880880917307340820066456419195877039970908109908221992925424585030574269", + "17591732412986269470826282099678922890996647592922237928486497997144096433314", + "5282593184575641056912422403901924986019740793240905758215569065763629999318", + "16013130707598525718519250412251656096494468043256226360413191733653074896117", + "928381583587170989315021718439506896903185927814675820160976165627097308915", + "13354336789663524324458402003354905134416094005220899335023797754517805691310", + "8780135673134081873589118311874067764073719549433574820315100541871522642766", + ], + vec![ + "3334957744389892864165113989538814646945861179021194859030934481494560681812", + "10553413566358881045095498839713459314577909144176577153981801574128014927353", + "18894321506279909207228932263261226433242541255661384643559047811974513999438", + "20211894014628303327332299342564779073614790317614402383971270594430055013904", + "16723480621932556506775906903415088312771104391224076734252099577243237899106", + "1131872547334579236404174618548801749854242069301712398106619948805304881636", + "17386814048141719093058723520379257085987299288710382497237609774141718421404", + "13729980537487612221640320393867198844745491357830417754869369043292518007370", + "15860780436383591737179656321807464721751913977397035980422407138400867838633", + ], + vec![ + "14708550460111247278740231297332510059116901767161326454481923990389610737973", + "3132820559166321299152015048428879769905404947939291493327190426785911502819", + "8658132367999084824971296219169212568783540935524918908332001856872807119287", + "21064783047501777742084787259676320053480170916619513986794406566953069418035", + "20731000104011695148048713576219525164619502119638555785381543866326561323", + "17189725817866212967650950297463469529475851286172280116066228706121595462088", + "3310440878606659516028312898499559492876015493892608849966645073367377278233", + "18463918215326370595980949760897480127622730018343709491036454088497976892863", + "10894192430593140913557164014343360386192963621862346779515699758352916852228", + ], + vec![ + "5060610877870389107953459328006060153180283860738879092399406248484265273634", + "9068988823145592214189961315730261367007076042069390630024839612151270430414", + "13160707893890865447331361630522644819624543031829773191665491273833460019183", + "13920568292534026180186486064598876780779571940988254327823480971820885713801", + "3894011501178134026216736522445829906312115650019712122802932677318433032635", + "17895318821130376385979570244603067634449453259842805202694945793852667231847", + "9777993060458301797155055013115849176281006051494461044565335406558308324220", + "16521293541516305251718414192107787058980727971856888501176820100904791554730", + "7744063601405355255689420547832904761861257642931934580021876189691881462544", + ], + vec![ + "5444730929053688962452159157646022068806222098484627080046464163159451208522", + "1524118152994294864739915388438939180298324297960159419600850033701763764640", + "1334622237342346242862023763160346671504959163544406543315614662442562816653", + "16126317914306849967682996412350336172782726693375105190424151365140854833923", + "6345975085253358297751050638846919833013142450462810543971050115910612860460", + "2703875280053263252177031410407166981522153304496807669518295313468095058674", + "20550626512184448884716175825490086259235894802178999642552696391947509065676", + "15013718986700828670892638677446258841869291160144196138236407826511808592486", + "4682264015512203762723381542642871160915706748420642731100634327658667608042", + ], + vec![ + "12834108073603507925748862283503586970613250684810871463629807392488566121352", + "8422606792378744850363509404165092879785007388646473871019846954536829739979", + "9339209090550177650528715604504958143078492516052997365409534971861874881780", + "9141831918422847136631159987994781722269889810731887947045878986971886716767", + "18329180549061748373684938917948729366786279119056979983310618862430068636631", + "2009551904565170718789964252583363785971078331314490170341991643087565227885", + "3859729780601667888281187160881197567257456581829833310753128034179061564519", + "8535335342372994336873304745903510543599314397287086554558824692658347277251", + "14148514289641991520153975838000398174635263164584825009402034843810351225518", + ], + ], + vec![ + vec![ + "5029285279710800539227619495938136407778783814400587102957398897867261120664", + "21661833903534656620291231766157513264428291380933208423519374035927473262119", + "21013170147855726227668315492699186959893088673047129690411646575996043835024", + "15893628062504267735591398483514002406192781085288489283447316241330749546879", + "9860639032243003377544947110034203265885715041305770375052648470285182020229", + "10431760628292478929366440566994655480900443273305000842144090945543100651218", + "4662341343242273661833461144031815716144681076466659112993661636426666579986", + "6674279191498784183427663914511569570797862586816649467168170855788360268943", + "16895097041920841073767278653214275321407577186751547609698446652984399225877", + "8168606076413192332279322347673356872630772122089948509553934257426773045038", + ], + vec![ + "12091567755121016869657080116466607855522522017768906776539212195551888602502", + "4684576201081771194613696765517034834984066296253124029929753160055156611363", + "16693488266039456124835102259365515976900969074532557489095946797080826193662", + "7638443036775258881709317582832080783911189229963788890221615286494482929025", + "10111436214822932149781668218956845833675824936886829015449750181332010388640", + "896682691957564465177669890535917423987915406885797833670239687119295318467", + "12612639059115228106858238115822505521432423470330120640591982767272085175034", + "1851711744209473345586117150836616408053748535684022739058625441026889320297", + "14132260688735080257390420980422269734275443926576061985351678038992087770902", + "487493866037948515547037886552479973316400139387425953088274857424154262588", + ], + vec![ + "7712516772901240105339429973116360243232161870164307482409826131312962380842", + "20295556720945067049585659016570679551265845058805648954004989969704769135170", + "378208946912325140295069471345064814132951473534378635003955801655986417900", + "15111601008893945567629460471315838423301021468457758533702272669431620017222", + "1503682435556321218669089857094247703956565058167121192612334331910088441071", + "13084874799693933186811120569396911285611047490876409383659779579088985591229", + "17464483161247836988344436558341194021876261750085348252730901647076441211862", + "6628743087463083391707355927377412170189936607932592258517748766250528223430", + "15153763588458144568353947674975114179172744555450771328418442212716084083525", + "11217853102739260248713425002157925483291370125178251466195670948291389406199", + ], + vec![ + "11275485266433075885440484136400353724892671196084163231314370685019444807048", + "20167106354875398113371399754994549089359568833089630824992752829251678891797", + "14151330869211746069130604993916224881047448810615413435448712767752320095045", + "17260356243574396880210370581740651566334589568095587416844511054569255137183", + "12436078462666286197074526218535647721230687376129721353230123441759960021666", + "12001627458343654011606323250787666795709808266974343548842843520227918922255", + "15944850302839498288636342399223012131590208876255723227505947857641523034493", + "8444103924869263585176528654612076203716402818569041992813095331662367021655", + "13015682914180762871967848617514355587762125694235380084430680565032083402270", + "16200183380426364054409550129683752323493215428097334915015688753327665325485", + ], + vec![ + "13717643109958965551675619584464549580820722892266661529182798599670194908199", + "19801725181447377274232761944437523251067599053402428862557912155522673980500", + "8260354277364856843022982286494019620277496829494935775254726797533957063267", + "124621144162335766862972192337737579448571172779117809776129849377329817478", + "16488884047551411705397223604196364132975353217876182634038895586664127388979", + "17336432076451490238716890901095007360946878388179175784603587179384718443321", + "1210338460555723584699132156502555539583432069430631008706741082485009017102", + "5933432012048351362807861976737945204535374770355507745694008880123055490802", + "5127952499969178010015035020598142881788437616516517827214405489972695632240", + "21100924218139544842807404598627913291698574448527131003096325470925085906016", + ], + vec![ + "7683521602764604419863026286445694988900727173175219514555132623764360793654", + "20928394065137007852706990901925870323120588543710137320004640014111073449000", + "21375535333469484792161302750563386607223088895810564711097025913956371171769", + "8663517227154706072248636076587789834246541965140682871530851124960776424787", + "9182938389356039217318590654716613493414550996824701664670650439783557720226", + "8327338979442122743919832154397496089418582414082199116629974300650113777515", + "2474727241701323049333019668054716886184808783449917153147248751503852312804", + "8543922237501430855864877057711792269479294116675004771113148647309219620030", + "7863611214303285947093025404346084345102544167615769255495752297507346719791", + "1448902069752048144992778676670381235906144579949631101518897035253311063307", + ], + vec![ + "19501657783346989621892787238946890715709847672294934508902622542828235185048", + "17076525025777667838921778388186176564387475624769926249793144074465528465933", + "2381176586418291387279201678056498732033435079507661703992537801751492053086", + "20723508866659831749949206314442193102431573526415976696387848305764994281574", + "17461795780729443663350296040956479984433953861306521086706732257263430387445", + "14849025218838139413138931958408289986915143240245452275066866730847749323920", + "21207204042106390965753782189145584243052148578812105334769740484186308017901", + "3105302592226642624386332562899903659948819667537402316192380465808886843623", + "8765266846991616382097124552983206033439769882065573909634090515268812396114", + "9950016446092650730639179912416912603745831292536616469358668786853463197224", + ], + vec![ + "11739731747351277092817771330729393674312591071236310446088293450266807414263", + "5424991773995591044103668717299468589013142114099340604018933512575789323446", + "14582885509715812510585748465607279869582209618804039923778041514988867577359", + "12468934763690970929325823037406509081405444759649987929912706732364016057892", + "2792793293657306144108993077959195845478902430027171873963281969527327256602", + "8841327809851437433386666692145437950603022633472031964220924157605803799391", + "7845859360796082275932181771457755704129556353505380746504571839006944723429", + "10731793207832149137187382442869034250153492853628224932026933458041993639295", + "5597792614864287090861003890414825257635680048696075527563498604714157576447", + "2638669099010916296300870639816763122907432841565512299246441500223692345671", + ], + vec![ + "7150832464835357604208338666096132398994318721877322228060899549998179405057", + "5470477812928960639347760417261508685840724903499112719517942324191018679706", + "1063854480993555660259858748055514950231824974684462401269695511649059715242", + "14508243449586598349750829047481358081191713699373322296041764577478835760927", + "14872220983064543437506211589956319796231014912750035729896461676577407407598", + "9523202653584689553554068772241228948237208444616905879849472383190180438058", + "10557133197819890801524243760013157188954914093770589635201319240903423455316", + "4973822148190287060777561091733583032026446820262414806412485028147721872972", + "12017319043066808147670914562193696608548297038020764496633388575589573229927", + "20958507279974171556413354796214800332148109902768069171659933168603089927180", + ], + vec![ + "16142225389165963605704721785850680620029805525816101628767304750729950332962", + "21691255103889531967215183091383836488808797368461467004501598817850515277674", + "13360009791215314413428942977255018953699328534302248245107197249816193370823", + "5270206696221786165451075835596925139630328202641350960582852969440862939023", + "2626561181956261201864606929566987806068271006198808163435823619705436605447", + "5520368836328496672510351296660387187466158872913871354651108826881774455909", + "21597143280250120305740582323272730661347349587666707484376745221123282421748", + "5891209530846741397700015863630938364586207627850850447237189083999656313978", + "1202436381171550812585103405636986166232789491390007497511342220946215395818", + "9920320882147650877649039705433660083926352954797066179512349368247190410310", + ], + ], + vec![ + vec![ + "1098498142837982582047608372723518751721607512716925277273595859756333857326", + "498382712248562027578374863343601618793781182132084383060312181008958381971", + "19040726265283429618662679510157690394832296024968480927415996691029230011306", + "10367579130776133414495805974535693744211249758950881275217429221792836643614", + "1229596364469449066712193908302977020022727834238778132871229393863406546866", + "5594347757215876411130934611555467571639435097442631641074898978663329410864", + "625275312666547608222628560378372315159605662141936411119837279426221363981", + "15485529557721639677666143827295121022852505628489596851713462276650737776670", + "12156576509577081554587930818670905775536581975823788207855134544267814269606", + "1981640929928975005466842670997136169304057407742291166386016130552621471939", + "9375079124430521740651903984797221620963928972304905809259607327125669559872", + ], + vec![ + "268697279437287801043057266739136500465135819021738115532631740070584831216", + "9310725094036396036773344350803037792624399505581573214229419814378683970851", + "6144934044671205976376028664002834283864020049596457260475210339996948797436", + "4985941506647510031967748765284991041503308370910665002557248958100799063851", + "15851062719909725150709309168582658649310704358483047683106225599004779349418", + "9869770840966008659377598457679699092337106962689936558150689057592239644963", + "4964286354328869036674130011248598806906438908586967212984901377099285878228", + "13408525694456518383125684465410538061086669117275911801498275369395798296201", + "18263306792332242197764383101132914152275840410710698264525919817458731671889", + "10401786441956087930118823951510684636068781082958380915651220354850381871543", + "12496745101887166473879957440401384727148915595227764657145046356182346897947", + ], + vec![ + "56825204182651219072479187681186238157981743937496557304633023935549648224", + "7949519580094467639897040111470236633243836928348452962417270559805860514707", + "3509286722306670968352119363633866055096352721394520084890481975258162907251", + "21359945526252146173553061920944871506626324563977081669248710516265311530589", + "14649491209868365229844087258057697734286269047837985905275053819765825128984", + "12122186136173879572357400046587658543826161883897136171993927935307093999926", + "2666476328185593105035429309804341325262753927547102747066987631391232293139", + "21005241858197204874543384881533661499138265185107903730534607574687765896488", + "4866331653274711303641000079325074227730641553230218424779550288347820225149", + "938689939079340009195180604139206414955240264736983491692686499992823741696", + "950493909161345219342597929783079468041198261349024441783356363638640688155", + ], + vec![ + "8227093387774305505218050843028014038423742476679149203160700406235271548925", + "298899716277443866412562171123535849674476895336539413683307522836440058745", + "6985094123716229565713211140430519589886023406928617334981414752732877292051", + "4561102873171162160916461632027561255705058072826965137552144392802414262261", + "15422356128912397775473168682864290042256748428952418907369066530964035265216", + "21534011877473706794700774934355764894917955655606512952257743854629820348396", + "9461908500272520643111839486963426035162115487175673718316249722520977894185", + "9042969964854694648113546554619141983055960736166619708191725199599555275062", + "1441104948831954255692318866730011748129225465895791664253095290347818907280", + "19417400621113450826458192671383621002793369580946623762558060167661227354799", + "8244773274459817591888745631242804467035454174608673362960589130536385507190", + ], + vec![ + "17088086767144106377842029064730946925009348520592888187451688601493882340857", + "12886019902209719236096958359125451092745638766392722988311451127550961945660", + "20280862819329644063010032903732505647194710429034928708829957501178343790858", + "13239701144341900586601825324587185682073736334523805955933121583949546821724", + "2994618864933374534869864629648211464657674590007913715843569952783382900518", + "3072221011986428615228338853345294533299624086589539664037325300531050793357", + "13594276105600327401961157952766116939399999497643063180657161489419638074478", + "12904364780884039213184464580277965622079185353283126471569179129906875486852", + "15088962493677593800057541234990587773412340265413268221386103386021880406010", + "14138285403526705785804535000245522290348086552790608567368815987904186155718", + "13481415964846572771441311017814910258609608797603836070350286657768815710822", + ], + vec![ + "15459769479990273742477151452466966963353767555965255520456901549474045452607", + "8586052864861352028352866296665876117392195296860481710367953704812400661703", + "180502622991267551120688532508657597773982647209049478186474242637299204110", + "4785745751361586866577727263713743688205421961646731269452058881240942369409", + "4583871856798894230250707953295146343968130822948818555994825096960225600041", + "12377924729639905725281972784629126900954187435957722012223715002490809152047", + "21554415644278070156493674075483844873249829791940344144484983897474364915950", + "8390225843490125870104241611355504124284851919520955291024552578484662824128", + "2330476067094130593913781764168287559468546989640021387799865123741354870445", + "15749497374252464770935521609391859230015300749964554524771184068776070217841", + "16817654103281917947623051388088441309787140809596505043937473012669498321704", + ], + vec![ + "9987656178378986905964646161927549614205785047077068310684205046327286932204", + "21450061958292240283686535241652971764195183478875921481624114699420928365160", + "3904617432242099936494425054740854886663050476318725032541401300619628714123", + "21454964104289781104446533610149551385791852085041524046710270949744081353102", + "10768409462143965702783360646769759623397882338491564999208626639994081655791", + "19385613828688830964519526099114207553837496617978489639408163709100497624509", + "9385292780799468553063371906778802189174789542685475364513544798199315486080", + "19882577122462819381545089778080532575686772634821281258975533828284349988146", + "1462201549484596350490921057903425036211202388283463006651220816599917679116", + "16564642856725628254155356607086672564976261497486137590399143770170930986182", + "11606470848655267736219046910932382494518380844147406842964119623341701511194", + ], + vec![ + "546921055225672463086391798419385468083264065960104350335293012629066408625", + "12676737821548820987278730174038033161886561534502963159950183188070064038340", + "16429180804851559661054910451008618941371882312211198495282444364589225325606", + "8318514508896823373027050528521007144041407638548138855564062559664141902892", + "18546910687432012966956995548470714600618104024117576926439677823609854961263", + "12006683905722730408249989907056432037202625403043550391187503858618155798348", + "10816814135685807143320832554644398181525372167669730953193258726693903362148", + "1969445073620598650457101028079888612893685228913473332116076918643068711808", + "16873795316557869761040796336264749169213884122126281483001377666183529927793", + "8441268321647668856014389726368355391497206989491787976537908376817970369132", + "3378086906271763133245748026584767009750550242946195995254881868035794898559", + ], + vec![ + "12721353531573613369892164015903035636498816100971168742462654106875931342664", + "14969430369156214890953989610124286618925370029259450629468188666450865580556", + "8545723361883060050915916338313252821252873299513393695440138873537985282439", + "947668284380905375962163908708231363459059635485281084900173592739603282382", + "4418352807772484492818068921024797225893951828921880350002134747344565378254", + "18146914067008843660990756743559427698617136456156926109157771781314720068545", + "2353279078725994188579023195684884389261433430819033940093641668202046052763", + "18228226015329570627220992288018909552101992748538110505558715089403194764144", + "2251557590571495628913478692960173580728135227602564510397207128937882297417", + "20421664597091787362209209474226188711714308866665750343509458297343168321800", + "8187951594294388715811532560312339537604737243977265499957088579012554679278", + ], + vec![ + "15810834190411667509425096842396102750984990364193499272150958331088983323159", + "16884308240478579935994044823717491481297317573500280152191710196639752382061", + "234497484353824748419812158321111328486478789224631887096763967543932891899", + "21452418791072076854500976656696245147472896609273403517249960331326136475572", + "10860322289080285812992522532751459911253736747190334349942615321085283282595", + "149826608572716492570322179195234088797160854886751475825283168005807771516", + "11491761442863092383423796629001188933840969144934642247702733820824608517603", + "12099180244453415217270377899736157198045626379801787493348249001794558732373", + "13177983303979037999809722097100345612970493007300007493855625634642663397908", + "6849052800275826145043024580348093078809773712986428314364827674907764829568", + "21486255029472594818259653174918852363002807142725698741685253190938680807594", + ], + vec![ + "11451503340703054732459437884000132607423536025797075877436151438425159994269", + "8462539135531767509735697608276067216182907546891182278996691315801807234639", + "19944711893825824667372913293784300313762563232409638194240029859435259601775", + "10396631238556297232793544122243237485091433966091043100758266678889110827200", + "20667999270580360504376758654763163152764187226267414436968564661080084475852", + "10424436665500877000658892169756884171624649701456443210945810183301667922053", + "13894422482417998868290238401966517700776990643618129177567797594771207188055", + "9076475964444407787992938909179730031379198268423789105813333967195259669658", + "20479003631920854685589262232015009286810147171298477411667705150903826855301", + "9928015403359312830073752955992978705151208358029077246413002475277600546387", + "13981618256931763962905358530247354996931923386029793318275706908114940457317", + ], + ], + vec![ + vec![ + "20214838738486568883466588390719332066160511773018226407137866846447805607366", + "7161524737853996242838650618412058002168848579199128467811556550737619970970", + "2264369418377007316930430297757084139629356094085160360541578125176213258694", + "18691044064909968568998201940845291098399339626807500263611343942450116503516", + "15978743992268694554518277110515494413411623432213713029162001242329212269562", + "6711615239704822975151699228936015251056551262955961924747531220602950448829", + "14954997163751606686696628499315041796272082739441018134122451910369305642115", + "21573550100361192110069886620445669562472881453105471211193858578537227040439", + "21785281999660091964290541777959906196912107196794342243439922177000502203701", + "2946923208312508080510106804563669422427642075683605437758174474435322095802", + "14039283821812338763616072949057938719426671560747126284782727998420210694521", + "2531474643515410792989587528850930504447014242967363822821359471367799986101", + ], + vec![ + "14281461695965914110119049602449207565231627068856382054789426564141005041994", + "2155595480001027852247471998853878746887483662385654030663226564169133356539", + "6212474220474204735846033034823136351584003532895558668927059407038678087162", + "21589299957493491709069669042662513245508573637668760884022386808061869005942", + "5228547858762057503048110033821407961973668275986265942002757629551762149969", + "1151995769496843179907951142523838829938796346663877830241077357918848539138", + "16195901973518083237059346288792924649902586274815274684503783828189220931050", + "6205461827971201267719191643863468322713562983419848159871959495317073732623", + "21004710389082547785746156915318076260017385298749146368429985483091499557183", + "10094301525352802553607719810440185681054064961117719137647202357989110756759", + "1174362264673060234121108394303385502501621739298129145129042091221378391858", + "14586772089804608057953886654898255839796797046217599185042293580394420546552", + ], + vec![ + "704103301411330239947625288325002010320119746677418877341164806595452864925", + "7447867166827402056774077383104558156866119014007569966692643297177923018546", + "4252152864489296917539284690826221964698345550054947572793948075436067436040", + "3675525234832046985215853449128143168168428943627479235047788418993254287405", + "20125795627598431311475910664717716586147044241536953058242999762934679572886", + "9159576094573932436478222856304524043339640337232471953289062354187369243885", + "10410289328536677868407694844650868516861553712016012272941004725559785872650", + "18813119519933909103102649065156934680537361290190751928265976568411443987994", + "15043786404237278119878717250753259786450872051876817420168142382486008024593", + "16614805203312302723146840789675006378900903626996105116400354962001922700157", + "899949298359737140980259063526066233582477211127560605822280959405167872532", + "8350589775626940122507262589996655703528509795097550101006133878991750882468", + ], + vec![ + "10881253968160794744779175936360108103824976232977458894007732866457848744711", + "19359742822671794584060954988237182553116341604406926658049749172292672638977", + "10716853194721085390661796797973316855886234718612858006131046035921078793777", + "1194676839570189281149587289656564753779383829131008000754135056646064455278", + "11530412134598354110310733773537950950490005376234226554463355736782774653810", + "7158806839647137330333220334046918613209783693378018773439140974716028082046", + "18873459493111992992450800068055835432261777460679870727272006783676545919785", + "4597339034364379110034269874329162788488647975988086437272199171979371177111", + "16047595573111403874356093398802733070084530893238592035018321960924442437232", + "192949463851654477795020911703008125546432931266166268873310745978202434603", + "4826544617576366487123936439697751633333779280970103286526767080486441353413", + "10372441609969764399977561535165700928227575842447057367716683958896898456242", + ], + vec![ + "21479608666927871465054861416648367371602717876964759897062141685818604541372", + "18757812710789932354215078701254559681588101606101822541277700443926569010598", + "8502339138598356500092304059172334649791727023646195989902300809704249803746", + "21240184871409684692673423121366677112492469214890212851758021155034260698420", + "2702659403779176675766431784851669876796725738129029887042678538644093630255", + "18760062461290937265331504644060340132840729161526164449611377215801441916965", + "9598514148929007169331478849372274288455651725546984183500169574552892743616", + "12460679873938368098608659480431260988399308425323633114529665233186673892475", + "20582262751655750693560201069767758489467289978119794831247596435694971251287", + "7495462389257720258504478831214292184152544822380786356126692935003910627822", + "15847020891468169726540675640439992039404102490965287792626266482436024810091", + "13444178956365729587956577087448840645730541657243126743158358416431709484781", + ], + vec![ + "975733333906184480394673719901416555779305044861384485566696694336272649841", + "3016935868211088289963870855929013645268121688015888423636516996750583017171", + "20123197829824640950428347870445510232078708523077317828689832072338303017047", + "18496031799198869774970797646230665906722932354114482887753612521775690376535", + "448875332457320150287933426080386825611557032389972932765197125881964153702", + "15686083476904717209874986881961195356503069952883501862704199048297926079733", + "7399632407841430295111381086121470926608686430000074868388902950170939693998", + "19157441199146430337309347165554892283908758853741856357912555742738097866135", + "16120175937370916934366957179931217076202557540631878137626313655342796978134", + "17363463873417672052573440102339969267068334412527908172228668014397269133762", + "19764937897808275673467150361977575240242645746672288031015882089680753193420", + "4264866715026149043371443488601547814355809386242957666273811883512215893986", + ], + vec![ + "15361071774597522987390988933793735468585435977940286138223232105339041682390", + "13444894080484049025660420839638753203298145906295848687612728375851966859563", + "21344396291142953621865942956005813155481114773979414786364869990164493168988", + "13658955537084761077271566555621122724333408573482369456630860179831273897019", + "12249794154563702076745009616085271813195258124596555920372455161542247237218", + "2325936171131642979629131064685171177284405924159468319138840745089808621723", + "3077792516542862676300186898187316876000625806438082696997401720196346610884", + "21531439209065692564653170259849715075994439889756241721092517464459744953429", + "765723669836774164873260120197059605145439283015732643840276151768662398969", + "18430565163341347334129211602477703661982280889871625277638214021594755964149", + "15168574820004856312411802521805000105968244665018577358614174215627811033660", + "15609931056593305381714243964783225295053513474263648739398875586829969929857", + ], + vec![ + "13057901697952283349663465856361305032896972742145291496691475939407531431061", + "12802339382735521870414423620343194986509343830854539673006232369799979885569", + "7880620299082787885902391014823825400306816285911629201048471522567587002433", + "11085221899164994413080236199596538381402309021910771788195135649489784323294", + "5662061777175931509849062158785593075054461300898808576328927259801174692172", + "19620207415640534190314969542389551464821476135583607027506853686406083753807", + "1396012663571482634431038119696061726217340333644346862093678929991918911771", + "2833239640477482582925766504780450890721725782645633022528100604619065406714", + "9289278993548596713194730547769009982667061443580050906003394115646319823584", + "255970566924787837673441110425992267446525707891905710167559324774004600788", + "1607914894461957709182037732125046273691353312066921168498378132410220447224", + "18182823650001333075321511247233769219797858542696762318647781137777390858484", + ], + vec![ + "7933393968545943401801081658073805133658457161128306876557740191220424567009", + "20347911076420909832061080138703827506796370399337016973599032573292195453934", + "21705355682416154516146726727072637540254191883301906287097797468012136754530", + "4393707213821090202627671673506613966066953344462172841905371093203947245835", + "20015218870609611793683104277034599032802947064261475029925414549380954228847", + "1857954279082383201486002148223947538500417662449637107611316684336169564836", + "17075622394357639776259605879156105089449277115338468776425087829255085998708", + "7849339039625631210191134106813689727565217371730065596482503614929894173038", + "21512601485458872387622978217203423557092449252654722032828165846830386134980", + "18829825907628826679915224363735067358668372607988097049308159580108100510295", + "20145344934445170391525281095510437469996020214770888614087514859850402376676", + "9313354461544201805378332544085825218707302313348145137439630918018863309279", + ], + vec![ + "10073510764514576042491642785075889098754556687860419668420630560526859371108", + "11174613823246619246542059297257164876488140873425479553593597508295299674750", + "14486836623332191458290523271325176557072260063250466764030358280051240942286", + "1932726606175618877183776650118686155013167275195994452359992776843317764341", + "10586981584735794740885178709528523597770788130558769643251430679627096503451", + "17058731514535449611097320348142652958393616886312564975789110366863616539420", + "21546144187559470183347034044609056404441744756503592317087407561629774536920", + "5681882870231768621749544290358493454695957383787481123871436386675876219635", + "6603033703828934401094376159910456525337139277249114676008536852402499584614", + "1075347119451441392402288921187671249679641364496638526228862984392689015760", + "9887880282527621962449293235959776308591956208594163166185549404667941094205", + "3081779595493746844428351914840666042619592907445560123915127502392400574614", + ], + vec![ + "11109844704163389102553826717541117344605357734084342755776036340022417198082", + "5060345909602600407449982784585458050225699107485058131116856520723613936306", + "20049893406143885619592680397871697055896501875354968455865404394786911398458", + "11740809795693360891733016778293494519471041728488086332325924371909574885493", + "21414777615318644939200434569971788107661288737252832241371433802590137831626", + "19926309906539946638451151936495517057597377615887396199326446649447508281702", + "5833294070005894544680949322571753681474561462111500624110195335953784263127", + "20316262126697618722223967532370347145297985363803056816800332573538115921683", + "20118897454905330779316757365327082825225674670546613715170828215358297124461", + "15893782176793316439240260419014348246083695310846638270933249304684265430800", + "12847296795001788271556697499714377689095182754228824085698104180563585670787", + "17258109440267943312537478894153608811927087776527641627893802618672319064807", + ], + vec![ + "3727185744255496747036491258134142468721926815259510264718979349995349167789", + "2377620008282598351802066487452475263179928244128123362464911386705146759528", + "20330733534745333298462159658402131849518313653717741882717272744687077336453", + "3063488930518144343621406800230347607891775381984489334408858649400823600099", + "11822391183098027641060542512210687183510613996100060945754635806285989372827", + "2697686870567304805976687716601580249659499813659634827192211658186812105269", + "19466890284409856892962357589067669895394760875472697889494886746493744150398", + "1006970646211395884475799222625896618366447925898943829426435645426534803620", + "18668143903499292595688863135570950175417970684200058312498191992564173409237", + "374118929819602952730503470915153310582862106749955863047933775501492632816", + "8098759627317959799834443934069068232617039455327629644555780572940389866941", + "5647931789489182000343586961287147762347200093731102535565999902997464444183", + ], + ], + vec![ + vec![ + "5891205978627836991071144083270417159015157070199928807771268303875194037650", + "19534191765629085451497649051014772157774065629075791332793195826681584551273", + "5154833515272483128294702820663628026710043323095920240638701304804298499578", + "7917593571945709638335150893778153193741477651398934233734658265336884279055", + "5133163238095742835090645087711007173805146496653007212988348307349716673728", + "19458003745533910239158707983408152209004063097952693956218574434126899070042", + "18880819400751577287416293176849355951596193714265500681157024197361640709188", + "11433257809059443065528679883569438998689217744131300496692049205047550090935", + "12190874701550908088290603272755607342096152398135156662834905887211629834704", + "3673886960353993252497154566539843726250940370616316569888448647738018022083", + "15676037835112699420746702265028664494892600184195941373794207326709270851677", + "5045635616511022726309482514512221209262777381751689684810362174166837266849", + "2127981970274354891783037834911068612842150500572698772082540184222710046966", + ], + vec![ + "20602209860969247631763456039704661822909928028055826436834118113792574371849", + "4493454930923344041221912772221535937546211498548091351164191172571413962846", + "9203273896007845628978022785284502260659411177801743914849998536940830966257", + "8789969715987458351416076625905723956294447007026950650495844175328857015476", + "11215930522605102963220331022508304708093835095809374254680583403572809751875", + "15586225257380986275249577321891268850474446160605827963612996219805386502932", + "10011841080310254678847831138830289501574615297642717372149423820287945856079", + "18753960408421275836614693391945489354883623026056573684871883182548779915774", + "19761678450406536764850099419131825403291221931719095841429266089353917202891", + "2072721799733232450097521331054430993573774079728747665078766019206508544636", + "10615297085623730419003352440151421233872764050371800287995783143303761635742", + "11342862179098306415193268089882628716478112844171129584590093902612740081938", + "19276661508999391381559540866976056457016683157876039262437370976462342153704", + ], + vec![ + "3487982371390545412669202630006964510064537478038100559383689697998101381695", + "18019611455528497754832260490613820837001396745087990928355304172772344827985", + "18731969803319425707048526160946688629598037600738751037795347491343115736279", + "18895516979789867152215547520753345684534505439453679476362827176682322481937", + "8262582236770254192527817333585360308520228688394271238254948357217070957179", + "20124670759706967221386035867404978156598790198778905768160002435038055915086", + "10113512603622787997151768792636528607526786828914243169997168136386113705095", + "915897670578586705347124681284501818659263249883815809455861196950322359631", + "4168315355477923626825760085789663510629998017921421169386695143739645254818", + "13671994112691093230470350971338683534216964112891455368255908216954091232088", + "16886224211742114996348237388698196253930997227482938831037908300450123060344", + "3345133367703042017339663005080189359441174937067366586009093723866269451347", + "21528583089657067992968569213666076092311468898762774519530397406988724032331", + ], + vec![ + "15876161034145690426475777675897218203065468785806228994483284137836054650127", + "11419482087592638487692501143058453465931464811952523437138882421550619359191", + "4688593371456663565609532492788107789533208004746508669973851893459273665535", + "1201806670097794327812047975382630669548999745861216990648173033237996826404", + "4317641195125807665177432835324854194367911827066332519796115671103402289320", + "7278153623621857829571838333149240184056003767208572498343141321166882833584", + "5645725384264681461759518050072125001915558414870126637288820197391715227313", + "7876944044995178879031614460771670730631140542631541219377182212657483769883", + "1817650660807237476840344988506407016951597837358142384730920692904089879519", + "5477456541807551375261337022497006230056471139241891672239301675658950367705", + "8048211508931499636316723219242009338536169470228918968914286373316199192147", + "11051780522682663717015921863167554166331060525740053284975151807269395431450", + "13621239165564266256293257623306520070257833884735472109300551735647149439281", + ], + vec![ + "2212937635665982737914958126511628913962157442295931340442990688391698941226", + "15995366165560744217392074544914614299200056620022955679432568011246760194348", + "8186603384193770310414376291688089375415922904100458138117461272757184852177", + "19591014640167727612037871145675698427320771791339346286884839214170680861630", + "6878084246380728147562027775456286883121281123291292075367753371891198993189", + "2177050211387664317673794964274713735596159455191994291603735988793477650579", + "19810792753868883549077084303872022596455081266982011682803771833184330522738", + "7185072414158632003497987061744951789947697798790757573674746012007540132625", + "12527008463897431318214816404214269326472255194708737027196205809865368523993", + "6934500447964393691613594947677420114877610140521721836488732706620555412923", + "9978011727059765171039296158502240318826874847845043732001483806732259491882", + "21367223873262404675887107131444254925505042466133465670356500592380419754092", + "12370989539828127569760369184182336850673006315469364895069603190681475159813", + ], + vec![ + "4771734208255151020750966033073146490824522462970752283771863328392876062708", + "13551343845317029011162863399460125746613189002552375164523344552618567494698", + "8714428409330855425634336943651573814895603648572558273360471650145732556280", + "1770920281347553432035718101936298919487500537138994976517066719980578590089", + "3110069281490803391353365800012007306367848815614936878141004366920256162421", + "587101336788172489216190547515347729725635829809300681040400739386253763168", + "2745547964008447408503376832407161412155228373377123760513770235899201269964", + "15688219884606649780982718944113231917978875761031663915052600865004707442286", + "18825709614401251798160680403375685428394659815656068061728877494732182115807", + "7344398268236623675422623600003139537460576229211381042555723883054380022043", + "14666515770263042245313469306170077834894759906373286169967918153150186862642", + "6262353441640473491135912890626291592970997790093308164286742582769628052614", + "16647307543328963728423591228360400112670150511841037950484862728187168155597", + ], + vec![ + "11187123547390829437191210933751439038277808812390863028310714957203862953416", + "13431586020033401007013925927716006954532655767977222332198563123215088393612", + "4290575536028694423523505804878297212249395907285796384174966179335089734293", + "9525030500997851642842588010076299538258273880797610368114449809143832950303", + "8240494019366037169932737683997756281590058122972608854062263901069681117554", + "20634410655079842888667296641045124414486057143740858179591482529433244800210", + "2021226937398532158458585055746155459624344885692396128118875161667614679890", + "13363628208058779432402710458326211021009444288989875416757721068391318188214", + "14662421589311461388753832631349921077594459767269924751258576584313288868105", + "18478701421001679788418312436274921897007545359172305786472370930338255515306", + "779644354087716689348274274240595541489283221242495213448957276905050464536", + "16071592196394048404777963063722475415819376772419538934537115615105548954438", + "5095096770582161819227893847981354649325178848130636101047350986634230116037", + ], + vec![ + "1243295118881144894548654933667320243992122811397983231810580344448403973343", + "11884934205846782297010667633102865650294795721122133935339824653150509106639", + "7458968983251027899406062962031140351528726088472453510482489928822496580100", + "19572605475586099575374380909719328911692508931262625802140140705257944509766", + "14705309817743162695613012501115465410697971407093611587529338557210155341093", + "21814585268359946040619047839768523980706543116273413618895661291550785045639", + "18720305501197276565912107809183977276090965285535057360911917408689742145019", + "2134301697439195186325742384937390317718398738774895777564128344393744278579", + "16999326242022117650983709520661797031983791094852258286603416430772587131676", + "17897483181215416614794986081059087805317610826416633427262022077916365348849", + "19707797946013555426424189263942163273279448488563211841018471715309464788783", + "14555678829341308540860562709255991938855501651550888461483653488337939676588", + "17257409408848021559108687223120061819076248102607600439065783833668882002860", + ], + vec![ + "3083159817330696927114122348973911210253613266522114299928693807761894470034", + "5736074496230638296274343498461296106748247754169694274901381380232637436330", + "8207744709591183622611260068351833593643143431375276434360211505091128037806", + "16073710603427960567922233549405442518423088068367439127980767364626490766482", + "16125801016656798988611163501719363451449395969542389751490084517803061425074", + "16681204974924630782971582682795720527615927905982945319130944791490607417696", + "4072675318306311800303326010748274698511258916524447342766005819081244518392", + "4639558473350853876171991553789446979158416238030006798108198266387155784407", + "21611752344375994669307116989730257280581712049771305171467376136735830835317", + "14260028812889714557229612460335412900866192266288236233734870104907234066106", + "10936007367915129326030460455513265303372033050181411601450223671258879981020", + "2935032369592212871409648743766195391225915910970902425024269583756879977136", + "6634946569637959135045435256486295750841113686207268069245788404426148269439", + ], + vec![ + "11165382706437522214793349607928919108508947068233467479625942161240196013032", + "11449774151698349588558943383567398137746718964787475388291636245211033594857", + "13380655477865684658511486065341626238240224687038830357479380314844874141318", + "1556090800260299290436338214947407050034615159120446561828975680392439133850", + "15775229412830292677008903643751483031582598935755329498528261914480871637362", + "8325948986690458545596228454116700887740572176003019243020371356605705227449", + "1530006957398320461897940887072398082651602436763497487522949690691142033613", + "12096799031117418724262752691656478204625211872574986459351576236141568686903", + "9795222686269696766812901618791046177266354705263547407732303299461050133927", + "6370027108686216641431817942352503637286925173249339052075608610090399016749", + "16881432515653361341795686702127944966732199129855247935726797972793170639701", + "15351738821101585856536273249878864428731819041333447251288973888111661451683", + "14781212701946742438784746658712056984412254191444809612525158953148214912100", + ], + vec![ + "8091550554023025707193058566806958042583606199181127012808071174695106343115", + "20490495862854672187041438553984493686275844004543178578410057111061213880755", + "17273768908086623408127314492263145283983205996943328025810362733169697859553", + "19294495315219029609698328900049261980545541811825479502505060031138576089112", + "21659964890056395567978937545379633715401240283937936880886676845913261767053", + "17982445074266408124204445317785538167802060185652418682509052997213396963809", + "5844393214733022541634389892381973171593154485646342141850588851005973351855", + "18594392739980641449638044568401634303115397702236811642652121212412266849233", + "8182160648431978634742268417253967926524505311200391645921674911687111696608", + "11615953679796573972512524871850400010935503185676276201708450621253942540441", + "21529769273680682324960067458105490598252059794192747768640910191459525561125", + "20132110404365493609540330952369583903023878161175287878881490874880122068662", + "3315629685104800403477925330007368560121731964009894641262206418774875779654", + ], + vec![ + "20760167657218552641600617661638902204729190730886821404831449731791027856388", + "1071944235595105837840075721866496337725631499557288435858051131598364359180", + "4555500238184379140256400675916267083899817767012366155141824954325999920862", + "12550383095401941417929336389002623533497339330808819244458405679309028814897", + "16242206659396631583090203067480642438705316999988728264056381863300603790054", + "9739751068073084582742270086389269366580429568378316378361121134559060472609", + "16116599372526867528428771037225046273420084760475362036998100512782645537424", + "1491702476187736766465155485454380021314952117101776564498935819251125640550", + "15487639992401023512588653485898591177260483949656489128772103961337143916568", + "271607781293753174262565976623664759968566553298322241892863651425822643900", + "19977950168772761551778240748644447848771422612925087742515420134526515662483", + "1983058998587842721058540590280805932874010898105761473162166721490888500174", + "16107724245058262116195892590046753877901405295502298275519986777803068771465", + ], + vec![ + "15598969808860428995774387003121151871293432204528482957206560135604646381090", + "10303850219152079194793643117738367623863138704730923818757626414538626924093", + "18042134015692222011976424010811982750427479608456170876100049843530175591980", + "11698490610713203406365860893495577403678312400711273827266244766764136895745", + "15094763799279956189651458728729592947034549021140257103479085265792492443257", + "430096731859098382312819496464652103427606481282347941948051379574546904741", + "13960717870097098006695192936395126361902142536383841733120824678277505383661", + "4016844697779547662080765040347308557842613782172342555085194018348439875647", + "21390612758814913695838461279472506230937295081984131634720827665924667792338", + "15210153052017283712229693210655704356560541803226219169450332030313730637768", + "1405020343631287949667260064722407285384539868534544303707265307694982887517", + "923081188208761071201163943024810005498690637139303388717205039798310044759", + "11733793144318360060340673323677375331041661345320756410073354731608712531433", + ], + ], + vec![ + vec![ + "6418344278839121997761558068555633277874924383297235060428040203550148460392", + "8184778893153361724502825398680471446632259194563037088246379746010351701224", + "16103007220917684483813510789286348056519805127857943417823167430289370248882", + "1664056765289606259902279533842090994664529145577166075019619213360544081038", + "8189267971733078428327714274800548471520787418839983750528172780925243373109", + "20200362011107872066803394413626937903139046091127740529060907959370256880701", + "20173744990845412211550008592188171997284132875646553363208340317991304601908", + "6100976759548353184263451545777211359935324012594548692714862113681123862281", + "18589557631793259794347972680714314322014920073994928130094285735070065431315", + "774191617468212021433032703138192471679212014828288788368078839883023639562", + "20846157077077136618808870082870348881758556999252332666235423866411633465885", + "179369838162302125553370844232732082673907343764950159722856079645852949296", + "11918621764929568738238867861947162353407822663185301208219638335882724852664", + "11892816132266551039449220442540498829071526084314780371963132054098089857199", + ], + vec![ + "8372083054789567618141127024727893763407629214826505908070525202510871464376", + "16053969929668995455194287538126250235271805322133461918670713060143921845064", + "2376335354846722834191665301267088635977856417140218787958824096999457654386", + "8473768787638105406889032631028566536048259675966039382891971280359035809717", + "21341339254986951084972542739281440827262568377712659704364142966685544694259", + "17589661461505870684154172724042456165609752814624225501433267429299923279866", + "15569410058783548405562051853887675489795673100717406458705097884992918832740", + "17136771849960699223133648686528512780844440317239376836819594891344485260741", + "6846911134505306255484642794298233221271816466086606204236441947984501580805", + "6155197242495613968880604860842601809115711093712877692064968695514089066009", + "19128637117872288039529749360298403408432890998345732113683578733270478526860", + "13897081066927368111242039741190751095002227555149381235627883407347099966197", + "15568696369607733677931070776042128239961624292553408918258251667007167792827", + "4872469898347155985390501972210222637651779849978701189099596399070936407527", + ], + vec![ + "15828528305683107589096901962734302130704783164486093165237194118210566499447", + "10871050448146531061933214597828428556087596885695624079458134367495768692641", + "12715634392841723603484337993449575047813504874083783048519693646075495401499", + "12461797447292058643518857326956961860724022201671935652194772338021756072767", + "7893478478385050482361413970069327892342442172936930424757486435631374257835", + "13837601157198138379089270567935062044589875195895421018230835162664685103799", + "2902437942374588332095798046833013227638771976745087670719351344275677524328", + "15243444720000907684100993103252257759861356192301299607302082943722781818072", + "13807772002950549127635782715429970069282430778664455286304012934232212216437", + "3330690659470353458591000516836956263198779643900957759109026769401030561064", + "9121369550752168091283493588432030055987339875340008013960004670271046125246", + "6735940425069065421825600687003545396352913420833444906054707032006918504438", + "10202597085447755780667010145999569476263425973948073114389503196598866401333", + "5502428069812047253902185475715178213199056100606031376530298129227524479345", + ], + vec![ + "16644412428296109976288812904703533310452124314681543539244699753829624611041", + "1464363769917768267070780357984170193149530071521363359029977430003041058712", + "6585015011013232733155666746473112211355795487658434466373981554623709413097", + "4801399347914387190330170488585953929447785020623558112311440395749307391856", + "4112082032915966312546686950757741516554419896344654985273514512341960565972", + "21751105223203500709422523072334627517145925318798961657655356624798705469220", + "5444707496026644829581718915396971639630623832272466243662913303978147462160", + "5176202236175268355216491019205403607765794084697970681965844070084688885903", + "9306814982626014542830328909308268815941037317672165275254890008767120833129", + "18534005003473959617581160840952814838772020918476059581821124675494141739706", + "6315286473605163880327953940950267064586093973100720152185112301408202766527", + "1300066066523772310953083996541204931152213396378337235691979863222476540925", + "5067928636570884230858740896001720688497565237268231912398775294420405805509", + "2247332707031505717534336329466562637772796336116582429349574314234357562544", + ], + vec![ + "20247738241445291688801934041857783193064556313940428743035963593744371184825", + "18242310613256758222060583109097399506427347785291803988073944852458874238653", + "5027570650503078047623512055050961603632044524914664539379503584245086748701", + "5171024028215683374631525538977404535998938725569475537905229563957776539718", + "14944506678316768982115249709678873125670683211913646815567280613875065136559", + "12712774808537003317921729077604843728755135888798177519726799585299850232729", + "9704917525949617705578174784620125192847872142914494686332094535178307346294", + "17607293541936391773356775760016259535976314844718033784671775110177131099056", + "2540563558441922228123722363766317044293335648393481767268774186670778379682", + "675334497725789143197575210295522345522852999942555409554666160997486976627", + "19406946394055111935833464724872576724279555593094398662505995447037826031689", + "8556081865419484437161415079267380957278647215963771014478927152338629734722", + "10894080579102201350420363592007910695129177124810422954037601558695648517625", + "11291505870061211613677608925985023369330908318817731122393740145823745286941", + ], + vec![ + "8111345701049008354923033690718534410144029586027127161268652239467844080405", + "274549942856353845785392053622966579448945647367587770109876363273061435394", + "4517253471300397604524436610993375842851058850598308811197142784491633632173", + "752091920065645178354359484693693144698238715470242001046768604290011335506", + "11638201273705718037686872429810169270152128290712392950719778292205581621583", + "347106139963113855692776969661437659762102942024424980057845079543094637582", + "1650860247124995235720423411540903470864782697117302631679816892337391491913", + "8807792864573824348524944774842835780541376663413796103538010142332713129239", + "10125706840777901469452374931444076850109537279493387272544675392762656076263", + "5796395502360267028606772833560634747652475684290748049574810918512176530377", + "14560087906294745333868694378307270211143393355422503000240374502300675908843", + "5122547319055760404581514483238475236540700695938727023605315976547513018758", + "18167310745991466802649320845690518166441060923615799361858509593334862918793", + "10537655786889979411145772153623144374332103428122704649668615330715372491734", + ], + vec![ + "11129217221221505592409814225825346415830118409870141057639470413354985898470", + "18539905463366886572265160849053355497514707079972544561033138019460289616722", + "2634262960559341073751666364573144239402802922297326052528609874036724778513", + "1017221748705774701515487698826243372900579204850532621904642815268966836932", + "17514607882958712820434977243901228312981191640605665595923587928949930664369", + "11518730158165740016295488007249832672982237183652963149460237152135828893220", + "5440554707898671641433725775650782970626686693839748603607869391440450924607", + "9147974268228093219515993293158817299424235911620662153289209094112083583914", + "2705991777416683673465834362340927783587369064825521543877658261521166181909", + "17763220243034576321349123132976335282008457858814906290437636386824597776861", + "8436811158855395670172615633911662578819734431001698203244903207934616540973", + "4138616319619099661442960332848564292509386403496259477312793995345740346110", + "9291305887217504987438822522544685995385674372729325355668719643387679293273", + "14247130176192495492949419984506575479387281081069847984799112525576996955413", + ], + vec![ + "12065917784915207956255864287163607339403293417584561373088222422519855200010", + "19602746430676351974790620090862300757670420200072717172839368523905726952498", + "5634613092261261536249683912838127927279222476821160426063089671641025921660", + "5043354945289735676261322233679902891599697472766188245131942353534121350357", + "10504830582720502950783794220870443419986496189960249704278002268186024527222", + "14773755085011014730752864609252484899166588993023999143755304644745097411069", + "15143011250372146369484566133567610168314155803929775363148643430052742055690", + "9296771043817098875687880718048618354875037373605143322099708291917193542563", + "6699308928121904151061270394393246387724926649022798867634982215175491150673", + "8773562200655600334022608356584787571874596251190350038742467377669146368640", + "14351113364159322541281738731216101468935785403577478179790191188832046493458", + "4850132968055386067280912095292570467587181719320385350609813213372507065742", + "4016458733475657342057293585429845015911706822034026494547861057484844319736", + "894041043510502707790816962794342134661931379046385946357294445947889380857", + ], + vec![ + "6102901509904208647404960172211548023168535043766794923435155807898706549347", + "10993930772305308408754972248679389846078570700140268311987303413959565163567", + "11304109937008720250639855591630423562437629896442798574433639679310105935745", + "2101572929952921976477335632619843501489349436900225186251308254022656908969", + "13379549674365217138865497711163371499213584223441782700932894243483907931587", + "14594340674649653462364863346385318403203482098904810919462071947226757935441", + "10647634642733631076053157841634424396589261258510712678605967658799137793311", + "16930068860033006574251855928288208559689461032565007963103701897524112820278", + "17170753006961827437085793102001841977757115057767702296590976802337127094191", + "1342928489123424058754093123906133488378103161461686346784407392402405815911", + "355084123756415397117817901422581736826549282147584490336790542339114994995", + "1823092998982212793902589678970070284970565355035702454684653415443223765731", + "8048898551230697881244098474076915607341905762324328681953519068200924158237", + "20856146965109368880184165603695312280799455722407374791306423939515039038196", + ], + vec![ + "3432336669019104452964292940253917813738689308738628946720655243686051453920", + "7245438991832359030357502486353272155562833935372540938834365796871211337300", + "3373527222057951116939099747150655397463396105930227294848620975346900604136", + "12572707687046208161448564696692430877391470466184921096766838283998472321208", + "12384937031493229201662431219560608524659573369707802134091983819133706078063", + "20462122407152292556380602425948480298757076111535435284512383591498863731385", + "6622785585380387259638611864923325325049433660844748518649420260935388464763", + "15605049021670133989806310757216368923392900885847286376362426319164543334301", + "14810486805240500676478878806350063220126440203863567013665308737654824897393", + "15365995118119349988306703047684161019037838200991362610041019844939301169864", + "6214064907470154787016516294417895267553707205697453843662274325114029144555", + "21692877109550228305351038417910800050989918141485758185602644390604582268196", + "7958034635501608074408556743462969750498597833797740641656952760348926890967", + "3158783210920420629823137370399691077131051120551658723733852791768119909942", + ], + vec![ + "18819671751132769006885776104610704012597692175792895108910904654781356258396", + "4790325452934584098003515312147561388538271922609950099121379835100064976005", + "20767398895337785696143628393192433940154143348446221959395714109953426025406", + "21100955173515864394919601160078443835098475047602620649008862351655083694950", + "8821416529246363042674973639302381036248538012124317741611227124444469290957", + "11914021995756592924439683950035443074155751236836696847913625157420325157778", + "12885168008148287764892654933214399102034605991806678959486007885552095995306", + "4425275709248360981167156075250953689813562430283330510520431316578062369047", + "18741351324856319300007832572892392651059227679283122747711533395263296376480", + "684786537545646459534722549414114801405982388707719975074226812265976115381", + "13474309605538568830758681457803561340228343878559353019653388997246494295147", + "3099805728977762711509412402176547022850118685798164610570416531465753528610", + "5600770441217208920894248156825173605916487562076226390167638135518086562704", + "20319458329312269677818220957673767032133429098791178878849925747919552800984", + ], + vec![ + "14900034607445803864669093098274289660238359682591825230729114910199159461945", + "8290880045417869099036293157381173265982569186829040493570954991061128070937", + "8462436298566072387124764625279911648753174589013128335782578822029407672023", + "21859976115370951722195695482147975930683297060804395404861331672395447064815", + "14955925753372802734448760267566451635799685206346879293698701403481312089613", + "4065981601972608953318716423564125873552717375448854762316325928896715511302", + "16523330234791629267329601436136683980570251446067965291433875700044665982992", + "4829516041540259457263557932051130738530942234255982016822863700315113125159", + "2798840870433591285859944008589519120500790120158397573735407833376475300691", + "13606709616318037902590277227595176470474803011913892797662975188860939656033", + "18594031070203820621139505381680984797252179318940256457018473319622484612714", + "301595919185954926511829797241004376609778538475902874115890821742528188064", + "13821866899865257052128875138353714301663063129600329885914206051645789155403", + "17834817495579398016717972195069792832976969906967797534885124084571666971093", + ], + vec![ + "4636638693344568063056245513561087534038777759740617868439601311740450428791", + "19461094558355290408553329139619939302588770167904059927666632659470708174566", + "21540578068459849172758651661944081878533817564350404794583097681041474789761", + "14656354515483866868842463518575118611017107704362419507056354562832024225447", + "343560765432454876700403976911389497782754407830340801930660700142029455668", + "11849359483183996767521484728570765305101196328390648813094255236259946055317", + "19924264286421201319107239943837407504286665549555105416180422159851955997381", + "17166797941774367858319514708612731492719223682833034509589752159955652705269", + "214236542688014950402766598120744795751883810511956979430464011049570919618", + "19396313302865541199110558245182888004201133198902041449761385765703954241755", + "12933296125492490585010683271492258153065303286717891025958189212827073719981", + "17844270568289843619005627429285364222068221173113885235581641198349558307966", + "10272636157097124940050637562161546985351212351240072791897429490752295849402", + "5635761628763643716582314870927054669889487541831762994265390120663404976213", + ], + vec![ + "1986614715532243876888195532508093896345436225715262830320266933005235142097", + "1081989267417492031457620947123272024310181199896785177670601875483149154563", + "4271010751492446271792663900865386872716262596127435260947966701647960153580", + "9432817034096362918055925335622289410018247097406473925807967486887418646785", + "8420506466048434939907866067225441403679080978454172178355845135440301602325", + "7476612931957868870953074766426582066042735713430654491467754928300129405389", + "7004218213610744415525118134908394594325377744218316765510260162880307132371", + "7571768879245095309014348656876595924444469219593531275918644914891061799835", + "4094897072683886403820666572344492999293005026807228977160362626188210714131", + "16648450944544843693538650431603587114533063135176857105384828552675810607958", + "12887042974366913908128212909540148628955501312789089034196573637089727885967", + "7707639242815954375609957852547086529799646052590213478924819089112009057667", + "8823950326593148986044014943552213420762296615584865468926316064433145020153", + "3784973153813546220636380916429273484146041804997715013288159720673291711004", + ], + ], + vec![ + vec![ + "1954546571818731885139861264947334230782822161673023234242993080695489129982", + "11606713580838194823093847718802359011098299538034455148401855555744041817997", + "21778217939341959600865514937973379081571132553754734185669152755967486158807", + "11867012199835162777599593543744285374463489953452947402200134749407575327780", + "20668200962959535110219664454556867828577715202494491079283962871771719016091", + "6796938349934826085352626361055311106987991567096993611616805270698773290279", + "15108030096316731537404525399718062561401239877230837132486990179727134215091", + "18618583058942935584876943765894457772128324732451762769633954204661267055617", + "7446958258820445329937058505234183740111199633995331064868799738609505041620", + "11019126795578266009911151080068316016022306110283709712693862589215772062237", + "17644961526468872013219663511656737898249108220341985100127433673616476030536", + "4959721361611533340499147366149623398780635086479466110353420780375692399477", + "18273613083607267201259595982191169247452947601227995394305633285537292365096", + "17816466502776842735116945485728134149282831962573761460376746436502757322332", + "7013781340485780306773324480395548266877763825891494701746512901494705653158", + ], + vec![ + "7793291197073594006386853421213450159077336220644997691715731402410704643042", + "3426005025972529257284910903433598760993095858232060658495826014698591260944", + "18530832095369567225742997294004908129637537286260217494648426754251364141983", + "16489909564793485793960504581924093693287639849995832883358263301067754354184", + "15126602449686250365534081130480301443166072957206187316416707568927051456663", + "13994979972845996867477162556668014834350043400046615820474382058282820089898", + "17892071176071030024436108339592708638442586845389229765280031864359446154887", + "7094246519433675669226318744483462997736245331529142696208838903133391196837", + "19739600791550679646703071148379836779124671330492407813260108679076122705926", + "16577895124793812992345966235533166228538388644746952252700985971901794098608", + "2190990407832635064016354900528055762572032133913345251583721394536626731922", + "10838969594099257399038118686024400001327577210604256394537002295046250661365", + "13742554186879139633322968994905507641568437399912823098239782636831322642395", + "10281113667801091149613944447670705624056560574926411753502305328318932013688", + "7661208680673970050246952651218127022141152720979640414729369551173790735959", + ], + vec![ + "14369836811580283035547554195559038793886958236571577920508487931208924192768", + "20603628573396476191496332378884772502350107937108583985752646932901407759112", + "19296916296835469264085474516279583782033370007674993417080564950885860980156", + "10983867448590555143664432588641225682254935452824608025544914671100236945380", + "5670198946055747149234813634846142209283829958947146164536023332201358566553", + "4904816432035963931263837796941455228547544800276020247096183162764093041386", + "928528370618860212551901809222389226336726628142306562102221490519648216649", + "8727385187994811157471310113729025912812882704232858255495018737569420129281", + "19909768217191699902186248006262494556099457367519802119733085801884256380544", + "10635786582281955931244778086998962127059196955758207056871772748744817883737", + "7140512340052162441606422433836236465795273624186668144911701254961330905493", + "16598081311443832517669265039250197623929992506944409626575335140315057620768", + "2339664320384903939910962081546057089170206846484766939921698239663651706239", + "425509623704802982425483674266195224640999670982140442030650575449074971057", + "7922384239142329258156226873732902413897900318612725000714450267548570680404", + ], + vec![ + "8178140403014386057685967488315772252114289881535707170540858306748328725322", + "12689293740944871195190670877158259851710828253354810002997981152414697198513", + "13670630626216376948528966598720909229691593992164633421606526176324419533442", + "20189490101967313329851160663874367593390331759675962821030507426149184002493", + "18209972608416650990264895614325602746017028678399567737887116829945804399280", + "20353660437114078502000672122042327871511027701339587880609263231648053792209", + "367135858451744056025051491593060073950844607000402056456474235270560576836", + "13355850760886700974133527239382497141869096511168824351814359808886023658462", + "7206193356029734986150290058613471641978817208643432940709861990432648635433", + "7885684183122679587266799938650213096329650494585142531776846669540995068168", + "19085115218990181267812208821832153255121894513890241319104580206329327134131", + "16305675470941528258170184941405206862153955794946952667798249341324791515500", + "15443626257895746936982356461453477742473783071787883800166168668037169561924", + "101832047855527584987088220264952346019960111874606050409415217845556024488", + "10576438072746903138917852030571732352003417543540340689583487864994727144138", + ], + vec![ + "5996861730264922256270512962050361669936822432104376503237345294243995854540", + "14877973900502178557219336745361213333854789301797456671201806787562463919326", + "14807962843542542498914061591358875654692300327506360640837865566998761281322", + "3133673265931719924452668737189159279894652423873815799856403146721022028744", + "2314426743898183021393131908284299082806555710249089245305873178073379019830", + "15353836455896084897563929713128028858175788390437902641700134508986437653318", + "5529981971838869469294842442312128910934708838384001405870007618574232226406", + "21863108219378799978996648633069571801923287451100447450849597846874069699478", + "6773528450923012634292634195479655092490402578779439394568805920957004744133", + "12150245180431051120309675366247495517352377611113958096501103925281912163211", + "11142442323884902255425165263749428309435092933107089893872191462936441527962", + "7030165611221942623542847326918501014233687676615371955108018311000952911338", + "14168907664945894221515023422776939138433274836712427741726190314020662482321", + "17973846874050037633502661848899122581090847479984048542694367819419188584711", + "6612448947387099268202244798863603173886774177350810153571814261011002084641", + ], + vec![ + "20765273984039816245168454930434370234220284726385931011063596091927027011108", + "12525833775624943075128880966259784896817535866921245846013552547690890352574", + "18082141488353658073882233625595393585704703572017716887747923068948432979709", + "12080205172928213829055364897249628749790838461826174687455161036760925324146", + "10426041417079669712788047630796875947997831039494087898318197116078426849054", + "18333367395418670733687742418586004501344157225223371831515062599898496336393", + "10666844346085567030848134043176991777319226647942683934134661343455999941894", + "20287202184725945519955164847740850432153598475156573942705745729215691030796", + "17942851314410450183054332374663618442963349517519641485232231950262698445043", + "17672277011389568686180232934337352157780343745417630591806280730146798908966", + "17416106918062278234521335281965623696779795380548750331807903068461573518054", + "15034390385078628923681181367678507353936042776187855843799428131823528700439", + "15016371809918204032764565101078018512566551812562861502095795302834732872947", + "8176229788878503959342848267153225222150151339952249831413185552792554528595", + "14202549166569309182319866775579092322766621157492056208423752359103429675445", + ], + vec![ + "6628758202046565882882491271332141326521031973243028104017889062740759748530", + "20267845326067450413789379016153439637066264448919236391605812427944953078755", + "2438946774028723892708023594952994993532105735189593503088246493623252811398", + "5327774123437518227973303235331602588839413198088244869937007412210139714640", + "16416517260868931624699960600760845305546648577328049221217547593071007584547", + "21691457642736313179352706050711464825492028639914839210493298427277168769684", + "17369736170805089474636304643282290719726533149056710536120639858255935606857", + "19460761623902421883797374762298555710671254062576987287084819867262496770119", + "19770570144034267396127078712986043464609355920552337517533085194608634179666", + "20904722049832148410244764905538463264520496768863784169293376826852051688706", + "6086931305514615639236334006857789100145606465861722355610937306339550862", + "5885641636117295888159072068000551173102681944020015073964039109891861226751", + "2197549059218467728366947205357858398035068309306368786367182781869500529089", + "18571065033075196607590252486530861399537536653506142751073877421696969841444", + "8754088881400442345643534933850221698544089985357770542959718766123813634810", + ], + vec![ + "13673463077059539437815915980077307152850526782227553623693374041649724049605", + "827897346385894242944663854685785871137033256170575635435612086616249561082", + "3256718342276213157296321691616951565542440296040693556287210483669841487973", + "18851058760089844863118102177423730353882359970674430675542303019981882750705", + "21009037983427297652279654800570889577926790955118786173230430780907667982896", + "19370673591737489444054265538393258291592098201577177240415593550679982651270", + "9712794467513451079466753095103777002587307366322848872714822737566534970868", + "2452976395290300719873209484043914405675637974162415011707015440506646332236", + "13967023770779438454858978860214792451127045212657472381516830319420403024355", + "18974770134907327058718913691556562240688992993972407935785848010954975834526", + "18005343276101020422248769804338953747590444642920980587346957205121649916277", + "5364199751574723768938730543610903684616886041855996090009230701935892264768", + "16915141432748433783158989990154900013143930156431056052460984382677436665679", + "9810457740455050658326943855759399108575402539560713791636000764640385927272", + "15711844859260073612371012979328688796642677336582424352155989490394966892994", + ], + vec![ + "2523486975208775388230636032695576725855997180931786065064150527465407276212", + "12939257203114853364537111886847673104871159136302860798643783368852456402126", + "18563343508729873190283517746040347988882591986176993103658794343898711153424", + "9139767925154848725661711816797304370425590863714334419686930754659416933343", + "15630326979358561783620795846763021145439701823262337294600523076394775855291", + "16709031855693747432049197217266634836607267701623669179857743766059308291076", + "11081746589259753124653594380015131650915622160245647873370327872758282529429", + "10263829532434991046602117509549967441368717347217075372460446855507340910410", + "923380097607272775621985864770232207712801803675470117823528453022294342573", + "7060362012752050086965449046391069479205357779670943566418766734533864254186", + "4238871118210220589598309748597547342336859622832314796736348778105851398663", + "17520061366255155846404852213753339526277619564174678951991892080505590972066", + "10513625869281904114245087023227471195681135249236672625281292889978751612829", + "8435396899666453466602702234562279601174578748121165208762270334814881381944", + "8088078454252433245088686773582075061475116946251984942060002979516553775360", + ], + vec![ + "2719987334353537600366656327639544587227927648913835976421439609622334518069", + "1024019320641379568207362641296952564452568447918936948059464814762366331275", + "13889412498086825909291896540147715217051215696137185869382874120375855480535", + "16901630530096437974516169843541514517956751790577876352535912471650304576719", + "10977539500432168331426791033212854950231005312634634920276038346698892818211", + "3226460659346175003896135924099734866664778523605375090881255390738403665617", + "9695421696482260394078309163365413177132015345359377667904366174083251929056", + "11269053203885423427900382169641426379373759430258387104391167619152696936070", + "5178750298399029508026924620615685679610392082191932524033828050686124044833", + "12845878982355860044505488053971997443594073436267126888909625977253125523142", + "7530981388399357124357431126610695946065175975095472306777796169245607001944", + "14058213441446348117716607452759269076404820355922112411973297063005877380478", + "825603012201903073682942337154197674883919500964784037574585377691889312422", + "10236993586198323123785803013039327931978354285685191819502917433935835639701", + "9438970111160688934509448828104684236155844660381402912193342504181825365420", + ], + vec![ + "11536612122721678319037657954738688943272460041908847457419482683492719528721", + "4048128893355211133472225346691072554088570917135573376272009214966234274059", + "17007960555125781716346334106074020327440615260084049810189285619997415816473", + "2935744638594795881476272405224480626548498961519135317809162650064622710267", + "6384493312721061401062408865799313573644091862395937725107886310975229942194", + "10507848115923740198082149097677194763453026968238422206438345199258995348681", + "18755782391252715265425541321566381935042481942506333926799033963914433188574", + "1622030934879728521636669415221999170954870898240640125007128754133416241951", + "19178897048453000979590659690957596324038669245300140765620928017217201486492", + "7668471074291870526245483897884601792626426080083647233981123797699500787980", + "17022938204221917796509718984925895198444138607270396412440297468084153383727", + "10938747411001421463106680010228586254730710894241856448408311145676137003709", + "1892143994611253681927160695719312882099525827316460372080933907151205825399", + "2626413664304179483436880400231214693597358131317388676910101259191110264005", + "10976814250018194880310517382191223839713741375476951941358522267556104616194", + ], + vec![ + "3267603976137604608815546917515683877598008503122930381370588099122094818035", + "18223585230504941070194267966378685287221743128395324427323638965512681791787", + "4055897021092860484143383650117982675609656498724344612791022670810747280835", + "18652001434191198724037217430343155151673545332667032591923572773249520166995", + "1179210983342192637294098069949454912191992256395734070923896011947222260627", + "4403412539347069757548448548289536146089860634393235869990028179479631393017", + "18208249577016536190404023195559477353692681610041814639755282640930299265764", + "5253459060178003600605009461295776576191151024266914967218417406063967602725", + "2110599375707753504956307604156004992055199034205281989577749327575131764193", + "16838175205667561737978735977781331049290662487428014461885404122880770700959", + "6473428079010461623647807107937762759737150259352991014918746820779470984847", + "8337370031139132243770630686523670334344396638842630818638144451253681713442", + "5852133535345551978469538570221409138541345120679970583582105205614182914641", + "7693908046708935218171096369565374697059710647347392990894755587360287791527", + "6754690467826351700887172852005234976131445583530162984365436173814346372178", + ], + vec![ + "4362899351088205531982963806583486557201252717995038448293398829823910923472", + "11518397041006514564038599401506526387562942749501723393674197214904315107893", + "20606341697536003623317613291213380804130123512962185582210369767659416485838", + "16897394754877405156789353426985842311670174197348619627467370676352261158652", + "11049995264887964858828368499123384474282091734658191426291499678845498016770", + "18903841016151023909305743424460730902070062204415137089939274033985227379247", + "14501632343069777665672565757138143573066425682965558756989443143462299059377", + "11936194426294671569251421865691095594275214629276606276242590758676139955663", + "8684782852463301178275527204056308121145836348455196441596832143888384190591", + "13840275015334112173632265864573045139112521216777064496416258170300441524371", + "8976112149735004651499648151657522459186187854485087924493254571044062238478", + "2557541446593153253492913007582627823644717754910327615163106890559828872362", + "17214289010670114093415697072867115184169717632618753776383803280726887828982", + "9277044732799923560347274951803854995664839245943597020159605756847120319168", + "8665104485244718969383349524127237156930430459852710098382428996861193438718", + ], + vec![ + "2966017993337369327831105148290320997881600321998609267125699685969931023637", + "20703140915572601301330743722461592884427012015286406537986295678495182028439", + "12415056396133226456247587270673507158810318408454307171336801889305959276558", + "14096884501745579659192341381525893498221351476730589189812251926483574089240", + "11380799045102603249740262962085086862746282867943901718244205293076495402152", + "11397463999860523006350413477163951990037313029979805067679629038011006323456", + "3989254560279764593104713297200294887781503399600736805260233256187721580128", + "12670526207690537332382598355517632246478654103765566238996179271593311461311", + "3183711571356392622250181639411196710255078687860623143026450897732409025180", + "5610846600257417510307213084599977483933519996901968341741797171439650039141", + "3280606490416179974005759319341626407586508917823138878220428529454629673364", + "1201982324417186063031536229293952219287079604094432487446300310977814955299", + "5320694228353869326806779260357179675523748849691821041819016623807887766991", + "1117900147109997141002482710095589298468009897854242933473562031850755107739", + "3423874914270570048663861326353594445564054387733265522218157141041404209456", + ], + vec![ + "15544724812507000325032356684034497915485954044805225704411638706645864153677", + "5773122431233952373926318394008190376724448498619094117536291976195311877322", + "6101823265492636176451963193766486622777300610881276372298697176417958756135", + "15795396300010870823125638802470599845845464744307444307899702370966825169519", + "1323789030194931509684647858838729962688902410898850967128356366290242773839", + "5751046064881673173633677922158261597917572500845688735304279201507132509829", + "1621252171583823353515150633750260236914561977816101468910968069661001399932", + "12193773521417435700759146251386454694422997324768376620870510312596267301181", + "6582582178277044206368630428791785430498389945338461249283089656681050213384", + "14215781677876725356925186332463972498447213260700771466349787162195918816425", + "5782842445406193701766362226063474843566378485612132749823957396025995938674", + "5452153017648783662501027666999013472879951066118424395570738985848450672673", + "54899108049022846277426184613878330780751769989719315816516065174629128493", + "8847320923102214377720246218239804718366581789144394009065472718259977212062", + "7818599458828105010909362503034203380908251186730393621503231459166558068065", + ], + ], + vec![ + vec![ + "19647061463337916460942375553072101475191437675089764130648797272059706835097", + "2987900412319695329324667493933426290750629320482434345012869808788189293747", + "14313117549814523542459271158255968194819696107203500245376504355915249564569", + "635066671179149779961724809079155342626591882143599249747638714005480456001", + "14160366375280976850992425663667859199067402849136919009370279834492741756927", + "6973916440684075662378599037972982797550158082488606172483341283171694141353", + "407790128607292443078618781455551950270304278197678311107891073846005921099", + "1875793830194257638983834574124736838833728874912304344706772047211830871895", + "101555677977911034029979807139724697918613026657646487138174278033141465909", + "13298961474358064737775518932222238976786587146906206646633234612439936576772", + "6675018665213382228528485041578965344759847379196981998842754547093440230230", + "5085649234634970209690321129917296688853246686378177913913323311616242468355", + "10058141944442728296289308385948277117189357184119821310668675797744136293133", + "20711981720256091912789603700019290285604375596717389895155646132584571552203", + "20115432152302860531854002084546199214679745925822431241410388037137709465378", + "19426738311039094155622173280735935805207149231732138766959497422037163547769", + ], + vec![ + "7740589787985988848427674257205602851899971532434369842038308874897481875095", + "11072265639503386933704945672016505140436978537584329931993329650203494086219", + "6167282302581750408390138662907316184354012779517813053982109604767767995057", + "14593714320140781629003483490890381863557111469157054599498274206519671343499", + "17959188687624917851017921366866983692604241271917787434145985166811823698158", + "10852786592684215415216400376119268936907433212885674472022333115957039052793", + "15899441678259173360040901233792251513972059637300348276334545233380063193689", + "3640175378514868793712597306483649195648235320181954901691448087453970656158", + "19498930515578230344335483600141550927765501643188753803487668144320311818295", + "4153883544158745158953668931089517690854504894896391299015592025101035411270", + "19024468701496237603291237797335586206588375930028220273546773163298357041151", + "7469727364011292433851252680653746774195189525727608179319902706399363717756", + "2372143841469285674441303263292066347817168610069150223765733476276718069613", + "2516526351266496289030890575774410993157441063594813081137075222758309555822", + "20958751338961200084885567700868871946051162714262967700193597995642229058459", + "9198209373895042225521605474867845062450002141670817279014351290187429107128", + ], + vec![ + "543785608759854122795367682791595958842618445464321379849398930724000250504", + "10214529630060513503750965897811894289300014475522844219670830726679857175601", + "11576753654045835303746511804171201194442330501175712221979130082457712862265", + "6214928611453392028562534794962748192402530967301618657847917468183855957477", + "6248903930557664471829331572570457764958370320737816568669654972084840708363", + "3521559114442643806761280511561190556015853803605505266866910604261521098953", + "14207749404758918058098136067805881181486166837455095244160881284733449919110", + "9959485107346230833915817969343930335833003289106263613217998567268111531500", + "17002458248120505483758089120825692383088865286608827557586088545674133219848", + "9310286746554253001882911152696415122865977191166769045081952245779941262056", + "833245639626789987010046903814146615257437312131003591772116076699143834195", + "8257332153195419962290907487481324519003765405123021230564312430389478396079", + "15127724347963527967475442670935452967842333763417615675896327776913208692165", + "15791631600664089304301903868070551535052107017766205491164731100213785544191", + "3248589614829341629004884091016822219853816257771914825780122055933452087513", + "17215199223989028745431952733663229031216291778213241728328297124270973463797", + ], + vec![ + "3857684745108028860654397149812523817069881299315264066597992653650257401551", + "4707785116452305555993924679316564589154347100943642537399862884483438576343", + "19430682328356065477111453488344441289467658065205729792227680437122893422861", + "8005988640968242998051528980068908390083328633663970547195021707967989536508", + "1972474227742829959658839187518313253567182690341134307491795498427960575880", + "6504813065413498635983080741406156525863657160083764580567056987831449046042", + "5823311218891803691266204716746992257279538141703406410574718561307174926795", + "9892303067707797586148875186586047934481214044907972144908705198351662761557", + "20467423831764780786043971286447965746242601887189594828393353559483921550575", + "5337137105639218811346004301122986797373254603744281473362301032791465429184", + "2653918865001450389595199059314513619487087198676481143857196098234024054997", + "20026090683375374670866007502511215153733777854247692013299401340222837331064", + "16088029123818655662676092939046004587731443682967462740467056646463545748825", + "9880178757459464201483861677712096813007025248923714154921858424834034903165", + "1227858189983101698453184059397045112686910656353893224019532173573557918655", + "6965709790321124552058584230424761849742693958580766537537673695015364525547", + ], + vec![ + "5275724511243540616354496187333612866929959836267482390875038898914899476257", + "697708336385781014957549769788950342363636191998726381071876409126144042559", + "7274584324261857876506709208086520820725839679509101845928052585127373751594", + "1101072498472320542658663987709974387416478403320298285132888772486638626384", + "17063249509595154712877503960715103016753273139274556931196815282616091591377", + "20468232842910222775240425801279694589286852891430236774476461428028768660386", + "10839957331597622631657614186340514237771754591887181416690281526344756522470", + "1833441125433983427564061829081424752522350755265858559398836992598910515884", + "18955730579934733484387457001397648556717991843841809299503396866826874046919", + "8193171082824386660318148864436464606096456472585333569988889002087311061541", + "6800731829409783994258949782115883803874917294598056504156236185152975271613", + "4551221506539437319374784319536342657448457365716669137274070321896962382201", + "3888700085587860510427705376785182344099574784427861867496328978292244934753", + "8086322087822351497126170321910559010882234382816099821864406027930561491554", + "13275797274085199955841117698566970822958536692349164078040808025934114965830", + "11798506987450083560046523556681776539473600393190500985018551824337777992733", + ], + vec![ + "2379081429050928317988088394722736405728459402480510127050576787799908525809", + "2158947553437093664557813698796314628878318098916390925037304154608297340081", + "11904049624504424229914369023060185670359894203980447724969113153014864088654", + "21129595246904679929428089867320350013514202309069019924095527072919847726344", + "10893562472341509760161513998095439702562664638408764329166649578524495942254", + "14633782125268548143403043594739012390811363821154748677494041549086652426818", + "18155420130909256009162482779733306385315875131491307204196352931575522168643", + "12073522950076264054413053294532869251854443128423131910399999522064467473027", + "1433592116103756425832298952472313408701354429203600638317025112329710147915", + "2210939565463298865317782595691956567659826882335372151952428383797077275627", + "17035360868359161456401993589512915729326589319922635525934508061308509305732", + "21403800287219776827894322644981677663016408317172756418765747341745060868637", + "13463317002652268594305080031749651114168039804631789430404782211764311412845", + "19738499492349409431828527491123847227085394983018723982858408988105307624104", + "2012548380220619299131832783872761872147153098580334235039922730491934764706", + "3325274441705326523449614352431988173829782789776117744919906973769657338996", + ], + vec![ + "5261611144921901341966147913919865209616390993972727644394713260572315512744", + "18987697050242894331980397947115962487019662790026980590641254086717180862945", + "8658141027857622941054124779019043605220504649377920644749538450450805414621", + "11298428708044619749095290390778425959792777464903586113463716315584533582828", + "6730200291399992595132121834599191803078178940321882359439272645986988925939", + "16058286461189478903573915480209402516073069688039571574175048313793344696582", + "9740895146643188739739241045620497326490653096157416163918867637699590812365", + "17328668678982472669285290349933801381460489699965770954259262923597437466085", + "21089229510079204828717685354260991995629733636903215847138008238449607565274", + "20640971546156771190021485453412235742638585574517108137718546522103899393969", + "14758279983387100491873648446401986574422791750180622274744397880182747812100", + "1331898546985028774480334813742156878861378216830516346949642945416964272379", + "6432287430987511826080726363315893796139259314225964668680871966245781390173", + "16771287021606049252082476128446106722127174299597407353702759915141825150750", + "8558856604643032676967156921137773032066151674912302830855999926475047747086", + "3441849687388033123111488396776112259878496892302987380166582753348946609870", + ], + vec![ + "20817116194964519717309108464421257788806753886196720998666047916921548668924", + "19363239836951813038374327912605477961457473367759250309818663552575087804364", + "8719722538679135055399244869855972116946451760806505569767286592823561841553", + "18664054074328463099250618543796241821469021451703648566147509976488389212302", + "14668897608285076749626150823646322752663015099871458303607991619920343960884", + "8824985320268620533295858061606775496359110158594681923758227994736311199135", + "10765520116421824752776648993191019870707037690612646148788741126433863060128", + "20754227554163810768271776561488490692278680037121708279136293739447289576147", + "8507072847563043340105426835824153184629689984787563844408253684598778757305", + "6766982373679017786884251724806484438649942596522690604198707242527640673411", + "3038766798814116247860373387571799940341461487105503437312437210868806237693", + "16132175023628563044043762398003871532172614031006064729051923614189729264142", + "15583173149116838843387513514855791665649616393679968646432984027900294981739", + "19200443718712964237956082975258333421930476944060656325774330146577168149713", + "14490821043935432280588585568226041328772039440696419883978899443298638245193", + "1261830229525183456874822855513761625054204680497477037321364189175040481068", + ], + vec![ + "6528746667003363057717101918351735481714469206031070610241614606650021871543", + "16147698956945808666133328464174436996026072559773234518262594815923002983587", + "9020387669972688980419006674825908656426016085797207362353154226605692909040", + "6727316761823910734900206867002954254557029243225097482815337322560175181198", + "10066421681146255853671223544720366622786875122426340101570461526567311479729", + "18114193263469715956238812322551819970497722041025850638963351240642707536449", + "13327552382593937204593701292574430198134175441510741573417228229955049364251", + "2372604211171385703747757710474646305749482500024237878826421281702483230858", + "13257727745849193909326785093877285673934675536283265665870765530981203548766", + "6028193081122651452411463574343231811776375151328081689399842891316362242212", + "8508301356193721985012355411615100178521599009635936162890863637274261948848", + "19464559199695905284994131173285166577427724356611906328878634139911049316349", + "11574946347736941315258330071986157639717219704847732435648573723449097294965", + "14316018291870434740761571976364226850140038868497601980741769481529398163257", + "10918196690875147279977362872452345319770767457845834002916792583407449275430", + "8977373069224380198540140180493576791843577554452269707469880849832228035023", + ], + vec![ + "748498829648879147053737200607377785638767247375633990031472844537260809404", + "7873158704115081877804196477528352958470140833786962209738121862287852609943", + "8630532424574483719830065132415752445222218233997041715460638881404278125797", + "8690582614704926771670051368117061261335922283383440650770249469863376973533", + "11095347717221488007795836937657301037546485308926406743891578760518489637433", + "14135401679286508502504277387212121656373093920904597158275723422439876100612", + "14738090907871182095556666808390406734966899260337679732930591106508814238308", + "69949271807030541733792162811562320986072778465870031251424993196153906266", + "1261108319753649612663311207745706802298135850234573661502446278242936235395", + "16817683438765699400477322528948826720336276287491287100775393652707943792575", + "18841362612982270174762542916999427955157117780377439797570032391179795654286", + "21870116979686159000730008975387147484906370787640570497473602061164852395071", + "2765949947644452455039725847864010340741814376903283748968022076584286340602", + "17243705140322781483942034937718263695017457618400778609034996357553437986248", + "13677914966377093417490296499705767815775553283213762175449591670735007344873", + "13297897273167025228957171745153893110275891317806768533464851402665750442708", + ], + vec![ + "13343269561671098171091946421541340634645677702710756455899883309946421878045", + "14317554923995329326292532110843156058636017277221221405605647959782965284991", + "2449835610256525707119222686954432076774548565002604197859382557987062142872", + "17311927259294224200654531686487034697399582221230204382526629700762752029323", + "15886029754147081563564215095016637219622964863827251334461319377673888336370", + "12975391569205596000382467418571211360327385366404855968892273321920864753986", + "5192224731376769981697271181929966876988577937843948018413420047649317448463", + "10676192139479409715075805869252336543157972214291179434959380291895052573000", + "11177450837775344504988539319102121281143354970746599512770721409890402968920", + "4593200667847399069176143966880767249193687931869738276411303724780636851859", + "11038090380551563944847929106606106685586830480239388947878234434263502089528", + "3953526418885419728011595573117200571065709475826662733812952860173033412620", + "11423581837569206292763368836201420979900393158634684009052097987935130296343", + "20821758092880168608657749212670937227806187953778513378055795779476865339010", + "18497750301637542715216545677959957759969933594321504330433834545748130561538", + "12908315310864070359072899712184126229744818024807969170422172983759986468742", + ], + vec![ + "18124554128224712379655197019948407579501104121202515283344405665022477997811", + "20982975342803604005070898815103511622812678185245827078739170834137855132820", + "269825514811016046965635325890713556615518696022373524499024558861784638050", + "3147172016143608266119085281262979524079358702373693860744797997889998689295", + "14386832245166477008833710911810567249931220515383598373556096298357174022469", + "4556487278328022691163443795787718624849832853076824895328263286768388362379", + "12261472135716169178595791281788338424856082203277018628926152780653238868197", + "3899423277681311798156637809536718065846612626667684730473026778811334914007", + "19506309861341587023369919042973949592579256277585657370274971571040135953685", + "1364959409282923580897524375843789492029158451437094417717346158650761726050", + "16825446178437335546349323854223244861262257417842514939476542139147191650927", + "8507209116997169365742612629060440573797814488088100151461758543065101868641", + "15267004752470933248572062004321128218304784520473623806984809921883550707694", + "676031704648473427598859615894926588607941948575683685792835248653139785855", + "5619669402121492986528563034254744932241765329516105050276049374453441613893", + "14704798323824402102639327448519792804756861685698966598005087155126928897024", + ], + vec![ + "16320067378138810368504584396122999292945236808095532790918287639367557973453", + "8146733655224190459272793912328710535983522769849572460217349885461291275505", + "1038180418056776651442944028459510265058633383281360520702142043667403503844", + "19104250152149288692194160087229108962380481983770051876357439473931889382526", + "7003760916474780870091321276888809099928758016210575511830123521067523691017", + "10460150809039904156668983747345347198316841366879181914914418086579576664491", + "15677112907432790716289265075133862681087874169637399306212310599581157175963", + "15326287388823547786897864243344800490244989953594543352512215080754525987008", + "3009920542142872962638960374061083879344081833005888204328736035225746795718", + "1804978488347291728619316877980070589260679228487014904460247370976082660690", + "1328483773995482788116589592947585572244503408960547493086897090179230375909", + "5730439196427856076422854580234519707227885379777920110477133774925338997125", + "12981431367443547352573507131765244291012615436617972351790438163822109185806", + "4832711978673748239567077367987729540684018769513731999388791063624971084279", + "19167638139894327951096186708600927728591679782746822664161578344690189946483", + "9333793061773227893961520586484148770892826436173136355616167263506645189532", + ], + vec![ + "21458443518750111068075382716496819469049134888053123021475459386077573760694", + "10205061553685164402371459751106832224694007401400200656551443744478399832956", + "9830442925198991171494436686328858756494894392913894165312258843542937207416", + "13609869649628867442619044498926584416410429910199812031508542862339177409898", + "842857359216662427573900948838829890161571314532391785590044951074431433210", + "6704851129269714864143856350805682503777715960622547687053167421313207852468", + "20114446898395957281817578351485444375476540075666338352767091837280210668931", + "6130491715603374999851365684496448519606340852139128448851532580625582546602", + "15813600594451539718733724931622603275717510629305297903420212550967482486778", + "21327142130781371825633810115678136219928778056926678460292750153897861437357", + "4961568602907543961625596532526706517274095072299784820035412496941108876522", + "9960714813540172203971946479714057278358565379915043327324100653488017320531", + "19766028424299726292403979387148081559608033800073407130824876437622345769610", + "19128679427621049663909949398415698465159247423858348746959133844645715231748", + "5570166864868188450021144960131468276106515498742461735810689530781856406802", + "11574972995586621052272541749980259251569951388173301707052886832340902170154", + ], + vec![ + "20877646438494519923058752260065237612204466401313282232221152388173388627982", + "5249150519585813956946898091205522450918428396100844955321690157312140444303", + "2017741632554727420098342601911590665808744692822556685407780092354922864904", + "1195760854074467363227832424961613965990883686618742557387108941759791735821", + "11466582138640916980683611003811079018804741425452823176665968956853901549307", + "10985903304141344987201754580174851046824447026961915755527591886735857840658", + "2130569969210610976943124127703960718576010294778156297713757734434872381369", + "10738808247531379378397673739325665568136689079862172683794674460448121540040", + "20614646033198180892625991863201166456931543657809805208583071176938057085966", + "565997125213498936861304726982380864240733960104507001725677609359585569840", + "10632097546602816816944445466416073366486654512740953706603375905768461201631", + "12929362833112356946255271584627031609627907912912902502403907291451582319157", + "1034235212357952436868793031480652544314617407845212103021627643626485031876", + "19390762319422155950976700977771604452581304443563816543281343170335005291057", + "10630153844633439282958810722979033212891017579520387012386923832074337305798", + "14190876500956732147461925775340768352695586121304109940717530850819588911999", + ], + vec![ + "18722506055380266423054060346625995391170752586033471909467419883841861306716", + "3056819986793075694786756176651004538794778835114033048299678024064951583754", + "4672570536584218848208255703572454924953635491594309524306431682544106754221", + "17351556719883029551473146382008643929874047263147825865359162665615894766393", + "15361589507494181649833267508353254535596250253216356073840778948791727807159", + "13693471199005207103868448237123737586403755421081623632730820742927025187060", + "17755277847125531485682000612777686738631414648862078678723432159826928724703", + "5078737090654746516628738054730387217943533822956354885634428155918832329055", + "12147601749747781924069337935019031145159705806951967042421913575214356549816", + "14365231440612787726412058658929032228572314258997026523542183583106877612565", + "7278303658563994843919131396912585917500535615791945995381401546353032136647", + "16203755920169126984249498560164803107868240707492521482933949021054510520315", + "6791925607504018751125155518211487306271141824074365658905258365090537532910", + "13823494237593720607868138054959291887740146822262268248432322209124930846096", + "11009501160902109690977091445438703229756969339078969536565574715162502634351", + "14720462490975063947234490477382491041961626472580003583159938559677559185952", + ], + ], + vec![ + vec![ + "11497693837059016825308731789443585196852778517742143582474723527597064448312", + "9160854578263429171202421862962594026987177464192712717562131193605088890171", + "16140003334191084124451468943070902129052879491017160345910048022420147165440", + "13954253824852759534031493316905992731351625718124698909948022659536770029356", + "21692459647877833789326815072729212414846887919903018341690717828718320112005", + "9941936267230985844518782624440910125063679135232844826673261884947459743883", + "13764916706054812213341909699290503443927147550756936312875016380348026052252", + "19102599208524798070012402067365820884265931087114568811319734727534891174260", + "2317229314815846955024814528087757341110607641360330608288042339421595574836", + "18416483069534816725178879766589878658686265350707575814092642317380006218736", + "1008780931278741447191637805167409477999443010661365677836100477728938308997", + "2545090804346934163783014162536858416885322260022963915511642447380970940906", + "20063061892576784746234714844937263854658165123147516223299128773175198821424", + "10515454963476061878165006305843100325941655508909556343534889232612007413255", + "14666046876279128708964624720946075308028756066224010008571298456055047416803", + "1019066804447509488848959767263827580870207313924599851872882869076383737080", + "12069305948801710705684828347680772060569105557945593846885134778987150642368", + ], + vec![ + "8621808318996908879998215444507382011199442894883948814246574848625262495021", + "2880093917191730817222149621749122107421670637456732204857760380124742164752", + "6542220672426887509675431131054437027921301676718161645952700116082427886835", + "5244163576308284656156828799646671881031097312780189786429450879353224489935", + "6473177356818363685990488940547034234726012773074061935352613261396549623686", + "21820960109882302233412313690073759484098924860992104203363318963429862834269", + "776485012941102583811996326817291151707768276005464663608504425462324969189", + "16008040671461692654565857317129301282959438973184407738728929267807682783872", + "11432621469217532329151110587073289606303873577842245393046608426744660231625", + "16529428848681190297024382986484471912959470051547049854507168832330777582917", + "21022141832384945339899318910964518260971220396886777286264903115370862218195", + "14654032557013894559632377088090851151746560959506805696507500157500224672350", + "21354688910115519251326230418165921377662159943573060390104844506964336391116", + "7752619774088278019865202458496784783724532278543560344508935599686049023521", + "9970654674664205783578937362441466301698784253920856829108173973533602978434", + "8766781005151378907464491478911534398597711022218593484510275842885145890118", + "427418044823104424459481289119034112585817787122063948281766019090147258009", + ], + vec![ + "20178400825368362428846659280983736786989246199446877730902913555280765010239", + "20090950791842994139452610863206653079874108855048809192426038290381481405709", + "20312256534186716461922298801781816516042265527822903054862895650988285562148", + "4909922693172591670749898596465752034935631291352031623980892388245203503556", + "14711873682305388680005649678171045910409841883308457847530167875811246495050", + "15958770417311022337941451962731041577578914593218560089308342731268531712920", + "14344571866504726216497643454572836820480317972842515429281824926793932325980", + "1769397319845168475613819781273574132774109508454697099778007579313922258588", + "258587389395146525547707547116022862705614858555176588203787762094788370646", + "7022463667655232121918607020344762877802128330181623732816227821885112788637", + "19845060031908398041047500648731073426448577406797522741285587091948148114644", + "8929070527835967284189505459276001504282186650781989399671939877306459603924", + "3547034362934554702033015610070536051926221082690581599667998618549114761320", + "4305372853651357563855521637099663044320680997112932657745973067738472275743", + "12214176886158725776791687535468106829515395407992835497927312162638766770078", + "11706938131011539306398383828922578377803816015869195385220014980091795489607", + "11651169608106469169652973769680487604343355235752770879131657116772958352610", + ], + vec![ + "13534129170664288430416028489502009030456779206590118389136628926201783734674", + "17992046595622622161177230469344714863802535922717313714552838880957499215981", + "10357743233228120740298650287569640748031608153491097653220067758242532130547", + "14517928487614900276301089165901434951535050275402697067248151083596639118376", + "8209182069608252268840455827520737704804441580266130568152978886513947166844", + "7640073974915695432060688995568585354936052110685953897202450273254409304465", + "6665784939677502535233010310165049782941185917893655988878440622136707103599", + "5556533518127592657586282330044128807869230494205809390140992474026365014562", + "408852126690043032125614061393097734033642541042497038832349288207856020928", + "12457107183372565990532088400464843754189254530767241274690121422398153743230", + "13376606774696045471509234199808902800235186345177397461276986609303176540711", + "5984750790245793264714000637029537436625478804219132653560918517073545131213", + "17088785934598552415567637681327922806463774512289686863420148678865116179843", + "20571346584413672249720180719864302959756306192295084730012069713189235458689", + "10563908856437897624492808163035753573292724651291788140893440219493498317425", + "8196914932493081300314276778567572383087801740102758457948867897900124032622", + "15351358433647454670571026954149706648025357095082471550411625465102412004635", + ], + vec![ + "4691549575923073479244290910433477874429633596189924034857922132851997509067", + "3824402350445187488499181297883462500055483166807595223590583390670577007868", + "3079709149206454455742256725666572935951085219797765997598190006202700553625", + "2933435916857570611285367519434342227981452027299670163614250683347221879812", + "11563256620627039928684054332499213986056102448749960304814905960272568400553", + "823982800920919472728462051408065816783743200056445901787723684868401502814", + "1426387027752743868839120378047531362360888408160839303820390910661721602405", + "5731997056751920185589748689260608921390513807500493745181552863591316000292", + "7720993839832885597994588400736035173902383878486875722645777844101744411689", + "9002464001048295091481045293483875664362475441902824699977741340020558338559", + "14092406920820325227424145554147519809410886190773484884502907926085878880530", + "17941121573263204671416572834368313711647830547916231506552438869447449377380", + "14129082317750218835304685520412323779932243077309313102580200435673568399019", + "12243264707350346605364305720479795822428336866265087370053925276897423448873", + "7359586883838006703688461248312304702229090925413466255532354254039350309505", + "3965462104895971860844762333128974051506845133345812196538391893357098668635", + "20413404046776512481224629835753522701244606906272947012890416028042446470875", + ], + vec![ + "14776939713848231582251698583594764736648030077584017202377553055729297756934", + "11733430377692682072369036122380634083002891720790435745639760545087660184574", + "11292503903510690808481905838273174776860675950299588217800551517281190922743", + "11420684871520848382159461165975179232780830769432469479502922603701278643559", + "508745459215920279034800716428719752357838311731203417677851933253804443780", + "13406614833603475717176189537057020401687589054028958458013676908546295198427", + "139498778461763532268768837474164379463641791532876816780917343085192436149", + "21267978943610728192699568453293742013765519272282009809779840168468272374983", + "13427075011225899058346282386775414644140701782157119231274761492276104178003", + "19408556542747941554117161987423225644412569826994655839704848575188694207985", + "4344748623903456736892311801593408666061687792073497811421388122550378864729", + "5249164170024197498338412206444867159273343488553715674803882832943638673489", + "2429321160057297680775462145791389342017255648014188548442207641044604477112", + "17633034583356484958669009250049760097861376611937917426871239574846566954163", + "8589358080626653532622087734866363152181033731195407703922685134228472217961", + "169706674245923892154983046053808641575955705892301306744269839968148939837", + "6930563539197568226045059034503291611681517204525149696500944995384070682620", + ], + vec![ + "7715180204730071272045176332163669182843407084675929323110162515552729145466", + "18820951479360410886797033460215573843065563410033088307349452904607006418510", + "13004571734426490172877737218587476803131320809388224624418159739666018276230", + "4221983194911935567520445796137770165826124860682996668925096525627918503987", + "4179458328609322852016864400883248432169808675570811233121213062838243996150", + "1974895668668582620251979849937803690939422905200315076249511583941627363923", + "6163089641798041487723906004413611225955533949531028903999813030048150618255", + "20798314848405704563578428763355242237484138146926032039199072579614133708498", + "7390763848541838674951447729994978703104555741288179669331719960925737939679", + "17595709281213749734228944927123024058411855966868873405155429088809356857614", + "2441295378821425129112278178696474169691086102217838124236465522719015824771", + "17849999656709233176331949642982487670074039937621948427273232063967495006615", + "5474039350730649299741439140946492457291098791158740216537321189511814004320", + "18047496680368319496003204418900793303422432417949101604087210129655489944730", + "13429638037186326961998474643589136448656547552567706898682870898125573018456", + "4946359485751570678621380009145072972898871622865400112232372288432448523287", + "3957822358540559545601980592836183988567881320017369675759228588453032530432", + ], + vec![ + "2400564715392273231728553914090327718988368277691346375047322875638060719294", + "11894303179337833272080120828007835602120013500741388580434416759507002392538", + "855198138664096487124576201178969627556714572486300747020353650684651888948", + "16178438790960495615141009256088177242852822581784859562011828222911238142141", + "10137977256085689928230181030370096331013301569857962720687404778057694535741", + "20515298296047282701750471139118794292164841708209011112551973440387123890479", + "7578927989884657210580284649728673292510875058413984297956940891614841867974", + "15739538064110791981043195085211350004676897766248503311173839899207608217532", + "8509314140684268376822128791119356380924264099968476717867240237437611156406", + "17940958334079989608306082569922896755033794405963583994940471979845228834401", + "6805144082112931458671099527607595264417843202533041916539891329055761729898", + "17799985834198911964923035884156388240555414131807336706586014102549806733421", + "1321093977038377443723007121319910985126631474786194145179087170534580192225", + "7212420993868874204016591911998823569295893131341249414736874789036080080431", + "16508732240056273863067547854850721821696261984346034975271352570374366672941", + "19365952558655609049762470933563228578883041309045062714419724629518231309330", + "7130642306151081144305696424018041594798737863203511582301667374235931034428", + ], + vec![ + "15515575256858646879456258778282520667217724217234033369846512585375869363745", + "9059306962111196078284859952597377729932287486280210246946890053176853282710", + "4280792737479805409403664514498090636723785279466801897971750554236293020515", + "597858655089478477234738420519139785711327216887739704481840585427214898574", + "12083197860096972935386715826619665719725493525449003092099143765304129114681", + "12386885105651539176174534724546204378869340659228252756723599802198672140462", + "16104345036536728728283892631581380860380214418375736872156768647788333934514", + "1354879242449295308208627398119082438254972230604954870747255418847391619159", + "4337243085646703769896498772355566596731636687256987520433742534413482763248", + "21848361732679483806572599977716282165817086425830260890883893707113846583427", + "19219603360817893268138318807528436572901663409914252265449565639651815377666", + "8493170221045553556330983879086435859112709446579471993956965243640551891229", + "14527043796091130553415865581526659472541220106744153300268446542314624889828", + "7937111786465239058321924657743649234315319708955946415168847089269341907969", + "6983241618969891267833664988834562719925952220932975709556427480787427509845", + "18465592203176453842524453315376851907098534348906659566313290009668304127477", + "12577134888425026368283611608059363450080978991251364658919457233283032077618", + ], + vec![ + "6518118228984271075704215109336988269949556606855830580887066004852197959585", + "10874313757780612756454383662805810655295466490423990025119534270332368723291", + "20050459982999023948350579488832955163413000705527333267976511300912322921717", + "21437528840108163281775491180120464654045652656938712316426352947376535924261", + "15993399358508475124653838111269121783855992741631266590611036066175654211556", + "10666318855988978766724392469406816805194254878125837815249460550109965279109", + "3728246313656508848829733684629154197051824118611903835393981369401120614690", + "15672779156766891637063280303644284349935441934769848438404666835306555334745", + "20385059098581842810391414884461531594818480948222590493458925664185735049630", + "17350905999329080753256083745369335770368978719306867594625495391694963226620", + "6853271030225637900654747228083647747830481256853322607732231926920221636638", + "16945013335725553221697952514726788415224349981949301561114619373330552300437", + "13958698773337419850196158271441769489630950623502500296722238460406723080346", + "10720560039907520317176701532328409797933913846226344831945799921818292744504", + "21881661898012375513399335499754096939362343783241122010305516740752509759219", + "8000150875389840177411621828177856485533123076967778453164076865957788973133", + "12006864256015504014085835403867962462497397391751885107034795661085483190829", + ], + vec![ + "11134943591559521791276826061536197135026619606969540608969613264694780202214", + "10460719249321273180939167776515335033037028258913526408809327052344611741158", + "15622824325483665989612723680117847052463187830077568039968213833454442303285", + "15410746446975895232352042328675463711076427815985485297730903996168105249910", + "2891625203408623652388062275887825901052275992286085168525244670232353662516", + "13945346776936592111645435552497641082181197055210791224507452108313960355724", + "9948029837520576958543862437428843878940881432043095435233721163595331057646", + "19462884070334019417166507501239463855294968830363882698967905077860898932836", + "5520136928844106525731832126160315598282989291025512087174203871698688956372", + "2261360495098633227748653797124151186175710067614537829940284371045336769476", + "18416255543912854662465760974639117371049579168655995592136361451572699752296", + "11463536517819692876416279640167390882172379596277754722588804736317693209031", + "14766312573746115666714530391277822821010415216258152152785909105008723593246", + "15974413313983607427146441647805917978765835122483385258268287590594890695726", + "7395768998784322986017026062700445312131764953109410144512127957624588026520", + "4984362060666297962621166548113407854009922708767986933509108968930963325593", + "7856069925664789206382562869453172139307214363990979700110954142509543954720", + ], + vec![ + "13392340056392075670742743235567931160245313927053798436913893965097578743589", + "14474853581934896987119860016624045909083123926480713073931600741515836999440", + "10281094117655562522718238098582121237113987849950975777935895552307296780258", + "15651874975250045926713763993802349605521485743295256479167713866101959393837", + "18837584337473843738351569365992574544592556787094567312567026738414350732486", + "5422285873429437751528536004788420694267218180077508101272917323525729776286", + "14483434861134394018133707852914799521209887335043004813883706597879855694501", + "20781651897373919207655051244184479648667009194959049646213659882342077548670", + "13257874746816536319517386553976680827294792028033921278407244416529098958298", + "11687595443717328453023567060513955787814475781716013805208754435947875015986", + "18166734702075655056906373297658555632769934998914813942424547912757194661408", + "21844245024899402789239043296889438934444349492098488274411135961103932824086", + "11576523423366505825808301659798885009429028155669986846400153307591026628871", + "1148929907457849288972409801053032039492913919668345502756020163532587226569", + "9833563661199700341560575887921549871699630430379479441644037429312353663854", + "3530072023449326955819177530541286351102246058096342120743109127661619847487", + "9578572618820421025088920868463234434017082077820664789170518853528041438058", + ], + vec![ + "7903274455513569732248555355877155817202990193424390098928646605922794954894", + "15657165496965632442135478212817895834512397576120080820666617370995124184076", + "20874620177603797416855214546759257732117862468392283423272496519554421621175", + "15225141515575386127960844403303707527145779098407107474807381929305493685913", + "18969726739742369826201131743053235807095357084892793088520738053078283905792", + "2273322388759602026766688787958421446004694547879317377854849512027808056744", + "5432511453110863684214390264939773007164867954188379597097897639266721931777", + "16573736113133010502307046980851924227669732687124639246608245168226674694938", + "14442377229880210285366376088368281053151209045775399428755468734230536622166", + "11507669956883827819118311484641373285663729813488745641363568933392081679659", + "17839532429606263422276008800408286253970022114288361307186094837217135904945", + "4014265539378515041529068347957642340321904838486974789543291691351911347680", + "13003411109936526663340169024379119873659186776343250211166084846025445488231", + "15306462549196010658398578543921194922332897913051564489815921371400376655492", + "15374920278441335059913374044144421033417626851032526544458034333565246831914", + "2323707387573936061377018731706151895551673463355017998838984100857163359959", + "8763825614293136074070194100490720958859071057754803255698169463529260604989", + ], + vec![ + "6460078619951263360498950096593765796985616066844041272594234887640757495947", + "7787749571541900537576366919010287855513576825542236245962970793208463720908", + "14155132064389382746286911268123763500605059883946776474093143918456417640061", + "5273412399684398435707041325417233001212071630727434066521150499193222197699", + "21782771343726562685905794523874393783448988772056027768682759741108535654588", + "2051311409953010480673263657665054154914165583084681916263406447692393737285", + "11875661765858469891704167021983258181748059479218144774825851054326067416765", + "21068403881106541076710977164706790160208140346094887767675202443752560686192", + "15758340092420689120259589661569467106735378390624556577895360824207644286190", + "6348044865909997285104441438862139025250301814988835887095459638724790173542", + "17932524652786058307278475190078972097828770914834668973535335630530452917847", + "3228816608788245618072625224844244257443056161113290604232896419878090903926", + "9551656383427589703749567396517141384933708835078892692797520811547619069163", + "9020946637763713728445703977273148745690000656147983844173946393849341364502", + "2943971707938849936044214925657955353752398302351355306608002652427585494465", + "13685248050363412502458409958081650237171619758299111626717716567774759779438", + "2868302441860272746035818268943730589208611466934920188905195434962368539498", + ], + vec![ + "12942754961762450702258615422302669970585456811961698112554744196254280397924", + "7774153016753223166594232439290374237307352882928845881491063153885238423849", + "6049199094489456460150873785624904803705527267070980629871787636829670320696", + "20845774618508072345571200270048422316984213457783733272821856328966613453129", + "893781271752145245996199566953390937322128434854461459523685354415462146991", + "18253521160421279022112163574719081086152283091051794425756555232523003389714", + "5830356839546054218884630677325272050228211705054095093735137780865196640272", + "465724850238100756077164119125411924005501292693566847128509233889037994810", + "16128424014911176575708362980592727342883849823936273728991741993116151256846", + "16294469866182032082852110477156803007474009685855833013024070339538767961172", + "16065302076211391028679793764673039756452069543133653373534107626161947643947", + "16884841668405833752583472630774457863811531316950980947099417366816649918715", + "6491186733352076588617073683591626846805330965399318749556699217006305107353", + "2905363039904017404089840194168764066155916074074586587258377722869451022895", + "12278525316798802696433043227895855967349302508482435733539545800309845622462", + "17314019937917464307399357201462393625411723762603710024519926241513301595993", + "17575148837153403621130441476206668397295797814863081080474688530411862819003", + ], + vec![ + "15471095648400918007606825575051718247465842587885842548618709676930106301461", + "12384318072593682092503177281279533170809948746241154089695346932340260672911", + "485123300957579906724434519828279717066415303115967428444773045074341666269", + "20783388705359037084238123327815399486599342641041862648140815340928809400500", + "782158089782171747510228803754257660300288627956397010472288943774913698434", + "3478639244366860518133129066736643188173227661380443503605881541719237123785", + "8117881660412001220282982503758841397343065193097821242261528946890929063115", + "35058721234476129650326366428341402515138917944396335645144933468879076532", + "16397938679668108498255642177027044558510343548921376375827648132906803583443", + "2433453154751221667718635947799318194191827076977739122814782387249355591958", + "10029257080729083671923349509739320383181145104464214096029001591053185820564", + "10656149073844062963681322014553075060763965763326275398946747079560564035850", + "16593959744982924702318121631183966060100893770061806448540495161947421822987", + "2068414540408163070577553011598011878961687148891918803076043034635892035594", + "7626934390068570344424013149524663454707020514194937543157326823804903603467", + "4554638618925430597188146675680715151198309496396245054063619103455584547039", + "13496396626587678250552586498039471308586222626132206600246125554024514007655", + ], + vec![ + "9386575758165199373292193827891788760863572720909068403298778509513288095168", + "7915179166050735066974287284338956896350001911949145779842510041370266325973", + "8167168351770465939827858686491835211463722244546741051891842055610292036496", + "2984855641991264563125921669666111398496570671860076360618117725463255935294", + "13345515131307851631101763161069239153529744919878592460694942948582652858318", + "1683899377816547722982571372970082226593844001913781056647398610840773630210", + "18082738493041031740109434905429676829872619916356658605260447196047710914008", + "3093627219579176143734483600677215286836843343902256951787659223143740127833", + "13711569243726999863512778161983125470458400981069655361767578939766971032706", + "2942999073656444791256166118886574877976523928599259988730412230442182398832", + "13741805436257583212406513632778404280140012772934699700695904335718144229392", + "2966496260001027437433299921197242880503083867421600405476235949236365134313", + "12214449406116917832159291589682410934022154504967698746834536840379875421993", + "14724028677081535225097028894192068729072210977241429998194582705094787450320", + "18532472576071611894578331306492326674151870705350144561012248059523768664658", + "12590949238667856614747230064159254583777806754508472794550424398198576585120", + "13228220894074693515947418568115512670466893414535562052872530653586084906533", + ], + ], + ]; + + (c_str, m_str) +} diff --git a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs new file mode 100644 index 00000000..0194a3a9 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs @@ -0,0 +1,306 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::executor::zk_stuff::bn254::poseidon::constants::*; +use crate::executor::zk_stuff::{FrRepr}; +use ark_bn254::Fr; +use ark_ff::{BigInteger, PrimeField}; +use byte_slice_cast::AsByteSlice; +use crate::executor::zk_stuff::error::ZkCryptoError::{InputTooLong, InvalidInput}; +use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; + +use ff::PrimeField as OtherPrimeField; +use neptune::poseidon::HashMode::OptimizedStatic; +use neptune::Poseidon; +use std::cmp::Ordering; + +/// The output of the Poseidon hash function is a field element in BN254 which is 254 bits long, so +/// we need 32 bytes to represent it as an integer. +pub const FIELD_ELEMENT_SIZE_IN_BYTES: usize = 32; + +/// The degree of the Merkle tree used to hash multiple elements. +pub const MERKLE_TREE_DEGREE: usize = 16; + +mod constants; + +/// Define a macro to calculate the poseidon hash of a vector of inputs using the neptune library. +macro_rules! define_poseidon_hash { + ($inputs:expr, $poseidon_constants:expr) => {{ + let mut poseidon = Poseidon::new(&$poseidon_constants); + poseidon.reset(); + for input in $inputs.iter() { + poseidon.input(bn254_to_fr(*input)).expect("The number of inputs must be aligned with the constants"); + } + poseidon.hash_in_mode(OptimizedStatic); + + // Neptune returns the state element with index 1 but we want the first element to be aligned + // with poseidon-rs and circomlib's implementation which returns the 0'th element. + // + // See: + // * https://github.com/lurk-lab/neptune/blob/b7a9db1fc6ce096aff52b903f7d228eddea6d4e3/src/poseidon.rs#L698 + // * https://github.com/arnaucube/poseidon-rs/blob/f4ba1f7c32905cd2ae5a71e7568564bb150a9862/src/lib.rs#L116 + // * https://github.com/iden3/circomlib/blob/cff5ab6288b55ef23602221694a6a38a0239dcc0/circuits/poseidon.circom#L207 + poseidon.elements[0] + }}; +} + +/// Poseidon hash function over BN254. The input vector cannot be empty and must contain at most 16 +/// elements, otherwise an error is returned. +pub fn poseidon(inputs: Vec) -> Result { + if inputs.is_empty() || inputs.len() > 16 { + return Err(ZkCryptoError::InputLengthWrong(inputs.len())); + } + + // Instances of Poseidon and PoseidonConstants from neptune have different types depending on + // the number of inputs, so unfortunately we need to use a macro here. + let result = match inputs.len() { + 1 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U1), + 2 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U2), + 3 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U3), + 4 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U4), + 5 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U5), + 6 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U6), + 7 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U7), + 8 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U8), + 9 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U9), + 10 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U10), + 11 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U11), + 12 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U12), + 13 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U13), + 14 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U14), + 15 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U15), + 16 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U16), + _ => return Err(InvalidInput), + }; + Ok(fr_to_bn254fr(result)) +} + +/// Calculate the poseidon hash of the field element inputs. If there are no inputs, return an error. +/// If input length is <= 16, calculate H(inputs), if it is <= 32, calculate H(H(inputs[0..16]), +/// H(inputs[16..])), otherwise return an error. +/// +/// This functions must be equivalent with the one found in the zk_login circuit. +pub(crate) fn poseidon_zk_login(inputs: Vec) -> ZkCryptoResult { + if inputs.is_empty() || inputs.len() > 32 { + return Err(ZkCryptoError::InputLengthWrong(inputs.len())); + } + poseidon_merkle_tree(inputs) +} + +/// Calculate the poseidon hash of the field element inputs. If the input length is <= 16, calculate +/// H(inputs), otherwise chunk the inputs into groups of 16, hash them and input the results recursively. +pub fn poseidon_merkle_tree(inputs: Vec) -> Result { + if inputs.len() <= MERKLE_TREE_DEGREE { + poseidon(inputs) + } else { + poseidon_merkle_tree( + inputs + .chunks(MERKLE_TREE_DEGREE) + .map(|chunk| poseidon(chunk.to_vec())) + .collect::>>()?, + ) + } +} + +/// Calculate the poseidon hash of an array of inputs. Each input is interpreted as a BN254 field +/// element assuming a little-endian encoding. The field elements are then hashed using the poseidon +/// hash function ([poseidon_merkle_tree]) and the result is serialized as a little-endian integer (32 +/// bytes). +/// +/// If one of the inputs is in non-canonical form, e.g. it represents an integer greater than the +/// field size or is longer than 32 bytes, an error is returned. +/// +/// This function is used as an interface to the poseidon hash function in the sui-framework. +pub fn poseidon_bytes( + inputs: &Vec>, +) -> Result<[u8; FIELD_ELEMENT_SIZE_IN_BYTES], ZkCryptoError> { + let mut field_elements = Vec::new(); + for input in inputs { + field_elements.push(canonical_le_bytes_to_field_element(input)?); + } + let output_as_field_element = poseidon_merkle_tree(field_elements)?; + Ok(field_element_to_canonical_le_bytes( + &output_as_field_element, + )) +} + +/// Given a binary representation of a BN254 field element as an integer in little-endian encoding, +/// this function returns the corresponding field element. If the field element is not canonical (is +/// larger than the field size as an integer), an `FastCryptoError::InvalidInput` is returned. +/// +/// If more than 32 bytes is given, an `FastCryptoError::InputTooLong` is returned. +fn canonical_le_bytes_to_field_element(bytes: &[u8]) -> Result { + match bytes.len().cmp(&FIELD_ELEMENT_SIZE_IN_BYTES) { + Ordering::Less => Ok(Fr::from_le_bytes_mod_order(bytes)), + Ordering::Equal => { + let field_element = Fr::from_le_bytes_mod_order(bytes); + // Unfortunately, there doesn't seem to be a nice way to check if a modular reduction + // happened without doing the extra work of serializing the field element again. + let reduced_bytes = field_element.into_bigint().to_bytes_le(); + if reduced_bytes != bytes { + return Err(InvalidInput); + } + Ok(field_element) + } + Ordering::Greater => Err(InputTooLong(bytes.len())), + } +} + +/// Convert a BN254 field element to a byte array as the little-endian representation of the +/// underlying canonical integer representation of the element. +fn field_element_to_canonical_le_bytes(field_element: &Fr) -> [u8; FIELD_ELEMENT_SIZE_IN_BYTES] { + let bytes = field_element.into_bigint().to_bytes_le(); + <[u8; FIELD_ELEMENT_SIZE_IN_BYTES]>::try_from(bytes) + .expect("The result is guaranteed to be 32 bytes") +} + +/// Convert an ff field element to an arkworks-ff field element. +fn fr_to_bn254fr(fr: crate::executor::zk_stuff::Fr) -> Fr { + // We use big-endian as in the definition of the BN254 prime field (see fastcrypto-zkp/src/lib.rs). + Fr::from_be_bytes_mod_order(fr.to_repr().as_byte_slice()) +} + +/// Convert an arkworks-ff field element to an ff field element. +fn bn254_to_fr(fr: Fr) -> crate::executor::zk_stuff::Fr { + let mut bytes = [0u8; 32]; + // We use big-endian as in the definition of the BN254 prime field (see fastcrypto-zkp/src/lib.rs). + bytes.clone_from_slice(&fr.into_bigint().to_bytes_be()); + crate::executor::zk_stuff::Fr::from_repr_vartime(FrRepr(bytes)) + .expect("The bytes of fr are guaranteed to be canonical here") +} +/* +#[cfg(test)] +mod test { + use crate::bn254::poseidon::poseidon_bytes; + use crate::bn254::poseidon::{poseidon, poseidon_merkle_tree}; + use crate::bn254::{poseidon::poseidon_zk_login, zk_login::Bn254Fr}; + use ark_bn254::Fr; + use ark_ff::{BigInteger, PrimeField}; + use lazy_static::lazy_static; + use proptest::arbitrary::Arbitrary; + use proptest::collection; + use std::str::FromStr; + + fn to_bigint_arr(vals: Vec) -> Vec { + vals.into_iter().map(Bn254Fr::from).collect() + } + + #[test] + fn poseidon_test() { + let input1 = Fr::from_str("134696963602902907403122104327765350261").unwrap(); + let input2 = Fr::from_str("17932473587154777519561053972421347139").unwrap(); + let input3 = Fr::from_str("10000").unwrap(); + let input4 = Fr::from_str( + "50683480294434968413708503290439057629605340925620961559740848568164438166", + ) + .unwrap(); + let hash = poseidon(vec![input1, input2, input3, input4]).unwrap(); + assert_eq!( + hash, + Fr::from_str( + "2272550810841985018139126931041192927190568084082399473943239080305281957330" + ) + .unwrap() + ); + } + #[test] + fn test_to_poseidon_hash() { + assert!(poseidon_merkle_tree(to_bigint_arr(vec![])).is_err()); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![1])) + .unwrap() + .to_string(), + "18586133768512220936620570745912940619677854269274689475585506675881198879027" + ); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![1, 2])) + .unwrap() + .to_string(), + "7853200120776062878684798364095072458815029376092732009249414926327459813530" + ); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + ])) + .unwrap() + .to_string(), + "4203130618016961831408770638653325366880478848856764494148034853759773445968" + ); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 + ])) + .unwrap() + .to_string(), + "9989051620750914585850546081941653841776809718687451684622678807385399211877" + ); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29 + ])) + .unwrap() + .to_string(), + "4123755143677678663754455867798672266093104048057302051129414708339780424023" + ); + assert_eq!( + poseidon_merkle_tree(to_bigint_arr(vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + ])) + .unwrap() + .to_string(), + "15368023340287843142129781602124963668572853984788169144128906033251913623349" + ); + assert!(poseidon_zk_login(to_bigint_arr(vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32 + ])) + .is_err()); + } + + #[test] + fn test_hash_to_bytes() { + let inputs: Vec> = vec![vec![1u8]]; + let hash = poseidon_bytes(&inputs).unwrap(); + // 18586133768512220936620570745912940619677854269274689475585506675881198879027 in decimal + let expected = + hex::decode("33018202c57d898b84338b16d1a4960e133c6a4d656cfec1bd62a9ea00611729") + .unwrap(); + assert_eq!(hash.as_slice(), &expected); + + // 7853200120776062878684798364095072458815029376092732009249414926327459813530 in decimal + let inputs: Vec> = vec![vec![1u8], vec![2u8]]; + let hash = poseidon_bytes(&inputs).unwrap(); + let expected = + hex::decode("9a1817447a60199e51453274f217362acfe962966b4cf63d4190d6e7f5c05c11") + .unwrap(); + assert_eq!(hash.as_slice(), &expected); + + // Input larger than the modulus + let inputs = vec![vec![255; 32]]; + assert!(poseidon_bytes(&inputs).is_err()); + + // Input smaller than the modulus + let inputs = vec![vec![255; 31]]; + assert!(poseidon_bytes(&inputs).is_ok()); + } + + #[cfg(test)] + lazy_static! { + static ref POSEIDON_ARK: poseidon_ark::Poseidon = poseidon_ark::Poseidon::new(); + } + + proptest::proptest! { + #[test] + fn test_against_poseidon_ark(r in collection::vec(<[u8; 32]>::arbitrary(), 1..16)) { + + let inputs = r.into_iter().map(|ri| ark_bn254::Fr::from_le_bytes_mod_order(&ri)).collect::>(); + let expected = POSEIDON_ARK.hash(inputs.clone()).unwrap().into_bigint().to_bytes_le(); + + let actual = poseidon_bytes(&inputs.iter().map(|i| i.into_bigint().to_bytes_le().to_vec()).collect::>()).unwrap(); + assert_eq!(&actual, expected.as_slice()); + } + } +} +*/ diff --git a/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs new file mode 100644 index 00000000..503ab539 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs @@ -0,0 +1,192 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use std::borrow::Borrow; +use std::ops::Neg; + +use ark_bn254::{Bn254, Fq12, Fr, G1Affine, G2Affine}; +use ark_ec::bn::G2Prepared; +use ark_ec::pairing::Pairing; +use ark_groth16::{Groth16, PreparedVerifyingKey as ArkPreparedVerifyingKey}; +use ark_snark::SNARK; + +use crate::executor::zk_stuff::bn254::api::SCALAR_SIZE; +use crate::executor::zk_stuff::bn254::{FieldElement, Proof, VerifyingKey}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; + +//#[cfg(test)] +//#[path = "unit_tests/verifier_tests.rs"] +//mod verifier_tests; + +/// This is a helper function to store a pre-processed version of the verifying key. +/// This is roughly homologous to [`ark_groth16::data_structures::PreparedVerifyingKey`]. +/// Note that contrary to Arkworks, we don't store a "prepared" version of the gamma_g2_neg_pc, +/// delta_g2_neg_pc fields because they are very large and unpractical to use in the binary api. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PreparedVerifyingKey { + /// The element vk.gamma_abc_g1, + /// aka the `[gamma^{-1} * (beta * a_i + alpha * b_i + c_i) * G]`, where i spans the public inputs + pub vk_gamma_abc_g1: Vec, + /// The element `e(alpha * G, beta * H)` in `E::GT`. + pub alpha_g1_beta_g2: Fq12, + /// The element `- gamma * H` in `E::G2`, for use in pairings. + pub gamma_g2_neg_pc: G2Affine, + /// The element `- delta * H` in `E::G2`, for use in pairings. + pub delta_g2_neg_pc: G2Affine, +} + +impl PreparedVerifyingKey { + /// Verify Groth16 proof using the prepared verifying key (see more at + /// [`PreparedVerifyingKey`]), a vector of public inputs and + /// the proof. + pub fn verify( + &self, + public_inputs: &[FieldElement], + proof: &Proof, + ) -> Result { + let x: Vec = public_inputs.iter().map(|x| x.0).collect(); + Groth16::::verify_with_processed_vk(&self.into(), &x, &proof.0) + .map_err(|e| ZkCryptoError::GeneralError(e.to_string())) + } + + /// Serialize the prepared verifying key to its vectors form. + pub fn serialize(&self) -> Result>, ZkCryptoError> { + let mut res = Vec::new(); + + let mut vk_gamma = Vec::new(); + for g1 in &self.vk_gamma_abc_g1 { + let mut g1_bytes = Vec::new(); + g1.serialize_compressed(&mut g1_bytes) + .map_err(|_| ZkCryptoError::InvalidInput)?; + vk_gamma.append(&mut g1_bytes); + } + res.push(vk_gamma); + + let mut fq12 = Vec::new(); + self.alpha_g1_beta_g2 + .serialize_compressed(&mut fq12) + .map_err(|_| ZkCryptoError::InvalidInput)?; + res.push(fq12); + + let mut gamma_bytes = Vec::new(); + self.gamma_g2_neg_pc + .serialize_compressed(&mut gamma_bytes) + .map_err(|_| ZkCryptoError::InvalidInput)?; + res.push(gamma_bytes); + + let mut delta_bytes = Vec::new(); + self.delta_g2_neg_pc + .serialize_compressed(&mut delta_bytes) + .map_err(|_| ZkCryptoError::InvalidInput)?; + res.push(delta_bytes); + Ok(res) + } + + /// Deserialize the prepared verifying key from the serialized fields of vk_gamma_abc_g1, + /// alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc + pub fn deserialize>(bytes: &Vec) -> Result { + if bytes.len() != 4 { + return Err(ZkCryptoError::InputLengthWrong(bytes.len())); + } + + let vk_gamma_abc_g1_bytes = bytes[0].borrow(); + if vk_gamma_abc_g1_bytes.len() % SCALAR_SIZE != 0 { + return Err(ZkCryptoError::InvalidInput); + } + + let mut vk_gamma_abc_g1: Vec = Vec::new(); + for g1_bytes in vk_gamma_abc_g1_bytes.chunks(SCALAR_SIZE) { + let g1 = G1Affine::deserialize_compressed(g1_bytes) + .map_err(|_| ZkCryptoError::InvalidInput)?; + vk_gamma_abc_g1.push(g1); + } + + let alpha_g1_beta_g2 = Fq12::deserialize_compressed(bytes[1].borrow()) + .map_err(|_| ZkCryptoError::InvalidInput)?; + + let gamma_g2_neg_pc = G2Affine::deserialize_compressed(bytes[2].borrow()) + .map_err(|_| ZkCryptoError::InvalidInput)?; + + let delta_g2_neg_pc = G2Affine::deserialize_compressed(bytes[3].borrow()) + .map_err(|_| ZkCryptoError::InvalidInput)?; + + Ok(PreparedVerifyingKey { + vk_gamma_abc_g1, + alpha_g1_beta_g2, + gamma_g2_neg_pc, + delta_g2_neg_pc, + }) + } +} + +impl From<&PreparedVerifyingKey> for ArkPreparedVerifyingKey { + /// Returns a [`ark_groth16::data_structures::PreparedVerifyingKey`] corresponding to this for + /// usage in the arkworks api. + fn from(pvk: &PreparedVerifyingKey) -> Self { + // Note that not all the members are set here, but we set enough to be able to run + // Groth16::::verify_with_processed_vk. + let mut ark_pvk = ArkPreparedVerifyingKey::default(); + ark_pvk.vk.gamma_abc_g1 = pvk.vk_gamma_abc_g1.clone(); + ark_pvk.alpha_g1_beta_g2 = pvk.alpha_g1_beta_g2; + ark_pvk.gamma_g2_neg_pc = G2Prepared::from(&pvk.gamma_g2_neg_pc); + ark_pvk.delta_g2_neg_pc = G2Prepared::from(&pvk.delta_g2_neg_pc); + ark_pvk + } +} + +impl From<&VerifyingKey> for PreparedVerifyingKey { + fn from(vk: &VerifyingKey) -> Self { + (&vk.0).into() + } +} + +impl VerifyingKey { + /// Deserialize a serialized Groth16 verifying key in compressed format using arkworks' canonical serialisation format: https://docs.rs/ark-serialize/latest/ark_serialize/. + pub fn deserialize(bytes: &[u8]) -> ZkCryptoResult { + ark_groth16::VerifyingKey::::deserialize_compressed(bytes) + .map(VerifyingKey) + .map_err(|_| ZkCryptoError::InvalidInput) + } +} + +impl From<&ark_groth16::VerifyingKey> for PreparedVerifyingKey { + fn from(vk: &ark_groth16::VerifyingKey) -> Self { + PreparedVerifyingKey { + vk_gamma_abc_g1: vk.gamma_abc_g1.clone(), + alpha_g1_beta_g2: Bn254::pairing(vk.alpha_g1, vk.beta_g2).0, + gamma_g2_neg_pc: vk.gamma_g2.neg(), + delta_g2_neg_pc: vk.delta_g2.neg(), + } + } +} +/* +#[cfg(test)] +mod tests { + use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; + use crate::dummy_circuits::DummyCircuit; + use ark_bn254::{Bn254, Fr}; + use ark_groth16::Groth16; + use ark_snark::SNARK; + use ark_std::rand::thread_rng; + use ark_std::UniformRand; + + #[test] + fn test_serialization() { + const PUBLIC_SIZE: usize = 128; + let rng = &mut thread_rng(); + let c = DummyCircuit:: { + a: Some(::rand(rng)), + b: Some(::rand(rng)), + num_variables: PUBLIC_SIZE, + num_constraints: 10, + }; + let (_, vk) = Groth16::::circuit_specific_setup(c, rng).unwrap(); + let pvk = PreparedVerifyingKey::from(&vk); + + let serialized = pvk.serialize().unwrap(); + let deserialized = PreparedVerifyingKey::deserialize(&serialized).unwrap(); + assert_eq!(pvk, deserialized); + } +} +*/ diff --git a/tvm_vm/src/executor/zk_stuff/curve_utils.rs b/tvm_vm/src/executor/zk_stuff/curve_utils.rs new file mode 100644 index 00000000..52f4eadc --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/curve_utils.rs @@ -0,0 +1,194 @@ +use ark_bn254::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ec::CurveGroup; +use ark_ff::BigInteger; +use ark_ff::PrimeField; +//use hex::serde; +//use fastcrypto::error::FastCryptoError; +use num_bigint::BigUint; +use schemars::JsonSchema; + +use serde::Serialize; +use serde::Deserialize; + +use crate::executor::zk_stuff::error::ZkCryptoError; +/// A G1 point in BN254 serialized as a vector of three strings which is the canonical decimal +/// representation of the projective coordinates in Fq. +pub type CircomG1 = Vec; + +/// A G2 point in BN254 serialized as a vector of three vectors each being a vector of two strings +/// which are the canonical decimal representation of the coefficients of the projective coordinates +/// in Fq2. +pub type CircomG2 = Vec>; + +/// A struct that stores a Bn254 Fq field element as 32 bytes. +#[derive(Debug, Clone, JsonSchema, Eq, PartialEq)] +pub struct Bn254FqElement(#[schemars(with = "String")] [u8; 32]); + +impl std::str::FromStr for Bn254FqElement { + type Err = ZkCryptoError; + + fn from_str(s: &str) -> Result { + let big_int = Fq::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; + let be_bytes = big_int.into_bigint().to_bytes_be(); + be_bytes + .try_into() + .map_err(|_| ZkCryptoError::InvalidInput) + .map(Bn254FqElement) + } +} + +impl std::fmt::Display for Bn254FqElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let big_int = BigUint::from_bytes_be(&self.0); + let radix10 = big_int.to_string(); + f.write_str(&radix10) + } +} + +// Bn254FqElement's serialized format is as a radix10 encoded string +impl Serialize for Bn254FqElement { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bn254FqElement { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; + std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) + } +} + +/// A struct that stores a Bn254 Fr field element as 32 bytes. +#[derive(Debug, Clone, JsonSchema, Eq, PartialEq)] +pub struct Bn254FrElement(#[schemars(with = "String")] [u8; 32]); + +impl Bn254FrElement { + /// Returns the unpadded version of the field element. This returns with leading zeros removed. + pub fn unpadded(&self) -> &[u8] { + let mut buf = self.0.as_slice(); + + while !buf.is_empty() && buf[0] == 0 { + buf = &buf[1..]; + } + + // If the value is '0' then just return a slice of length 1 of the final byte + if buf.is_empty() { + &self.0[31..] + } else { + buf + } + } + + /// Returns the padded version of the field element. This returns with leading zeros preserved to 32 bytes. + pub fn padded(&self) -> &[u8] { + &self.0 + } +} +impl std::str::FromStr for Bn254FrElement { + type Err = ZkCryptoError; + + fn from_str(s: &str) -> Result { + let big_int = Fr::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; + let be_bytes = big_int.into_bigint().to_bytes_be(); + be_bytes + .try_into() + .map_err(|_| ZkCryptoError::InvalidInput) + .map(Bn254FrElement) + } +} + +impl std::fmt::Display for Bn254FrElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let big_int = BigUint::from_bytes_be(&self.0); + let radix10 = big_int.to_string(); + f.write_str(&radix10) + } +} + +// Bn254FrElement's serialized format is as a radix10 encoded string +impl Serialize for Bn254FrElement { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bn254FrElement { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; + std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) + } +} + +/// Convert Bn254FqElement type to arkworks' Fq. +impl From<&Bn254FqElement> for Fq { + fn from(f: &Bn254FqElement) -> Self { + Fq::from_be_bytes_mod_order(&f.0) + } +} + +/// Convert Bn254FrElement type to arkworks' Fr. +impl From<&Bn254FrElement> for Fr { + fn from(f: &Bn254FrElement) -> Self { + Fr::from_be_bytes_mod_order(&f.0) + } +} + +/// Deserialize a G1 projective point in BN254 serialized as a vector of three strings into an affine +/// G1 point in arkworks format. Return an error if the input is not a vector of three strings or if +/// any of the strings cannot be parsed as a field element. +pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result { + if s.len() != 3 { + return Err(ZkCryptoError::InvalidInput); + } + + println!("a s CircomG1: {:?}", s); + + let zz = G1Projective::new_unchecked((&s[0]).into(), (&s[1]).into(), (&s[2]).into()).into_affine(); + println!("a zz CircomG1: {:?}", zz); + + + let g1: G1Affine = + G1Projective::new_unchecked((&s[0]).into(), (&s[1]).into(), (&s[2]).into()).into(); + + if !g1.is_on_curve() || !g1.is_in_correct_subgroup_assuming_on_curve() { + return Err(ZkCryptoError::InvalidInput); + } + + Ok(g1) +} + +/// Deserialize a G2 projective point from the BN254 construction serialized as a vector of three +/// vectors each being a vector of two strings into an affine G2 point in arkworks format. Return an +/// error if the input is not a vector of the right format or if any of the strings cannot be parsed +/// as a field element. +pub(crate) fn g2_affine_from_str_projective(s: &CircomG2) -> Result { + if s.len() != 3 || s[0].len() != 2 || s[1].len() != 2 || s[2].len() != 2 { + return Err(ZkCryptoError::InvalidInput); + } + + let g2: G2Affine = G2Projective::new_unchecked( + Fq2::new((&s[0][0]).into(), (&s[0][1]).into()), + Fq2::new((&s[1][0]).into(), (&s[1][1]).into()), + Fq2::new((&s[2][0]).into(), (&s[2][1]).into()), + ) + .into(); + + if !g2.is_on_curve() || !g2.is_in_correct_subgroup_assuming_on_curve() { + return Err(ZkCryptoError::InvalidInput); + } + + Ok(g2) +} diff --git a/tvm_vm/src/executor/zk_stuff/error.rs b/tvm_vm/src/executor/zk_stuff/error.rs new file mode 100644 index 00000000..9a1a073c --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/error.rs @@ -0,0 +1,54 @@ + +use thiserror::Error; + +pub type ZkCryptoResult = Result; + +/// Collection of errors to be used in fastcrypto. +#[derive(Clone, Debug, Error, Eq, PartialEq)] +pub enum ZkCryptoError { + /// Invalid value was given to the function + #[error("Invalid value was given to the function")] + InvalidInput, + + /// Input is to short. + #[error("Expected input of length at least {0}")] + InputTooShort(usize), + + /// Input is to long. + #[error("Expected input of length at most {0}")] + InputTooLong(usize), + + /// Input length is wrong. + #[error("Expected input of length exactly {0}")] + InputLengthWrong(usize), + + /// Invalid signature was given to the function + #[error("Invalid signature was given to the function")] + InvalidSignature, + + /// Invalid proof was given to the function + #[error("Invalid proof was given to the function")] + InvalidProof, + + /// Not enough inputs were given to the function, retry with more + #[error("Not enough inputs were given to the function, retry with more")] + NotEnoughInputs, + + /// Invalid message was given to the function + #[error("Invalid message was given to the function")] + InvalidMessage, + + /// Message should be ignored + #[error("Message should be ignored")] + IgnoredMessage, + + /// General cryptographic error. + #[error("General cryptographic error: {0}")] + GeneralError(String), + + /// General opaque cryptographic error. + #[error("General cryptographic error")] + GeneralOpaqueError, +} + + diff --git a/tvm_vm/src/executor/zk_stuff/mod.rs b/tvm_vm/src/executor/zk_stuff/mod.rs new file mode 100644 index 00000000..ef336769 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/mod.rs @@ -0,0 +1,26 @@ +use thiserror::Error; + +use ark_bn254::{Bn254}; // use ark_bn254::{Bn254, Fr}; +use ark_serialize::CanonicalDeserialize; +use derive_more::From; + +use ff::PrimeField; + +//pub mod alphabet; +pub mod curve_utils; +//pub mod encodings; +pub mod error; +pub mod zk_login; +pub mod utils; +pub mod bn254; +pub mod jwt_utils; + +/// Definition of the BN254 prime field. +#[derive(PrimeField)] +#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] +#[PrimeFieldGenerator = "5"] +#[PrimeFieldReprEndianness = "big"] +pub struct Fr([u64; 4]); + +#[derive(Debug, From)] +pub struct VerifyingKey(pub(crate) ark_groth16::VerifyingKey); diff --git a/tvm_vm/src/executor/zk_stuff/utils.rs b/tvm_vm/src/executor/zk_stuff/utils.rs new file mode 100644 index 00000000..54e7a989 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/utils.rs @@ -0,0 +1,73 @@ + +use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; +use crate::executor::zk::Bn254Fr; +use crate::executor::zk_stuff::curve_utils::Bn254FrElement; +use crate::executor::zk_stuff::error::ZkCryptoError; +use fastcrypto::hash::{Blake2b256, HashFunction}; +// use fastcrypto::rsa::Base64UrlUnpadded; +// use fastcrypto::rsa::Encoding; +use num_bigint::BigUint; + +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::str::FromStr; +use base64ct::{Base64UrlUnpadded, Encoding}; + +use super::zk_login::hash_ascii_str_to_field; + +const ZK_LOGIN_AUTHENTICATOR_FLAG: u8 = 0x05; +const MAX_KEY_CLAIM_NAME_LENGTH: u8 = 32; +const MAX_KEY_CLAIM_VALUE_LENGTH: u8 = 115; +const MAX_AUD_VALUE_LENGTH: u8 = 145; + + + +pub fn gen_address_seed( + salt: &str, + name: &str, // i.e. "sub" + value: &str, // i.e. the sub value + aud: &str, // i.e. the client ID +) -> Result { + let salt_hash = poseidon_zk_login(vec![(&Bn254FrElement::from_str(salt)?).into()])?; + gen_address_seed_with_salt_hash(&salt_hash.to_string(), name, value, aud) +} + +/// Same as [`gen_address_seed`] but takes the poseidon hash of the salt as input instead of the salt. +pub(crate) fn gen_address_seed_with_salt_hash( + salt_hash: &str, + name: &str, // i.e. "sub" + value: &str, // i.e. the sub value + aud: &str, // i.e. the client ID +) -> Result { + Ok(poseidon_zk_login(vec![ + hash_ascii_str_to_field(name, MAX_KEY_CLAIM_NAME_LENGTH)?, + hash_ascii_str_to_field(value, MAX_KEY_CLAIM_VALUE_LENGTH)?, + hash_ascii_str_to_field(aud, MAX_AUD_VALUE_LENGTH)?, + (&Bn254FrElement::from_str(salt_hash)?).into(), + ])? + .to_string()) +} + + +/// Given a 33-byte public key bytes (flag || pk_bytes), returns the two Bn254Fr split at the 128 bit index. +pub fn split_to_two_frs(eph_pk_bytes: &[u8]) -> Result<(Bn254Fr, Bn254Fr), ZkCryptoError> { + // Split the bytes deterministically such that the first element contains the first 128 + // bits of the hash, and the second element contains the latter ones. + let (first_half, second_half) = eph_pk_bytes.split_at(eph_pk_bytes.len() - 16); + let first_bigint = BigUint::from_bytes_be(first_half); + // TODO: this is not safe if the buffer is large. Can we use a fixed size array for eph_pk_bytes? + let second_bigint = BigUint::from_bytes_be(second_half); + + let eph_public_key_0 = Bn254Fr::from(first_bigint); + let eph_public_key_1 = Bn254Fr::from(second_bigint); + Ok((eph_public_key_0, eph_public_key_1)) +} + + + +/// The response struct for the test issuer JWT token. +#[derive(Debug, Serialize, Deserialize)] +pub struct TestIssuerJWTResponse { + /// JWT token string. + pub jwt: String, +} diff --git a/tvm_vm/src/executor/zk_stuff/zk_login.rs b/tvm_vm/src/executor/zk_stuff/zk_login.rs new file mode 100644 index 00000000..bf3223ce --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/zk_login.rs @@ -0,0 +1,657 @@ + +use crate::executor::zk_stuff::{error::ZkCryptoResult, jwt_utils::JWTHeader}; + +use serde_json::Value; + +use super::utils::split_to_two_frs; +use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; +use crate::executor::zk_stuff::curve_utils::{ + g1_affine_from_str_projective, g2_affine_from_str_projective, Bn254FrElement, CircomG1, + CircomG2, +}; +pub use ark_bn254::{Bn254, Fr as Bn254Fr}; +pub use ark_ff::ToConstraintField; +use ark_ff::Zero; +use ark_groth16::Proof; +pub use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use crate::executor::zk_stuff::error::ZkCryptoError; +use itertools::Itertools; +use num_bigint::BigUint; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::str::FromStr; +use ark_ec::AffineRepr; + + +//#[cfg(test)] +//#[path = "unit_tests/zk_login_tests.rs"] +//mod zk_login_tests; + +#[cfg(feature = "e2e")] +#[cfg(test)] +#[path = "unit_tests/zk_login_e2e_tests.rs"] +mod zk_login_e2e_tests; + +pub const MAX_HEADER_LEN: u8 = 248; +pub const PACK_WIDTH: u8 = 248; +pub const ISS: &str = "iss"; +pub const BASE64_URL_CHARSET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +pub const MAX_EXT_ISS_LEN: u8 = 165; +pub const MAX_ISS_LEN_B64: u8 = 4 * (1 + MAX_EXT_ISS_LEN / 3); + +/// Key to identify a JWK, consists of iss and kid. +#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord)] +pub struct JwkId { + /// iss string that identifies the OIDC provider. + pub iss: String, + /// kid string that identifies the JWK. + pub kid: String, +} + +impl JwkId { + /// Create a new JwkId. + pub fn new(iss: String, kid: String) -> Self { + Self { iss, kid } + } +} + +/// The provider config consists of iss string and jwk endpoint. +#[derive(Debug)] +pub struct ProviderConfig { + /// iss string that identifies the OIDC provider. + pub iss: String, + /// The JWK url string for the given provider. + pub jwk_endpoint: String, +} + +impl ProviderConfig { + /// Create a new provider config. + pub fn new(iss: &str, jwk_endpoint: &str) -> Self { + Self { + iss: iss.to_string(), + jwk_endpoint: jwk_endpoint.to_string(), + } + } +} + +/// Supported OIDC providers. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum OIDCProvider { + /// See https://accounts.google.com/.well-known/openid-configuration + Google, + /// See https://id.twitch.tv/oauth2/.well-known/openid-configuration + Twitch, + /// See https://www.facebook.com/.well-known/openid-configuration/ + Facebook, + /// See https://kauth.kakao.com/.well-known/openid-configuration + Kakao, + /// See https://appleid.apple.com/.well-known/openid-configuration + Apple, + /// See https://slack.com/.well-known/openid-configuration + Slack, + /// This is a test issuer maintained by Mysten that will return a JWT non-interactively. + TestIssuer, +} + +impl FromStr for OIDCProvider { + type Err = ZkCryptoError; + + fn from_str(s: &str) -> Result { + match s { + "Google" => Ok(Self::Google), + "Twitch" => Ok(Self::Twitch), + "Facebook" => Ok(Self::Facebook), + "Kakao" => Ok(Self::Kakao), + "Apple" => Ok(Self::Apple), + "Slack" => Ok(Self::Slack), + "TestIssuer" => Ok(Self::TestIssuer), + _ => Err(ZkCryptoError::InvalidInput), + } + } +} + +impl ToString for OIDCProvider { + fn to_string(&self) -> String { + match self { + Self::Google => "Google".to_string(), + Self::Twitch => "Twitch".to_string(), + Self::Facebook => "Facebook".to_string(), + Self::Kakao => "Kakao".to_string(), + Self::Apple => "Apple".to_string(), + Self::Slack => "Slack".to_string(), + Self::TestIssuer => "TestIssuer".to_string(), + } + } +} + +impl OIDCProvider { + /// Returns the provider config consisting of iss and jwk endpoint. + pub fn get_config(&self) -> ProviderConfig { + match self { + OIDCProvider::Google => ProviderConfig::new( + "https://accounts.google.com", + "https://www.googleapis.com/oauth2/v2/certs", + ), + OIDCProvider::Twitch => ProviderConfig::new( + "https://id.twitch.tv/oauth2", + "https://id.twitch.tv/oauth2/keys", + ), + OIDCProvider::Facebook => ProviderConfig::new( + "https://www.facebook.com", + "https://www.facebook.com/.well-known/oauth/openid/jwks/", + ), + OIDCProvider::Kakao => ProviderConfig::new( + "https://kauth.kakao.com", + "https://kauth.kakao.com/.well-known/jwks.json", + ), + OIDCProvider::Apple => ProviderConfig::new( + "https://appleid.apple.com", + "https://appleid.apple.com/auth/keys", + ), + OIDCProvider::Slack => { + ProviderConfig::new("https://slack.com", "https://slack.com/openid/connect/keys") + } + OIDCProvider::TestIssuer => ProviderConfig::new( + "https://oauth.sui.io", + "https://jwt-tester.mystenlabs.com/.well-known/jwks.json", + ), + } + } + + /// Returns the OIDCProvider for the given iss string. + pub fn from_iss(iss: &str) -> Result { + match iss { + "https://accounts.google.com" => Ok(Self::Google), + "https://id.twitch.tv/oauth2" => Ok(Self::Twitch), + "https://www.facebook.com" => Ok(Self::Facebook), + "https://kauth.kakao.com" => Ok(Self::Kakao), + "https://appleid.apple.com" => Ok(Self::Apple), + "https://slack.com" => Ok(Self::Slack), + "https://oauth.sui.io" => Ok(Self::TestIssuer), + _ => Err(ZkCryptoError::InvalidInput), + } + } +} + +/// Struct that contains info for a JWK. A list of them for different kids can +/// be retrieved from the JWK endpoint (e.g. ). +/// The JWK is used to verify the JWT token. +#[derive(PartialEq, Eq, Hash, Debug, Clone, Serialize, Deserialize, PartialOrd, Ord)] +pub struct JWK { + /// Key type parameter, https://datatracker.ietf.org/doc/html/rfc7517#section-4.1 + pub kty: String, + /// RSA public exponent, https://datatracker.ietf.org/doc/html/rfc7517#section-9.3 + pub e: String, + /// RSA modulus, https://datatracker.ietf.org/doc/html/rfc7517#section-9.3 + pub n: String, + /// Algorithm parameter, https://datatracker.ietf.org/doc/html/rfc7517#section-4.4 + pub alg: String, +} + +/// Reader struct to parse all fields in a JWK from JSON. +#[derive(Debug, Serialize, Deserialize)] +pub struct JWKReader { + e: String, + n: String, + #[serde(rename = "use", skip_serializing_if = "Option::is_none")] + my_use: Option, + kid: String, + kty: String, + alg: String, +} + +impl JWK { + /// Parse JWK from the reader struct. + pub fn from_reader(reader: JWKReader) -> ZkCryptoResult { + let trimmed_e = trim(reader.e); + if reader.alg != "RS256" || reader.kty != "RSA" || trimmed_e != "AQAB" { + return Err(ZkCryptoError::InvalidInput); + } + Ok(Self { + kty: reader.kty, + e: trimmed_e, + n: trim(reader.n), + alg: reader.alg, + }) + } +} + +/// Trim trailing '=' so that it is considered a valid base64 url encoding string by base64ct library. +fn trim(str: String) -> String { + str.trim_end_matches('=').to_owned() +} + +/*/// Fetch JWKs from the given provider and return a list of JwkId -> JWK. +pub async fn fetch_jwks( + provider: &OIDCProvider, + client: &Client, +) -> Result, ZkCryptoError> { + let response = client + .get(provider.get_config().jwk_endpoint) + .send() + .await + .map_err(|e| { + ZkCryptoError::GeneralError(format!( + "Failed to get JWK {:?} {:?}", + e.to_string(), + provider + )) + })?; + let bytes = response.bytes().await.map_err(|e| { + ZkCryptoError::GeneralError(format!( + "Failed to get bytes {:?} {:?}", + e.to_string(), + provider + )) + })?; + parse_jwks(&bytes, provider) +}*/ + +/// Parse the JWK bytes received from the given provider and return a list of JwkId -> JWK. +pub fn parse_jwks( + json_bytes: &[u8], + provider: &OIDCProvider, +) -> Result, ZkCryptoError> { + let json_str = String::from_utf8_lossy(json_bytes); + let parsed_list: Result = serde_json::from_str(&json_str); + if let Ok(parsed_list) = parsed_list { + if let Some(keys) = parsed_list["keys"].as_array() { + let mut ret = Vec::new(); + for k in keys { + let parsed: JWKReader = serde_json::from_value(k.clone()) + .map_err(|_| ZkCryptoError::GeneralError("Parse error".to_string()))?; + + ret.push(( + JwkId::new(provider.get_config().iss, parsed.kid.clone()), + JWK::from_reader(parsed)?, + )); + } + return Ok(ret); + } + } + Err(ZkCryptoError::GeneralError( + "Invalid JWK response".to_string(), + )) +} + +/// A claim consists of value and index_mod_4. +#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Claim { + pub value: String, + pub index_mod_4: u8, +} + +/// A structed of parsed JWT details, consists of kid, header, iss. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct JWTDetails { + kid: String, + header: String, + iss: String, +} + +impl JWTDetails { + /// Read in the Claim and header string. Parse and validate kid, header, iss as JWT details. + pub fn new(header_base64: &str, claim: &Claim) -> Result { + let header = JWTHeader::new(header_base64)?; + let ext_claim = decode_base64_url(&claim.value, &claim.index_mod_4)?; + Ok(JWTDetails { + kid: header.kid, + header: header_base64.to_string(), + iss: verify_extended_claim(&ext_claim, ISS)?, + }) + } +} + +/// All inputs required for the zk login proof verification and other public inputs. +#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ZkLoginInputs { + proof_points: ZkLoginProof, + iss_base64_details: Claim, + header_base64: String, + address_seed: Bn254FrElement, + #[serde(skip)] + jwt_details: JWTDetails, +} + +/// The reader struct for the proving service response. +#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ZkLoginInputsReader { + proof_points: ZkLoginProof, + iss_base64_details: Claim, + header_base64: String, + #[serde(skip)] + jwt_details: JWTDetails, +} + +impl ZkLoginInputs { + /// Parse the proving service response and pass in the address seed. Initialize the jwt details struct. + pub fn from_json(value: &str, address_seed: &str) -> Result { + let reader: ZkLoginInputsReader = + serde_json::from_str(value).map_err(|_| ZkCryptoError::InvalidInput)?; + Self::from_reader(reader, address_seed) + } + + /// Initialize ZkLoginInputs from the + pub fn from_reader( + reader: ZkLoginInputsReader, + address_seed: &str, + ) -> Result { + ZkLoginInputs { + proof_points: reader.proof_points, + iss_base64_details: reader.iss_base64_details, + header_base64: reader.header_base64, + address_seed: Bn254FrElement::from_str(address_seed) + .map_err(|_| ZkCryptoError::InvalidInput)?, + jwt_details: reader.jwt_details, + } + .init() + } + + /// Initialize JWTDetails by parsing header_base64 and iss_base64_details. + pub fn init(&mut self) -> Result { + self.jwt_details = JWTDetails::new(&self.header_base64, &self.iss_base64_details)?; + Ok(self.to_owned()) + } + + /// Get the parsed kid string. + pub fn get_kid(&self) -> &str { + &self.jwt_details.kid + } + + /// Get the parsed iss string. + pub fn get_iss(&self) -> &str { + &self.jwt_details.iss + } + + /// Get the zk login proof. + pub fn get_proof(&self) -> &ZkLoginProof { + &self.proof_points + } + + /// Get the address seed string. + pub fn get_address_seed(&self) -> &Bn254FrElement { + &self.address_seed + } + + /// Calculate the poseidon hash from selected fields from inputs, along with the ephemeral pubkey. + pub fn calculate_all_inputs_hash( + &self, + eph_pk_bytes: &[u8], + modulus: &[u8], + max_epoch: u64, + ) -> Result { + if self.header_base64.len() > MAX_HEADER_LEN as usize { + return Err(ZkCryptoError::GeneralError("Header too long".to_string())); + } + + let addr_seed = (&self.address_seed).into(); + let (first, second) = split_to_two_frs(eph_pk_bytes)?; + + let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string())?).into(); + let index_mod_4_f = + (&Bn254FrElement::from_str(&self.iss_base64_details.index_mod_4.to_string())?).into(); + + let iss_base64_f = + hash_ascii_str_to_field(&self.iss_base64_details.value, MAX_ISS_LEN_B64)?; + let header_f = hash_ascii_str_to_field(&self.header_base64, MAX_HEADER_LEN)?; + let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH)?; + poseidon_zk_login(vec![ + first, + second, + addr_seed, + max_epoch_f, + iss_base64_f, + index_mod_4_f, + header_f, + modulus_f, + ]) + } +} +/// The struct for zk login proof. +#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] +pub struct ZkLoginProof { + a: CircomG1, + b: CircomG2, + c: CircomG1, +} + +impl ZkLoginProof { + /// Parse the proof from a json string. + pub fn from_json(value: &str) -> Result { + let proof: ZkLoginProof = + serde_json::from_str(value).map_err(|_| ZkCryptoError::InvalidProof)?; + Ok(proof) + } + + /// Convert the Circom G1/G2/GT to arkworks G1/G2/GT + pub fn as_arkworks(&self) -> Result, ZkCryptoError> { + println!(""); + println!("&self.a {:?}", &self.a); + println!("&self.b {:?}", &self.b); + + println!(""); + + + let bb = g2_affine_from_str_projective(&self.b)?; + println!("&self.b bb {:?}", bb); + println!("&self.b bb.x {:?}", bb.x); + println!("&self.b bb.y {:?}", bb.y); + + let bby = bb.y; + let bby_ = -bby; + + println!("-bb.y {:?}", bby_); + + + // let aa = g1_affine_from_str_projective(&self.a)?; + // println!("&self.a aa {:?}", aa); + // println!("&self.a aa.y {:?}", aa.y); + // + // let yy_ = -aa.y; + // println!("-aa.y {:?}", yy_); + // println!("-aa.y.to_string() {:?}", yy_.to_string()); + // + // println!("&self.a aa.y.to_string() {:?}", aa.y.to_string()); + // println!("&self.a aa.y.0 {:?}", aa.y.0); + // println!("&self.a aa.y.0.to_string() {:?}", aa.y.0.to_string()); + + println!(""); + + return Ok(Proof { + a: g1_affine_from_str_projective(&self.a)?, + b: g2_affine_from_str_projective(&self.b)?, + c: g1_affine_from_str_projective(&self.c)?, + }); + } +} + +/// Parse the extended claim json value to its claim value, using the expected claim key. +fn verify_extended_claim( + extended_claim: &str, + expected_key: &str, +) -> Result { + // Last character of each extracted_claim must be '}' or ',' + if !(extended_claim.ends_with('}') || extended_claim.ends_with(',')) { + return Err(ZkCryptoError::GeneralError( + "Invalid extended claim".to_string(), + )); + } + + let json_str = format!("{{{}}}", &extended_claim[..extended_claim.len() - 1]); + let json: Value = serde_json::from_str(&json_str).map_err(|_| ZkCryptoError::InvalidInput)?; + let value = json + .as_object() + .ok_or(ZkCryptoError::InvalidInput)? + .get(expected_key) + .ok_or(ZkCryptoError::InvalidInput)? + .as_str() + .ok_or(ZkCryptoError::InvalidInput)?; + Ok(value.to_string()) +} + +/// Parse the base64 string, add paddings based on offset, and convert to a bytearray. +fn decode_base64_url(s: &str, i: &u8) -> Result { + if s.len() < 2 { + return Err(ZkCryptoError::GeneralError( + "Base64 string smaller than 2".to_string(), + )); + } + let mut bits = base64_to_bitarray(s)?; + match i { + 0 => {} + 1 => { + bits.drain(..2); + } + 2 => { + bits.drain(..4); + } + _ => { + return Err(ZkCryptoError::GeneralError( + "Invalid first_char_offset".to_string(), + )); + } + } + + let last_char_offset = (i + s.len() as u8 - 1) % 4; + match last_char_offset { + 3 => {} + 2 => { + bits.drain(bits.len() - 2..); + } + 1 => { + bits.drain(bits.len() - 4..); + } + _ => { + return Err(ZkCryptoError::GeneralError( + "Invalid last_char_offset".to_string(), + )); + } + } + + if bits.len() % 8 != 0 { + return Err(ZkCryptoError::GeneralError( + "Invalid bits length".to_string(), + )); + } + + Ok(std::str::from_utf8(&bitarray_to_bytearray(&bits)?) + .map_err(|_| ZkCryptoError::GeneralError("Invalid UTF8 string".to_string()))? + .to_owned()) +} + +/// Map a base64 string to a bit array by taking each char's index and covert it to binary form with one bit per u8 +/// element in the output. Returns [ZkCryptoError::InvalidInput] if one of the characters is not in the base64 charset. +fn base64_to_bitarray(input: &str) -> ZkCryptoResult> { + input + .chars() + .map(|c| { + BASE64_URL_CHARSET + .find(c) + .map(|index| index as u8) + .map(|index| (0..6).rev().map(move |i| index >> i & 1)) + .ok_or(ZkCryptoError::InvalidInput) + }) + .flatten_ok() + .collect() +} + +/// Convert a bitarray (each bit is represented by a u8) to a byte array by taking each 8 bits as a +/// byte in big-endian format. +fn bitarray_to_bytearray(bits: &[u8]) -> ZkCryptoResult> { + if bits.len() % 8 != 0 { + return Err(ZkCryptoError::InvalidInput); + } + Ok(bits + .chunks(8) + .map(|chunk| { + let mut byte = 0u8; + for (i, bit) in chunk.iter().rev().enumerate() { + byte |= bit << i; + } + byte + }) + .collect()) +} + +/// Pads a stream of bytes and maps it to a field element +pub fn hash_ascii_str_to_field(str: &str, max_size: u8) -> Result { + let str_padded = str_to_padded_char_codes(str, max_size)?; + hash_to_field(&str_padded, 8, PACK_WIDTH) +} + +fn str_to_padded_char_codes(str: &str, max_len: u8) -> Result, ZkCryptoError> { + let arr: Vec = str + .chars() + .map(|c| BigUint::from_slice(&([c as u32]))) + .collect(); + pad_with_zeroes(arr, max_len) +} + +fn pad_with_zeroes(in_arr: Vec, out_count: u8) -> Result, ZkCryptoError> { + if in_arr.len() > out_count as usize { + return Err(ZkCryptoError::GeneralError("in_arr too long".to_string())); + } + let mut padded = in_arr; + padded.resize(out_count as usize, BigUint::zero()); + Ok(padded) +} + +/// Maps a stream of bigints to a single field element. First we convert the base from +/// inWidth to packWidth. Then we compute the poseidon hash of the "packed" input. +/// input is the input vector containing equal-width big ints. inWidth is the width of +/// each input element. +pub fn hash_to_field( + input: &[BigUint], + in_width: u16, + pack_width: u8, +) -> Result { + let packed = convert_base(input, in_width, pack_width)?; + poseidon_zk_login(packed) +} + +/// Helper function to pack field elements from big ints. +fn convert_base( + in_arr: &[BigUint], + in_width: u16, + out_width: u8, +) -> Result, ZkCryptoError> { + if out_width == 0 { + return Err(ZkCryptoError::InvalidInput); + } + let bits = big_int_array_to_bits(in_arr, in_width as usize)?; + let mut packed: Vec = bits + .rchunks(out_width as usize) + .map(|chunk| Bn254Fr::from(BigUint::from_radix_be(chunk, 2).unwrap())) + .collect(); + packed.reverse(); + match packed.len() != (in_arr.len() * in_width as usize).div_ceil(out_width as usize) { + true => Err(ZkCryptoError::InvalidInput), + false => Ok(packed), + } +} + +/// Convert a big int array to a bit array with 0 paddings. +fn big_int_array_to_bits(integers: &[BigUint], intended_size: usize) -> ZkCryptoResult> { + integers + .iter() + .map(|integer| { + let bits = integer.to_radix_be(2); + match bits.len().cmp(&intended_size) { + Less => { + let extra_bits = intended_size - bits.len(); + let mut padded = vec![0; extra_bits]; + padded.extend(bits); + Ok(padded) + } + Equal => Ok(bits), + Greater => Err(ZkCryptoError::InvalidInput), + } + }) + .flatten_ok() + .collect() +} + From 6b92329055af485d8ca61fa145432fa53b96918a Mon Sep 17 00:00:00 2001 From: alinat Date: Wed, 2 Oct 2024 08:49:38 +0300 Subject: [PATCH 02/19] add vergrth --- tvm_assembler/src/simple.rs | 2 + tvm_client/src/json_interface/runtime.rs | 8 +- tvm_tests/src/test_framework.rs | 790 ++++++++++ tvm_tests/src/test_zk.rs | 1594 +++++++++++++++++++++ tvm_tests/src/test_zk_.rs | 139 ++ tvm_vm/src/executor/crypto.rs | 34 +- tvm_vm/src/executor/zk_stuff/jwt_utils.rs | 76 + 7 files changed, 2628 insertions(+), 15 deletions(-) create mode 100644 tvm_tests/src/test_framework.rs create mode 100644 tvm_tests/src/test_zk.rs create mode 100644 tvm_tests/src/test_zk_.rs create mode 100644 tvm_vm/src/executor/zk_stuff/jwt_utils.rs diff --git a/tvm_assembler/src/simple.rs b/tvm_assembler/src/simple.rs index 391ec349..22395937 100644 --- a/tvm_assembler/src/simple.rs +++ b/tvm_assembler/src/simple.rs @@ -842,6 +842,8 @@ impl Engine { MINTSHELL => 0xC7, 0x28 CALCBKREWARD => 0xC7, 0x29 CALCMINSTAKE => 0xC7, 0x30 + VERGRTH16 => 0xC7, 0x31 + POSEIDON_ZKLOGIN => 0xC7, 0x32 } #[cfg(feature = "groth")] diff --git a/tvm_client/src/json_interface/runtime.rs b/tvm_client/src/json_interface/runtime.rs index 7737c64a..c58d771b 100644 --- a/tvm_client/src/json_interface/runtime.rs +++ b/tvm_client/src/json_interface/runtime.rs @@ -37,8 +37,8 @@ pub(crate) trait AsyncHandler { // Handlers pub(crate) struct RuntimeHandlers { - sync_handlers: HashMap>, - async_handlers: HashMap>, + sync_handlers: HashMap>, + async_handlers: HashMap>, api: API, } @@ -57,11 +57,11 @@ impl RuntimeHandlers { self.api.modules.push(module); } - pub fn register_sync(&mut self, function_name: String, handler: Box) { + pub fn register_sync(&mut self, function_name: String, handler: Box) { self.sync_handlers.insert(function_name, handler); } - pub fn register_async(&mut self, function_name: String, handler: Box) { + pub fn register_async(&mut self, function_name: String, handler: Box) { self.async_handlers.insert(function_name, handler); } } diff --git a/tvm_tests/src/test_framework.rs b/tvm_tests/src/test_framework.rs new file mode 100644 index 00000000..a29dc5a8 --- /dev/null +++ b/tvm_tests/src/test_framework.rs @@ -0,0 +1,790 @@ +/* +* Copyright (C) 2019-2023 TON Labs. All Rights Reserved. +* +* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use +* this file except in compliance with the License. +* +* 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 TON DEV software governing permissions and +* limitations under the License. +*/ + +#![allow(dead_code)] +use std::{convert::Into, ffi::CStr, os::raw::c_char, sync::Arc}; +use tvm_assembler::{CompileError, compile_code}; +//use failure::{Error}; +use anyhow::{Error}; +use tvm_vm::{ + int, + error::{tvm_exception_code, tvm_exception_or_custom_code, TvmError}, + executor::{Engine, gas::gas_state::Gas, IndexProvider, BehaviorModifiers}, smart_contract_info::SmartContractInfo, + stack::{Stack, StackItem, integer::IntegerData, savelist::SaveList}, + types::Exception +}; +//use failure::Error as Error; +use tvm_types::{ + BuilderData, Cell, Result, SliceData, + types::ExceptionCode, HashmapE, HashmapType, BocWriter +}; + +use tvm_block::GlobalCapabilities; + +pub type Bytecode = SliceData; + +#[allow(dead_code)] +pub mod create { + use super::*; + + pub fn cell>(data:T) -> StackItem { + let data = data.as_ref().to_vec(); + StackItem::Cell(BuilderData::with_bitstring(data).unwrap().into_cell().unwrap()) + } + + pub fn builder>(data:T) -> StackItem { + let builder = BuilderData::with_bitstring(data.as_ref().to_vec()).unwrap(); + StackItem::builder(builder) + } + + pub fn slice>(data:T) -> StackItem { + let data = data.as_ref().to_vec(); + let slice = SliceData::new(data); + StackItem::Slice(slice) + } + + pub fn tuple>(data: &T) -> StackItem { + let data = data.as_ref().to_vec(); + StackItem::tuple(data) + } +} + +fn logger_init() { + // do not init twice + if log::log_enabled!(log::Level::Info) { + return + } + let log_level = if cfg!(feature = "verbose") { + log::LevelFilter::Trace + } else { + log::LevelFilter::Info + }; + let encoder_boxed = Box::new(log4rs::encode::pattern::PatternEncoder::new("{m}")); + let config = if cfg!(feature = "log_file") { + let file = log4rs::append::file::FileAppender::builder() + .encoder(encoder_boxed) + .build("log/log.txt") + .unwrap(); + log4rs::config::Config::builder() + .appender(log4rs::config::Appender::builder().build("file", Box::new(file))) + .build(log4rs::config::Root::builder().appender("file").build(log_level)) + .unwrap() + } else { + let console = log4rs::append::console::ConsoleAppender::builder() + .encoder(encoder_boxed) + .build(); + log4rs::config::Config::builder() + .appender(log4rs::config::Appender::builder().build("console", Box::new(console))) + .build(log4rs::config::Root::builder().appender("console").build(log_level)) + .unwrap() + }; + log4rs::init_config(config).ok(); +} + +pub struct TestCaseInputs { + code: String, + ctrls: SaveList, + stack: Stack, + refs: Vec, + gas: Option, + library: HashmapE, + behavior_modifiers: Option, + capabilities: u64, + block_version: u32, + skip_fift_check: bool, + index_provider: Option>, +} + +impl TestCaseInputs { + + pub fn new( + code: String, + stack: Stack, + refs: Vec, + capabilities: u64 + ) -> TestCaseInputs { + logger_init(); + TestCaseInputs { + code, + ctrls: SaveList::new(), + stack, + refs, + gas: None, + library: HashmapE::with_bit_len(256), + behavior_modifiers: None, + capabilities, + block_version: 0, + skip_fift_check: false, + index_provider: None, + } + } + + pub fn with_ref(mut self, cell: Cell) -> TestCaseInputs { + assert!(self.refs.len() < 4); + self.refs.push(cell); + self + } + + pub fn with_refs(mut self, refs: Vec) -> TestCaseInputs { + self.refs = refs; + self + } + + pub fn with_root_data(self, root_data: Cell) -> TestCaseInputs { + self.with_ctrl(4, StackItem::Cell(root_data)) + } + + pub fn with_temp_data(self, temp_data: SmartContractInfo) -> TestCaseInputs { + self.with_ctrl(7, temp_data.into_temp_data_item()) + } + + // do not run with stack - use refs, then do PUSHREF* + pub fn with_stack(mut self, stack: Stack) -> TestCaseInputs { + self.stack = stack; + self + } + + pub fn with_capability(mut self, capability: tvm_block::GlobalCapabilities) -> TestCaseInputs { + self.skip_fift_check = true; + self.capabilities |= capability as u64; + self + } + + pub fn with_block_version(mut self, block_version: u32) -> TestCaseInputs { + self.skip_fift_check = true; + self.block_version = block_version; + self + } + + pub fn skip_fift_check(mut self, skip: bool) -> TestCaseInputs { + if skip { + self.skip_fift_check = skip; + } + self + } + + pub fn with_index_provider(mut self, index_provider: Arc) -> TestCaseInputs { + self.index_provider = Some(index_provider); + self + } + + pub fn with_ctrl(mut self, ctrl: usize, mut item: StackItem) -> TestCaseInputs { + self.ctrls.put(ctrl, &mut item) + .expect("test arguments must be valid"); + self + } + + pub fn with_gas(mut self, gas: Gas) -> TestCaseInputs { + self.gas = Some(gas); + self + } + + pub fn with_gas_limit(self, gas_limit: i64) -> TestCaseInputs { + self.with_gas(Gas::test_with_limit(gas_limit)) + } + + pub fn with_library(mut self, library: HashmapE) -> TestCaseInputs { + self.library = library; + self + } + + pub fn with_behavior_modifiers(mut self, behavior_modifiers: BehaviorModifiers) -> TestCaseInputs { + self.skip_fift_check = true; + self.behavior_modifiers = Some(behavior_modifiers); + self + } + + pub fn expect_bytecode(self, bytecode: Vec) -> TestCaseInputs { + self.expect_bytecode_extended(bytecode, None) + } + + pub fn expect_bytecode_extended(self, bytecode: Vec, message: Option <&str>) -> TestCaseInputs { + let inputcode = SliceData::new(bytecode); + let compilation_result = compile_code(&self.code); + match compilation_result { + Ok(ref selfcode) => { + let mut selfcode = selfcode.clone(); + let mut bytevec = vec![]; + while selfcode.remaining_bits() != 0 { + bytevec.append(&mut selfcode.get_bytestring(0)); + if selfcode.remaining_references() > 0 { + selfcode = SliceData::load_cell(selfcode.reference(0).unwrap()).unwrap(); + } else { + break; + } + } + bytevec.push(0x80); + let selfcode = SliceData::new(bytevec); + if !selfcode.eq(&inputcode) { + match message { + Some(msg) => panic!( + "{}Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", + msg, inputcode, selfcode), + None => panic!( + "Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", + inputcode, selfcode), + } + }; + }, + Err(e) => { + match message { + Some(msg) => panic!("{}{}", msg, e), + None => panic!("{}", e), + } + } + } + self + } + + pub fn expect_compilation_failure(self, error: CompileError) -> TestCaseInputs { + self.expect_compilation_failure_extended(error, None) + } + + pub fn expect_compilation_failure_extended(self, error: CompileError, message: Option <&str>) -> TestCaseInputs { + let compilation_result = compile_code(&self.code); + match message { + None => { + let actual = compilation_result.expect_err(&format!("Error expected {}", error)); + assert_eq!( + error, actual, + "Expected (left): <{}>, but was (right): <{}>.", + error, actual + ) + }, + Some(msg) => { + let actual = compilation_result.expect_err(&format!("{}. Error expected {}", msg, error)); + assert_eq!( + error, actual, + "{}\nExpected (left): <{}>, but was (right): <{}>.", + msg, error, actual + ) + }, + } + self + } +} + +impl From for TestCase { + fn from(inputs: TestCaseInputs) -> Self { + TestCase::new(inputs) + } +} + +pub struct TestCase { + executor: Option, + compilation_result: std::result::Result, + execution_result: Result, +} + +impl TestCase { + fn executor(&self, message: Option<&str>) -> &Engine { + match self.executor { + Some(ref exectuor) => exectuor, + None => { + let err = self.compilation_result.as_ref().unwrap_err(); + match message { + Some(msg) => panic!("{}No executor was created, because of bytecode compilation error {:?}", msg, err), + None => panic!("No executor was created, because of bytecode compilation error {:?}", err) + } + } + } + } +} + +fn compare_with_fift( + bytecode: SliceData, + library: HashmapE, + code: String, + executor: &Engine, + execution_result: &Result, + gas_remaining: i32 +) { + #[cfg(windows)] + let lib_name = "vm_run_shared.dll"; + #[cfg(not(windows))] + let lib_name = "./vm_run_shared.so"; + if let Ok(lib) = libloading::Library::new(lib_name) { + let mut data = vec![]; + assert!(bytecode.pos() == 0); + let mut roots = vec![bytecode.cell_opt().unwrap().clone()]; + if let Some(root) = library.data() { + roots.push(root.clone()); + } + let bag = BocWriter::with_roots(roots).unwrap(); + bag.write(&mut data).unwrap(); + // code is written to BOC and can be checked with FIFT + // "fift.boc" file>B B>boc *mut c_char + > = lib.get(b"run_vm_boc_with_gas_and_commit").unwrap(); + let free_mem: libloading::Symbol< + unsafe extern "C" fn(*const c_char) -> *mut c_char + > = lib.get(b"free_mem").unwrap(); + let res = run_boc(data.as_ptr(), size as i32, gas_remaining); + fift_result = CStr::from_ptr(res).to_string_lossy().into_owned().trim().to_string(); + free_mem(res); + } + let tvm_result = match execution_result { + Ok(ref result) => { + let stack = executor.get_stack_result_fift(); + match stack.is_empty() { + true => format!("{} {}{}", result, executor.gas_used(), executor.get_committed_state_fift()), + false => format!("{} {} {}{}", stack, result, executor.gas_used(), executor.get_committed_state_fift()) + } + } + Err(ref err) => { + if let Some(ExceptionCode::OutOfGas) = tvm_exception_code(err) { + let gas = executor.gas_used(); + format!("{} {} {}{}", gas, !(ExceptionCode::OutOfGas as i32), gas, executor.get_committed_state_fift()) + } else { + let err = tvm_exception_or_custom_code(err); + format!("0 {} {}{}", err, executor.gas_used(), executor.get_committed_state_fift()) + } + } + }; + if tvm_result != fift_result { + log::info!("bytecode: {}\n", &StackItem::Slice(bytecode).dump_as_fift()); + log::info!("code:\n{}\n", code); + assert_eq!(tvm_result, fift_result); + } + } else { + panic!("no shared dll found") + } +} + +impl TestCase { + pub(super) fn new(args: TestCaseInputs) -> TestCase { + match compile_code(&args.code) { + Ok(bytecode) => { + let code = if args.refs.is_empty() { + bytecode.clone() + } else if bytecode.remaining_references() + args.refs.len() <= BuilderData::references_capacity() { + let mut builder = bytecode.as_builder(); + args.refs.iter().rev().for_each(|reference| { + builder.checked_prepend_reference(reference.clone()).unwrap(); + }); + SliceData::load_builder(builder).unwrap() + } else { + log::error!(target: "compile", "Cannot use 4 refs with long code"); + bytecode.clone() + }; + log::trace!(target: "compile", "code: {}\n", code); + let mut executor = Engine::with_capabilities(args.capabilities) + .setup_with_libraries( + code.clone(), + Some(args.ctrls.clone()), + Some(args.stack.clone()), + args.gas.clone(), + vec![args.library.clone()] + ); + executor.set_block_version(args.block_version); + if let Some(modifiers) = args.behavior_modifiers { + executor.modify_behavior(modifiers); + } + if let Some(index_provider) = args.index_provider.clone() { + executor.set_index_provider(index_provider) + } + let execution_result = executor.execute(); + if cfg!(feature = "fift_check") && args.stack.is_empty() && args.ctrls.is_empty() && !args.skip_fift_check { + let gas = args.gas.map(|gas| gas.get_gas_remaining() as i32).unwrap_or(1000000); + compare_with_fift(code, args.library, args.code, &executor, &execution_result, gas) + } + TestCase { + executor: Some(executor), + compilation_result: Ok(bytecode), + execution_result, + } + } + Err(e) => TestCase { + executor: None, + compilation_result: Err(e), + execution_result: Ok(-1), + } + } + } + + // TODO: call this from fn new + pub fn with_bytecode( + code: Bytecode, + ctrls: Option, + stack: Option, + library: HashmapE + ) -> TestCase { + logger_init(); + + let mut executor = Engine::with_capabilities(0).setup_with_libraries( + code.clone(), + ctrls.clone(), + stack.clone(), + None, + vec![library.clone()] + ); + let execution_result = executor.execute(); + if cfg!(feature = "fift_check") && stack.is_none() && ctrls.is_none() { + compare_with_fift( + code.clone(), + library, + format!("{:x}", code), + &executor, + &execution_result, + 1000000 + ) + } + log::trace!("bytecode: {}", code); + TestCase { + executor: Some(executor), + compilation_result: Ok(code), + execution_result, + } + } + + pub fn get_root(&self) -> Option { + if let Some(ref eng) = self.executor { + if let StackItem::Cell(c) = eng.get_committed_state().get_root() { + return Some(c.clone()) + } + } + None + } + + pub fn get_actions(&self) -> Option { + if let Some(ref eng) = self.executor { + if let StackItem::Cell(c) = eng.get_committed_state().get_actions() { + return Some(c.clone()) + } + } + None + } +} + +pub trait Expects { + fn expect_stack(self, stack: &Stack) -> TestCase; + fn expect_stack_extended(self, stack: &Stack, message: Option<&str>) -> TestCase; + fn expect_empty_stack(self) -> TestCase; + fn expect_int_stack(self, stack_contents: &[i32]) -> TestCase; + fn expect_item(self, stack_item: StackItem) -> TestCase; + fn expect_item_extended(self, stack_item: StackItem, message: Option<&str>) -> TestCase; + fn expect_success(self) -> TestCase; + fn expect_success_extended(self, message: Option <&str>) -> TestCase; + fn expect_ctrl(self, ctrl: usize, item: &StackItem) -> TestCase; + fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) -> TestCase; + fn expect_failure(self, exception_code: ExceptionCode) -> TestCase; + fn expect_custom_failure(self, custom_code: i32) -> TestCase; + fn expect_custom_failure_extended bool>(self, op: F, exc_name: &str, message: Option <&str>) -> TestCase; + fn expect_failure_extended(self, exception_code: ExceptionCode, message: Option <&str>) -> TestCase; + fn expect_root_data(self, cell: Cell) -> TestCase; + fn expect_same_results(self, other: Self); + fn expect_gas(self, max_gas_limit: i64, gas_limit: i64, gas_credit: i64, gas_remaining: i64) -> TestCase; + fn expect_steps(self, steps: u32) -> TestCase; + fn stack(self) -> Stack; +} + +impl> Expects for T { + fn expect_stack(self, stack: &Stack) -> TestCase { + self.expect_stack_extended(stack, None) + } + + fn expect_stack_extended(self, stack: &Stack, message: Option<&str>) -> TestCase { + let test_case: TestCase = self.into(); + let executor = test_case.executor(message); + match test_case.execution_result { + Ok(_) => { + if !executor.eq_stack(stack) { + if let Some(msg) = message { + log::info!("{}", msg) + } + log::info!(target: "tvm", "\nExpected stack: \n{}", stack); + log::info!( + target: "tvm", + "\n{}\n", + executor.dump_stack("Actual Stack:", false) + ); + panic!("Stack is not expected") + } + } + // TODO this is not quite right: execution may fail but still produce a stack + Err(ref e) => { + log::info!(target: "tvm", "\nExpected stack: \n{}", stack); + //print_failed_detail_extended(&test_case, e, message); + panic!("Execution error: {:?}", e) + } + } + test_case + } + + fn expect_empty_stack(self) -> TestCase { + self.expect_stack(&Stack::new()) + } + + // Order of items in array like in spec docs right item is top item + fn expect_int_stack(self, stack_contents: &[i32]) -> TestCase { + let mut stack = Stack::new(); + for element in stack_contents { + stack.push(int!(*element)); + } + self.expect_stack(&stack) + } + + fn expect_item(self, stack_item: StackItem) -> TestCase { + self.expect_item_extended(stack_item, None) + } + + fn expect_item_extended(self, stack_item: StackItem, message: Option<&str>) -> TestCase { + self.expect_stack_extended(Stack::new().push(stack_item), message) + } + + fn expect_success(self) -> TestCase { + self.expect_success_extended(None) + } + + fn expect_success_extended(self, message: Option <&str>) -> TestCase { + let test_case: TestCase = self.into(); + let executor = test_case.executor(message); + print_stack(&test_case, executor); + if let Err(ref e) = test_case.execution_result { + match message { + None => { + //print_failed_detail_extended(&test_case, e, message); + panic!("Execution error: {:?}", e); + } + Some(msg) => { + //print_failed_detail_extended(&test_case, e, message); + panic!("{}\nExecution error: {:?}", msg, e); + } + } + } + test_case + } + + fn expect_ctrl(self, ctrl: usize, item: &StackItem) -> TestCase { + self.expect_ctrl_extended(ctrl, item, None) + } + + fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) -> TestCase { + let test_case: TestCase = self.into(); + let executor = test_case.executor(message); + match test_case.execution_result { + Ok(_) => executor.assert_ctrl(ctrl, item), + Err(ref e) => { + //print_failed_detail_extended(&test_case, e, message); + panic!("Execution error: {}", e); + } + }; + test_case + } + + fn expect_failure(self, exception_code: ExceptionCode) -> TestCase { + self.expect_failure_extended(exception_code, None) + } + + fn expect_custom_failure_extended bool>( + self, + op: F, + exc_name: &str, + message: Option <&str> + ) -> TestCase { + let test_case: TestCase = self.into(); + let executor = test_case.executor(message); + match test_case.execution_result { + Ok(_) => { + log::info!( + target: "tvm", + "Expected failure: {}, however execution succeeded.", + exc_name + ); + print_stack(&test_case, executor); + match message { + None => panic!( + "Expected failure: {}, however execution succeeded.", + exc_name + ), + Some(msg) => panic!( + "{}.\nExpected failure: {}, however execution succeeded.", + msg, exc_name + ) + } + } + Err(ref e) => { + if let Some(TvmError::TvmExceptionFull(e, msg2)) = e.downcast_ref() { + if op(e) { + match message { + Some(msg) => panic!( + "{} - {}\nNon expected exception: {}, expected: {}", + msg2, msg, e, exc_name + ), + None => panic!( + "{}\nNon expected exception: {}, expected: {}", + msg2, e, exc_name + ) + } + } + } else { + let code = e.downcast_ref::(); + match code { + Some(code) => { + let e = Exception::from(*code); + if op(&e) { + panic!("Non expected exception: {}, expected: {}", e, exc_name) + } + } + None => { + if op(&Exception::from(ExceptionCode::FatalError)) { + panic!("Non expected exception: {}, expected: {}", e, exc_name) + } + } + } + } + } + } + test_case + } + + fn expect_custom_failure(self, custom_code: i32) -> TestCase { + self.expect_custom_failure_extended( + |e| e.custom_code() != Some(custom_code), + "custom exception", + None + ) + } + + fn expect_failure_extended( + self, + exception_code: ExceptionCode, + message: Option <&str> + ) -> TestCase { + self.expect_custom_failure_extended( + |e| e.exception_code() != Some(exception_code), + &format!("{}", exception_code), + message + ) + } + + fn expect_root_data(self, cell: Cell) -> TestCase { + self.expect_ctrl(4, &StackItem::Cell(cell)) + } + + fn expect_same_results(self, other: Self) { + let case1 = self.expect_success(); + let case2 = other.expect_success(); + let stack = case2.executor.unwrap().withdraw_stack(); + case1.expect_stack_extended(&stack, Some("results are not the same!")); + } + + fn expect_gas( + self, + max_gas_limit: i64, + gas_limit: i64, + gas_credit: i64, + gas_remaining: i64 + ) -> TestCase { + let test_case: TestCase = self.into(); + let gas = test_case.executor(None).get_gas(); + assert_eq!(gas.get_gas_limit_max(), max_gas_limit); + assert_eq!(gas.get_gas_limit(), gas_limit); + assert_eq!(gas.get_gas_credit(), gas_credit); + assert_eq!(gas.get_gas_remaining(), gas_remaining); + test_case + } + + fn expect_steps(self, steps: u32) -> TestCase { + let test_case: TestCase = self.into(); + assert_eq!(test_case.executor(None).steps(), steps); + test_case + } + + fn stack(self) -> Stack { + let test_case: TestCase = self.into(); + test_case.executor(None).stack().clone() + } +} + +fn print_stack(test_case: &TestCase, executor: &Engine) { + if test_case.execution_result.is_ok() { + log::info!(target: "tvm", "Post-execution:\n"); + log::info!(target: "tvm", "{}", executor.dump_stack("Post-execution stack state", false)); + log::info!(target: "tvm", "{}", executor.dump_ctrls(false)); + } +} + +/*#[allow(dead_code)] +fn print_failed_detail(case: &TestCase, exception: &Error) { + print_failed_detail_extended(case, exception, None) +} + +fn print_failed_detail_extended(case: &TestCase, exception: &Error, message: Option <&str>) { + log::info!(target: "tvm", "exception: {:?}\n", exception); + let msg2 = if let Some(TvmError::TvmExceptionFull(_e, msg2)) = exception.downcast_ref() { + msg2.clone() + } else { + String::new() + }; + match message { + Some(ref msg) => log::info!( + target: "tvm", + "{} failed with {} {}.\nBytecode: {:x?}\n", + msg, exception, msg2, case.compilation_result + ), + None => log::info!( + target: "tvm", + "failed with {} {}.\nBytecode: {:x?}\n", + exception, msg2, case.compilation_result + ) + } +}*/ + +pub fn test_case_with_refs(code: &str, references: Vec) -> TestCaseInputs { + TestCaseInputs::new(code.to_string(), Stack::new(), references, 0) +} + +pub fn test_case_with_ref(code: &str, reference: Cell) -> TestCaseInputs { + TestCaseInputs::new(code.to_string(), Stack::new(), vec![reference], 0) +} + +pub fn test_case(code: impl ToString) -> TestCaseInputs { + TestCaseInputs::new(code.to_string(), Stack::new(), vec![], 0) +} + +pub fn test_case_with_bytecode(code: Bytecode) -> TestCase { + TestCase::with_bytecode(code, None, None, Default::default()) +} + +#[allow(dead_code)] +pub fn test_single_argument_fail(cmd: &str, argument: isize) { + let code = format!("{} {}", cmd, argument); + test_case(code) + .expect_compilation_failure(CompileError::out_of_range(1, 1, cmd, "arg 0")); +} + +#[allow(dead_code)] +pub fn expect_exception(code: &str, exc_code: ExceptionCode) { + test_case(code).expect_failure(exc_code); +} + +#[allow(dead_code)] +pub fn expect_exception_with_capability( + code: &str, + exc_code: ExceptionCode, + capability: GlobalCapabilities, + check_fift: bool +) { + test_case( + code, + ) + .with_capability(capability) + .skip_fift_check(!check_fift) + .expect_failure(exc_code); +} diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs new file mode 100644 index 00000000..1423a9b5 --- /dev/null +++ b/tvm_tests/src/test_zk.rs @@ -0,0 +1,1594 @@ +/* +* Copyright (C) 2019-2023 TON Labs. All Rights Reserved. +* +* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use +* this file except in compliance with the License. +* +* 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 TON DEV software governing permissions and +* limitations under the License. +*/ + +use num_traits::Zero; // Для работы с большими числами +use std::iter::repeat; + +use std::collections::HashMap; +use std::slice; +use std::str::FromStr; +use std::time::Instant; +use ark_std::rand::rngs::StdRng; +use ark_std::rand::SeedableRng; +use base64ct::Encoding as bEncoding; +use fastcrypto::ed25519::Ed25519KeyPair; +use base64::decode; +use ark_ff::biginteger::BigInteger; +use ed25519::signature::Signer; + +use fastcrypto::traits::{KeyPair, ToFromBytes}; +use tvm_types::{ + types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, + Sha256 +}; + +//use tvm_vm::executor::zk_stuff::zk_login::{hash_ascii_str_to_field, hash_to_field, MAX_HEADER_LEN, MAX_ISS_LEN_B64, PACK_WIDTH}; + + +#[cfg(feature = "signature_no_check")] +use ton_vm::executor::BehaviorModifiers; +use tvm_vm::{ + boolean, + executor::serialize_currency_collection, + int, + stack::{ + integer::{ + serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, + IntegerData, + }, + serialization::{Deserializer, Serializer}, + Stack, StackItem, + }, + SmartContractInfo, + utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, +}; + +use tvm_vm::executor::zk_stuff::error::ZkCryptoError; +use tvm_types::{BuilderData, Cell, SliceData}; +use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, Claim, JWK, JwkId, OIDCProvider, ZkLoginInputs}; +use fastcrypto_zkp::bn254::utils::{gen_address_seed, get_zk_login_address}; +use fastcrypto_zkp::zk_login_utils::Bn254FrElement; +use num_bigint::BigUint; + +use serde::{Deserialize}; +use serde_derive::Serialize; +use serde_json::Value; +use tvm_vm::executor::zk::calculate_poseidon_hash; +use crate::test_framework::{Expects, test_case, test_case_with_refs}; + +pub const SUI_DATA_FROM_REACT_1: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJ4bW5KVzMxcnV6S01HaXIwMVlQR1lMMHhEWSIsIm5iZiI6MTcxNTY4NzAzNiwiaWF0IjoxNzE1Njg3MzM2LCJleHAiOjE3MTU2OTA5MzYsImp0aSI6IjliNjAxZDI1ZjAwMzY0MGMyODg5YTJhMDQ3Nzg5MzgyY2IxY2ZlODcifQ.rTa9KA9HoYm04Agj71D0kDkvsCZ35SeeihBGbABYckBRxaUlCy6LQ-sEaVOTgvnL_DgVn7hx8g3sSmnhJ9kHzj5e6gtUoxoWAe8PuGyK2bmqhmPrQMeEps9f6m2EToQCIA_Id4fGCjSCktjJBi47QHT_Dhe6isHdKk1pgSshOyvCF1VjIvyyeGY5iWQ4cIRBMQNlNBT11o6T01SY6B9DtiiFN_0-ok5taIjQgtMNG6Cwr3tCnqXftuGGQrHlx15y8VgCPODYi-wOtvUbzI2yfx53PmRD_L8O50cMNCrCRE3yYR5MNOu1LlQ_EACy5UFsCJR35xRz84nv-6Iyrufx1g\",\"userPassToIntFormat\":\"981021191041055255531141165751\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":155,\"1\":147,\"2\":37,\"3\":82,\"4\":183,\"5\":109,\"6\":227,\"7\":144,\"8\":85,\"9\":248,\"10\":20,\"11\":45,\"12\":92,\"13\":103,\"14\":160,\"15\":221,\"16\":101,\"17\":44,\"18\":30,\"19\":86,\"20\":96,\"21\":85,\"22\":24,\"23\":224,\"24\":106,\"25\":63,\"26\":13,\"27\":130,\"28\":8,\"29\":119,\"30\":247,\"31\":67},\"secretKey\":{\"0\":192,\"1\":16,\"2\":35,\"3\":54,\"4\":100,\"5\":14,\"6\":88,\"7\":217,\"8\":164,\"9\":21,\"10\":154,\"11\":233,\"12\":248,\"13\":208,\"14\":188,\"15\":4,\"16\":52,\"17\":244,\"18\":125,\"19\":103,\"20\":99,\"21\":26,\"22\":225,\"23\":60,\"24\":140,\"25\":75,\"26\":228,\"27\":157,\"28\":137,\"29\":220,\"30\":1,\"31\":65,\"32\":155,\"33\":147,\"34\":37,\"35\":82,\"36\":183,\"37\":109,\"38\":227,\"39\":144,\"40\":85,\"41\":248,\"42\":20,\"43\":45,\"44\":92,\"45\":103,\"46\":160,\"47\":221,\"48\":101,\"49\":44,\"50\":30,\"51\":86,\"52\":96,\"53\":85,\"54\":24,\"55\":224,\"56\":106,\"57\":63,\"58\":13,\"59\":130,\"60\":8,\"61\":119,\"62\":247,\"63\":67}}},\"zkAddr\":\"0x290623ea2fe67e77502c931e015e910720b59cf99994bfe872da851245a6adb8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"4240296169193969312736577528388333411353554120022978085193148043577551744781\",\"5805161066003598301896048908428560240907086333477483881772048922050706263054\",\"1\"],\"b\":[[\"12834391737669124973917765536412427456985620342194191639017091262766903638891\",\"17565396762846717347409742387259908749145765976354144805005547481529916658455\"],[\"10704310067924910937030159163683742097178285875135929496314190235513445131794\",\"5158907077493606386023392148737817037260820737072162547798816810512684527243\"],[\"1\",\"0\"]],\"c\":[\"1422540522119231707130773229384414857146368773886805969586218853559909475064\",\"8843079196273712399340537238369227864378150337693574970239878271571912585171\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJuTJVK3beOQVfgULVxnoN1lLB5WYFUY4Go/DYIId/dD\"}"; +pub const SUI_DATA_FROM_REACT_2: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjJKd0VMbjJfUV9Rd0VsTC1rWTFPRnFqdXZCMCIsIm5iZiI6MTcxNTY4NzAyOSwiaWF0IjoxNzE1Njg3MzI5LCJleHAiOjE3MTU2OTA5MjksImp0aSI6ImU2YjM1ZjJmNmFkNjIzOWEwMDAxMTJiMWI5YWI2MWQ0MjRkMGM1OTIifQ.QcrEDE9qmPZKX83nU3Tx2BN8fsinb_mmXkO1Qf7Uv1QTd0NjirSeu7C4Vn9WDNWDaIR-BgCfhOlkwMQPljcahqC4AN43N_66tvbEsXjtEdFejslXrGG4D_BEKvtmD7_WkW388LyU2PxKgtdDfpYFgmuT6wTM2TO5dTbrGrDyn88q3pkPfefC5a8Wi1V6zECfFdSV-pKQlxtPaImi7s3CKAUMDu1n-jcT-Ho2aTgrWKAzhXE56tgEWOpXQO06eJsWCSOqoZSLYtatTrZr4d38U7QRQiNlH-ydHv4zXt1tixLLJ0wvPx-dQaCnCl1kW1orYkJGFfHgjx6A9z5Ol4afuw\",\"userPassToIntFormat\":\"101119106102103\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":194,\"1\":38,\"2\":203,\"3\":255,\"4\":219,\"5\":127,\"6\":105,\"7\":129,\"8\":234,\"9\":222,\"10\":71,\"11\":169,\"12\":108,\"13\":94,\"14\":28,\"15\":48,\"16\":111,\"17\":221,\"18\":113,\"19\":110,\"20\":5,\"21\":226,\"22\":19,\"23\":230,\"24\":232,\"25\":67,\"26\":255,\"27\":179,\"28\":6,\"29\":10,\"30\":209,\"31\":63},\"secretKey\":{\"0\":44,\"1\":32,\"2\":251,\"3\":184,\"4\":109,\"5\":252,\"6\":105,\"7\":67,\"8\":208,\"9\":111,\"10\":86,\"11\":214,\"12\":192,\"13\":135,\"14\":169,\"15\":48,\"16\":162,\"17\":36,\"18\":216,\"19\":145,\"20\":232,\"21\":64,\"22\":17,\"23\":14,\"24\":29,\"25\":56,\"26\":39,\"27\":118,\"28\":143,\"29\":250,\"30\":31,\"31\":66,\"32\":194,\"33\":38,\"34\":203,\"35\":255,\"36\":219,\"37\":127,\"38\":105,\"39\":129,\"40\":234,\"41\":222,\"42\":71,\"43\":169,\"44\":108,\"45\":94,\"46\":28,\"47\":48,\"48\":111,\"49\":221,\"50\":113,\"51\":110,\"52\":5,\"53\":226,\"54\":19,\"55\":230,\"56\":232,\"57\":67,\"58\":255,\"59\":179,\"60\":6,\"61\":10,\"62\":209,\"63\":63}}},\"zkAddr\":\"0x9d28c04a423b33d6901065b2e23440d80c963e2d8cf60619aed131cf302a3345\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"10113442204684515220664612836724727112601024759319365467272456423129044788607\",\"1622056145268645528934658046911045406324940175278473377024147189407527440953\",\"1\"],\"b\":[[\"16638441944380099215425740101953753038808466958852552979180365845498468757656\",\"15160836857346434734063515954042830497610079883703780011464867547889770445695\"],[\"18562910453341688699790780964434211467815845944672185772065803860963710445937\",\"8200691834141582017549140597895023392490964486044036655696113278873832146838\"],[\"1\",\"0\"]],\"c\":[\"4229037146526046139176767312447148765936834700862335953317784850097077554287\",\"14155516063621997063825085002662503289554536312724791903045026922766401869119\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AMImy//bf2mB6t5HqWxeHDBv3XFuBeIT5uhD/7MGCtE/\"}"; +pub const SUI_DATA_FROM_REACT_3: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkFadlVHUkI5MU5VZmdnYVV5bUdCQU9kSmM2ayIsIm5iZiI6MTcxNTY4NzAyMiwiaWF0IjoxNzE1Njg3MzIyLCJleHAiOjE3MTU2OTA5MjIsImp0aSI6ImZiNGNhMzdjOGE5MjEzOTFjZTE2ZDQwNmE2NmVmYjA1MTQxNTg5YjYifQ.C7zNP2sxRMF62irwNjO2y_JVMjYLqGk6sAWy0rKoXswa7SA6KhPrWocMAB2GKaQW-CeqUzMJdypgJz1RcMzmOWg30cv4diEgqBSM1I1ocOI5ivRE2Atj8g-Oj2uAm_DBvuJBLzTA6wfb34QTasOTZqLsMyoaQavxUprzPi-1z-MUE-darDjZ-IkWu7SctdEzNhSuUfQPJo_sbN5_38dQm300plXK-9iJgDxMWmT4NPO91hSQaGKbBm_euMI-fBAfYwARMnlaTETvSiCNSAyzphNrBi9kU49BFi5X04GoIkSW4zFwb74OeFbL49_14AZZ9Z2Mw7EPQ9sAAjzanxPUfA\",\"userPassToIntFormat\":\"98118101102104106100\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":219,\"1\":225,\"2\":68,\"3\":197,\"4\":249,\"5\":59,\"6\":249,\"7\":200,\"8\":218,\"9\":242,\"10\":184,\"11\":214,\"12\":247,\"13\":159,\"14\":9,\"15\":162,\"16\":60,\"17\":174,\"18\":162,\"19\":13,\"20\":111,\"21\":5,\"22\":61,\"23\":179,\"24\":155,\"25\":167,\"26\":207,\"27\":6,\"28\":174,\"29\":163,\"30\":23,\"31\":23},\"secretKey\":{\"0\":28,\"1\":117,\"2\":37,\"3\":14,\"4\":166,\"5\":188,\"6\":125,\"7\":36,\"8\":70,\"9\":193,\"10\":162,\"11\":142,\"12\":79,\"13\":218,\"14\":210,\"15\":131,\"16\":217,\"17\":32,\"18\":88,\"19\":246,\"20\":195,\"21\":214,\"22\":135,\"23\":80,\"24\":27,\"25\":198,\"26\":131,\"27\":31,\"28\":3,\"29\":240,\"30\":199,\"31\":129,\"32\":219,\"33\":225,\"34\":68,\"35\":197,\"36\":249,\"37\":59,\"38\":249,\"39\":200,\"40\":218,\"41\":242,\"42\":184,\"43\":214,\"44\":247,\"45\":159,\"46\":9,\"47\":162,\"48\":60,\"49\":174,\"50\":162,\"51\":13,\"52\":111,\"53\":5,\"54\":61,\"55\":179,\"56\":155,\"57\":167,\"58\":207,\"59\":6,\"60\":174,\"61\":163,\"62\":23,\"63\":23}}},\"zkAddr\":\"0xeccbb76b41c1fd5e19950f0c005e5d2a2596b9cc510e98b6f69bb3cf590b3cf8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"11651445672013969095011012560101085321682180365624939394143647198080899422642\",\"1099774502834574451399947043208869188329872135932897351612210181871486714260\",\"1\"],\"b\":[[\"4095258550782358133185755302461547336434190495389756275789648565352453295275\",\"11290282088300413285686821769617771231670721476484846359206004074570380534935\"],[\"10130196410049440247754977520268298700433580296307256932070052957562923587210\",\"18578315450133100598244014262861961858129311260491371986249505812898194068790\"],[\"1\",\"0\"]],\"c\":[\"3621803486710965065098877836422521469652420656514094958857631583114966034063\",\"10775419351495516109888010278620848514990288696189982169937651175162131341248\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ANvhRMX5O/nI2vK41vefCaI8rqINbwU9s5unzwauoxcX\"}"; +pub const SUI_DATA_FROM_REACT_4: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Inh4VjZnc3RReGY2WW5Kb0QyMXMtZkNWdm9ESSIsIm5iZiI6MTcxNTY4NzAxNSwiaWF0IjoxNzE1Njg3MzE1LCJleHAiOjE3MTU2OTA5MTUsImp0aSI6ImQzOWJjMTUyOWVhODMwNTRiNGU0MDRlNDRhMmE4ZWRjOTJlZWFiYWYifQ.u23WQFEtc4TldMtNqrU7DiYdL33X2QySNxueCW79LQHc00P7g-Pu7xPX0XK_TLxP6ReZEdpdCmjfG6g--XBYXh313FKcqVhcrtKdBE06jf5acAf4fQ3TVzG5CFWqjISRhLL0eGjX20DZm8drrSFYTgfWPl9ANo6TV2IFF6BR9TOO_flxzmXPRVvER9ZA4QO52JCqagVYBw4bFZcUebiN_KXYuXOYWzUAiHM7lKUdVKoCte9JDKnTfRNg3r-i5tt5Oiovswwh9jubQd5c8nCQckQ8Fj9T5nPmlfPtF282kfd76xlHckvL94mM3HUKNuFrxeiFX07f_5Ff7NxvQ3QPgw\",\"userPassToIntFormat\":\"118102101104106\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":25,\"1\":68,\"2\":102,\"3\":77,\"4\":86,\"5\":118,\"6\":203,\"7\":106,\"8\":41,\"9\":192,\"10\":205,\"11\":144,\"12\":20,\"13\":158,\"14\":42,\"15\":167,\"16\":18,\"17\":30,\"18\":27,\"19\":103,\"20\":51,\"21\":222,\"22\":226,\"23\":224,\"24\":168,\"25\":111,\"26\":16,\"27\":214,\"28\":128,\"29\":165,\"30\":10,\"31\":183},\"secretKey\":{\"0\":204,\"1\":128,\"2\":233,\"3\":135,\"4\":233,\"5\":64,\"6\":127,\"7\":97,\"8\":231,\"9\":135,\"10\":123,\"11\":149,\"12\":126,\"13\":145,\"14\":173,\"15\":252,\"16\":33,\"17\":141,\"18\":251,\"19\":181,\"20\":223,\"21\":9,\"22\":77,\"23\":32,\"24\":19,\"25\":187,\"26\":3,\"27\":180,\"28\":110,\"29\":49,\"30\":114,\"31\":167,\"32\":25,\"33\":68,\"34\":102,\"35\":77,\"36\":86,\"37\":118,\"38\":203,\"39\":106,\"40\":41,\"41\":192,\"42\":205,\"43\":144,\"44\":20,\"45\":158,\"46\":42,\"47\":167,\"48\":18,\"49\":30,\"50\":27,\"51\":103,\"52\":51,\"53\":222,\"54\":226,\"55\":224,\"56\":168,\"57\":111,\"58\":16,\"59\":214,\"60\":128,\"61\":165,\"62\":10,\"63\":183}}},\"zkAddr\":\"0x9440174050c8a69f3736aade438d256444387d7f99afaf9b5a9f29c6f0fba0c3\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12337032776119704699956096862904448418119911526311506121881119564201699892276\",\"21261432927871679671381948020842646421823600661053961908567605147368225372658\",\"1\"],\"b\":[[\"361501104451650926380087094710685809078127996371826342961671838349546013669\",\"6224896865231367783073876006741593926823975323893517814398563485217838362592\"],[\"17991862631010087641911530148948529285385885925990265147692471125933697566220\",\"3919918348467391624469564417209140189505145619892305626999747602773689849635\"],[\"1\",\"0\"]],\"c\":[\"2974798412198231516644318932878285282801453498857240613838304706754188993145\",\"18411763423260631630440151338922210964792206590205572668118109635459867927504\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ABlEZk1WdstqKcDNkBSeKqcSHhtnM97i4KhvENaApQq3\"}"; +pub const SUI_DATA_FROM_REACT_5: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlZXM0VrSmp5ZXM0M2pvNENXU0FyU1pORHk5ayIsIm5iZiI6MTcxNTY4NzAwNywiaWF0IjoxNzE1Njg3MzA3LCJleHAiOjE3MTU2OTA5MDcsImp0aSI6IjMwNDczMjk0MmI3MDQzOTUzN2M3OTE4YTIyZDMxODA1YTVjYzkzZTYifQ.sa6ee8fcMhF3JgGQcl03IY0alries0KC7SRH-HVUnA5cqTVYomJ6fr0NTDJmYXNKOeIcaT85LLN0ALsKtEQdZjhu1g4m16kbS-5MybFIXT85JIPhBOz7zYldrbiy-Me8XRNWPkR3X_lV9pwqvYJTnZ0ley5dDITRvIXE1w2ZmjGNDlDxG3aM2XOQDICQ1ztsCZkn20ShuvG7tZHq7cp7K0hd6JdX0fFRY85eSIeapW7NnnWdvJi2xvuiCcwqm8sshldcJI5uU9xikhoN2WA7c8fJ5rtshqp5-RtTOfbzLn2a6m0WeDE0JqUd8jbh6_T8mGtYYeYMAWfWb-jVPa8aNg\",\"userPassToIntFormat\":\"118981041155255\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":76,\"1\":252,\"2\":245,\"3\":48,\"4\":8,\"5\":126,\"6\":211,\"7\":60,\"8\":249,\"9\":241,\"10\":111,\"11\":107,\"12\":148,\"13\":35,\"14\":224,\"15\":237,\"16\":179,\"17\":74,\"18\":84,\"19\":7,\"20\":130,\"21\":96,\"22\":198,\"23\":40,\"24\":23,\"25\":4,\"26\":50,\"27\":62,\"28\":191,\"29\":222,\"30\":119,\"31\":195},\"secretKey\":{\"0\":217,\"1\":194,\"2\":91,\"3\":84,\"4\":244,\"5\":214,\"6\":113,\"7\":57,\"8\":79,\"9\":43,\"10\":104,\"11\":85,\"12\":61,\"13\":225,\"14\":26,\"15\":139,\"16\":139,\"17\":206,\"18\":110,\"19\":48,\"20\":118,\"21\":99,\"22\":130,\"23\":122,\"24\":59,\"25\":6,\"26\":224,\"27\":144,\"28\":146,\"29\":25,\"30\":147,\"31\":225,\"32\":76,\"33\":252,\"34\":245,\"35\":48,\"36\":8,\"37\":126,\"38\":211,\"39\":60,\"40\":249,\"41\":241,\"42\":111,\"43\":107,\"44\":148,\"45\":35,\"46\":224,\"47\":237,\"48\":179,\"49\":74,\"50\":84,\"51\":7,\"52\":130,\"53\":96,\"54\":198,\"55\":40,\"56\":23,\"57\":4,\"58\":50,\"59\":62,\"60\":191,\"61\":222,\"62\":119,\"63\":195}}},\"zkAddr\":\"0x71444450505074fe9d9205f02747fb34f49dda22eb33eaf7929bb8561ffd45f2\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"4549343359411304649846201661164616647369749072820883051997393354186530425088\",\"3937997833930688873121017483900547354352969510911658484353113904856895725039\",\"1\"],\"b\":[[\"737118397015523176881783675037843258491735390512712007670938320351154476838\",\"18093386738096496776241258608856280732173952478987786488484944779094702670649\"],[\"17783469782238073070748856104623185946400565050372789961482242728023613389739\",\"15824649467012100671772283318060553156148444804907193757065241285355958322525\"],[\"1\",\"0\"]],\"c\":[\"15112690010634489290938122084488710379345235713605729023472643459768097669053\",\"21568492795931010980780236148561695295582527237009199544419907898465140630575\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AEz89TAIftM8+fFva5Qj4O2zSlQHgmDGKBcEMj6/3nfD\"}"; +pub const SUI_DATA_FROM_REACT_6: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjMySWx6VWJuSFY4MV9QTTBJSDBSZmFveVN1TSIsIm5iZiI6MTcxNTY4NzAwMCwiaWF0IjoxNzE1Njg3MzAwLCJleHAiOjE3MTU2OTA5MDAsImp0aSI6ImRhOTU5NmIwMTljOTQ2NWE4MzA0MWIxMDA3OTI2OGU3NDgwY2ZjMDkifQ.HFkMZFhHu6BGBbWhC1NwCvJ9_bKOL8jOdOHuRG21mKh-CaJPffnGtaVNcwEJjf4jOVVPPZNfcJPWOd7KoT_R2Giw7An2dUcJFvVJHUv4h55u4DinU50R7h7ACyEl5GwbKCI-cgxORbcoUdQRukDt1zJHe1eeWm1S8URlE2f4U0w2tPPaE_NmChIRyvU_CjB0dLwxzIWU74pvnbkLSSD2pTWhGbLT1yNhfMTh6yukLyEt2kWvNdZOgGbDfIU6xFjxJLtnPrm5WGiOiWyBmMuDput47-ns4821l3KogdIbWr6TLWW0PMwyJuHnif5pV7wJI9JL5XdFv8KZ0IReAYOIEg\",\"userPassToIntFormat\":\"1021035256\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":169,\"1\":238,\"2\":219,\"3\":251,\"4\":231,\"5\":87,\"6\":175,\"7\":233,\"8\":185,\"9\":44,\"10\":161,\"11\":207,\"12\":48,\"13\":166,\"14\":79,\"15\":104,\"16\":225,\"17\":53,\"18\":68,\"19\":236,\"20\":49,\"21\":204,\"22\":99,\"23\":208,\"24\":2,\"25\":134,\"26\":101,\"27\":212,\"28\":221,\"29\":142,\"30\":69,\"31\":196},\"secretKey\":{\"0\":94,\"1\":128,\"2\":26,\"3\":130,\"4\":137,\"5\":40,\"6\":61,\"7\":27,\"8\":79,\"9\":58,\"10\":100,\"11\":117,\"12\":200,\"13\":118,\"14\":156,\"15\":202,\"16\":165,\"17\":34,\"18\":238,\"19\":237,\"20\":90,\"21\":63,\"22\":84,\"23\":119,\"24\":86,\"25\":2,\"26\":221,\"27\":177,\"28\":224,\"29\":4,\"30\":233,\"31\":99,\"32\":169,\"33\":238,\"34\":219,\"35\":251,\"36\":231,\"37\":87,\"38\":175,\"39\":233,\"40\":185,\"41\":44,\"42\":161,\"43\":207,\"44\":48,\"45\":166,\"46\":79,\"47\":104,\"48\":225,\"49\":53,\"50\":68,\"51\":236,\"52\":49,\"53\":204,\"54\":99,\"55\":208,\"56\":2,\"57\":134,\"58\":101,\"59\":212,\"60\":221,\"61\":142,\"62\":69,\"63\":196}}},\"zkAddr\":\"0xb1dfac568641e785f1fbd385f43f9ab5751f30e942ffd0618ea3cacf2feb884f\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12140334820013650239749561964826061158522594132954339836339110630367427672527\",\"21543355833919541708094668850466443067263177907229807762067953508321817783804\",\"1\"],\"b\":[[\"11929519532343982399968491980281874410531815035766070083344475081372092452425\",\"13741260533480647813301201467326069876472210148610447598292633272004546481630\"],[\"14605296808789442404291984821803068302067977919075239981788942874792752578522\",\"20230214791286972912596895174545361255719543417377972941442631629070781210055\"],[\"1\",\"0\"]],\"c\":[\"6046227686259383004231849145260526357580306829730644608118177932582255490991\",\"1343314209137088066016224766407952045954639818725548553059063245802388749310\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AKnu2/vnV6/puSyhzzCmT2jhNUTsMcxj0AKGZdTdjkXE\"}"; +pub const SUI_DATA_FROM_REACT_7: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjhJNGF5NDF5THpHWnk4czNCUGR3QzItR2Q5ayIsIm5iZiI6MTcxNTY4Njk5MywiaWF0IjoxNzE1Njg3MjkzLCJleHAiOjE3MTU2OTA4OTMsImp0aSI6ImFjYmJiNmQ3NGY0ZmU3MjMxYzc2ZDQxNzE0ZDM4NDJiNzZlNDU4YzIifQ.nsmqj7tDDv7wJSn47YfaFBXabPYVBjZosGzH_bPHZZToPfvdQyXZrO5CXbaJmojxTPRmzZ2bPI39K9GMX7Y8gaOqk_LYHR7eemVaEj0wNpPPtmUFmHmyrL8nPkTN0a-87L2eu6t7yBZtEiT5e2Jz46RBu9rQL138seOvK3vm0YwhtnLGxhZQnoAKu076qZ_ItlsRn9PqM-sd83bqQoG_SPQVCZL6spWoFunXtj1FeKE-3gRRD8BopORDhFp4xytWDamd1XgIdCNp0a8u7mvElPZCjc3ZUAtFYBWwvfI9r2wN5X4gbNe_pbfpBmgg-2zxwt6c32IhNXlrDQkLxJYqkg\",\"userPassToIntFormat\":\"9899115100106104\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":35,\"1\":64,\"2\":69,\"3\":29,\"4\":242,\"5\":9,\"6\":183,\"7\":224,\"8\":98,\"9\":254,\"10\":210,\"11\":82,\"12\":213,\"13\":2,\"14\":137,\"15\":66,\"16\":71,\"17\":61,\"18\":80,\"19\":154,\"20\":135,\"21\":100,\"22\":176,\"23\":189,\"24\":187,\"25\":96,\"26\":245,\"27\":194,\"28\":163,\"29\":250,\"30\":15,\"31\":37},\"secretKey\":{\"0\":117,\"1\":94,\"2\":35,\"3\":85,\"4\":116,\"5\":80,\"6\":126,\"7\":55,\"8\":166,\"9\":193,\"10\":94,\"11\":109,\"12\":238,\"13\":86,\"14\":132,\"15\":192,\"16\":225,\"17\":240,\"18\":26,\"19\":65,\"20\":211,\"21\":18,\"22\":195,\"23\":36,\"24\":225,\"25\":158,\"26\":143,\"27\":141,\"28\":21,\"29\":174,\"30\":139,\"31\":13,\"32\":35,\"33\":64,\"34\":69,\"35\":29,\"36\":242,\"37\":9,\"38\":183,\"39\":224,\"40\":98,\"41\":254,\"42\":210,\"43\":82,\"44\":213,\"45\":2,\"46\":137,\"47\":66,\"48\":71,\"49\":61,\"50\":80,\"51\":154,\"52\":135,\"53\":100,\"54\":176,\"55\":189,\"56\":187,\"57\":96,\"58\":245,\"59\":194,\"60\":163,\"61\":250,\"62\":15,\"63\":37}}},\"zkAddr\":\"0x2130548addf21464dba0598e4306193fc658433793260241bd224fa5a186eea1\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"11563763779979887221682129962776185026792805331576343366100386476995832665737\",\"11230623338801856741023013148077980370341441565413488652841279984753971030674\",\"1\"],\"b\":[[\"459996434316864652818633810305056376561329097756558823429320916262609240883\",\"9149790799426074072032368390512074348954812141386022619414187192076850710684\"],[\"21136831034524197906636931934376551157061262869485003235799208746070603082410\",\"7423352680736750974836973800304252036668418183885087029886854244313632685127\"],[\"1\",\"0\"]],\"c\":[\"13616579662900237409901679872544397096722160915603059752960265571802149963290\",\"17724386432768174493966206493099783171212386514205046762827409640509581679264\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ACNARR3yCbfgYv7SUtUCiUJHPVCah2Swvbtg9cKj+g8l\"}"; +pub const SUI_DATA_FROM_REACT_8: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjlzWGhqc0xVZlNmdE12bl9iYmQtWkEwZnY5OCIsIm5iZiI6MTcxNTY4Njk4NiwiaWF0IjoxNzE1Njg3Mjg2LCJleHAiOjE3MTU2OTA4ODYsImp0aSI6IjhiNDUzYjUzNTY4MGU3OWZkZWUyOGE3NDVmMzgzMDBkMmNmYjNmODQifQ.a2fpzvW0PxyOcvE8P6WEtIs_mdfTQ9kJb4MIUC5T5uRYJ9ySqSa2qT-MICspGYBuNzCtWIvI6KHY9cIWE2XF3yv7d7gTk_IkhXJud0s5hMhsIxWuNXla_-HducNufaXxXxWYJ2g8dy2xsIMnPr5OC-r4dAX3DM3AchB8qA-RYJdtgwlLytyANp6I35BRT7ewXyDDdlqMLnz5dv4xh1y1wrXFL7VDyzV2XVTK3ap12Cev9IZtHnSGsDgl-vEXj1OYIyiaDgtDhA7rfLXWRTQEeVnRpF-v3AIwZmRu1qaXFoqUbMaSQpFotwb6m8fMQ1q9efOK1Xrv8dL3jBDcUA3w3w\",\"userPassToIntFormat\":\"98118115106\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":52,\"1\":224,\"2\":199,\"3\":19,\"4\":180,\"5\":128,\"6\":181,\"7\":171,\"8\":55,\"9\":210,\"10\":168,\"11\":100,\"12\":198,\"13\":241,\"14\":150,\"15\":156,\"16\":226,\"17\":233,\"18\":32,\"19\":175,\"20\":153,\"21\":53,\"22\":23,\"23\":58,\"24\":196,\"25\":29,\"26\":16,\"27\":170,\"28\":245,\"29\":46,\"30\":71,\"31\":177},\"secretKey\":{\"0\":47,\"1\":184,\"2\":41,\"3\":167,\"4\":98,\"5\":225,\"6\":50,\"7\":146,\"8\":173,\"9\":129,\"10\":201,\"11\":41,\"12\":181,\"13\":239,\"14\":8,\"15\":249,\"16\":159,\"17\":200,\"18\":159,\"19\":80,\"20\":194,\"21\":79,\"22\":41,\"23\":26,\"24\":200,\"25\":82,\"26\":74,\"27\":200,\"28\":38,\"29\":172,\"30\":84,\"31\":187,\"32\":52,\"33\":224,\"34\":199,\"35\":19,\"36\":180,\"37\":128,\"38\":181,\"39\":171,\"40\":55,\"41\":210,\"42\":168,\"43\":100,\"44\":198,\"45\":241,\"46\":150,\"47\":156,\"48\":226,\"49\":233,\"50\":32,\"51\":175,\"52\":153,\"53\":53,\"54\":23,\"55\":58,\"56\":196,\"57\":29,\"58\":16,\"59\":170,\"60\":245,\"61\":46,\"62\":71,\"63\":177}}},\"zkAddr\":\"0xd704fd1fa5b1d8603b91081d104c08a025e9a952cd6b5b44324fcca2ed432737\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12104554633236481277286668189930576438264898269322388260846346074721767290773\",\"12396613925509861793005815245783240999567113519994130032649036118285018908597\",\"1\"],\"b\":[[\"1950992742588131071369658940220202257834946772534232957497529743913085624908\",\"13592611568444679350754388983552527571019415309901710535712414143531288069409\"],[\"16680699225604481493782973126773355417557338915104879244979908308676269902149\",\"7242446539394843603528008588061352122030003516933411896066602483137632866329\"],[\"1\",\"0\"]],\"c\":[\"17095909781059243761149234557016161052123209525874162987135833613569429453315\",\"8531296608559822287633863219696197152375138627859243631029781182381653695377\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ADTgxxO0gLWrN9KoZMbxlpzi6SCvmTUXOsQdEKr1Lkex\"}"; +pub const SUI_DATA_FROM_REACT_9: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImRLMlRMdjktRXFnaGR3SWQzMzlPNXZmN1JENCIsIm5iZiI6MTcxNTY4Njk3OSwiaWF0IjoxNzE1Njg3Mjc5LCJleHAiOjE3MTU2OTA4NzksImp0aSI6IjQxYTgwZTI3N2U5NzIxYjcwZDkyMjRkMWY5MzRlNjJhYTYwNzcyZGEifQ.NLM6YIR61HOzlEVS1ianwnFoG6OfSeLyuGpjH-Wt7eiWt27fHbDhOWTo-2ysx7cXuAl3gV8ZzMta24QSpjIiiaooGdurX92cWuDcARyewX5_4UuwBWBTXe66irHuqjwIOB2WwyN6PuOwvM6Y_IcL9vPwg76iJoupbeCHXBswiRVzVyBQus1k9SGigU8_ZuwGYoTLPd68MX7Z68NrK7mCF04Xaijs__zwJigIhVOK3TXN2Xy84Ha76mrXJRJZuWErrSNWagVO-dxb2oMT8vm5ND9aJ4q4NaIeGa8PIN2X1cfg9A6LZVBsGIc9JV2FG39yK4T2XAH6tn_HtoMzy_Vuvg\",\"userPassToIntFormat\":\"10011898115106104\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":78,\"1\":247,\"2\":200,\"3\":7,\"4\":84,\"5\":131,\"6\":33,\"7\":223,\"8\":6,\"9\":241,\"10\":100,\"11\":90,\"12\":91,\"13\":2,\"14\":31,\"15\":23,\"16\":138,\"17\":130,\"18\":115,\"19\":150,\"20\":202,\"21\":79,\"22\":12,\"23\":132,\"24\":168,\"25\":153,\"26\":155,\"27\":131,\"28\":31,\"29\":69,\"30\":170,\"31\":112},\"secretKey\":{\"0\":98,\"1\":144,\"2\":57,\"3\":245,\"4\":40,\"5\":191,\"6\":248,\"7\":149,\"8\":147,\"9\":12,\"10\":229,\"11\":76,\"12\":157,\"13\":3,\"14\":241,\"15\":94,\"16\":134,\"17\":124,\"18\":226,\"19\":177,\"20\":31,\"21\":140,\"22\":224,\"23\":58,\"24\":57,\"25\":95,\"26\":235,\"27\":246,\"28\":120,\"29\":89,\"30\":33,\"31\":149,\"32\":78,\"33\":247,\"34\":200,\"35\":7,\"36\":84,\"37\":131,\"38\":33,\"39\":223,\"40\":6,\"41\":241,\"42\":100,\"43\":90,\"44\":91,\"45\":2,\"46\":31,\"47\":23,\"48\":138,\"49\":130,\"50\":115,\"51\":150,\"52\":202,\"53\":79,\"54\":12,\"55\":132,\"56\":168,\"57\":153,\"58\":155,\"59\":131,\"60\":31,\"61\":69,\"62\":170,\"63\":112}}},\"zkAddr\":\"0x4493e2aab6fcd5d7259e066291ed6f42f6e0b732ecbd38bbaf8a98546a7d0cba\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"6187760498712900389422022394560825973187662358740291343829568808375698843239\",\"3663904360488418820404220406786944885702547623862334490191838865255632801941\",\"1\"],\"b\":[[\"17208058907245387104889127891010282196539728213379257608213444054211064433036\",\"9822512703540345824827246410723992174766686970531763618190197664729418117984\"],[\"9555481236549941306688205540885297760448987185399187813240300069134845655152\",\"17967781633941820778916846359708064205041390458485667635199415296702341964940\"],[\"1\",\"0\"]],\"c\":[\"12374452924342055287727719327288397498526425907741014437332085255604038084453\",\"7084903967634108603521121616612807600817728267672878238097194166039392876060\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AE73yAdUgyHfBvFkWlsCHxeKgnOWyk8MhKiZm4MfRapw\"}"; +pub const SUI_DATA_FROM_REACT_10: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZjdk1UaEZFdjFzVTBGVGR1M3Z5TmxlVUd0MCIsIm5iZiI6MTcxNTY4Njk3MiwiaWF0IjoxNzE1Njg3MjcyLCJleHAiOjE3MTU2OTA4NzIsImp0aSI6ImFiMDMwNTMzZjQyOWJmOGFhMDNmYzZhYjAxZjg2MGQ3MTg5ZDBlNjkifQ.f11q7mTu1uScsGvj4-KgVHHEhfAqk53JbAIC0PT8-CU40D4fSWbBoyXrUUQw6zly4KsyqazAFJ_1JqjiFvYFOhCAsoGWpgiA-hnL4QK-uxqUV4ule7Wt9xs8QVPivYxTrK2jmDgPGosvTUmlrGeyZk2XwilO3mbTe5wN-zMkUF0zUTdlIBTPrKbXMS1PklWTjUgDa1bXb-hOaFILkfZ4UgQI3PYHjZul3Rm_UUHHHVRkLgt0M449CGjuKSsIFvVkslfL319_71DLo7W0sYkJkWGOa482vTvyHgR9SjalUPV4TzPhpe_6DZZlKna7MXgq4FWOS9710PC6_HAXF2n-ag\",\"userPassToIntFormat\":\"11898100104102106115\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":146,\"1\":239,\"2\":26,\"3\":188,\"4\":228,\"5\":23,\"6\":17,\"7\":118,\"8\":183,\"9\":248,\"10\":93,\"11\":219,\"12\":0,\"13\":213,\"14\":164,\"15\":161,\"16\":140,\"17\":200,\"18\":97,\"19\":183,\"20\":135,\"21\":18,\"22\":103,\"23\":137,\"24\":234,\"25\":122,\"26\":246,\"27\":20,\"28\":155,\"29\":72,\"30\":212,\"31\":15},\"secretKey\":{\"0\":107,\"1\":202,\"2\":67,\"3\":226,\"4\":108,\"5\":41,\"6\":149,\"7\":181,\"8\":238,\"9\":3,\"10\":97,\"11\":189,\"12\":216,\"13\":94,\"14\":143,\"15\":210,\"16\":192,\"17\":213,\"18\":224,\"19\":200,\"20\":253,\"21\":67,\"22\":168,\"23\":88,\"24\":140,\"25\":106,\"26\":235,\"27\":247,\"28\":54,\"29\":146,\"30\":251,\"31\":123,\"32\":146,\"33\":239,\"34\":26,\"35\":188,\"36\":228,\"37\":23,\"38\":17,\"39\":118,\"40\":183,\"41\":248,\"42\":93,\"43\":219,\"44\":0,\"45\":213,\"46\":164,\"47\":161,\"48\":140,\"49\":200,\"50\":97,\"51\":183,\"52\":135,\"53\":18,\"54\":103,\"55\":137,\"56\":234,\"57\":122,\"58\":246,\"59\":20,\"60\":155,\"61\":72,\"62\":212,\"63\":15}}},\"zkAddr\":\"0xb86a18deea59af2850ab3800e2d46f63cfbea3bae309359089945d55949aef84\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"2575938484642353074459611431508941853614856803645537593538048270397701877180\",\"18525747234426619072147704335372433454079655655225636793928970068265541595508\",\"1\"],\"b\":[[\"5146896444986257903458872614168031344366471557324420746422302593221564486610\",\"19134791144810013840937258347062701987554745426617919650818846823708095832550\"],[\"3133101512761334334340993079649721452024653991833325456466256722050883608250\",\"21877263483512108853787895465249721341909931993800128255134630466114688578666\"],[\"1\",\"0\"]],\"c\":[\"3069457366306376197755607218741517434199413283376424243014529567457206056402\",\"4929625283757609606431630951067242799347282963225969540629139985267066740824\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJLvGrzkFxF2t/hd2wDVpKGMyGG3hxJniep69hSbSNQP\"}"; +pub const SUI_DATA_FROM_REACT_11: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkJ4RzlwNFhoV1B4WEt3NVRRdG9FbDljZzI5NCIsIm5iZiI6MTcxNTY4Njk0MSwiaWF0IjoxNzE1Njg3MjQxLCJleHAiOjE3MTU2OTA4NDEsImp0aSI6IjMyYmMxN2VjNWY3ZTQ5ZWRkOTM2MzVkZjE5MDk2N2E3NTg5Y2ZmNTgifQ.w3cT9MVhKTvnmAlmKClFFG6hjB2zrwHonYuN6l5S2unwyR6P_tGE42KhaFSNCY-imysy8k42awfmAafXwftKClLvqzk1T6bi5Li6caVd6-la8wj_FxNWkE5Cy-N4grOiEYJtV5SZezFzifmL6LOstv-Nc4X2b9Z6utuGOWYq3W9LNPveD0v5GnBCR6JRtHJkI6e5yZnMwDDE5o1P-LZbGuFXP75P6jseGem956the_WbrwIsnnTdFgjgjbXn_1gkh4SYGQ1ig0NVKcs75hUhKuQi7V6VqycuyXTgACOCsIfh2guoKha-APZUeul3z33zNbsqUcgkWwl6CkvDSdGWiQ\",\"userPassToIntFormat\":\"1145652515748\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":153,\"1\":152,\"2\":146,\"3\":133,\"4\":135,\"5\":137,\"6\":8,\"7\":27,\"8\":197,\"9\":109,\"10\":12,\"11\":221,\"12\":49,\"13\":15,\"14\":10,\"15\":1,\"16\":64,\"17\":236,\"18\":222,\"19\":97,\"20\":181,\"21\":214,\"22\":200,\"23\":214,\"24\":130,\"25\":247,\"26\":204,\"27\":212,\"28\":49,\"29\":33,\"30\":169,\"31\":172},\"secretKey\":{\"0\":159,\"1\":96,\"2\":35,\"3\":206,\"4\":32,\"5\":121,\"6\":5,\"7\":32,\"8\":37,\"9\":203,\"10\":15,\"11\":252,\"12\":99,\"13\":107,\"14\":57,\"15\":211,\"16\":139,\"17\":123,\"18\":6,\"19\":233,\"20\":56,\"21\":15,\"22\":35,\"23\":224,\"24\":243,\"25\":148,\"26\":44,\"27\":114,\"28\":112,\"29\":161,\"30\":226,\"31\":255,\"32\":153,\"33\":152,\"34\":146,\"35\":133,\"36\":135,\"37\":137,\"38\":8,\"39\":27,\"40\":197,\"41\":109,\"42\":12,\"43\":221,\"44\":49,\"45\":15,\"46\":10,\"47\":1,\"48\":64,\"49\":236,\"50\":222,\"51\":97,\"52\":181,\"53\":214,\"54\":200,\"55\":214,\"56\":130,\"57\":247,\"58\":204,\"59\":212,\"60\":49,\"61\":33,\"62\":169,\"63\":172}}},\"zkAddr\":\"0x41c25944949f0e3bf80fea41d9ab27acfa26e0b25ecd7e468235b2284e5b0c09\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"10607121052143170357142710430122120898934487918266599021712929788471219763472\",\"13359690919698524885136984693561112109891470903700041135375248695741012306373\",\"1\"],\"b\":[[\"3247989990207989646120856507929936403874972366284220250880918537588838028173\",\"20347831818628957019286012207626379731554938194907710010892594024137236752987\"],[\"18217798786390957788883983024823206348636485136705276787854998111125834676541\",\"11824109578691812603938426242725149605448845948255194504928078330266973720614\"],[\"1\",\"0\"]],\"c\":[\"16499583001208064509247079494271177710897656329498349773613236383353749984739\",\"1944718879141050229961827816471755841829876012643055740792265283564642185697\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJmYkoWHiQgbxW0M3TEPCgFA7N5htdbI1oL3zNQxIams\"}"; +pub const SUI_DATA_FROM_REACT_12: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IndNcWhEa3BxQllkSlowQVBwXzUtbVZDLUU2OCIsIm5iZiI6MTcxNTY4NjkzMywiaWF0IjoxNzE1Njg3MjMzLCJleHAiOjE3MTU2OTA4MzMsImp0aSI6IjEwNGRhZTE1ZWMwODRjODU3MzBjYTRiZGI1MThiZTkwZDdkMTQ3NmEifQ.KBzhI2UOTstRFpgkZiFFlCmhy-E0PwoWdfWhXem6Kr0HjOgCfr-a5TGVRyMf0b7-Tnf712tMPf4N7-uPSoyaBsmtiYmAudj8whha2obUVhzWjghiURrbYkiCBWys5Z4v3SnVKDqXPsUFmNucBSA3l6DIWbhLT4WqTszGY-Qc_cKhR-7y5i3t90lhGNmwrvCR72jAXaF-xbBvsaiMXxhfCS5fnMFNRibIE3tRx1r3mkx59etA8E3xQAu8LPzFyC0ecEKL0K6a5ZWNWBFPbGSzAhSK9D3ak1gzON6rhccCPpLRErk2MIhUQq4HBnOywg5Lf1w0onxhkJtU6docO2VVAA\",\"userPassToIntFormat\":\"11099104102117\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":173,\"1\":37,\"2\":48,\"3\":14,\"4\":54,\"5\":38,\"6\":225,\"7\":52,\"8\":254,\"9\":178,\"10\":32,\"11\":56,\"12\":162,\"13\":128,\"14\":135,\"15\":55,\"16\":10,\"17\":222,\"18\":131,\"19\":175,\"20\":166,\"21\":161,\"22\":145,\"23\":219,\"24\":44,\"25\":231,\"26\":183,\"27\":245,\"28\":141,\"29\":178,\"30\":237,\"31\":92},\"secretKey\":{\"0\":108,\"1\":38,\"2\":149,\"3\":222,\"4\":132,\"5\":184,\"6\":128,\"7\":164,\"8\":27,\"9\":101,\"10\":217,\"11\":92,\"12\":24,\"13\":245,\"14\":209,\"15\":31,\"16\":88,\"17\":174,\"18\":237,\"19\":144,\"20\":78,\"21\":127,\"22\":73,\"23\":195,\"24\":194,\"25\":229,\"26\":208,\"27\":176,\"28\":220,\"29\":60,\"30\":229,\"31\":253,\"32\":173,\"33\":37,\"34\":48,\"35\":14,\"36\":54,\"37\":38,\"38\":225,\"39\":52,\"40\":254,\"41\":178,\"42\":32,\"43\":56,\"44\":162,\"45\":128,\"46\":135,\"47\":55,\"48\":10,\"49\":222,\"50\":131,\"51\":175,\"52\":166,\"53\":161,\"54\":145,\"55\":219,\"56\":44,\"57\":231,\"58\":183,\"59\":245,\"60\":141,\"61\":178,\"62\":237,\"63\":92}}},\"zkAddr\":\"0xe5433ade6e56883e0cc13044783fc6e0d835db866e8ef69d305622f4dbfd7730\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"20315021530892971959830664693110327999639349964485536174303351139810441711270\",\"9363226245552972448215999928614529638129956136095863617353608229521342156596\",\"1\"],\"b\":[[\"13215029653817105228530429395766730210769586389024965762310641194113200165202\",\"7799676398333409903573594921069872917500921399080042730183754684502821618481\"],[\"13048821293399627652827197503115267831066766008561767009809325017447715880491\",\"331361016081752781071859245948286166830568341165278760117629920699739892753\"],[\"1\",\"0\"]],\"c\":[\"7347702391542317289078324477957712035210582056186479239076715504548941012834\",\"795883936884678581860170407596096541519605830081875833581950897247827301651\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AK0lMA42JuE0/rIgOKKAhzcK3oOvpqGR2yznt/WNsu1c\"}"; +pub const SUI_DATA_FROM_REACT_13: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjVqNVBySXFpYW9xaUNFWkR0eklNazY2MUotRSIsIm5iZiI6MTcxNTY4NjkyNCwiaWF0IjoxNzE1Njg3MjI0LCJleHAiOjE3MTU2OTA4MjQsImp0aSI6IjJmYzk0MmM1MDBiMmJmNGE5YzZiZjUwN2Y0MjU4NTg3MGM4YmQ5N2QifQ.GU70HImKkqZyGmWAC_onzc-ccUhALeT7ebQ0LrE0QGqjCZyCnonjOeDhatB4Q1GQCVQ-KPWKCdg4NNPCPvKwLYAjwNF0sorwS5h6jKKVvRgT_t12dbDzrPKJE7xW0_0kfmfj7lKGZp_W4HNVxd_hlPiwJb56X0ZVkt3pwpkwBe8MU-Nzb3QyrJtDRJDDb4v_bVdOJSyUNEtssFvAgFB4diGI_GFQzZpbQnBeciST-lS7rGHpItnlwe0mRNf3e34S7A7wUOo_YTvy-TKTViSekMdkMKt9hgGkti9c4dYwI8NMExe4wtnLFVOh6XZ0FtrdnVGrYZFMWTJjNGizUmFMZQ\",\"userPassToIntFormat\":\"525451555057114102\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":221,\"1\":11,\"2\":223,\"3\":171,\"4\":2,\"5\":140,\"6\":112,\"7\":100,\"8\":233,\"9\":182,\"10\":68,\"11\":219,\"12\":126,\"13\":215,\"14\":96,\"15\":164,\"16\":201,\"17\":227,\"18\":132,\"19\":169,\"20\":157,\"21\":120,\"22\":187,\"23\":16,\"24\":40,\"25\":208,\"26\":174,\"27\":209,\"28\":89,\"29\":163,\"30\":255,\"31\":62},\"secretKey\":{\"0\":5,\"1\":6,\"2\":91,\"3\":164,\"4\":51,\"5\":203,\"6\":161,\"7\":246,\"8\":61,\"9\":156,\"10\":92,\"11\":96,\"12\":69,\"13\":141,\"14\":93,\"15\":73,\"16\":208,\"17\":85,\"18\":37,\"19\":52,\"20\":167,\"21\":121,\"22\":63,\"23\":221,\"24\":215,\"25\":165,\"26\":48,\"27\":232,\"28\":136,\"29\":10,\"30\":71,\"31\":92,\"32\":221,\"33\":11,\"34\":223,\"35\":171,\"36\":2,\"37\":140,\"38\":112,\"39\":100,\"40\":233,\"41\":182,\"42\":68,\"43\":219,\"44\":126,\"45\":215,\"46\":96,\"47\":164,\"48\":201,\"49\":227,\"50\":132,\"51\":169,\"52\":157,\"53\":120,\"54\":187,\"55\":16,\"56\":40,\"57\":208,\"58\":174,\"59\":209,\"60\":89,\"61\":163,\"62\":255,\"63\":62}}},\"zkAddr\":\"0x0934ba96e39b32a66b83afdd089d9534b91336d0c72324acb72b718e2d8adcd8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"3292113297742390468701372446942400025026948502434627571571387058022780524172\",\"4608365882159831859997420943605862565647863626478617897572911626264555729258\",\"1\"],\"b\":[[\"5662407938030293510048180382159430467791189346676904212329490391470516566946\",\"14655907382794614210872210515582570998106075620115645016125280695488094003217\"],[\"3337061425406207163991320131711738442766654603337106758166291266688030689117\",\"4469383376673348053098454774700074508703514397281065469277327859575940584146\"],[\"1\",\"0\"]],\"c\":[\"6592007510647447256322156763481821378802835999285873915184749854236303252416\",\"16208563039085392733361585085996378606127672981771155339865393880548209917912\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AN0L36sCjHBk6bZE237XYKTJ44SpnXi7ECjQrtFZo/8+\"}"; +pub const SUI_DATA_FROM_REACT_14: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjN6eHc2SUFERzVXcjJDR244SGczS1Q3Nm1qOCIsIm5iZiI6MTcxNTY4NjkwNSwiaWF0IjoxNzE1Njg3MjA1LCJleHAiOjE3MTU2OTA4MDUsImp0aSI6IjNkOTM4NmFlODMxZDVhYjdiZTI1NjcxMDhmZjhkMTM1N2YzNDZjOTUifQ.R3s_OfTiDlMMSFsEfp4xM6rLoJ99GALalEE1TVG8aneruEWuI1qxz241YmX9r9-49t1ja5BfO0eh3Fu_p6lg1O32sNSLR626Mvrv1Ph60syPQN01Tam4RCV_YBK3b2Pj-rWeJq3WSCGQg2rab2QyHy3Al9VPdXlkbaaH69QzRSXFyNojixgo92cPhABxbAxI1a5pYmzwwfkDDO0FY5uRUt3w4wuBhx9gQ6g_kboF03pIzQ5kvGUYBPGax66faTzulAGdTADmU9xgG6denQoZWn3Lh6dfdQX8KXkn9jVY8gMIY_rbobc8nkIMmslsjjio7BXb90-YD_WJT5so5Cre3A\",\"userPassToIntFormat\":\"1031021041155552\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":97,\"1\":100,\"2\":35,\"3\":169,\"4\":212,\"5\":9,\"6\":238,\"7\":108,\"8\":186,\"9\":80,\"10\":106,\"11\":26,\"12\":209,\"13\":87,\"14\":84,\"15\":117,\"16\":235,\"17\":25,\"18\":81,\"19\":248,\"20\":137,\"21\":197,\"22\":146,\"23\":139,\"24\":214,\"25\":127,\"26\":143,\"27\":179,\"28\":137,\"29\":79,\"30\":181,\"31\":216},\"secretKey\":{\"0\":70,\"1\":76,\"2\":130,\"3\":97,\"4\":75,\"5\":0,\"6\":7,\"7\":122,\"8\":166,\"9\":56,\"10\":85,\"11\":179,\"12\":143,\"13\":55,\"14\":136,\"15\":47,\"16\":75,\"17\":211,\"18\":125,\"19\":145,\"20\":130,\"21\":206,\"22\":118,\"23\":212,\"24\":87,\"25\":200,\"26\":130,\"27\":38,\"28\":65,\"29\":93,\"30\":37,\"31\":44,\"32\":97,\"33\":100,\"34\":35,\"35\":169,\"36\":212,\"37\":9,\"38\":238,\"39\":108,\"40\":186,\"41\":80,\"42\":106,\"43\":26,\"44\":209,\"45\":87,\"46\":84,\"47\":117,\"48\":235,\"49\":25,\"50\":81,\"51\":248,\"52\":137,\"53\":197,\"54\":146,\"55\":139,\"56\":214,\"57\":127,\"58\":143,\"59\":179,\"60\":137,\"61\":79,\"62\":181,\"63\":216}}},\"zkAddr\":\"0x87b9236aadcbc8de1a2bce17bb104cbae2f8c955f89808ee2d258cf2bc1cce1f\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"18415333747085688267133796133445868671450647215619171648016630248725573444572\",\"13021999644739913954648136527237689315935942107782566659768353668730521796833\",\"1\"],\"b\":[[\"10379715945772584677584721710592153467187645980157575584584703890180885281296\",\"21114541349211062821701871386552875726196087055162878583823021987759476907947\"],[\"21741245524391086016724288544952241247835975701957615054057894483829435111137\",\"19675246006347690391662817422022652459552259504790883596539945355325572896761\"],[\"1\",\"0\"]],\"c\":[\"6388980351498388564470364481867721519510272532387680761911853865824806443040\",\"2927953057998420964296253396822428516251336255094433794401337892358172944522\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AGFkI6nUCe5sulBqGtFXVHXrGVH4icWSi9Z/j7OJT7XY\"}"; +pub const SUI_DATA_FROM_REACT_15: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjRtbk1TajFjTmdlSUU4Unk3Z2dBOWNRVWRLSSIsIm5iZiI6MTcxNTY4Njg3MywiaWF0IjoxNzE1Njg3MTczLCJleHAiOjE3MTU2OTA3NzMsImp0aSI6ImVmYzU3YjVmMGEzZmEwZGI2ZTQzNWFhZjI4OTEwNjY2YjM0NWViNmEifQ.YRFPl_szPP8iBid__ACAj4Etr4YDZEmeawFTas_MFw7rR_sD_tQ268F2g9O4VOU3VWSWT-LCG1gp_NdRVvb5SFBzuMIYp4YrUEvzJdaO_ab1a2Xp_EVVEmjMwNHVpnFZjS9El0e0oOmaw_PQgC2soauJkfLvRhayx-_Vps7htHm94PW1aHBOxwr2HpR58mjzT4JyutyiioCLgLqhnvGW4N6CBlx6iLNfITk0wwsAOHRcdjW_hk0hHarjMy3U2VdbcPkmq1OIg8ZDQo2jbUGEWevUC6zrGeNWYjp38f3Wo1NUqf7_ne0YeJEBtyK5r9BuDxdr6YRyUXKnpxJpr9cZ-Q\",\"userPassToIntFormat\":\"5256515057\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":226,\"1\":91,\"2\":63,\"3\":50,\"4\":152,\"5\":120,\"6\":233,\"7\":249,\"8\":177,\"9\":205,\"10\":1,\"11\":233,\"12\":153,\"13\":199,\"14\":101,\"15\":124,\"16\":112,\"17\":15,\"18\":160,\"19\":228,\"20\":124,\"21\":169,\"22\":57,\"23\":196,\"24\":118,\"25\":117,\"26\":94,\"27\":132,\"28\":228,\"29\":108,\"30\":145,\"31\":117},\"secretKey\":{\"0\":168,\"1\":100,\"2\":5,\"3\":144,\"4\":15,\"5\":220,\"6\":219,\"7\":42,\"8\":52,\"9\":1,\"10\":7,\"11\":203,\"12\":43,\"13\":71,\"14\":99,\"15\":90,\"16\":8,\"17\":66,\"18\":137,\"19\":155,\"20\":200,\"21\":27,\"22\":69,\"23\":112,\"24\":209,\"25\":173,\"26\":109,\"27\":93,\"28\":152,\"29\":210,\"30\":96,\"31\":194,\"32\":226,\"33\":91,\"34\":63,\"35\":50,\"36\":152,\"37\":120,\"38\":233,\"39\":249,\"40\":177,\"41\":205,\"42\":1,\"43\":233,\"44\":153,\"45\":199,\"46\":101,\"47\":124,\"48\":112,\"49\":15,\"50\":160,\"51\":228,\"52\":124,\"53\":169,\"54\":57,\"55\":196,\"56\":118,\"57\":117,\"58\":94,\"59\":132,\"60\":228,\"61\":108,\"62\":145,\"63\":117}}},\"zkAddr\":\"0xc2e01f23756fd4fc3e8ee98f96751729c911acc1b8abc4e5d8f732a0b6a69602\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"6734924940747627006546678824977458478287976951246203795880487352562116664933\",\"14763323532227801517600705873776227782564830701170466315373208681644431001874\",\"1\"],\"b\":[[\"19846719805329609703868726781640931109590522837532762309497922458996335263239\",\"15420764526732603133646176483042915906318651960194518136943858294265541434918\"],[\"3657954841783806502381750774780312041530173171470043250309926815017975476219\",\"3502207265482905042029962996793932548717468210237619905023157797841132512624\"],[\"1\",\"0\"]],\"c\":[\"1288521393482492105362792882426011805774869298603270001189992299082351112997\",\"3336108234609612516660580995781529303851605528785003185796473743343393403477\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AOJbPzKYeOn5sc0B6ZnHZXxwD6DkfKk5xHZ1XoTkbJF1\"}"; +pub const SUI_DATA_FROM_REACT_16: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImpKS0poeXJtbHE3T1UxU0NwZnlfX2F3MEZxVSIsIm5iZiI6MTcxNTY4Njg2NSwiaWF0IjoxNzE1Njg3MTY1LCJleHAiOjE3MTU2OTA3NjUsImp0aSI6Ijg4ZDVmNTg1OGMzNDIwMmY1OTAyOWE5ODM4YzhhOWMzYWVlMDZjNDMifQ.cjuamUo90ycOmkGffs4qe6Ozb0q-UhG6oG4pLf3a5zMgRUXr_PcKNj9GcHujqYzWFbVsiuYdoVwMmPsHeKmLnkuIDS4mwT0z-LhWvYrXdx2FksXyv0ECIBJNGHWNtf6JyhA_3XGYSqzn4sQncKxHK82aFAJZYaPfXCgKJJK0c9PFjONxY2nQoDV-IM89vm6x9vpNPjYxMxxE60p_5qceLLU9pgy4jgP2Eyco0sGfCFTry7zVqgYsMSinh_UIWk4naihDtgrZxAdNkoAA-4PQkWxrlTO8b68YQp8K4ncerUwmOJDs-0NUxDm8mTjwq47Qgf_UAcTxVN9_YpIqEoxdwQ\",\"userPassToIntFormat\":\"100102104119101105101121102\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":109,\"1\":20,\"2\":190,\"3\":101,\"4\":236,\"5\":16,\"6\":171,\"7\":49,\"8\":222,\"9\":170,\"10\":22,\"11\":241,\"12\":224,\"13\":116,\"14\":18,\"15\":124,\"16\":48,\"17\":1,\"18\":20,\"19\":126,\"20\":94,\"21\":16,\"22\":164,\"23\":173,\"24\":180,\"25\":226,\"26\":71,\"27\":184,\"28\":218,\"29\":162,\"30\":145,\"31\":87},\"secretKey\":{\"0\":131,\"1\":117,\"2\":15,\"3\":104,\"4\":243,\"5\":100,\"6\":1,\"7\":157,\"8\":31,\"9\":54,\"10\":163,\"11\":215,\"12\":45,\"13\":202,\"14\":70,\"15\":51,\"16\":77,\"17\":200,\"18\":206,\"19\":59,\"20\":210,\"21\":59,\"22\":129,\"23\":250,\"24\":53,\"25\":166,\"26\":201,\"27\":57,\"28\":9,\"29\":13,\"30\":255,\"31\":18,\"32\":109,\"33\":20,\"34\":190,\"35\":101,\"36\":236,\"37\":16,\"38\":171,\"39\":49,\"40\":222,\"41\":170,\"42\":22,\"43\":241,\"44\":224,\"45\":116,\"46\":18,\"47\":124,\"48\":48,\"49\":1,\"50\":20,\"51\":126,\"52\":94,\"53\":16,\"54\":164,\"55\":173,\"56\":180,\"57\":226,\"58\":71,\"59\":184,\"60\":218,\"61\":162,\"62\":145,\"63\":87}}},\"zkAddr\":\"0x3a26feb6fa552d6e2796e37cfcfaa19ff8d09b9b3e30060557f313ec82e7809a\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"17553248964460513660899064860794334313854327380740726458707730696116622715951\",\"19780935404993030841853448182973442738138094386982905919654095638585438825727\",\"1\"],\"b\":[[\"21560192083940754229490187081097411180154947135453319375957763951829010741758\",\"19864576266509862087012277908356289924851686435133221538927641836878678315039\"],[\"5332198541444016097635381835036279771892300735490162251066050727152100828695\",\"4562785582599067136108384927870755899035073041220030123445496806313655366742\"],[\"1\",\"0\"]],\"c\":[\"17180793399699270264610473764500109290307106335241771936808740744446379111802\",\"19531923144281240440166451089649574065952850605237982747209921274042428958350\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AG0UvmXsEKsx3qoW8eB0EnwwARR+XhCkrbTiR7jaopFX\"}"; +pub const SUI_DATA_FROM_REACT_17: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxPYUk4MkJHS1lSWXVETVRMVXU4Z0ktV3ZsayIsIm5iZiI6MTcxNTY4Njg1NywiaWF0IjoxNzE1Njg3MTU3LCJleHAiOjE3MTU2OTA3NTcsImp0aSI6ImMyOGE2MTEwYzMwYmQ0ZDkzMmEwOTNlOWVmZjllNzEyZjUzYWI2MjQifQ.fHYn7sAFbOtPneSX_YBA52ASidwosnl42uWF7RmroUU132sPO3Jmzf7tqZrqQFu04Y1G2LeGvTeHklUowVdWdKQkomV9bCeputcMRkDPD9-5-UJdpDY8eIAzfHzWN9nWyu5St0Iz0S0FIth6cesMmPUkCrq6pCUyHLWgrxUoICuYIbbtEO5ZVnF8lIeMjUTLXT4_9svFBRhugkD0nvHnQnWS8H0ijS53lCs8z7xVy0cm_MawsCMpApMQvWm-4CeIq69p3m2HXclXNmwSxg7oeGDKn-yqhPaXX3Pn4PfHKPj-XHXOR2rr9uG2lYi73yOyDve84wCXzV9kmiUnc0YGUQ\",\"userPassToIntFormat\":\"515253575654\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":100,\"1\":216,\"2\":222,\"3\":171,\"4\":27,\"5\":27,\"6\":171,\"7\":132,\"8\":172,\"9\":13,\"10\":174,\"11\":188,\"12\":196,\"13\":208,\"14\":35,\"15\":125,\"16\":10,\"17\":214,\"18\":5,\"19\":29,\"20\":118,\"21\":41,\"22\":114,\"23\":70,\"24\":166,\"25\":37,\"26\":189,\"27\":136,\"28\":37,\"29\":106,\"30\":245,\"31\":15},\"secretKey\":{\"0\":75,\"1\":60,\"2\":159,\"3\":196,\"4\":243,\"5\":180,\"6\":224,\"7\":198,\"8\":228,\"9\":147,\"10\":22,\"11\":104,\"12\":69,\"13\":182,\"14\":80,\"15\":232,\"16\":127,\"17\":195,\"18\":43,\"19\":2,\"20\":99,\"21\":206,\"22\":161,\"23\":47,\"24\":106,\"25\":44,\"26\":131,\"27\":5,\"28\":133,\"29\":110,\"30\":82,\"31\":140,\"32\":100,\"33\":216,\"34\":222,\"35\":171,\"36\":27,\"37\":27,\"38\":171,\"39\":132,\"40\":172,\"41\":13,\"42\":174,\"43\":188,\"44\":196,\"45\":208,\"46\":35,\"47\":125,\"48\":10,\"49\":214,\"50\":5,\"51\":29,\"52\":118,\"53\":41,\"54\":114,\"55\":70,\"56\":166,\"57\":37,\"58\":189,\"59\":136,\"60\":37,\"61\":106,\"62\":245,\"63\":15}}},\"zkAddr\":\"0x89045412e3f5c808e7bf0ea6d47008a6c75f14b48a7fea54f420b03d3298ef4e\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"257137064185145448465242836924275827726618300508610920187643303682623341809\",\"13136104385342155450873138185971548464179081219858145555616259274682267182602\",\"1\"],\"b\":[[\"9623367967771069752036280248035047299371597257306258748768218269896381701321\",\"12210765432002064938981141260402135327544184192147240766501813387730760651726\"],[\"15251118264052002493837427778759923199895437430037469672801786148252966111936\",\"12243121821747384937988506024826071890328897029202152518609157933400978560340\"],[\"1\",\"0\"]],\"c\":[\"4201350126073080124441494110984461007902792066210632786985402248838880518314\",\"10425614983366289743736253875955608779721351186796918402238008669517994775682\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AGTY3qsbG6uErA2uvMTQI30K1gUddilyRqYlvYglavUP\"}"; +pub const SUI_DATA_FROM_REACT_18: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlhhakktZ0NqbFVVY3ZBTFdmcDlyTURCelBzVSIsIm5iZiI6MTcxNTY4Njg0OSwiaWF0IjoxNzE1Njg3MTQ5LCJleHAiOjE3MTU2OTA3NDksImp0aSI6IjZmYmI3NmEzN2NjOTAwYTQ5NThlYmNlZmNmYmVhNjMzMzkyMzM2OTUifQ.RqLBHMZMuXbsZGW5YGDNbfTSGG5Ezv_XtJRvMbBIXytAqGoT70RrfZSwU3e8yXaq-o4RBoeypQIygj_Sjxq0JJXVRuypVqkbismASkWKWH77avFgRUe0Etvc8EFXupmwj1biRpURUukroVUyjktOI17m3DvFIIan7_rq3SQBNxLyjFZav517zaJaUVXdYMDAYIEVs1Es04G2kWTxBYQ6iu0jyHtuNcg9_kosGQEZjnp2HsnvegrRwloyjuFByMRv90bRuV6cc3f-3GPO23tcrhFzeoOQXUfcSdlqE3C92gb6E_3uBld414mNj2LelnagKtpvPjTCgX3tic2c7fB_CQ\",\"userPassToIntFormat\":\"989911510011710554\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":81,\"1\":243,\"2\":172,\"3\":238,\"4\":183,\"5\":132,\"6\":17,\"7\":7,\"8\":200,\"9\":125,\"10\":73,\"11\":248,\"12\":71,\"13\":220,\"14\":159,\"15\":138,\"16\":16,\"17\":207,\"18\":25,\"19\":103,\"20\":70,\"21\":23,\"22\":193,\"23\":72,\"24\":27,\"25\":94,\"26\":241,\"27\":155,\"28\":98,\"29\":155,\"30\":212,\"31\":118},\"secretKey\":{\"0\":89,\"1\":13,\"2\":132,\"3\":115,\"4\":95,\"5\":59,\"6\":196,\"7\":68,\"8\":136,\"9\":46,\"10\":22,\"11\":70,\"12\":5,\"13\":188,\"14\":76,\"15\":116,\"16\":156,\"17\":15,\"18\":226,\"19\":232,\"20\":167,\"21\":204,\"22\":143,\"23\":148,\"24\":230,\"25\":69,\"26\":18,\"27\":166,\"28\":234,\"29\":47,\"30\":178,\"31\":31,\"32\":81,\"33\":243,\"34\":172,\"35\":238,\"36\":183,\"37\":132,\"38\":17,\"39\":7,\"40\":200,\"41\":125,\"42\":73,\"43\":248,\"44\":71,\"45\":220,\"46\":159,\"47\":138,\"48\":16,\"49\":207,\"50\":25,\"51\":103,\"52\":70,\"53\":23,\"54\":193,\"55\":72,\"56\":27,\"57\":94,\"58\":241,\"59\":155,\"60\":98,\"61\":155,\"62\":212,\"63\":118}}},\"zkAddr\":\"0xa41d812b2137a9e701512dd1e77643b94c3eff566c5be50365d174d1db60a415\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"17614076016833085587577424708926810169376585820815427961767207039192652769013\",\"14135032500684844024372302628625185135058981148802759791768119531914068811069\",\"1\"],\"b\":[[\"12223738407851653989769057205672802523120105196291312843502064346721414495287\",\"633499823246797838323329834422571844397737716575556571535890211670105511423\"],[\"6003190178099558462113377195569012506764289704920013648574803015959961275195\",\"2773541228770509456407096233964565540804779880988894871588471857181885931620\"],[\"1\",\"0\"]],\"c\":[\"1069242590881057236271046634996302431045048055413724998035360474439616694142\",\"4170832142623397447640837445675045579300900045561776497865454715900704844006\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AFHzrO63hBEHyH1J+Efcn4oQzxlnRhfBSBte8Ztim9R2\"}"; +pub const SUI_DATA_FROM_REACT_19: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxyN2JvekNHNUw4UHlLVVNPRzNwMDZYYVM1USIsIm5iZiI6MTcxNTY4Njg0MSwiaWF0IjoxNzE1Njg3MTQxLCJleHAiOjE3MTU2OTA3NDEsImp0aSI6Ijc2MzdiMGMyM2ZiMWIwZTFjMGEyYWE3NWVkOGMxNjA1YzE1YWFiZjAifQ.uNMFOgl9xdG5wljwZrIDzWm3SS_F9OLhR9avDGRhHSxYNSzexcOHtGT7HY9zsWloN9LWFZxu2t3yG-jWduo5qYgyM-OXpdAXLzfXZwQSNxgtXl2yisxeBU18_7lPpmjMzTMUPCXtJxrB75VYoZAybkyGnFmC_tPD13MIShT04iUGkNLFPpaof4BGxnmCE4hNob-tVijFTH_EIdNXg0fr-rQ-qxd3vw7NVDIF0yDNxCeSYMz0GKuGPlvXk3SPtUzfUfZaJFau3QpfcrXhkNrUS0fW3HcXRLMhiVqNIJ5Y5wYJdq5IvEe_lElrv4NS4apswDNVI1s7B_iMDvcjFASD9Q\",\"userPassToIntFormat\":\"5255515057565453\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":223,\"1\":83,\"2\":48,\"3\":161,\"4\":204,\"5\":195,\"6\":149,\"7\":141,\"8\":132,\"9\":65,\"10\":55,\"11\":201,\"12\":245,\"13\":60,\"14\":139,\"15\":236,\"16\":39,\"17\":130,\"18\":130,\"19\":162,\"20\":215,\"21\":104,\"22\":235,\"23\":117,\"24\":152,\"25\":71,\"26\":252,\"27\":46,\"28\":73,\"29\":54,\"30\":170,\"31\":251},\"secretKey\":{\"0\":90,\"1\":130,\"2\":14,\"3\":79,\"4\":237,\"5\":213,\"6\":128,\"7\":240,\"8\":11,\"9\":61,\"10\":50,\"11\":225,\"12\":67,\"13\":212,\"14\":26,\"15\":215,\"16\":84,\"17\":207,\"18\":4,\"19\":3,\"20\":95,\"21\":124,\"22\":35,\"23\":123,\"24\":72,\"25\":189,\"26\":115,\"27\":153,\"28\":16,\"29\":105,\"30\":73,\"31\":216,\"32\":223,\"33\":83,\"34\":48,\"35\":161,\"36\":204,\"37\":195,\"38\":149,\"39\":141,\"40\":132,\"41\":65,\"42\":55,\"43\":201,\"44\":245,\"45\":60,\"46\":139,\"47\":236,\"48\":39,\"49\":130,\"50\":130,\"51\":162,\"52\":215,\"53\":104,\"54\":235,\"55\":117,\"56\":152,\"57\":71,\"58\":252,\"59\":46,\"60\":73,\"61\":54,\"62\":170,\"63\":251}}},\"zkAddr\":\"0x37c4424a1b9970b94dd7276aecae5b9d1c035c7e3c88f4f1155aa0e5127ef6e4\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"7945493796354284921600453177054285773255312631482061079984629835363646515586\",\"2166517138136751277833084326208436279446476764263036612847849710284540628729\",\"1\"],\"b\":[[\"14768147580014515274920059533450969526917243519129235569375547705391356814034\",\"10926704359346438742364088104571886636979515204481541507299552373423645137538\"],[\"18345707220306299341155061798987886250677895640406984732019863169577306401665\",\"13781450607771983148196301814354815025344242496715512941320154501577226245887\"],[\"1\",\"0\"]],\"c\":[\"16100487697721354409255314346417284275475569122937970611421991273969908317416\",\"20037727069966515075925458192010761910249599063237527691300280470015098486501\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AN9TMKHMw5WNhEE3yfU8i+wngoKi12jrdZhH/C5JNqr7\"}"; +pub const SUI_DATA_FROM_REACT_20: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJlMTgtZlBDdV9ZRndybE43TDhKV1BHX3hFbyIsIm5iZiI6MTcxNTY4NjgzMSwiaWF0IjoxNzE1Njg3MTMxLCJleHAiOjE3MTU2OTA3MzEsImp0aSI6IjdmZTFkZTM5NDVkMjliYTBhOWQ4MGFlODZiZGRmNjkyMDE1N2RlMDcifQ.RMM8wIiEzZ97DVdngkDhKapTMZq-R7woI2yjclLqTgnYZKTZ5N9y67zFJLDfcg017VyyRK18OS1OLsnUgnphi3ULotImnJ2292VDBd7kxhyq9QAqfHVDK2-MYNlJXy53UIr2xS9td1aoHUDZkvBy690IhV4nPrxLOUhI8c4gAvpkfHFmAvxYuQoUu69c_hSzREhrVOa979t5nZuJjNWwUcwgD40To1DM6Dxwy186basvY4AyWPHcI4ARFoyPEMRFUOtO05fUrwUH8O63Ay6K1DwxaLXDzx4T7O9X9nlrCj2uROdahsv-Dj24hruudSYxi4GH2uO6u0a1RlTIvWJ-1A\",\"userPassToIntFormat\":\"525451525655\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":66,\"1\":155,\"2\":237,\"3\":117,\"4\":45,\"5\":166,\"6\":245,\"7\":92,\"8\":78,\"9\":225,\"10\":218,\"11\":156,\"12\":7,\"13\":132,\"14\":164,\"15\":47,\"16\":114,\"17\":174,\"18\":4,\"19\":86,\"20\":18,\"21\":212,\"22\":182,\"23\":62,\"24\":50,\"25\":219,\"26\":104,\"27\":185,\"28\":183,\"29\":108,\"30\":38,\"31\":252},\"secretKey\":{\"0\":13,\"1\":127,\"2\":13,\"3\":29,\"4\":128,\"5\":121,\"6\":142,\"7\":51,\"8\":210,\"9\":28,\"10\":131,\"11\":160,\"12\":209,\"13\":42,\"14\":214,\"15\":198,\"16\":137,\"17\":147,\"18\":155,\"19\":40,\"20\":86,\"21\":167,\"22\":168,\"23\":10,\"24\":249,\"25\":180,\"26\":188,\"27\":132,\"28\":41,\"29\":146,\"30\":192,\"31\":28,\"32\":66,\"33\":155,\"34\":237,\"35\":117,\"36\":45,\"37\":166,\"38\":245,\"39\":92,\"40\":78,\"41\":225,\"42\":218,\"43\":156,\"44\":7,\"45\":132,\"46\":164,\"47\":47,\"48\":114,\"49\":174,\"50\":4,\"51\":86,\"52\":18,\"53\":212,\"54\":182,\"55\":62,\"56\":50,\"57\":219,\"58\":104,\"59\":185,\"60\":183,\"61\":108,\"62\":38,\"63\":252}}},\"zkAddr\":\"0x86ab13e3c90b7f5b52a0e7d045425f1a5ce4f2938d82fe32013b5c5dffc8aa40\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"13280060882937967421268531103181473070897547065707830941266439167277535861998\",\"9934433138500558951890280258062370504217382435917636186873727481367280202864\",\"1\"],\"b\":[[\"3838124130316726849360987686807592227651253623250263168834039482151640975443\",\"10050190797101422174255450354163308725608018844614813729840170282126147936409\"],[\"18360080471111693027482741715722945557865825591442098780536696036281663618095\",\"1378964582828950987975075563637558653759765511530268169302574447782691787466\"],[\"1\",\"0\"]],\"c\":[\"1373142722414479432483215105546507593017308819682036641663292686387425172376\",\"3353210342014729825799146687716012229927760750084040417279416030868174996451\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AEKb7XUtpvVcTuHanAeEpC9yrgRWEtS2PjLbaLm3bCb8\"}"; +pub const SUI_DATA_FROM_REACT_21: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Im12NUNKY1dsMXE1ek03Y0lyR1ZUdHF6SnFTNCIsIm5iZiI6MTcxNTY4NjgxOSwiaWF0IjoxNzE1Njg3MTE5LCJleHAiOjE3MTU2OTA3MTksImp0aSI6IjYxMDM2YmQwZWE3YjI5MDY4MjgwODYxMzMyODZhODZlNmY0ZmMwNGEifQ.VE2a8s2ZuyTVklFwSvh05y_mGrDMJXww-5Pu3-UUIQi3sBQnMzpnvWo3MIb32rXxwU6Obtx9izsR-Csk-U0QH4WuseGHnhHA90lACdeXNXHUWNktsY62_z2lkseTlJQV_ccNVctNgqornxmtV6gRvihLKkYCJt08umhAcRe8-Fh9iNmlCf5sMngaA-k0bvIbdnxkoP0KI9em7sgpTDB0FJFCgVAVYkzQTuJJlfuKjeF0lgpLnkjTOtgMyCpuZrrxf9GH6wY2VSme3Zk6xVJfl5cC6YugQFs-t56CEhPDrm-LIlLTD9JuNAKctlRRaTmkTembZAzweu6Wqh322MDx1g\",\"userPassToIntFormat\":\"100102100102100115106107\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":227,\"1\":142,\"2\":234,\"3\":83,\"4\":36,\"5\":125,\"6\":219,\"7\":233,\"8\":159,\"9\":30,\"10\":60,\"11\":195,\"12\":110,\"13\":130,\"14\":105,\"15\":107,\"16\":44,\"17\":46,\"18\":151,\"19\":154,\"20\":116,\"21\":131,\"22\":237,\"23\":231,\"24\":159,\"25\":119,\"26\":35,\"27\":130,\"28\":56,\"29\":90,\"30\":121,\"31\":26},\"secretKey\":{\"0\":34,\"1\":107,\"2\":197,\"3\":227,\"4\":209,\"5\":156,\"6\":36,\"7\":233,\"8\":231,\"9\":171,\"10\":100,\"11\":210,\"12\":113,\"13\":247,\"14\":59,\"15\":222,\"16\":214,\"17\":129,\"18\":238,\"19\":254,\"20\":13,\"21\":13,\"22\":3,\"23\":151,\"24\":9,\"25\":173,\"26\":77,\"27\":113,\"28\":126,\"29\":7,\"30\":203,\"31\":52,\"32\":227,\"33\":142,\"34\":234,\"35\":83,\"36\":36,\"37\":125,\"38\":219,\"39\":233,\"40\":159,\"41\":30,\"42\":60,\"43\":195,\"44\":110,\"45\":130,\"46\":105,\"47\":107,\"48\":44,\"49\":46,\"50\":151,\"51\":154,\"52\":116,\"53\":131,\"54\":237,\"55\":231,\"56\":159,\"57\":119,\"58\":35,\"59\":130,\"60\":56,\"61\":90,\"62\":121,\"63\":26}}},\"zkAddr\":\"0xb092062dc38ee15b239fedd8955547cae553068e350add6a186a900308ca1704\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"19083893384522082364200015848081882762611466511855277173108395395690822433582\",\"15765871630522826744343212165387977339454134778029147662517994756792436892191\",\"1\"],\"b\":[[\"3347275249816013439391836622904014049361323482158752310150932588414843416768\",\"9261935324040115069949005166058871304117632278716385673922763868694265924905\"],[\"10774327302040930015542399179222458502634829694095804484749135988841930351850\",\"409015645239595129631982791901837203813000443262394810220799589635024410401\"],[\"1\",\"0\"]],\"c\":[\"805618312212200473153836203801534856685701602304097276485035246177305246575\",\"12984127923817330198936709848850019846193356630613954592225359007088568774616\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AOOO6lMkfdvpnx48w26CaWssLpeadIPt5593I4I4Wnka\"}"; + +pub const VALUE_PORTION_SIZE: usize = 126; + +pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"userPassToIntFormat\":\"9910010710611510499100106115107\",\"zkAddr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secretKey\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extendedEphemeralPublicKey\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; +#[derive(Debug, Deserialize)] +pub struct JwtData { + jwt: String, + userPassToIntFormat: String, + ephemeralKeyPair: EphemeralKeyPair, + zkAddr: String, + zkProofs: ZkProofs, + extendedEphemeralPublicKey: String, +} + +#[derive(Debug, Deserialize)] +pub struct EphemeralKeyPair { + keypair: Keypair +} + +#[derive(Debug, Deserialize)] +pub struct Keypair { + publicKey: HashMap,//HashMap, // publicKey: Vec, + secretKey: HashMap // secretKey: Vec // HashMap, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ZkProofs { + proofPoints: ProofPoints, + issBase64Details: IssBase64Details, + headerBase64: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ProofPoints { + a: Vec, + b: Vec>, + c: Vec +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct IssBase64Details { + value: String, + indexMod4: i32 +} + +#[derive(Debug, Deserialize)] +pub struct JwtDataDecodedPart1 { + alg: String, + kid: String, + typ: String +} + +#[derive(Debug, Deserialize)] +pub struct JwtDataDecodedPart2 { + iss: String, + azp: String, + aud: String, + sub: String, + nonce: String, + nbf: u32, + iat: u32, + exp: u32, + jti: String +} + +fn gen_keypair() -> ed25519_dalek::Keypair { + ed25519_dalek::Keypair::generate(&mut rand::thread_rng()) +} + +#[test] +fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); + + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ + \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ + \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ + [\"18769153619672444537277685186545610305405730219274884099876386487766026068190\",\ + \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ + \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ + \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + println!("proof_and_jwt: {}", proof_and_jwt); + + let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + + + println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("HERE public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("HERE public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + /** calcs poseidon **/ + + println!("====== Start Poseidon ========"); + + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + + let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + + let max_epoch_ = 142; + + let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + + println!("code : {:?}", code); + + test_case_with_refs(code.as_str(), vec![ modulus_cell.clone(), issAndHeaderBase64Details_cell, zk_seed_cell]) + .expect_stack(Stack::new() + .push(StackItem::Cell(public_inputs_cell.clone())) + ); + //.expect_success(); + + /** calcs vergrth16 **/ + + println!("====== Start VERGRTH16 ========"); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 0; //valid key id + //let verification_key_id: u32 = 1; //invalid key id + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); +} + +#[test] +fn test_poseidon_plus_vrgrth16() { + /** Common data generation **/ + + let user_pass_salt = "206703048842351542647799591018316385612"; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); + + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + println!("zk_seed: {}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + + println!("proof_and_jwt: {}", proof_and_jwt); + + let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + println!("modulus: {:?}", modulus); + + println!("modulus hex: {:?}", hex::encode(&modulus)); + + + let max_epoch = 10; + + //let max_epoch = 142; + + /** calcs poseidon **/ + + println!("====== Start Poseidon ========"); + + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + + let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + + //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + + let max_epoch_ = 142; + + let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + + + test_case_with_refs(code.as_str(), vec![ modulus_cell, issAndHeaderBase64Details_cell, zk_seed_cell]).expect_success(); + + /** calcs vergrth16 **/ + + println!("====== Start Vergrth16 ========"); + + let pp = zk_login_inputs.get_proof(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); + + let y1 = proof.a.y.0.to_bits_le(); + let y2 = proof.a.y.0.to_bits_be(); + //let y_ = -y; + + println!("proof.a: {:?}", proof.a); + + println!("proof.a.y: {:?}", proof.a.y); + + println!("proof.a.y.0: {:?}", proof.a.y.0); + + println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); + + println!("proof.a.x.0.to_string(): {:?}", proof.a.x.0.to_string()); + + println!("y1: {:?}", y1); + for i in 0..y1.len(){ + print!("{}", y1[i] as i32); + } + println!(""); + println!("y2: {:?}", y2); + for i in 0..y2.len(){ + print!("{}", y2[i] as i32); + } + println!(""); + //println!("y_: {:?}", y_); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 1; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + +} + +#[test] +fn test_eval_time_vrgrth16_new() { + //todo: later n must be extracted from 3d part of jwt + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ".to_string(), + alg: "RS256".to_string(), + }; + + /* + { + "e": "AQAB", + "kty": "RSA", + "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" +} + */ + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "0e345fd7e4a97271dffa991f5a893cd16b8e0827".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let sui_data = [SUI_DATA_FROM_REACT_1_NEW]; + + for i in 0..sui_data.len() { + println!("====================== Iter@ is {i} ========================="); + // parse + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + //println!("{:?}", jwt_data); + + let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); + println!("user_pass_salt is {user_pass_salt}"); + + let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); + + let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("ephemeral secret_key is {:?}", eph_secret_key); + println!("ephemeral public_key is {:?}", eph_pubkey); + + let eph_pubkey_len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", eph_pubkey_len); + + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); + + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + + let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); + println!("time_for_vergrth16 is {time_for_vergrth16}"); + + println!("=========================================="); + } + +} + +#[test] +fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); //vec![0x00]; + // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ + \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ + \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ + [\"18769153619672444537277685186545610305405730219274884099876386487766026068190\",\ + \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ + \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ + \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 0; //valid key id + //let verification_key_id: u32 = 1; //invalid key id + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); +} + +#[test] +fn test_proof_serialization() { + + let user_pass_salt = "206703048842351542647799591018316385612"; + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + + + println!("proof_and_jwt: {}", proof_and_jwt); + + let zk_login_inputs = tvm_vm::executor::zk_stuff::zk_login::ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + println!("zk_login_inputs: {:?}", zk_login_inputs); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + + println!("proof.a: {:?}", proof.a); + + println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); +} + +#[test] +fn test_vrgrth16_fresh() { + // Initial password was 567890 + let user_pass_salt = "535455565748"; + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed {zk_seed}"); + + let iss = "https://accounts.google.com"; + + let xxx = get_zk_login_address(&Bn254FrElement::from_str(&zk_seed).unwrap(), iss).unwrap(); + let xx = hex::encode(&xxx); + println!("xxx {xx}"); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"20032491544466004395942516676927853848812757556091814296260914209848471949133\",\"2383319895045368406863089991961299436327009667970727469594098906910899823518\",\"1\"],\"b\":[[\"17524079199473031626933714849790290610990375813469214348846178898325828270802\",\"14967860363718375858883445892553389848174133418448836833724123534259346456965\"],[\"8012103671455598651673212917030479015077366694912593401917441922282850889728\",\"9619406946838713340504188077859322423191842838375117333667670119492063405148\"],[\"1\",\"0\"]],\"c\":[\"1155327534990006564455106296492790109069125857506281397147103620914309288350\",\"11642927414888703901346255147864200862372140915112720472429308471936285279899\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\"}"; + + println!("proof_and_jwt: {}", proof_and_jwt); + + let issAndHeaderBase64Details = "\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; + println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "pi22xDdK2fz5gclIbDIGghLDYiRO56eW2GUcboeVlhbAuhuT5mlEYIevkxdPOg5n6qICePZiQSxkwcYMIZyLkZhSJ2d2M6Szx2gDtnAmee6o_tWdroKu0DjqwG8pZU693oLaIjLku3IK20lTs6-2TeH-pUYMjEqiFMhn-hb7wnvH_FuPTjgz9i0rEdw_Hf3Wk6CMypaUHi31y6twrMWq1jEbdQNl50EwH-RQmQ9bs3Wm9V9t-2-_Jzg3AT0Ny4zEDU7WXgN2DevM8_FVje4IgztNy29XUkeUctHsr-431_Iu23JIy6U4Kxn36X3RlVUKEkOMpkDD3kd81JPW4Ger_w".parse().unwrap(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "b2620d5e7f132b52afe8875cdf3776c064249d04".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + println!("modulus: {:?}", modulus); + + println!("modulus hex: {:?}", hex::encode(&modulus)); + + + let max_epoch = 142; + + //let max_epoch = 10; + + let mut eph_pubkey = vec![131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63]; + + println!("eph_pubkey : {:?}", eph_pubkey); + println!("eph_pubkey len : {:?}", eph_pubkey.len()); + + let pp = zk_login_inputs.get_proof(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 0; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); +} + +#[test] +fn test_poseidon_update() { + /** Common data generation **/ + let user_pass_salt = "206703048842351542647799591018316385612"; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); + + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + println!("zk_seed: {}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + + println!("proof_and_jwt: {}", proof_and_jwt); + + let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + println!("modulus: {:?}", modulus); + + println!("modulus hex: {:?}", hex::encode(&modulus)); + + println!("====== Start Poseidon ========"); + + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + + let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + + //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + + let max_epoch = "142"; //"200142"; + + let mut code = format!("PUSHINT {max_epoch} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + + println!("code : {code}"); + + test_case_with_refs(code.as_str(), vec![ modulus_cell, issAndHeaderBase64Details_cell, zk_seed_cell]).expect_success(); +} + + +#[test] +fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { + println!("===================================== START VRGRTH16 TEST ====================================="); + + let user_pass_salt = "206703048842351542647799591018316385612"; + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 10; + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 1; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + + + println!("===================================== START CHKSIGNS TEST ====================================="); + + let pair = gen_keypair(); + + let binding = proof_cell.clone(); + let first = binding.data(); + + + /*let mut b = BuilderData::with_raw(first, len).unwrap();*/ + let binding = public_inputs_cell.clone(); + let second = binding.data(); + //b.append_raw(second, len); + + let concatenated = [&first[..], &second[..]].concat(); + println!("len concatenated = {}", concatenated.len()); + + + //test cell with data and one not empty reference + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + //b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); + //let cell_hash = test_cell.repr_hash(); + //sign hash of data cell + let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); + + //put signature to separate slice + let len = signature.len() * 8; + let signature = SliceData::from_raw(signature, len); + + //put public key to integer + let pub_key = BuilderData::with_raw( + pair.public.to_bytes().to_vec(), + ed25519_dalek::PUBLIC_KEY_LENGTH * 8 + ).unwrap(); + + //put hash to integer + //let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), 256).unwrap(); + + test_case_with_refs(" + PUSHREFSLICE + PUSHREFSLICE + PUSHREFSLICE + PLDU 256 + CHKSIGNS + ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) + .expect_stack(Stack::new().push(int!(-1))); +} + + +#[test] +fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); //vec![0x00]; // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ + \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ + \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ + [\"18769153619672444537277685186545610305405730219274884099876386487766026068190\",\ + \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ + \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ + \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 0; + + //let verification_key_id: u32 = 1; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); +} + + + +fn secretKeyFromIntegerMap(keyData: HashMap)->Vec{ + let mut vec: Vec = Vec::new(); + for i in 0..=31 { + if let Some(value) = keyData.get(&i.to_string()) { + vec.push(value.clone()); + } + } + return vec; +} + +fn to_binary_string(value: &str) -> String { + let big_value = BigUint::parse_bytes(value.as_bytes(), 10).unwrap(); + big_value.to_str_radix(2) +} + +fn pad_string_to_256(input: &str) -> String { + let current_length = input.len(); + + if current_length >= 256 { + return input.to_string(); + } + + let zeros_to_add = 256 - current_length; + format!("{}{}", repeat('0').take(zeros_to_add).collect::(), input) +} + +fn bits_to_decimal_and_reverse(bits: &str) -> Vec { + let byte_chunks: Vec<&str> = bits.as_bytes().chunks(8).map(|chunk| { + std::str::from_utf8(chunk).unwrap() + }).collect(); + + let decimal_numbers: Vec = byte_chunks.iter() + .map(|byte| u8::from_str_radix(byte, 2).unwrap()) + .collect(); + + decimal_numbers.into_iter().rev().collect() +} + +fn prepare_hex_representation(init_x: &str, y: BigUint) -> String { + let mut binary_representation = pad_string_to_256(&to_binary_string(init_x)); + + let P: BigUint = BigUint::from_bytes_be(&[ + 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]); + + // Сравниваем y с p - y и меняем первый бит + if y > &P - &y { + binary_representation.replace_range(0..1, "1"); + } + + let reversed_byte_array = bits_to_decimal_and_reverse(&binary_representation); + + // Преобразуем массив байтов в hex-строку + let hex_string = reversed_byte_array.iter() + .map(|byte| format!("{:02x}", byte)) + .collect::(); + + hex_string +} + +#[test] +fn test_proof_stuff() { + let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 + , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 + , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + + for i in 0..sui_data.len() { + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + let json_string = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + print!("{:?}, \n", json_string); + } + + for i in 0..sui_data.len() { + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + + ////// + + let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); + println!("user_pass_salt is {user_pass_salt}"); + + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); + + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("----------------------------------"); + + + /////////// + + + + let json_string = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + println!("json_string ={:?}", json_string);//jwt_data.zkProofs); + + + + let data: Value = serde_json::from_str(&*json_string).unwrap(); + println!("data = {:?}", data); + + let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("a_x = {:?}", a_x); + println!("a_y = {:?}", a_y); + + let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("b0_x = {:?}", b0_x); + println!("b1_x = {:?}", b1_x); + println!("b1_y = {:?}", b1_y); + + let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("c_x = {:?}", c_x); + println!("c_y = {:?}", c_y); + + let hex_ax = prepare_hex_representation(a_x, a_y); + let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + let hex_b1x = prepare_hex_representation(b1_x, b1_y); + let hex_cx = prepare_hex_representation(c_x, c_y); + + let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + + println!("Serialized proof _ 0: {:?}", result); + + println!("Serialized proof _ 1: {:?}", hex::encode(&proof_as_bytes)); + + assert_eq!(result, hex::encode(&proof_as_bytes)); + + println!("==================="); + } + + + /* println!("Serialized proof"); + let json_string = r#"{"proofPoints":{"a":["8247215875293406890829839156897863742504615191361518281091302475904551111016","6872980335748205979379321982220498484242209225765686471076081944034292159666","1"],"b":[["21419680064642047510915171723230639588631899775315750803416713283740137406807","21566716915562037737681888858382287035712341650647439119820808127161946325890"],["17867714710686394159919998503724240212517838710399045289784307078087926404555","21812769875502013113255155836896615164559280911997219958031852239645061854221"],["1","0"]],"c":["7530826803702928198368421787278524256623871560746240215547076095911132653214","16244547936249959771862454850485726883972969173921727256151991751860694123976","1"]},"issBase64Details":{"value":"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1},"headerBase64":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"}"#; + + // Парсинг JSON-строки + let data: Value = serde_json::from_str(json_string).unwrap(); + + let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + + let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); + + let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + + let hex_ax = prepare_hex_representation(a_x, a_y); + let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + let hex_b1x = prepare_hex_representation(b1_x, b1_y); + let hex_cx = prepare_hex_representation(c_x, c_y); + + let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + + // ????? ??????????? + println!("Serialized proof: {}", result); + println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); + */ +} + +#[ignore] +#[test] +fn test_eval_time_vrgrth16() { + //todo: later n must be extracted from 3d part of jwt + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "xjWd1j8GmmWzuz732haG9HECXsSZBvxOBLph3FQhk_tplhWloI1ywx-RdopUZt1lndbOM9n99lZJkpQyNJ1sdy7JFgYLjqj-wtHdEaQlBGEQtmkW8zUjr_N3bmpsxGbPzOzlKe3qddtoxXvn9rI_RvHfJD1YY-6kayQeyPOBz_4ML1lvI_JHV-Bb1MSmSk3WaAh5PzeqleusmUT87Gqfu02cOPrY8cwugqo65D6-wzAEeVvceV8-c36TMoLU5csU05GBVplgd6Ouuw35ZsETG4si4QQJztC3KsZ4jhYM-aJ3jeFPt0r3cQooiXdZBp3JkXSpE-UUaOVPsXo7WiVmww".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "323b214ae6975a0f034ea77354dc0c25d03642dc".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + //let sui_data = [SUI_DATA_FROM_REACT_1]; + let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 + , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 + , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + + let mut sum_ratio: u128 = 0; + + for i in 0..sui_data.len() { + println!("====================== Iter@ is {i} ========================="); + // parse + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + //println!("{:?}", jwt_data); + + let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); + println!("user_pass_salt is {user_pass_salt}"); + + let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); + + let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("ephemeral secret_key is {:?}", eph_secret_key); + println!("ephemeral public_key is {:?}", eph_pubkey); + + let eph_pubkey_len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", eph_pubkey_len); + + /*let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); + + let jwt_header = splitted_jwt_strings + .get(0) + .expect("split always returns at least one element"); + + let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( + "Could not find separator in jwt string.", + )).unwrap(); + + let decoded_jwt_header = base64::decode(jwt_header).unwrap(); + let decoded_jwt_body = base64::decode(jwt_body).unwrap(); + + let converted_jwt_header = String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); + let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 conversion failed"); + + let parsed_jwt_header = serde_json::from_str::(&converted_jwt_header).unwrap(); + let parsed_jwt_body = serde_json::from_str::(&converted_jwt_body).unwrap(); + + println!( + "{}", + serde_json::to_string_pretty(&parsed_jwt_header) + .expect("to_string_pretty always works on serde_json::Value") + ); + println!( + "{}", + serde_json::to_string_pretty(&parsed_jwt_body) + .expect("to_string_pretty always works on serde_json::Value") + );*/ + + + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); + + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); + + + //let key = DecodingKey::from_secret(&[]); + //let mut validation = Validation::new(Algorithm::HS256); + //validation.insecure_disable_signature_validation(); + + //let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); + //let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion failed"); + //println!("jwt_string_3 is {:?}", jwt_string_3); + //JwtDataDecodedPart3 + //let jwt_data_decoded3: JwtDataDecodedPart3 = serde_json::from_str(&jwt_string_3).unwrap(); + + + //let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; + //println!("{:?}", encode(&jwt_data_1)); + //let jwt_string_3 = String::from_utf8(&jwt_data_3); + + //let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; + //let n = jwt_v_3["n"]; + + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + + let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); + let time_for_chcksgns = single_chcksgns(&eph_pubkey, &zk_login_inputs, &all_jwk); + println!("time_for_vergrth16 is {time_for_vergrth16}"); + println!("time_for_chcksgns is {time_for_chcksgns}"); + + let current_ratio = time_for_vergrth16/time_for_chcksgns; + println!("current_ratio is {current_ratio}"); + + sum_ratio = sum_ratio + current_ratio;/**/ + println!("sum_ratio is {sum_ratio}"); + println!("=========================================="); + } + let average_ratio = sum_ratio/(sui_data.len() as u128); + + println!("average ratio is {average_ratio}"); +} + +fn prepare_proof_and_public_key_cells_for_stack(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> (Cell, Cell) { + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + println!("kid = {}", kid); + println!("all_jwk = {:?}", all_jwk); + + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + (proof_cell, public_inputs_cell) +} + + + +fn single_vrgrth16(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { + let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); + + //let verification_key_id: u32 = 2; + let verification_key_id: u32 = 0; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + let start: Instant = Instant::now(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + start.elapsed().as_micros() +} + + + +fn single_chcksgns(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { + let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); + + let pair = gen_keypair(); + + let binding = proof_cell.clone(); + let first = binding.data(); + + let binding = public_inputs_cell.clone(); + let second = binding.data(); + + let concatenated = [&first[..], &second[..]].concat(); + + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); + + //put signature to separate slice + let len = signature.len() * 8; + let signature = SliceData::from_raw(signature, len); + + //put public key to integer + let pub_key = BuilderData::with_raw( + pair.public.to_bytes().to_vec(), + ed25519_dalek::PUBLIC_KEY_LENGTH * 8 + ).unwrap(); + + let start: Instant = Instant::now(); + test_case_with_refs(" + PUSHREFSLICE + PUSHREFSLICE + PUSHREFSLICE + PLDU 256 + CHKSIGNS + ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) + .expect_stack(Stack::new().push(int!(-1))); + start.elapsed().as_micros() + +} + + + + + + diff --git a/tvm_tests/src/test_zk_.rs b/tvm_tests/src/test_zk_.rs new file mode 100644 index 00000000..d026baaf --- /dev/null +++ b/tvm_tests/src/test_zk_.rs @@ -0,0 +1,139 @@ +/* +use std::collections::HashMap; +use std::slice; +use ark_std::rand::rngs::StdRng; +use ark_std::rand::SeedableRng; +use base64ct::Encoding as bEncoding; +use fastcrypto::ed25519::Ed25519KeyPair; + + +use fastcrypto::traits::KeyPair; +use rand::Rng; +//use similar::DiffableStr; +use tvm_block::{ + GlobalCapabilities, MsgAddressInt, Serializable, ACTION_CHANGE_LIB, ACTION_COPYLEFT, + ACTION_RESERVE, ACTION_SEND_MSG, ACTION_SET_CODE, +}; +use tvm_assembler::compile_code_to_cell; +use tvm_types::{ + types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, + Sha256 +}; + +#[cfg(feature = "signature_no_check")] +use ton_vm::executor::BehaviorModifiers; +use tvm_vm::{ + boolean, + executor::serialize_currency_collection, + int, + stack::{ + integer::{ + serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, + IntegerData, + }, + serialization::{Deserializer, Serializer}, + Stack, StackItem, + }, + SmartContractInfo, + utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, +}; + +use tvm_vm::executor::zk::ZkCryptoError; +use tvm_assembler::CompileError; +use tvm_types::{BuilderData, Cell, SliceData}; + +use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, OIDCProvider, ZkLoginInputs}; +use fastcrypto_zkp::bn254::utils::gen_address_seed; + +pub const VALUE_PORTION_SIZE: usize = 126; + +#[test] +fn test_vergrth16() { + let user_pass_salt = "206703048842351542647799591018316385612"; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 10; + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); + + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + let verification_key_id: u32 = 1; + + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; + + // ... run 'code', providing proof_cell, public_inputs_cell into stack.. +} + + + +*/ diff --git a/tvm_vm/src/executor/crypto.rs b/tvm_vm/src/executor/crypto.rs index 6664c895..bd2ccb0a 100644 --- a/tvm_vm/src/executor/crypto.rs +++ b/tvm_vm/src/executor/crypto.rs @@ -31,6 +31,9 @@ use crate::stack::StackItem; use crate::types::Exception; use crate::types::Status; +use std::time::Instant; +use bls12_381::Bls12; + const PUBLIC_KEY_BITS: usize = PUBLIC_KEY_BYTES * 8; const SIGNATURE_BITS: usize = SIGNATURE_BYTES * 8; const PUBLIC_KEY_BYTES: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; @@ -107,6 +110,8 @@ fn preprocess_signed_data<'a>(_engine: &Engine, data: &'a [u8]) -> Cow<'a, [u8]> } fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Status { + let start = Instant::now(); + engine.load_instruction(Instruction::new(name))?; fetch_stack(engine, 3)?; let pub_key = engine @@ -148,31 +153,38 @@ fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Statu let signature = match Signature::try_from(&signature[..SIGNATURE_BYTES]) { Ok(signature) => signature, Err(err) => - { - #[allow(clippy::collapsible_else_if)] - if engine.check_capabilities(GlobalCapabilities::CapsTvmBugfixes2022 as u64) { - engine.cc.stack.push(boolean!(false)); - return Ok(()); - } else { - if hash { + { + #[allow(clippy::collapsible_else_if)] + if engine.check_capabilities(GlobalCapabilities::CapsTvmBugfixes2022 as u64) { engine.cc.stack.push(boolean!(false)); return Ok(()); } else { - return err!(ExceptionCode::FatalError, "cannot load signature {}", err); + if hash { + engine.cc.stack.push(boolean!(false)); + return Ok(()); + } else { + return err!(ExceptionCode::FatalError, "cannot load signature {}", err); + } } } - } }; let data = preprocess_signed_data(engine, data.as_ref()); #[cfg(feature = "signature_no_check")] - let result = + let result = engine.modifiers.chksig_always_succeed || pub_key.verify(&data, &signature).is_ok(); #[cfg(not(feature = "signature_no_check"))] - let result = pub_key.verify(&data, &signature).is_ok(); + let result = pub_key.verify(&data, &signature).is_ok(); + + let duration = start.elapsed(); + + println!("Time elapsed by chcksign is: {:?}", duration); + engine.cc.stack.push(boolean!(result)); + println!("%%%result: {:?}", result); Ok(()) } + // CHKSIGNS (d s k – ?) // checks whether s is a valid Ed25519-signature of the data portion of Slice d // using public key k, similarly to CHKSIGNU. If the bit length of Slice d is diff --git a/tvm_vm/src/executor/zk_stuff/jwt_utils.rs b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs new file mode 100644 index 00000000..0af80ea0 --- /dev/null +++ b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs @@ -0,0 +1,76 @@ +//extern crate serde_derive; + +use crate::executor::zk_stuff::error::ZkCryptoError; +use base64ct::Base64UrlUnpadded; +use base64ct::Encoding; +use schemars::JsonSchema; +use serde::Serialize; +use serde::Deserialize; + +/// Claims that be in the payload body. +#[derive(Deserialize, Serialize, Debug)] +struct Claims { + pub iss: String, + pub aud: String, + pub sub: String, + pub nonce: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub azp: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub nbf: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub iat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub exp: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub jti: Option, +} + +impl Claims { + pub fn from_encoded(encoded: &str) -> Result { + let decoded = + Base64UrlUnpadded::decode_vec(encoded).map_err(|_| ZkCryptoError::InvalidInput)?; + let claims: Claims = + serde_json::from_slice(&decoded).map_err(|_| ZkCryptoError::InvalidInput)?; + Ok(claims) + } +} + +// Parse and validate a JWT token, returns sub and aud. +pub fn parse_and_validate_jwt(token: &str) -> Result<(String, String), ZkCryptoError> { + // Check if the token contains 3 parts. + let parts: Vec<&str> = token.split('.').collect(); + if parts.len() != 3 { + return Err(ZkCryptoError::InvalidInput); + } + // Check header is well formed and valid. + let _ = JWTHeader::new(parts[0])?; + + // Check if payload is well formed. + let payload = Claims::from_encoded(parts[1])?; + Ok((payload.sub, payload.aud)) +} + +/// Struct that represents a standard JWT header according to +/// https://openid.net/specs/openid-connect-core-1_0.html +#[derive(Default, Debug, Clone, PartialEq, Eq, JsonSchema, Hash, Serialize, Deserialize)] +pub struct JWTHeader { + alg: String, + pub kid: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub typ: Option, +} + +impl JWTHeader { + /// Parse the header base64 string into a [struct JWTHeader]. + pub fn new(header_base64: &str) -> Result { + let header_bytes = Base64UrlUnpadded::decode_vec(header_base64) + .map_err(|_| ZkCryptoError::InvalidInput)?; + let header: JWTHeader = + serde_json::from_slice(&header_bytes).map_err(|_| ZkCryptoError::InvalidInput)?; + if header.alg != "RS256" { + return Err(ZkCryptoError::GeneralError("Invalid header".to_string())); + } + Ok(header) + } +} From 6ce44f335e1242eea8ea1fe3da2db287860f0087 Mon Sep 17 00:00:00 2001 From: sehor05 Date: Thu, 3 Oct 2024 00:22:53 +0300 Subject: [PATCH 03/19] fix some warnings --- tvm_client/src/json_interface/runtime.rs | 12 +- tvm_tests/src/main.rs | 6 +- tvm_tests/src/test_framework.rs | 405 ++++--- tvm_tests/src/test_zk.rs | 1000 +++++++++-------- tvm_tests/src/test_zk_.rs | 294 ++--- tvm_vm/src/executor/crypto.rs | 27 +- tvm_vm/src/executor/engine/handlers.rs | 3 +- tvm_vm/src/executor/zk.rs | 790 ++++++------- tvm_vm/src/executor/zk_stuff/bn254/api.rs | 21 +- tvm_vm/src/executor/zk_stuff/bn254/mod.rs | 38 +- .../zk_stuff/bn254/poseidon/constants.rs | 41 +- .../executor/zk_stuff/bn254/poseidon/mod.rs | 370 +++--- .../src/executor/zk_stuff/bn254/verifier.rs | 109 +- tvm_vm/src/executor/zk_stuff/curve_utils.rs | 85 +- tvm_vm/src/executor/zk_stuff/error.rs | 3 - tvm_vm/src/executor/zk_stuff/jwt_utils.rs | 7 +- tvm_vm/src/executor/zk_stuff/mod.rs | 15 +- tvm_vm/src/executor/zk_stuff/utils.rs | 37 +- tvm_vm/src/executor/zk_stuff/zk_login.rs | 192 ++-- 19 files changed, 1769 insertions(+), 1686 deletions(-) diff --git a/tvm_client/src/json_interface/runtime.rs b/tvm_client/src/json_interface/runtime.rs index c58d771b..92a242f1 100644 --- a/tvm_client/src/json_interface/runtime.rs +++ b/tvm_client/src/json_interface/runtime.rs @@ -57,11 +57,19 @@ impl RuntimeHandlers { self.api.modules.push(module); } - pub fn register_sync(&mut self, function_name: String, handler: Box) { + pub fn register_sync( + &mut self, + function_name: String, + handler: Box, + ) { self.sync_handlers.insert(function_name, handler); } - pub fn register_async(&mut self, function_name: String, handler: Box) { + pub fn register_async( + &mut self, + function_name: String, + handler: Box, + ) { self.async_handlers.insert(function_name, handler); } } diff --git a/tvm_tests/src/main.rs b/tvm_tests/src/main.rs index 349e894f..27bae108 100644 --- a/tvm_tests/src/main.rs +++ b/tvm_tests/src/main.rs @@ -1,7 +1,5 @@ - +mod test_framework; mod test_zk; mod test_zk_; -mod test_framework; -fn main() { -} +fn main() {} diff --git a/tvm_tests/src/test_framework.rs b/tvm_tests/src/test_framework.rs index a29dc5a8..ff06673a 100644 --- a/tvm_tests/src/test_framework.rs +++ b/tvm_tests/src/test_framework.rs @@ -1,35 +1,42 @@ -/* -* Copyright (C) 2019-2023 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* 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 TON DEV software governing permissions and -* limitations under the License. -*/ +// Copyright (C) 2019-2023 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// 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 TON DEV software governing permissions and +// limitations under the License. #![allow(dead_code)] -use std::{convert::Into, ffi::CStr, os::raw::c_char, sync::Arc}; -use tvm_assembler::{CompileError, compile_code}; -//use failure::{Error}; -use anyhow::{Error}; -use tvm_vm::{ - int, - error::{tvm_exception_code, tvm_exception_or_custom_code, TvmError}, - executor::{Engine, gas::gas_state::Gas, IndexProvider, BehaviorModifiers}, smart_contract_info::SmartContractInfo, - stack::{Stack, StackItem, integer::IntegerData, savelist::SaveList}, - types::Exception -}; -//use failure::Error as Error; +use std::convert::Into; +use std::ffi::CStr; +use std::os::raw::c_char; +use std::sync::Arc; + +// use failure::{Error}; +use tvm_assembler::compile_code; +use tvm_assembler::CompileError; +use tvm_block::GlobalCapabilities; +// use failure::Error as Error; use tvm_types::{ - BuilderData, Cell, Result, SliceData, - types::ExceptionCode, HashmapE, HashmapType, BocWriter + types::ExceptionCode, BocWriter, BuilderData, Cell, HashmapE, HashmapType, Result, SliceData, }; - -use tvm_block::GlobalCapabilities; +use tvm_vm::error::tvm_exception_code; +use tvm_vm::error::tvm_exception_or_custom_code; +use tvm_vm::error::TvmError; +use tvm_vm::executor::gas::gas_state::Gas; +use tvm_vm::executor::BehaviorModifiers; +use tvm_vm::executor::Engine; +use tvm_vm::executor::IndexProvider; +use tvm_vm::int; +use tvm_vm::smart_contract_info::SmartContractInfo; +use tvm_vm::stack::integer::IntegerData; +use tvm_vm::stack::savelist::SaveList; +use tvm_vm::stack::Stack; +use tvm_vm::stack::StackItem; +use tvm_vm::types::Exception; pub type Bytecode = SliceData; @@ -37,17 +44,17 @@ pub type Bytecode = SliceData; pub mod create { use super::*; - pub fn cell>(data:T) -> StackItem { + pub fn cell>(data: T) -> StackItem { let data = data.as_ref().to_vec(); StackItem::Cell(BuilderData::with_bitstring(data).unwrap().into_cell().unwrap()) } - pub fn builder>(data:T) -> StackItem { + pub fn builder>(data: T) -> StackItem { let builder = BuilderData::with_bitstring(data.as_ref().to_vec()).unwrap(); StackItem::builder(builder) } - pub fn slice>(data:T) -> StackItem { + pub fn slice>(data: T) -> StackItem { let data = data.as_ref().to_vec(); let slice = SliceData::new(data); StackItem::Slice(slice) @@ -62,13 +69,10 @@ pub mod create { fn logger_init() { // do not init twice if log::log_enabled!(log::Level::Info) { - return + return; } - let log_level = if cfg!(feature = "verbose") { - log::LevelFilter::Trace - } else { - log::LevelFilter::Info - }; + let log_level = + if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { log::LevelFilter::Info }; let encoder_boxed = Box::new(log4rs::encode::pattern::PatternEncoder::new("{m}")); let config = if cfg!(feature = "log_file") { let file = log4rs::append::file::FileAppender::builder() @@ -80,9 +84,8 @@ fn logger_init() { .build(log4rs::config::Root::builder().appender("file").build(log_level)) .unwrap() } else { - let console = log4rs::append::console::ConsoleAppender::builder() - .encoder(encoder_boxed) - .build(); + let console = + log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed).build(); log4rs::config::Config::builder() .appender(log4rs::config::Appender::builder().build("console", Box::new(console))) .build(log4rs::config::Root::builder().appender("console").build(log_level)) @@ -106,13 +109,7 @@ pub struct TestCaseInputs { } impl TestCaseInputs { - - pub fn new( - code: String, - stack: Stack, - refs: Vec, - capabilities: u64 - ) -> TestCaseInputs { + pub fn new(code: String, stack: Stack, refs: Vec, capabilities: u64) -> TestCaseInputs { logger_init(); TestCaseInputs { code, @@ -179,8 +176,7 @@ impl TestCaseInputs { } pub fn with_ctrl(mut self, ctrl: usize, mut item: StackItem) -> TestCaseInputs { - self.ctrls.put(ctrl, &mut item) - .expect("test arguments must be valid"); + self.ctrls.put(ctrl, &mut item).expect("test arguments must be valid"); self } @@ -198,7 +194,10 @@ impl TestCaseInputs { self } - pub fn with_behavior_modifiers(mut self, behavior_modifiers: BehaviorModifiers) -> TestCaseInputs { + pub fn with_behavior_modifiers( + mut self, + behavior_modifiers: BehaviorModifiers, + ) -> TestCaseInputs { self.skip_fift_check = true; self.behavior_modifiers = Some(behavior_modifiers); self @@ -208,7 +207,11 @@ impl TestCaseInputs { self.expect_bytecode_extended(bytecode, None) } - pub fn expect_bytecode_extended(self, bytecode: Vec, message: Option <&str>) -> TestCaseInputs { + pub fn expect_bytecode_extended( + self, + bytecode: Vec, + message: Option<&str>, + ) -> TestCaseInputs { let inputcode = SliceData::new(bytecode); let compilation_result = compile_code(&self.code); match compilation_result { @@ -229,19 +232,19 @@ impl TestCaseInputs { match message { Some(msg) => panic!( "{}Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", - msg, inputcode, selfcode), + msg, inputcode, selfcode + ), None => panic!( "Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", - inputcode, selfcode), + inputcode, selfcode + ), } }; - }, - Err(e) => { - match message { - Some(msg) => panic!("{}{}", msg, e), - None => panic!("{}", e), - } } + Err(e) => match message { + Some(msg) => panic!("{}{}", msg, e), + None => panic!("{}", e), + }, } self } @@ -250,7 +253,11 @@ impl TestCaseInputs { self.expect_compilation_failure_extended(error, None) } - pub fn expect_compilation_failure_extended(self, error: CompileError, message: Option <&str>) -> TestCaseInputs { + pub fn expect_compilation_failure_extended( + self, + error: CompileError, + message: Option<&str>, + ) -> TestCaseInputs { let compilation_result = compile_code(&self.code); match message { None => { @@ -260,15 +267,16 @@ impl TestCaseInputs { "Expected (left): <{}>, but was (right): <{}>.", error, actual ) - }, + } Some(msg) => { - let actual = compilation_result.expect_err(&format!("{}. Error expected {}", msg, error)); + let actual = + compilation_result.expect_err(&format!("{}. Error expected {}", msg, error)); assert_eq!( error, actual, "{}\nExpected (left): <{}>, but was (right): <{}>.", msg, error, actual ) - }, + } } self } @@ -293,8 +301,14 @@ impl TestCase { None => { let err = self.compilation_result.as_ref().unwrap_err(); match message { - Some(msg) => panic!("{}No executor was created, because of bytecode compilation error {:?}", msg, err), - None => panic!("No executor was created, because of bytecode compilation error {:?}", err) + Some(msg) => panic!( + "{}No executor was created, because of bytecode compilation error {:?}", + msg, err + ), + None => panic!( + "No executor was created, because of bytecode compilation error {:?}", + err + ), } } } @@ -307,7 +321,7 @@ fn compare_with_fift( code: String, executor: &Engine, execution_result: &Result, - gas_remaining: i32 + gas_remaining: i32, ) { #[cfg(windows)] let lib_name = "vm_run_shared.dll"; @@ -329,11 +343,10 @@ fn compare_with_fift( let fift_result; unsafe { let run_boc: libloading::Symbol< - unsafe extern "C" fn(*const u8, i32, i32) -> *mut c_char + unsafe extern "C" fn(*const u8, i32, i32) -> *mut c_char, > = lib.get(b"run_vm_boc_with_gas_and_commit").unwrap(); - let free_mem: libloading::Symbol< - unsafe extern "C" fn(*const c_char) -> *mut c_char - > = lib.get(b"free_mem").unwrap(); + let free_mem: libloading::Symbol *mut c_char> = + lib.get(b"free_mem").unwrap(); let res = run_boc(data.as_ptr(), size as i32, gas_remaining); fift_result = CStr::from_ptr(res).to_string_lossy().into_owned().trim().to_string(); free_mem(res); @@ -342,17 +355,39 @@ fn compare_with_fift( Ok(ref result) => { let stack = executor.get_stack_result_fift(); match stack.is_empty() { - true => format!("{} {}{}", result, executor.gas_used(), executor.get_committed_state_fift()), - false => format!("{} {} {}{}", stack, result, executor.gas_used(), executor.get_committed_state_fift()) + true => format!( + "{} {}{}", + result, + executor.gas_used(), + executor.get_committed_state_fift() + ), + false => format!( + "{} {} {}{}", + stack, + result, + executor.gas_used(), + executor.get_committed_state_fift() + ), } } Err(ref err) => { if let Some(ExceptionCode::OutOfGas) = tvm_exception_code(err) { let gas = executor.gas_used(); - format!("{} {} {}{}", gas, !(ExceptionCode::OutOfGas as i32), gas, executor.get_committed_state_fift()) + format!( + "{} {} {}{}", + gas, + !(ExceptionCode::OutOfGas as i32), + gas, + executor.get_committed_state_fift() + ) } else { let err = tvm_exception_or_custom_code(err); - format!("0 {} {}{}", err, executor.gas_used(), executor.get_committed_state_fift()) + format!( + "0 {} {}{}", + err, + executor.gas_used(), + executor.get_committed_state_fift() + ) } } }; @@ -372,7 +407,9 @@ impl TestCase { Ok(bytecode) => { let code = if args.refs.is_empty() { bytecode.clone() - } else if bytecode.remaining_references() + args.refs.len() <= BuilderData::references_capacity() { + } else if bytecode.remaining_references() + args.refs.len() + <= BuilderData::references_capacity() + { let mut builder = bytecode.as_builder(); args.refs.iter().rev().for_each(|reference| { builder.checked_prepend_reference(reference.clone()).unwrap(); @@ -389,7 +426,7 @@ impl TestCase { Some(args.ctrls.clone()), Some(args.stack.clone()), args.gas.clone(), - vec![args.library.clone()] + vec![args.library.clone()], ); executor.set_block_version(args.block_version); if let Some(modifiers) = args.behavior_modifiers { @@ -399,9 +436,20 @@ impl TestCase { executor.set_index_provider(index_provider) } let execution_result = executor.execute(); - if cfg!(feature = "fift_check") && args.stack.is_empty() && args.ctrls.is_empty() && !args.skip_fift_check { + if cfg!(feature = "fift_check") + && args.stack.is_empty() + && args.ctrls.is_empty() + && !args.skip_fift_check + { let gas = args.gas.map(|gas| gas.get_gas_remaining() as i32).unwrap_or(1000000); - compare_with_fift(code, args.library, args.code, &executor, &execution_result, gas) + compare_with_fift( + code, + args.library, + args.code, + &executor, + &execution_result, + gas, + ) } TestCase { executor: Some(executor), @@ -409,53 +457,47 @@ impl TestCase { execution_result, } } - Err(e) => TestCase { - executor: None, - compilation_result: Err(e), - execution_result: Ok(-1), + Err(e) => { + TestCase { executor: None, compilation_result: Err(e), execution_result: Ok(-1) } } } } // TODO: call this from fn new pub fn with_bytecode( - code: Bytecode, - ctrls: Option, - stack: Option, - library: HashmapE + code: Bytecode, + ctrls: Option, + stack: Option, + library: HashmapE, ) -> TestCase { logger_init(); let mut executor = Engine::with_capabilities(0).setup_with_libraries( - code.clone(), + code.clone(), ctrls.clone(), stack.clone(), - None, - vec![library.clone()] + None, + vec![library.clone()], ); let execution_result = executor.execute(); if cfg!(feature = "fift_check") && stack.is_none() && ctrls.is_none() { compare_with_fift( - code.clone(), - library, - format!("{:x}", code), - &executor, - &execution_result, - 1000000 + code.clone(), + library, + format!("{:x}", code), + &executor, + &execution_result, + 1000000, ) } log::trace!("bytecode: {}", code); - TestCase { - executor: Some(executor), - compilation_result: Ok(code), - execution_result, - } + TestCase { executor: Some(executor), compilation_result: Ok(code), execution_result } } pub fn get_root(&self) -> Option { if let Some(ref eng) = self.executor { if let StackItem::Cell(c) = eng.get_committed_state().get_root() { - return Some(c.clone()) + return Some(c.clone()); } } None @@ -464,7 +506,7 @@ impl TestCase { pub fn get_actions(&self) -> Option { if let Some(ref eng) = self.executor { if let StackItem::Cell(c) = eng.get_committed_state().get_actions() { - return Some(c.clone()) + return Some(c.clone()); } } None @@ -479,16 +521,32 @@ pub trait Expects { fn expect_item(self, stack_item: StackItem) -> TestCase; fn expect_item_extended(self, stack_item: StackItem, message: Option<&str>) -> TestCase; fn expect_success(self) -> TestCase; - fn expect_success_extended(self, message: Option <&str>) -> TestCase; + fn expect_success_extended(self, message: Option<&str>) -> TestCase; fn expect_ctrl(self, ctrl: usize, item: &StackItem) -> TestCase; - fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) -> TestCase; + fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) + -> TestCase; fn expect_failure(self, exception_code: ExceptionCode) -> TestCase; fn expect_custom_failure(self, custom_code: i32) -> TestCase; - fn expect_custom_failure_extended bool>(self, op: F, exc_name: &str, message: Option <&str>) -> TestCase; - fn expect_failure_extended(self, exception_code: ExceptionCode, message: Option <&str>) -> TestCase; + fn expect_custom_failure_extended bool>( + self, + op: F, + exc_name: &str, + message: Option<&str>, + ) -> TestCase; + fn expect_failure_extended( + self, + exception_code: ExceptionCode, + message: Option<&str>, + ) -> TestCase; fn expect_root_data(self, cell: Cell) -> TestCase; fn expect_same_results(self, other: Self); - fn expect_gas(self, max_gas_limit: i64, gas_limit: i64, gas_credit: i64, gas_remaining: i64) -> TestCase; + fn expect_gas( + self, + max_gas_limit: i64, + gas_limit: i64, + gas_credit: i64, + gas_remaining: i64, + ) -> TestCase; fn expect_steps(self, steps: u32) -> TestCase; fn stack(self) -> Stack; } @@ -519,7 +577,7 @@ impl> Expects for T { // TODO this is not quite right: execution may fail but still produce a stack Err(ref e) => { log::info!(target: "tvm", "\nExpected stack: \n{}", stack); - //print_failed_detail_extended(&test_case, e, message); + // print_failed_detail_extended(&test_case, e, message); panic!("Execution error: {:?}", e) } } @@ -548,21 +606,21 @@ impl> Expects for T { } fn expect_success(self) -> TestCase { - self.expect_success_extended(None) + self.expect_success_extended(None) } - fn expect_success_extended(self, message: Option <&str>) -> TestCase { + fn expect_success_extended(self, message: Option<&str>) -> TestCase { let test_case: TestCase = self.into(); let executor = test_case.executor(message); print_stack(&test_case, executor); if let Err(ref e) = test_case.execution_result { match message { None => { - //print_failed_detail_extended(&test_case, e, message); + // print_failed_detail_extended(&test_case, e, message); panic!("Execution error: {:?}", e); } Some(msg) => { - //print_failed_detail_extended(&test_case, e, message); + // print_failed_detail_extended(&test_case, e, message); panic!("{}\nExecution error: {:?}", msg, e); } } @@ -574,13 +632,18 @@ impl> Expects for T { self.expect_ctrl_extended(ctrl, item, None) } - fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) -> TestCase { + fn expect_ctrl_extended( + self, + ctrl: usize, + item: &StackItem, + message: Option<&str>, + ) -> TestCase { let test_case: TestCase = self.into(); let executor = test_case.executor(message); match test_case.execution_result { Ok(_) => executor.assert_ctrl(ctrl, item), Err(ref e) => { - //print_failed_detail_extended(&test_case, e, message); + // print_failed_detail_extended(&test_case, e, message); panic!("Execution error: {}", e); } }; @@ -591,11 +654,11 @@ impl> Expects for T { self.expect_failure_extended(exception_code, None) } - fn expect_custom_failure_extended bool>( - self, - op: F, - exc_name: &str, - message: Option <&str> + fn expect_custom_failure_extended bool>( + self, + op: F, + exc_name: &str, + message: Option<&str>, ) -> TestCase { let test_case: TestCase = self.into(); let executor = test_case.executor(message); @@ -608,14 +671,11 @@ impl> Expects for T { ); print_stack(&test_case, executor); match message { - None => panic!( - "Expected failure: {}, however execution succeeded.", - exc_name - ), + None => panic!("Expected failure: {}, however execution succeeded.", exc_name), Some(msg) => panic!( - "{}.\nExpected failure: {}, however execution succeeded.", + "{}.\nExpected failure: {}, however execution succeeded.", msg, exc_name - ) + ), } } Err(ref e) => { @@ -623,13 +683,13 @@ impl> Expects for T { if op(e) { match message { Some(msg) => panic!( - "{} - {}\nNon expected exception: {}, expected: {}", + "{} - {}\nNon expected exception: {}, expected: {}", msg2, msg, e, exc_name ), None => panic!( - "{}\nNon expected exception: {}, expected: {}", + "{}\nNon expected exception: {}, expected: {}", msg2, e, exc_name - ) + ), } } } else { @@ -655,22 +715,22 @@ impl> Expects for T { fn expect_custom_failure(self, custom_code: i32) -> TestCase { self.expect_custom_failure_extended( - |e| e.custom_code() != Some(custom_code), - "custom exception", - None + |e| e.custom_code() != Some(custom_code), + "custom exception", + None, ) } fn expect_failure_extended( - self, - exception_code: ExceptionCode, - message: Option <&str> + self, + exception_code: ExceptionCode, + message: Option<&str>, ) -> TestCase { - self.expect_custom_failure_extended( - |e| e.exception_code() != Some(exception_code), - &format!("{}", exception_code), - message - ) + self.expect_custom_failure_extended( + |e| e.exception_code() != Some(exception_code), + &format!("{}", exception_code), + message, + ) } fn expect_root_data(self, cell: Cell) -> TestCase { @@ -689,7 +749,7 @@ impl> Expects for T { max_gas_limit: i64, gas_limit: i64, gas_credit: i64, - gas_remaining: i64 + gas_remaining: i64, ) -> TestCase { let test_case: TestCase = self.into(); let gas = test_case.executor(None).get_gas(); @@ -720,31 +780,31 @@ fn print_stack(test_case: &TestCase, executor: &Engine) { } } -/*#[allow(dead_code)] -fn print_failed_detail(case: &TestCase, exception: &Error) { - print_failed_detail_extended(case, exception, None) -} - -fn print_failed_detail_extended(case: &TestCase, exception: &Error, message: Option <&str>) { - log::info!(target: "tvm", "exception: {:?}\n", exception); - let msg2 = if let Some(TvmError::TvmExceptionFull(_e, msg2)) = exception.downcast_ref() { - msg2.clone() - } else { - String::new() - }; - match message { - Some(ref msg) => log::info!( - target: "tvm", - "{} failed with {} {}.\nBytecode: {:x?}\n", - msg, exception, msg2, case.compilation_result - ), - None => log::info!( - target: "tvm", - "failed with {} {}.\nBytecode: {:x?}\n", - exception, msg2, case.compilation_result - ) - } -}*/ +// #[allow(dead_code)] +// fn print_failed_detail(case: &TestCase, exception: &Error) { +// print_failed_detail_extended(case, exception, None) +// } +// +// fn print_failed_detail_extended(case: &TestCase, exception: &Error, message: +// Option <&str>) { log::info!(target: "tvm", "exception: {:?}\n", exception); +// let msg2 = if let Some(TvmError::TvmExceptionFull(_e, msg2)) = +// exception.downcast_ref() { msg2.clone() +// } else { +// String::new() +// }; +// match message { +// Some(ref msg) => log::info!( +// target: "tvm", +// "{} failed with {} {}.\nBytecode: {:x?}\n", +// msg, exception, msg2, case.compilation_result +// ), +// None => log::info!( +// target: "tvm", +// "failed with {} {}.\nBytecode: {:x?}\n", +// exception, msg2, case.compilation_result +// ) +// } +// } pub fn test_case_with_refs(code: &str, references: Vec) -> TestCaseInputs { TestCaseInputs::new(code.to_string(), Stack::new(), references, 0) @@ -765,8 +825,7 @@ pub fn test_case_with_bytecode(code: Bytecode) -> TestCase { #[allow(dead_code)] pub fn test_single_argument_fail(cmd: &str, argument: isize) { let code = format!("{} {}", cmd, argument); - test_case(code) - .expect_compilation_failure(CompileError::out_of_range(1, 1, cmd, "arg 0")); + test_case(code).expect_compilation_failure(CompileError::out_of_range(1, 1, cmd, "arg 0")); } #[allow(dead_code)] @@ -779,12 +838,10 @@ pub fn expect_exception_with_capability( code: &str, exc_code: ExceptionCode, capability: GlobalCapabilities, - check_fift: bool + check_fift: bool, ) { - test_case( - code, - ) - .with_capability(capability) - .skip_fift_check(!check_fift) - .expect_failure(exc_code); + test_case(code) + .with_capability(capability) + .skip_fift_check(!check_fift) + .expect_failure(exc_code); } diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index 1423a9b5..ecec6747 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -1,96 +1,40 @@ -/* -* Copyright (C) 2019-2023 TON Labs. All Rights Reserved. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* 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 TON DEV software governing permissions and -* limitations under the License. -*/ - -use num_traits::Zero; // Для работы с большими числами -use std::iter::repeat; +// Copyright (C) 2019-2023 TON Labs. All Rights Reserved. +// +// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not +// use this file except in compliance with the License. +// +// 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 TON DEV software governing permissions and +// limitations under the License. use std::collections::HashMap; -use std::slice; -use std::str::FromStr; +use std::iter::repeat; use std::time::Instant; -use ark_std::rand::rngs::StdRng; -use ark_std::rand::SeedableRng; + use base64ct::Encoding as bEncoding; -use fastcrypto::ed25519::Ed25519KeyPair; -use base64::decode; -use ark_ff::biginteger::BigInteger; use ed25519::signature::Signer; - -use fastcrypto::traits::{KeyPair, ToFromBytes}; -use tvm_types::{ - types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, - Sha256 -}; - -//use tvm_vm::executor::zk_stuff::zk_login::{hash_ascii_str_to_field, hash_to_field, MAX_HEADER_LEN, MAX_ISS_LEN_B64, PACK_WIDTH}; - - -#[cfg(feature = "signature_no_check")] -use ton_vm::executor::BehaviorModifiers; -use tvm_vm::{ - boolean, - executor::serialize_currency_collection, - int, - stack::{ - integer::{ - serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, - IntegerData, - }, - serialization::{Deserializer, Serializer}, - Stack, StackItem, - }, - SmartContractInfo, - utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, -}; - -use tvm_vm::executor::zk_stuff::error::ZkCryptoError; -use tvm_types::{BuilderData, Cell, SliceData}; -use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, Claim, JWK, JwkId, OIDCProvider, ZkLoginInputs}; -use fastcrypto_zkp::bn254::utils::{gen_address_seed, get_zk_login_address}; -use fastcrypto_zkp::zk_login_utils::Bn254FrElement; +use fastcrypto_zkp::bn254::zk_login::CanonicalSerialize; +use fastcrypto_zkp::bn254::zk_login::JwkId; +use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; +use fastcrypto_zkp::bn254::zk_login::JWK; use num_bigint::BigUint; - -use serde::{Deserialize}; +use serde::Deserialize; use serde_derive::Serialize; -use serde_json::Value; -use tvm_vm::executor::zk::calculate_poseidon_hash; -use crate::test_framework::{Expects, test_case, test_case_with_refs}; - -pub const SUI_DATA_FROM_REACT_1: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJ4bW5KVzMxcnV6S01HaXIwMVlQR1lMMHhEWSIsIm5iZiI6MTcxNTY4NzAzNiwiaWF0IjoxNzE1Njg3MzM2LCJleHAiOjE3MTU2OTA5MzYsImp0aSI6IjliNjAxZDI1ZjAwMzY0MGMyODg5YTJhMDQ3Nzg5MzgyY2IxY2ZlODcifQ.rTa9KA9HoYm04Agj71D0kDkvsCZ35SeeihBGbABYckBRxaUlCy6LQ-sEaVOTgvnL_DgVn7hx8g3sSmnhJ9kHzj5e6gtUoxoWAe8PuGyK2bmqhmPrQMeEps9f6m2EToQCIA_Id4fGCjSCktjJBi47QHT_Dhe6isHdKk1pgSshOyvCF1VjIvyyeGY5iWQ4cIRBMQNlNBT11o6T01SY6B9DtiiFN_0-ok5taIjQgtMNG6Cwr3tCnqXftuGGQrHlx15y8VgCPODYi-wOtvUbzI2yfx53PmRD_L8O50cMNCrCRE3yYR5MNOu1LlQ_EACy5UFsCJR35xRz84nv-6Iyrufx1g\",\"userPassToIntFormat\":\"981021191041055255531141165751\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":155,\"1\":147,\"2\":37,\"3\":82,\"4\":183,\"5\":109,\"6\":227,\"7\":144,\"8\":85,\"9\":248,\"10\":20,\"11\":45,\"12\":92,\"13\":103,\"14\":160,\"15\":221,\"16\":101,\"17\":44,\"18\":30,\"19\":86,\"20\":96,\"21\":85,\"22\":24,\"23\":224,\"24\":106,\"25\":63,\"26\":13,\"27\":130,\"28\":8,\"29\":119,\"30\":247,\"31\":67},\"secretKey\":{\"0\":192,\"1\":16,\"2\":35,\"3\":54,\"4\":100,\"5\":14,\"6\":88,\"7\":217,\"8\":164,\"9\":21,\"10\":154,\"11\":233,\"12\":248,\"13\":208,\"14\":188,\"15\":4,\"16\":52,\"17\":244,\"18\":125,\"19\":103,\"20\":99,\"21\":26,\"22\":225,\"23\":60,\"24\":140,\"25\":75,\"26\":228,\"27\":157,\"28\":137,\"29\":220,\"30\":1,\"31\":65,\"32\":155,\"33\":147,\"34\":37,\"35\":82,\"36\":183,\"37\":109,\"38\":227,\"39\":144,\"40\":85,\"41\":248,\"42\":20,\"43\":45,\"44\":92,\"45\":103,\"46\":160,\"47\":221,\"48\":101,\"49\":44,\"50\":30,\"51\":86,\"52\":96,\"53\":85,\"54\":24,\"55\":224,\"56\":106,\"57\":63,\"58\":13,\"59\":130,\"60\":8,\"61\":119,\"62\":247,\"63\":67}}},\"zkAddr\":\"0x290623ea2fe67e77502c931e015e910720b59cf99994bfe872da851245a6adb8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"4240296169193969312736577528388333411353554120022978085193148043577551744781\",\"5805161066003598301896048908428560240907086333477483881772048922050706263054\",\"1\"],\"b\":[[\"12834391737669124973917765536412427456985620342194191639017091262766903638891\",\"17565396762846717347409742387259908749145765976354144805005547481529916658455\"],[\"10704310067924910937030159163683742097178285875135929496314190235513445131794\",\"5158907077493606386023392148737817037260820737072162547798816810512684527243\"],[\"1\",\"0\"]],\"c\":[\"1422540522119231707130773229384414857146368773886805969586218853559909475064\",\"8843079196273712399340537238369227864378150337693574970239878271571912585171\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJuTJVK3beOQVfgULVxnoN1lLB5WYFUY4Go/DYIId/dD\"}"; -pub const SUI_DATA_FROM_REACT_2: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjJKd0VMbjJfUV9Rd0VsTC1rWTFPRnFqdXZCMCIsIm5iZiI6MTcxNTY4NzAyOSwiaWF0IjoxNzE1Njg3MzI5LCJleHAiOjE3MTU2OTA5MjksImp0aSI6ImU2YjM1ZjJmNmFkNjIzOWEwMDAxMTJiMWI5YWI2MWQ0MjRkMGM1OTIifQ.QcrEDE9qmPZKX83nU3Tx2BN8fsinb_mmXkO1Qf7Uv1QTd0NjirSeu7C4Vn9WDNWDaIR-BgCfhOlkwMQPljcahqC4AN43N_66tvbEsXjtEdFejslXrGG4D_BEKvtmD7_WkW388LyU2PxKgtdDfpYFgmuT6wTM2TO5dTbrGrDyn88q3pkPfefC5a8Wi1V6zECfFdSV-pKQlxtPaImi7s3CKAUMDu1n-jcT-Ho2aTgrWKAzhXE56tgEWOpXQO06eJsWCSOqoZSLYtatTrZr4d38U7QRQiNlH-ydHv4zXt1tixLLJ0wvPx-dQaCnCl1kW1orYkJGFfHgjx6A9z5Ol4afuw\",\"userPassToIntFormat\":\"101119106102103\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":194,\"1\":38,\"2\":203,\"3\":255,\"4\":219,\"5\":127,\"6\":105,\"7\":129,\"8\":234,\"9\":222,\"10\":71,\"11\":169,\"12\":108,\"13\":94,\"14\":28,\"15\":48,\"16\":111,\"17\":221,\"18\":113,\"19\":110,\"20\":5,\"21\":226,\"22\":19,\"23\":230,\"24\":232,\"25\":67,\"26\":255,\"27\":179,\"28\":6,\"29\":10,\"30\":209,\"31\":63},\"secretKey\":{\"0\":44,\"1\":32,\"2\":251,\"3\":184,\"4\":109,\"5\":252,\"6\":105,\"7\":67,\"8\":208,\"9\":111,\"10\":86,\"11\":214,\"12\":192,\"13\":135,\"14\":169,\"15\":48,\"16\":162,\"17\":36,\"18\":216,\"19\":145,\"20\":232,\"21\":64,\"22\":17,\"23\":14,\"24\":29,\"25\":56,\"26\":39,\"27\":118,\"28\":143,\"29\":250,\"30\":31,\"31\":66,\"32\":194,\"33\":38,\"34\":203,\"35\":255,\"36\":219,\"37\":127,\"38\":105,\"39\":129,\"40\":234,\"41\":222,\"42\":71,\"43\":169,\"44\":108,\"45\":94,\"46\":28,\"47\":48,\"48\":111,\"49\":221,\"50\":113,\"51\":110,\"52\":5,\"53\":226,\"54\":19,\"55\":230,\"56\":232,\"57\":67,\"58\":255,\"59\":179,\"60\":6,\"61\":10,\"62\":209,\"63\":63}}},\"zkAddr\":\"0x9d28c04a423b33d6901065b2e23440d80c963e2d8cf60619aed131cf302a3345\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"10113442204684515220664612836724727112601024759319365467272456423129044788607\",\"1622056145268645528934658046911045406324940175278473377024147189407527440953\",\"1\"],\"b\":[[\"16638441944380099215425740101953753038808466958852552979180365845498468757656\",\"15160836857346434734063515954042830497610079883703780011464867547889770445695\"],[\"18562910453341688699790780964434211467815845944672185772065803860963710445937\",\"8200691834141582017549140597895023392490964486044036655696113278873832146838\"],[\"1\",\"0\"]],\"c\":[\"4229037146526046139176767312447148765936834700862335953317784850097077554287\",\"14155516063621997063825085002662503289554536312724791903045026922766401869119\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AMImy//bf2mB6t5HqWxeHDBv3XFuBeIT5uhD/7MGCtE/\"}"; -pub const SUI_DATA_FROM_REACT_3: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkFadlVHUkI5MU5VZmdnYVV5bUdCQU9kSmM2ayIsIm5iZiI6MTcxNTY4NzAyMiwiaWF0IjoxNzE1Njg3MzIyLCJleHAiOjE3MTU2OTA5MjIsImp0aSI6ImZiNGNhMzdjOGE5MjEzOTFjZTE2ZDQwNmE2NmVmYjA1MTQxNTg5YjYifQ.C7zNP2sxRMF62irwNjO2y_JVMjYLqGk6sAWy0rKoXswa7SA6KhPrWocMAB2GKaQW-CeqUzMJdypgJz1RcMzmOWg30cv4diEgqBSM1I1ocOI5ivRE2Atj8g-Oj2uAm_DBvuJBLzTA6wfb34QTasOTZqLsMyoaQavxUprzPi-1z-MUE-darDjZ-IkWu7SctdEzNhSuUfQPJo_sbN5_38dQm300plXK-9iJgDxMWmT4NPO91hSQaGKbBm_euMI-fBAfYwARMnlaTETvSiCNSAyzphNrBi9kU49BFi5X04GoIkSW4zFwb74OeFbL49_14AZZ9Z2Mw7EPQ9sAAjzanxPUfA\",\"userPassToIntFormat\":\"98118101102104106100\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":219,\"1\":225,\"2\":68,\"3\":197,\"4\":249,\"5\":59,\"6\":249,\"7\":200,\"8\":218,\"9\":242,\"10\":184,\"11\":214,\"12\":247,\"13\":159,\"14\":9,\"15\":162,\"16\":60,\"17\":174,\"18\":162,\"19\":13,\"20\":111,\"21\":5,\"22\":61,\"23\":179,\"24\":155,\"25\":167,\"26\":207,\"27\":6,\"28\":174,\"29\":163,\"30\":23,\"31\":23},\"secretKey\":{\"0\":28,\"1\":117,\"2\":37,\"3\":14,\"4\":166,\"5\":188,\"6\":125,\"7\":36,\"8\":70,\"9\":193,\"10\":162,\"11\":142,\"12\":79,\"13\":218,\"14\":210,\"15\":131,\"16\":217,\"17\":32,\"18\":88,\"19\":246,\"20\":195,\"21\":214,\"22\":135,\"23\":80,\"24\":27,\"25\":198,\"26\":131,\"27\":31,\"28\":3,\"29\":240,\"30\":199,\"31\":129,\"32\":219,\"33\":225,\"34\":68,\"35\":197,\"36\":249,\"37\":59,\"38\":249,\"39\":200,\"40\":218,\"41\":242,\"42\":184,\"43\":214,\"44\":247,\"45\":159,\"46\":9,\"47\":162,\"48\":60,\"49\":174,\"50\":162,\"51\":13,\"52\":111,\"53\":5,\"54\":61,\"55\":179,\"56\":155,\"57\":167,\"58\":207,\"59\":6,\"60\":174,\"61\":163,\"62\":23,\"63\":23}}},\"zkAddr\":\"0xeccbb76b41c1fd5e19950f0c005e5d2a2596b9cc510e98b6f69bb3cf590b3cf8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"11651445672013969095011012560101085321682180365624939394143647198080899422642\",\"1099774502834574451399947043208869188329872135932897351612210181871486714260\",\"1\"],\"b\":[[\"4095258550782358133185755302461547336434190495389756275789648565352453295275\",\"11290282088300413285686821769617771231670721476484846359206004074570380534935\"],[\"10130196410049440247754977520268298700433580296307256932070052957562923587210\",\"18578315450133100598244014262861961858129311260491371986249505812898194068790\"],[\"1\",\"0\"]],\"c\":[\"3621803486710965065098877836422521469652420656514094958857631583114966034063\",\"10775419351495516109888010278620848514990288696189982169937651175162131341248\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ANvhRMX5O/nI2vK41vefCaI8rqINbwU9s5unzwauoxcX\"}"; -pub const SUI_DATA_FROM_REACT_4: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Inh4VjZnc3RReGY2WW5Kb0QyMXMtZkNWdm9ESSIsIm5iZiI6MTcxNTY4NzAxNSwiaWF0IjoxNzE1Njg3MzE1LCJleHAiOjE3MTU2OTA5MTUsImp0aSI6ImQzOWJjMTUyOWVhODMwNTRiNGU0MDRlNDRhMmE4ZWRjOTJlZWFiYWYifQ.u23WQFEtc4TldMtNqrU7DiYdL33X2QySNxueCW79LQHc00P7g-Pu7xPX0XK_TLxP6ReZEdpdCmjfG6g--XBYXh313FKcqVhcrtKdBE06jf5acAf4fQ3TVzG5CFWqjISRhLL0eGjX20DZm8drrSFYTgfWPl9ANo6TV2IFF6BR9TOO_flxzmXPRVvER9ZA4QO52JCqagVYBw4bFZcUebiN_KXYuXOYWzUAiHM7lKUdVKoCte9JDKnTfRNg3r-i5tt5Oiovswwh9jubQd5c8nCQckQ8Fj9T5nPmlfPtF282kfd76xlHckvL94mM3HUKNuFrxeiFX07f_5Ff7NxvQ3QPgw\",\"userPassToIntFormat\":\"118102101104106\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":25,\"1\":68,\"2\":102,\"3\":77,\"4\":86,\"5\":118,\"6\":203,\"7\":106,\"8\":41,\"9\":192,\"10\":205,\"11\":144,\"12\":20,\"13\":158,\"14\":42,\"15\":167,\"16\":18,\"17\":30,\"18\":27,\"19\":103,\"20\":51,\"21\":222,\"22\":226,\"23\":224,\"24\":168,\"25\":111,\"26\":16,\"27\":214,\"28\":128,\"29\":165,\"30\":10,\"31\":183},\"secretKey\":{\"0\":204,\"1\":128,\"2\":233,\"3\":135,\"4\":233,\"5\":64,\"6\":127,\"7\":97,\"8\":231,\"9\":135,\"10\":123,\"11\":149,\"12\":126,\"13\":145,\"14\":173,\"15\":252,\"16\":33,\"17\":141,\"18\":251,\"19\":181,\"20\":223,\"21\":9,\"22\":77,\"23\":32,\"24\":19,\"25\":187,\"26\":3,\"27\":180,\"28\":110,\"29\":49,\"30\":114,\"31\":167,\"32\":25,\"33\":68,\"34\":102,\"35\":77,\"36\":86,\"37\":118,\"38\":203,\"39\":106,\"40\":41,\"41\":192,\"42\":205,\"43\":144,\"44\":20,\"45\":158,\"46\":42,\"47\":167,\"48\":18,\"49\":30,\"50\":27,\"51\":103,\"52\":51,\"53\":222,\"54\":226,\"55\":224,\"56\":168,\"57\":111,\"58\":16,\"59\":214,\"60\":128,\"61\":165,\"62\":10,\"63\":183}}},\"zkAddr\":\"0x9440174050c8a69f3736aade438d256444387d7f99afaf9b5a9f29c6f0fba0c3\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12337032776119704699956096862904448418119911526311506121881119564201699892276\",\"21261432927871679671381948020842646421823600661053961908567605147368225372658\",\"1\"],\"b\":[[\"361501104451650926380087094710685809078127996371826342961671838349546013669\",\"6224896865231367783073876006741593926823975323893517814398563485217838362592\"],[\"17991862631010087641911530148948529285385885925990265147692471125933697566220\",\"3919918348467391624469564417209140189505145619892305626999747602773689849635\"],[\"1\",\"0\"]],\"c\":[\"2974798412198231516644318932878285282801453498857240613838304706754188993145\",\"18411763423260631630440151338922210964792206590205572668118109635459867927504\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ABlEZk1WdstqKcDNkBSeKqcSHhtnM97i4KhvENaApQq3\"}"; -pub const SUI_DATA_FROM_REACT_5: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlZXM0VrSmp5ZXM0M2pvNENXU0FyU1pORHk5ayIsIm5iZiI6MTcxNTY4NzAwNywiaWF0IjoxNzE1Njg3MzA3LCJleHAiOjE3MTU2OTA5MDcsImp0aSI6IjMwNDczMjk0MmI3MDQzOTUzN2M3OTE4YTIyZDMxODA1YTVjYzkzZTYifQ.sa6ee8fcMhF3JgGQcl03IY0alries0KC7SRH-HVUnA5cqTVYomJ6fr0NTDJmYXNKOeIcaT85LLN0ALsKtEQdZjhu1g4m16kbS-5MybFIXT85JIPhBOz7zYldrbiy-Me8XRNWPkR3X_lV9pwqvYJTnZ0ley5dDITRvIXE1w2ZmjGNDlDxG3aM2XOQDICQ1ztsCZkn20ShuvG7tZHq7cp7K0hd6JdX0fFRY85eSIeapW7NnnWdvJi2xvuiCcwqm8sshldcJI5uU9xikhoN2WA7c8fJ5rtshqp5-RtTOfbzLn2a6m0WeDE0JqUd8jbh6_T8mGtYYeYMAWfWb-jVPa8aNg\",\"userPassToIntFormat\":\"118981041155255\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":76,\"1\":252,\"2\":245,\"3\":48,\"4\":8,\"5\":126,\"6\":211,\"7\":60,\"8\":249,\"9\":241,\"10\":111,\"11\":107,\"12\":148,\"13\":35,\"14\":224,\"15\":237,\"16\":179,\"17\":74,\"18\":84,\"19\":7,\"20\":130,\"21\":96,\"22\":198,\"23\":40,\"24\":23,\"25\":4,\"26\":50,\"27\":62,\"28\":191,\"29\":222,\"30\":119,\"31\":195},\"secretKey\":{\"0\":217,\"1\":194,\"2\":91,\"3\":84,\"4\":244,\"5\":214,\"6\":113,\"7\":57,\"8\":79,\"9\":43,\"10\":104,\"11\":85,\"12\":61,\"13\":225,\"14\":26,\"15\":139,\"16\":139,\"17\":206,\"18\":110,\"19\":48,\"20\":118,\"21\":99,\"22\":130,\"23\":122,\"24\":59,\"25\":6,\"26\":224,\"27\":144,\"28\":146,\"29\":25,\"30\":147,\"31\":225,\"32\":76,\"33\":252,\"34\":245,\"35\":48,\"36\":8,\"37\":126,\"38\":211,\"39\":60,\"40\":249,\"41\":241,\"42\":111,\"43\":107,\"44\":148,\"45\":35,\"46\":224,\"47\":237,\"48\":179,\"49\":74,\"50\":84,\"51\":7,\"52\":130,\"53\":96,\"54\":198,\"55\":40,\"56\":23,\"57\":4,\"58\":50,\"59\":62,\"60\":191,\"61\":222,\"62\":119,\"63\":195}}},\"zkAddr\":\"0x71444450505074fe9d9205f02747fb34f49dda22eb33eaf7929bb8561ffd45f2\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"4549343359411304649846201661164616647369749072820883051997393354186530425088\",\"3937997833930688873121017483900547354352969510911658484353113904856895725039\",\"1\"],\"b\":[[\"737118397015523176881783675037843258491735390512712007670938320351154476838\",\"18093386738096496776241258608856280732173952478987786488484944779094702670649\"],[\"17783469782238073070748856104623185946400565050372789961482242728023613389739\",\"15824649467012100671772283318060553156148444804907193757065241285355958322525\"],[\"1\",\"0\"]],\"c\":[\"15112690010634489290938122084488710379345235713605729023472643459768097669053\",\"21568492795931010980780236148561695295582527237009199544419907898465140630575\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AEz89TAIftM8+fFva5Qj4O2zSlQHgmDGKBcEMj6/3nfD\"}"; -pub const SUI_DATA_FROM_REACT_6: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjMySWx6VWJuSFY4MV9QTTBJSDBSZmFveVN1TSIsIm5iZiI6MTcxNTY4NzAwMCwiaWF0IjoxNzE1Njg3MzAwLCJleHAiOjE3MTU2OTA5MDAsImp0aSI6ImRhOTU5NmIwMTljOTQ2NWE4MzA0MWIxMDA3OTI2OGU3NDgwY2ZjMDkifQ.HFkMZFhHu6BGBbWhC1NwCvJ9_bKOL8jOdOHuRG21mKh-CaJPffnGtaVNcwEJjf4jOVVPPZNfcJPWOd7KoT_R2Giw7An2dUcJFvVJHUv4h55u4DinU50R7h7ACyEl5GwbKCI-cgxORbcoUdQRukDt1zJHe1eeWm1S8URlE2f4U0w2tPPaE_NmChIRyvU_CjB0dLwxzIWU74pvnbkLSSD2pTWhGbLT1yNhfMTh6yukLyEt2kWvNdZOgGbDfIU6xFjxJLtnPrm5WGiOiWyBmMuDput47-ns4821l3KogdIbWr6TLWW0PMwyJuHnif5pV7wJI9JL5XdFv8KZ0IReAYOIEg\",\"userPassToIntFormat\":\"1021035256\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":169,\"1\":238,\"2\":219,\"3\":251,\"4\":231,\"5\":87,\"6\":175,\"7\":233,\"8\":185,\"9\":44,\"10\":161,\"11\":207,\"12\":48,\"13\":166,\"14\":79,\"15\":104,\"16\":225,\"17\":53,\"18\":68,\"19\":236,\"20\":49,\"21\":204,\"22\":99,\"23\":208,\"24\":2,\"25\":134,\"26\":101,\"27\":212,\"28\":221,\"29\":142,\"30\":69,\"31\":196},\"secretKey\":{\"0\":94,\"1\":128,\"2\":26,\"3\":130,\"4\":137,\"5\":40,\"6\":61,\"7\":27,\"8\":79,\"9\":58,\"10\":100,\"11\":117,\"12\":200,\"13\":118,\"14\":156,\"15\":202,\"16\":165,\"17\":34,\"18\":238,\"19\":237,\"20\":90,\"21\":63,\"22\":84,\"23\":119,\"24\":86,\"25\":2,\"26\":221,\"27\":177,\"28\":224,\"29\":4,\"30\":233,\"31\":99,\"32\":169,\"33\":238,\"34\":219,\"35\":251,\"36\":231,\"37\":87,\"38\":175,\"39\":233,\"40\":185,\"41\":44,\"42\":161,\"43\":207,\"44\":48,\"45\":166,\"46\":79,\"47\":104,\"48\":225,\"49\":53,\"50\":68,\"51\":236,\"52\":49,\"53\":204,\"54\":99,\"55\":208,\"56\":2,\"57\":134,\"58\":101,\"59\":212,\"60\":221,\"61\":142,\"62\":69,\"63\":196}}},\"zkAddr\":\"0xb1dfac568641e785f1fbd385f43f9ab5751f30e942ffd0618ea3cacf2feb884f\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12140334820013650239749561964826061158522594132954339836339110630367427672527\",\"21543355833919541708094668850466443067263177907229807762067953508321817783804\",\"1\"],\"b\":[[\"11929519532343982399968491980281874410531815035766070083344475081372092452425\",\"13741260533480647813301201467326069876472210148610447598292633272004546481630\"],[\"14605296808789442404291984821803068302067977919075239981788942874792752578522\",\"20230214791286972912596895174545361255719543417377972941442631629070781210055\"],[\"1\",\"0\"]],\"c\":[\"6046227686259383004231849145260526357580306829730644608118177932582255490991\",\"1343314209137088066016224766407952045954639818725548553059063245802388749310\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AKnu2/vnV6/puSyhzzCmT2jhNUTsMcxj0AKGZdTdjkXE\"}"; -pub const SUI_DATA_FROM_REACT_7: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjhJNGF5NDF5THpHWnk4czNCUGR3QzItR2Q5ayIsIm5iZiI6MTcxNTY4Njk5MywiaWF0IjoxNzE1Njg3MjkzLCJleHAiOjE3MTU2OTA4OTMsImp0aSI6ImFjYmJiNmQ3NGY0ZmU3MjMxYzc2ZDQxNzE0ZDM4NDJiNzZlNDU4YzIifQ.nsmqj7tDDv7wJSn47YfaFBXabPYVBjZosGzH_bPHZZToPfvdQyXZrO5CXbaJmojxTPRmzZ2bPI39K9GMX7Y8gaOqk_LYHR7eemVaEj0wNpPPtmUFmHmyrL8nPkTN0a-87L2eu6t7yBZtEiT5e2Jz46RBu9rQL138seOvK3vm0YwhtnLGxhZQnoAKu076qZ_ItlsRn9PqM-sd83bqQoG_SPQVCZL6spWoFunXtj1FeKE-3gRRD8BopORDhFp4xytWDamd1XgIdCNp0a8u7mvElPZCjc3ZUAtFYBWwvfI9r2wN5X4gbNe_pbfpBmgg-2zxwt6c32IhNXlrDQkLxJYqkg\",\"userPassToIntFormat\":\"9899115100106104\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":35,\"1\":64,\"2\":69,\"3\":29,\"4\":242,\"5\":9,\"6\":183,\"7\":224,\"8\":98,\"9\":254,\"10\":210,\"11\":82,\"12\":213,\"13\":2,\"14\":137,\"15\":66,\"16\":71,\"17\":61,\"18\":80,\"19\":154,\"20\":135,\"21\":100,\"22\":176,\"23\":189,\"24\":187,\"25\":96,\"26\":245,\"27\":194,\"28\":163,\"29\":250,\"30\":15,\"31\":37},\"secretKey\":{\"0\":117,\"1\":94,\"2\":35,\"3\":85,\"4\":116,\"5\":80,\"6\":126,\"7\":55,\"8\":166,\"9\":193,\"10\":94,\"11\":109,\"12\":238,\"13\":86,\"14\":132,\"15\":192,\"16\":225,\"17\":240,\"18\":26,\"19\":65,\"20\":211,\"21\":18,\"22\":195,\"23\":36,\"24\":225,\"25\":158,\"26\":143,\"27\":141,\"28\":21,\"29\":174,\"30\":139,\"31\":13,\"32\":35,\"33\":64,\"34\":69,\"35\":29,\"36\":242,\"37\":9,\"38\":183,\"39\":224,\"40\":98,\"41\":254,\"42\":210,\"43\":82,\"44\":213,\"45\":2,\"46\":137,\"47\":66,\"48\":71,\"49\":61,\"50\":80,\"51\":154,\"52\":135,\"53\":100,\"54\":176,\"55\":189,\"56\":187,\"57\":96,\"58\":245,\"59\":194,\"60\":163,\"61\":250,\"62\":15,\"63\":37}}},\"zkAddr\":\"0x2130548addf21464dba0598e4306193fc658433793260241bd224fa5a186eea1\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"11563763779979887221682129962776185026792805331576343366100386476995832665737\",\"11230623338801856741023013148077980370341441565413488652841279984753971030674\",\"1\"],\"b\":[[\"459996434316864652818633810305056376561329097756558823429320916262609240883\",\"9149790799426074072032368390512074348954812141386022619414187192076850710684\"],[\"21136831034524197906636931934376551157061262869485003235799208746070603082410\",\"7423352680736750974836973800304252036668418183885087029886854244313632685127\"],[\"1\",\"0\"]],\"c\":[\"13616579662900237409901679872544397096722160915603059752960265571802149963290\",\"17724386432768174493966206493099783171212386514205046762827409640509581679264\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ACNARR3yCbfgYv7SUtUCiUJHPVCah2Swvbtg9cKj+g8l\"}"; -pub const SUI_DATA_FROM_REACT_8: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjlzWGhqc0xVZlNmdE12bl9iYmQtWkEwZnY5OCIsIm5iZiI6MTcxNTY4Njk4NiwiaWF0IjoxNzE1Njg3Mjg2LCJleHAiOjE3MTU2OTA4ODYsImp0aSI6IjhiNDUzYjUzNTY4MGU3OWZkZWUyOGE3NDVmMzgzMDBkMmNmYjNmODQifQ.a2fpzvW0PxyOcvE8P6WEtIs_mdfTQ9kJb4MIUC5T5uRYJ9ySqSa2qT-MICspGYBuNzCtWIvI6KHY9cIWE2XF3yv7d7gTk_IkhXJud0s5hMhsIxWuNXla_-HducNufaXxXxWYJ2g8dy2xsIMnPr5OC-r4dAX3DM3AchB8qA-RYJdtgwlLytyANp6I35BRT7ewXyDDdlqMLnz5dv4xh1y1wrXFL7VDyzV2XVTK3ap12Cev9IZtHnSGsDgl-vEXj1OYIyiaDgtDhA7rfLXWRTQEeVnRpF-v3AIwZmRu1qaXFoqUbMaSQpFotwb6m8fMQ1q9efOK1Xrv8dL3jBDcUA3w3w\",\"userPassToIntFormat\":\"98118115106\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":52,\"1\":224,\"2\":199,\"3\":19,\"4\":180,\"5\":128,\"6\":181,\"7\":171,\"8\":55,\"9\":210,\"10\":168,\"11\":100,\"12\":198,\"13\":241,\"14\":150,\"15\":156,\"16\":226,\"17\":233,\"18\":32,\"19\":175,\"20\":153,\"21\":53,\"22\":23,\"23\":58,\"24\":196,\"25\":29,\"26\":16,\"27\":170,\"28\":245,\"29\":46,\"30\":71,\"31\":177},\"secretKey\":{\"0\":47,\"1\":184,\"2\":41,\"3\":167,\"4\":98,\"5\":225,\"6\":50,\"7\":146,\"8\":173,\"9\":129,\"10\":201,\"11\":41,\"12\":181,\"13\":239,\"14\":8,\"15\":249,\"16\":159,\"17\":200,\"18\":159,\"19\":80,\"20\":194,\"21\":79,\"22\":41,\"23\":26,\"24\":200,\"25\":82,\"26\":74,\"27\":200,\"28\":38,\"29\":172,\"30\":84,\"31\":187,\"32\":52,\"33\":224,\"34\":199,\"35\":19,\"36\":180,\"37\":128,\"38\":181,\"39\":171,\"40\":55,\"41\":210,\"42\":168,\"43\":100,\"44\":198,\"45\":241,\"46\":150,\"47\":156,\"48\":226,\"49\":233,\"50\":32,\"51\":175,\"52\":153,\"53\":53,\"54\":23,\"55\":58,\"56\":196,\"57\":29,\"58\":16,\"59\":170,\"60\":245,\"61\":46,\"62\":71,\"63\":177}}},\"zkAddr\":\"0xd704fd1fa5b1d8603b91081d104c08a025e9a952cd6b5b44324fcca2ed432737\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"12104554633236481277286668189930576438264898269322388260846346074721767290773\",\"12396613925509861793005815245783240999567113519994130032649036118285018908597\",\"1\"],\"b\":[[\"1950992742588131071369658940220202257834946772534232957497529743913085624908\",\"13592611568444679350754388983552527571019415309901710535712414143531288069409\"],[\"16680699225604481493782973126773355417557338915104879244979908308676269902149\",\"7242446539394843603528008588061352122030003516933411896066602483137632866329\"],[\"1\",\"0\"]],\"c\":[\"17095909781059243761149234557016161052123209525874162987135833613569429453315\",\"8531296608559822287633863219696197152375138627859243631029781182381653695377\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"ADTgxxO0gLWrN9KoZMbxlpzi6SCvmTUXOsQdEKr1Lkex\"}"; -pub const SUI_DATA_FROM_REACT_9: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImRLMlRMdjktRXFnaGR3SWQzMzlPNXZmN1JENCIsIm5iZiI6MTcxNTY4Njk3OSwiaWF0IjoxNzE1Njg3Mjc5LCJleHAiOjE3MTU2OTA4NzksImp0aSI6IjQxYTgwZTI3N2U5NzIxYjcwZDkyMjRkMWY5MzRlNjJhYTYwNzcyZGEifQ.NLM6YIR61HOzlEVS1ianwnFoG6OfSeLyuGpjH-Wt7eiWt27fHbDhOWTo-2ysx7cXuAl3gV8ZzMta24QSpjIiiaooGdurX92cWuDcARyewX5_4UuwBWBTXe66irHuqjwIOB2WwyN6PuOwvM6Y_IcL9vPwg76iJoupbeCHXBswiRVzVyBQus1k9SGigU8_ZuwGYoTLPd68MX7Z68NrK7mCF04Xaijs__zwJigIhVOK3TXN2Xy84Ha76mrXJRJZuWErrSNWagVO-dxb2oMT8vm5ND9aJ4q4NaIeGa8PIN2X1cfg9A6LZVBsGIc9JV2FG39yK4T2XAH6tn_HtoMzy_Vuvg\",\"userPassToIntFormat\":\"10011898115106104\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":78,\"1\":247,\"2\":200,\"3\":7,\"4\":84,\"5\":131,\"6\":33,\"7\":223,\"8\":6,\"9\":241,\"10\":100,\"11\":90,\"12\":91,\"13\":2,\"14\":31,\"15\":23,\"16\":138,\"17\":130,\"18\":115,\"19\":150,\"20\":202,\"21\":79,\"22\":12,\"23\":132,\"24\":168,\"25\":153,\"26\":155,\"27\":131,\"28\":31,\"29\":69,\"30\":170,\"31\":112},\"secretKey\":{\"0\":98,\"1\":144,\"2\":57,\"3\":245,\"4\":40,\"5\":191,\"6\":248,\"7\":149,\"8\":147,\"9\":12,\"10\":229,\"11\":76,\"12\":157,\"13\":3,\"14\":241,\"15\":94,\"16\":134,\"17\":124,\"18\":226,\"19\":177,\"20\":31,\"21\":140,\"22\":224,\"23\":58,\"24\":57,\"25\":95,\"26\":235,\"27\":246,\"28\":120,\"29\":89,\"30\":33,\"31\":149,\"32\":78,\"33\":247,\"34\":200,\"35\":7,\"36\":84,\"37\":131,\"38\":33,\"39\":223,\"40\":6,\"41\":241,\"42\":100,\"43\":90,\"44\":91,\"45\":2,\"46\":31,\"47\":23,\"48\":138,\"49\":130,\"50\":115,\"51\":150,\"52\":202,\"53\":79,\"54\":12,\"55\":132,\"56\":168,\"57\":153,\"58\":155,\"59\":131,\"60\":31,\"61\":69,\"62\":170,\"63\":112}}},\"zkAddr\":\"0x4493e2aab6fcd5d7259e066291ed6f42f6e0b732ecbd38bbaf8a98546a7d0cba\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"6187760498712900389422022394560825973187662358740291343829568808375698843239\",\"3663904360488418820404220406786944885702547623862334490191838865255632801941\",\"1\"],\"b\":[[\"17208058907245387104889127891010282196539728213379257608213444054211064433036\",\"9822512703540345824827246410723992174766686970531763618190197664729418117984\"],[\"9555481236549941306688205540885297760448987185399187813240300069134845655152\",\"17967781633941820778916846359708064205041390458485667635199415296702341964940\"],[\"1\",\"0\"]],\"c\":[\"12374452924342055287727719327288397498526425907741014437332085255604038084453\",\"7084903967634108603521121616612807600817728267672878238097194166039392876060\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AE73yAdUgyHfBvFkWlsCHxeKgnOWyk8MhKiZm4MfRapw\"}"; -pub const SUI_DATA_FROM_REACT_10: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZjdk1UaEZFdjFzVTBGVGR1M3Z5TmxlVUd0MCIsIm5iZiI6MTcxNTY4Njk3MiwiaWF0IjoxNzE1Njg3MjcyLCJleHAiOjE3MTU2OTA4NzIsImp0aSI6ImFiMDMwNTMzZjQyOWJmOGFhMDNmYzZhYjAxZjg2MGQ3MTg5ZDBlNjkifQ.f11q7mTu1uScsGvj4-KgVHHEhfAqk53JbAIC0PT8-CU40D4fSWbBoyXrUUQw6zly4KsyqazAFJ_1JqjiFvYFOhCAsoGWpgiA-hnL4QK-uxqUV4ule7Wt9xs8QVPivYxTrK2jmDgPGosvTUmlrGeyZk2XwilO3mbTe5wN-zMkUF0zUTdlIBTPrKbXMS1PklWTjUgDa1bXb-hOaFILkfZ4UgQI3PYHjZul3Rm_UUHHHVRkLgt0M449CGjuKSsIFvVkslfL319_71DLo7W0sYkJkWGOa482vTvyHgR9SjalUPV4TzPhpe_6DZZlKna7MXgq4FWOS9710PC6_HAXF2n-ag\",\"userPassToIntFormat\":\"11898100104102106115\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":146,\"1\":239,\"2\":26,\"3\":188,\"4\":228,\"5\":23,\"6\":17,\"7\":118,\"8\":183,\"9\":248,\"10\":93,\"11\":219,\"12\":0,\"13\":213,\"14\":164,\"15\":161,\"16\":140,\"17\":200,\"18\":97,\"19\":183,\"20\":135,\"21\":18,\"22\":103,\"23\":137,\"24\":234,\"25\":122,\"26\":246,\"27\":20,\"28\":155,\"29\":72,\"30\":212,\"31\":15},\"secretKey\":{\"0\":107,\"1\":202,\"2\":67,\"3\":226,\"4\":108,\"5\":41,\"6\":149,\"7\":181,\"8\":238,\"9\":3,\"10\":97,\"11\":189,\"12\":216,\"13\":94,\"14\":143,\"15\":210,\"16\":192,\"17\":213,\"18\":224,\"19\":200,\"20\":253,\"21\":67,\"22\":168,\"23\":88,\"24\":140,\"25\":106,\"26\":235,\"27\":247,\"28\":54,\"29\":146,\"30\":251,\"31\":123,\"32\":146,\"33\":239,\"34\":26,\"35\":188,\"36\":228,\"37\":23,\"38\":17,\"39\":118,\"40\":183,\"41\":248,\"42\":93,\"43\":219,\"44\":0,\"45\":213,\"46\":164,\"47\":161,\"48\":140,\"49\":200,\"50\":97,\"51\":183,\"52\":135,\"53\":18,\"54\":103,\"55\":137,\"56\":234,\"57\":122,\"58\":246,\"59\":20,\"60\":155,\"61\":72,\"62\":212,\"63\":15}}},\"zkAddr\":\"0xb86a18deea59af2850ab3800e2d46f63cfbea3bae309359089945d55949aef84\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"2575938484642353074459611431508941853614856803645537593538048270397701877180\",\"18525747234426619072147704335372433454079655655225636793928970068265541595508\",\"1\"],\"b\":[[\"5146896444986257903458872614168031344366471557324420746422302593221564486610\",\"19134791144810013840937258347062701987554745426617919650818846823708095832550\"],[\"3133101512761334334340993079649721452024653991833325456466256722050883608250\",\"21877263483512108853787895465249721341909931993800128255134630466114688578666\"],[\"1\",\"0\"]],\"c\":[\"3069457366306376197755607218741517434199413283376424243014529567457206056402\",\"4929625283757609606431630951067242799347282963225969540629139985267066740824\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJLvGrzkFxF2t/hd2wDVpKGMyGG3hxJniep69hSbSNQP\"}"; -pub const SUI_DATA_FROM_REACT_11: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkJ4RzlwNFhoV1B4WEt3NVRRdG9FbDljZzI5NCIsIm5iZiI6MTcxNTY4Njk0MSwiaWF0IjoxNzE1Njg3MjQxLCJleHAiOjE3MTU2OTA4NDEsImp0aSI6IjMyYmMxN2VjNWY3ZTQ5ZWRkOTM2MzVkZjE5MDk2N2E3NTg5Y2ZmNTgifQ.w3cT9MVhKTvnmAlmKClFFG6hjB2zrwHonYuN6l5S2unwyR6P_tGE42KhaFSNCY-imysy8k42awfmAafXwftKClLvqzk1T6bi5Li6caVd6-la8wj_FxNWkE5Cy-N4grOiEYJtV5SZezFzifmL6LOstv-Nc4X2b9Z6utuGOWYq3W9LNPveD0v5GnBCR6JRtHJkI6e5yZnMwDDE5o1P-LZbGuFXP75P6jseGem956the_WbrwIsnnTdFgjgjbXn_1gkh4SYGQ1ig0NVKcs75hUhKuQi7V6VqycuyXTgACOCsIfh2guoKha-APZUeul3z33zNbsqUcgkWwl6CkvDSdGWiQ\",\"userPassToIntFormat\":\"1145652515748\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":153,\"1\":152,\"2\":146,\"3\":133,\"4\":135,\"5\":137,\"6\":8,\"7\":27,\"8\":197,\"9\":109,\"10\":12,\"11\":221,\"12\":49,\"13\":15,\"14\":10,\"15\":1,\"16\":64,\"17\":236,\"18\":222,\"19\":97,\"20\":181,\"21\":214,\"22\":200,\"23\":214,\"24\":130,\"25\":247,\"26\":204,\"27\":212,\"28\":49,\"29\":33,\"30\":169,\"31\":172},\"secretKey\":{\"0\":159,\"1\":96,\"2\":35,\"3\":206,\"4\":32,\"5\":121,\"6\":5,\"7\":32,\"8\":37,\"9\":203,\"10\":15,\"11\":252,\"12\":99,\"13\":107,\"14\":57,\"15\":211,\"16\":139,\"17\":123,\"18\":6,\"19\":233,\"20\":56,\"21\":15,\"22\":35,\"23\":224,\"24\":243,\"25\":148,\"26\":44,\"27\":114,\"28\":112,\"29\":161,\"30\":226,\"31\":255,\"32\":153,\"33\":152,\"34\":146,\"35\":133,\"36\":135,\"37\":137,\"38\":8,\"39\":27,\"40\":197,\"41\":109,\"42\":12,\"43\":221,\"44\":49,\"45\":15,\"46\":10,\"47\":1,\"48\":64,\"49\":236,\"50\":222,\"51\":97,\"52\":181,\"53\":214,\"54\":200,\"55\":214,\"56\":130,\"57\":247,\"58\":204,\"59\":212,\"60\":49,\"61\":33,\"62\":169,\"63\":172}}},\"zkAddr\":\"0x41c25944949f0e3bf80fea41d9ab27acfa26e0b25ecd7e468235b2284e5b0c09\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"10607121052143170357142710430122120898934487918266599021712929788471219763472\",\"13359690919698524885136984693561112109891470903700041135375248695741012306373\",\"1\"],\"b\":[[\"3247989990207989646120856507929936403874972366284220250880918537588838028173\",\"20347831818628957019286012207626379731554938194907710010892594024137236752987\"],[\"18217798786390957788883983024823206348636485136705276787854998111125834676541\",\"11824109578691812603938426242725149605448845948255194504928078330266973720614\"],[\"1\",\"0\"]],\"c\":[\"16499583001208064509247079494271177710897656329498349773613236383353749984739\",\"1944718879141050229961827816471755841829876012643055740792265283564642185697\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AJmYkoWHiQgbxW0M3TEPCgFA7N5htdbI1oL3zNQxIams\"}"; -pub const SUI_DATA_FROM_REACT_12: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IndNcWhEa3BxQllkSlowQVBwXzUtbVZDLUU2OCIsIm5iZiI6MTcxNTY4NjkzMywiaWF0IjoxNzE1Njg3MjMzLCJleHAiOjE3MTU2OTA4MzMsImp0aSI6IjEwNGRhZTE1ZWMwODRjODU3MzBjYTRiZGI1MThiZTkwZDdkMTQ3NmEifQ.KBzhI2UOTstRFpgkZiFFlCmhy-E0PwoWdfWhXem6Kr0HjOgCfr-a5TGVRyMf0b7-Tnf712tMPf4N7-uPSoyaBsmtiYmAudj8whha2obUVhzWjghiURrbYkiCBWys5Z4v3SnVKDqXPsUFmNucBSA3l6DIWbhLT4WqTszGY-Qc_cKhR-7y5i3t90lhGNmwrvCR72jAXaF-xbBvsaiMXxhfCS5fnMFNRibIE3tRx1r3mkx59etA8E3xQAu8LPzFyC0ecEKL0K6a5ZWNWBFPbGSzAhSK9D3ak1gzON6rhccCPpLRErk2MIhUQq4HBnOywg5Lf1w0onxhkJtU6docO2VVAA\",\"userPassToIntFormat\":\"11099104102117\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":173,\"1\":37,\"2\":48,\"3\":14,\"4\":54,\"5\":38,\"6\":225,\"7\":52,\"8\":254,\"9\":178,\"10\":32,\"11\":56,\"12\":162,\"13\":128,\"14\":135,\"15\":55,\"16\":10,\"17\":222,\"18\":131,\"19\":175,\"20\":166,\"21\":161,\"22\":145,\"23\":219,\"24\":44,\"25\":231,\"26\":183,\"27\":245,\"28\":141,\"29\":178,\"30\":237,\"31\":92},\"secretKey\":{\"0\":108,\"1\":38,\"2\":149,\"3\":222,\"4\":132,\"5\":184,\"6\":128,\"7\":164,\"8\":27,\"9\":101,\"10\":217,\"11\":92,\"12\":24,\"13\":245,\"14\":209,\"15\":31,\"16\":88,\"17\":174,\"18\":237,\"19\":144,\"20\":78,\"21\":127,\"22\":73,\"23\":195,\"24\":194,\"25\":229,\"26\":208,\"27\":176,\"28\":220,\"29\":60,\"30\":229,\"31\":253,\"32\":173,\"33\":37,\"34\":48,\"35\":14,\"36\":54,\"37\":38,\"38\":225,\"39\":52,\"40\":254,\"41\":178,\"42\":32,\"43\":56,\"44\":162,\"45\":128,\"46\":135,\"47\":55,\"48\":10,\"49\":222,\"50\":131,\"51\":175,\"52\":166,\"53\":161,\"54\":145,\"55\":219,\"56\":44,\"57\":231,\"58\":183,\"59\":245,\"60\":141,\"61\":178,\"62\":237,\"63\":92}}},\"zkAddr\":\"0xe5433ade6e56883e0cc13044783fc6e0d835db866e8ef69d305622f4dbfd7730\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"20315021530892971959830664693110327999639349964485536174303351139810441711270\",\"9363226245552972448215999928614529638129956136095863617353608229521342156596\",\"1\"],\"b\":[[\"13215029653817105228530429395766730210769586389024965762310641194113200165202\",\"7799676398333409903573594921069872917500921399080042730183754684502821618481\"],[\"13048821293399627652827197503115267831066766008561767009809325017447715880491\",\"331361016081752781071859245948286166830568341165278760117629920699739892753\"],[\"1\",\"0\"]],\"c\":[\"7347702391542317289078324477957712035210582056186479239076715504548941012834\",\"795883936884678581860170407596096541519605830081875833581950897247827301651\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AK0lMA42JuE0/rIgOKKAhzcK3oOvpqGR2yznt/WNsu1c\"}"; -pub const SUI_DATA_FROM_REACT_13: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjVqNVBySXFpYW9xaUNFWkR0eklNazY2MUotRSIsIm5iZiI6MTcxNTY4NjkyNCwiaWF0IjoxNzE1Njg3MjI0LCJleHAiOjE3MTU2OTA4MjQsImp0aSI6IjJmYzk0MmM1MDBiMmJmNGE5YzZiZjUwN2Y0MjU4NTg3MGM4YmQ5N2QifQ.GU70HImKkqZyGmWAC_onzc-ccUhALeT7ebQ0LrE0QGqjCZyCnonjOeDhatB4Q1GQCVQ-KPWKCdg4NNPCPvKwLYAjwNF0sorwS5h6jKKVvRgT_t12dbDzrPKJE7xW0_0kfmfj7lKGZp_W4HNVxd_hlPiwJb56X0ZVkt3pwpkwBe8MU-Nzb3QyrJtDRJDDb4v_bVdOJSyUNEtssFvAgFB4diGI_GFQzZpbQnBeciST-lS7rGHpItnlwe0mRNf3e34S7A7wUOo_YTvy-TKTViSekMdkMKt9hgGkti9c4dYwI8NMExe4wtnLFVOh6XZ0FtrdnVGrYZFMWTJjNGizUmFMZQ\",\"userPassToIntFormat\":\"525451555057114102\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":221,\"1\":11,\"2\":223,\"3\":171,\"4\":2,\"5\":140,\"6\":112,\"7\":100,\"8\":233,\"9\":182,\"10\":68,\"11\":219,\"12\":126,\"13\":215,\"14\":96,\"15\":164,\"16\":201,\"17\":227,\"18\":132,\"19\":169,\"20\":157,\"21\":120,\"22\":187,\"23\":16,\"24\":40,\"25\":208,\"26\":174,\"27\":209,\"28\":89,\"29\":163,\"30\":255,\"31\":62},\"secretKey\":{\"0\":5,\"1\":6,\"2\":91,\"3\":164,\"4\":51,\"5\":203,\"6\":161,\"7\":246,\"8\":61,\"9\":156,\"10\":92,\"11\":96,\"12\":69,\"13\":141,\"14\":93,\"15\":73,\"16\":208,\"17\":85,\"18\":37,\"19\":52,\"20\":167,\"21\":121,\"22\":63,\"23\":221,\"24\":215,\"25\":165,\"26\":48,\"27\":232,\"28\":136,\"29\":10,\"30\":71,\"31\":92,\"32\":221,\"33\":11,\"34\":223,\"35\":171,\"36\":2,\"37\":140,\"38\":112,\"39\":100,\"40\":233,\"41\":182,\"42\":68,\"43\":219,\"44\":126,\"45\":215,\"46\":96,\"47\":164,\"48\":201,\"49\":227,\"50\":132,\"51\":169,\"52\":157,\"53\":120,\"54\":187,\"55\":16,\"56\":40,\"57\":208,\"58\":174,\"59\":209,\"60\":89,\"61\":163,\"62\":255,\"63\":62}}},\"zkAddr\":\"0x0934ba96e39b32a66b83afdd089d9534b91336d0c72324acb72b718e2d8adcd8\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"3292113297742390468701372446942400025026948502434627571571387058022780524172\",\"4608365882159831859997420943605862565647863626478617897572911626264555729258\",\"1\"],\"b\":[[\"5662407938030293510048180382159430467791189346676904212329490391470516566946\",\"14655907382794614210872210515582570998106075620115645016125280695488094003217\"],[\"3337061425406207163991320131711738442766654603337106758166291266688030689117\",\"4469383376673348053098454774700074508703514397281065469277327859575940584146\"],[\"1\",\"0\"]],\"c\":[\"6592007510647447256322156763481821378802835999285873915184749854236303252416\",\"16208563039085392733361585085996378606127672981771155339865393880548209917912\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AN0L36sCjHBk6bZE237XYKTJ44SpnXi7ECjQrtFZo/8+\"}"; -pub const SUI_DATA_FROM_REACT_14: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjN6eHc2SUFERzVXcjJDR244SGczS1Q3Nm1qOCIsIm5iZiI6MTcxNTY4NjkwNSwiaWF0IjoxNzE1Njg3MjA1LCJleHAiOjE3MTU2OTA4MDUsImp0aSI6IjNkOTM4NmFlODMxZDVhYjdiZTI1NjcxMDhmZjhkMTM1N2YzNDZjOTUifQ.R3s_OfTiDlMMSFsEfp4xM6rLoJ99GALalEE1TVG8aneruEWuI1qxz241YmX9r9-49t1ja5BfO0eh3Fu_p6lg1O32sNSLR626Mvrv1Ph60syPQN01Tam4RCV_YBK3b2Pj-rWeJq3WSCGQg2rab2QyHy3Al9VPdXlkbaaH69QzRSXFyNojixgo92cPhABxbAxI1a5pYmzwwfkDDO0FY5uRUt3w4wuBhx9gQ6g_kboF03pIzQ5kvGUYBPGax66faTzulAGdTADmU9xgG6denQoZWn3Lh6dfdQX8KXkn9jVY8gMIY_rbobc8nkIMmslsjjio7BXb90-YD_WJT5so5Cre3A\",\"userPassToIntFormat\":\"1031021041155552\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":97,\"1\":100,\"2\":35,\"3\":169,\"4\":212,\"5\":9,\"6\":238,\"7\":108,\"8\":186,\"9\":80,\"10\":106,\"11\":26,\"12\":209,\"13\":87,\"14\":84,\"15\":117,\"16\":235,\"17\":25,\"18\":81,\"19\":248,\"20\":137,\"21\":197,\"22\":146,\"23\":139,\"24\":214,\"25\":127,\"26\":143,\"27\":179,\"28\":137,\"29\":79,\"30\":181,\"31\":216},\"secretKey\":{\"0\":70,\"1\":76,\"2\":130,\"3\":97,\"4\":75,\"5\":0,\"6\":7,\"7\":122,\"8\":166,\"9\":56,\"10\":85,\"11\":179,\"12\":143,\"13\":55,\"14\":136,\"15\":47,\"16\":75,\"17\":211,\"18\":125,\"19\":145,\"20\":130,\"21\":206,\"22\":118,\"23\":212,\"24\":87,\"25\":200,\"26\":130,\"27\":38,\"28\":65,\"29\":93,\"30\":37,\"31\":44,\"32\":97,\"33\":100,\"34\":35,\"35\":169,\"36\":212,\"37\":9,\"38\":238,\"39\":108,\"40\":186,\"41\":80,\"42\":106,\"43\":26,\"44\":209,\"45\":87,\"46\":84,\"47\":117,\"48\":235,\"49\":25,\"50\":81,\"51\":248,\"52\":137,\"53\":197,\"54\":146,\"55\":139,\"56\":214,\"57\":127,\"58\":143,\"59\":179,\"60\":137,\"61\":79,\"62\":181,\"63\":216}}},\"zkAddr\":\"0x87b9236aadcbc8de1a2bce17bb104cbae2f8c955f89808ee2d258cf2bc1cce1f\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"18415333747085688267133796133445868671450647215619171648016630248725573444572\",\"13021999644739913954648136527237689315935942107782566659768353668730521796833\",\"1\"],\"b\":[[\"10379715945772584677584721710592153467187645980157575584584703890180885281296\",\"21114541349211062821701871386552875726196087055162878583823021987759476907947\"],[\"21741245524391086016724288544952241247835975701957615054057894483829435111137\",\"19675246006347690391662817422022652459552259504790883596539945355325572896761\"],[\"1\",\"0\"]],\"c\":[\"6388980351498388564470364481867721519510272532387680761911853865824806443040\",\"2927953057998420964296253396822428516251336255094433794401337892358172944522\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AGFkI6nUCe5sulBqGtFXVHXrGVH4icWSi9Z/j7OJT7XY\"}"; -pub const SUI_DATA_FROM_REACT_15: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjRtbk1TajFjTmdlSUU4Unk3Z2dBOWNRVWRLSSIsIm5iZiI6MTcxNTY4Njg3MywiaWF0IjoxNzE1Njg3MTczLCJleHAiOjE3MTU2OTA3NzMsImp0aSI6ImVmYzU3YjVmMGEzZmEwZGI2ZTQzNWFhZjI4OTEwNjY2YjM0NWViNmEifQ.YRFPl_szPP8iBid__ACAj4Etr4YDZEmeawFTas_MFw7rR_sD_tQ268F2g9O4VOU3VWSWT-LCG1gp_NdRVvb5SFBzuMIYp4YrUEvzJdaO_ab1a2Xp_EVVEmjMwNHVpnFZjS9El0e0oOmaw_PQgC2soauJkfLvRhayx-_Vps7htHm94PW1aHBOxwr2HpR58mjzT4JyutyiioCLgLqhnvGW4N6CBlx6iLNfITk0wwsAOHRcdjW_hk0hHarjMy3U2VdbcPkmq1OIg8ZDQo2jbUGEWevUC6zrGeNWYjp38f3Wo1NUqf7_ne0YeJEBtyK5r9BuDxdr6YRyUXKnpxJpr9cZ-Q\",\"userPassToIntFormat\":\"5256515057\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":226,\"1\":91,\"2\":63,\"3\":50,\"4\":152,\"5\":120,\"6\":233,\"7\":249,\"8\":177,\"9\":205,\"10\":1,\"11\":233,\"12\":153,\"13\":199,\"14\":101,\"15\":124,\"16\":112,\"17\":15,\"18\":160,\"19\":228,\"20\":124,\"21\":169,\"22\":57,\"23\":196,\"24\":118,\"25\":117,\"26\":94,\"27\":132,\"28\":228,\"29\":108,\"30\":145,\"31\":117},\"secretKey\":{\"0\":168,\"1\":100,\"2\":5,\"3\":144,\"4\":15,\"5\":220,\"6\":219,\"7\":42,\"8\":52,\"9\":1,\"10\":7,\"11\":203,\"12\":43,\"13\":71,\"14\":99,\"15\":90,\"16\":8,\"17\":66,\"18\":137,\"19\":155,\"20\":200,\"21\":27,\"22\":69,\"23\":112,\"24\":209,\"25\":173,\"26\":109,\"27\":93,\"28\":152,\"29\":210,\"30\":96,\"31\":194,\"32\":226,\"33\":91,\"34\":63,\"35\":50,\"36\":152,\"37\":120,\"38\":233,\"39\":249,\"40\":177,\"41\":205,\"42\":1,\"43\":233,\"44\":153,\"45\":199,\"46\":101,\"47\":124,\"48\":112,\"49\":15,\"50\":160,\"51\":228,\"52\":124,\"53\":169,\"54\":57,\"55\":196,\"56\":118,\"57\":117,\"58\":94,\"59\":132,\"60\":228,\"61\":108,\"62\":145,\"63\":117}}},\"zkAddr\":\"0xc2e01f23756fd4fc3e8ee98f96751729c911acc1b8abc4e5d8f732a0b6a69602\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"6734924940747627006546678824977458478287976951246203795880487352562116664933\",\"14763323532227801517600705873776227782564830701170466315373208681644431001874\",\"1\"],\"b\":[[\"19846719805329609703868726781640931109590522837532762309497922458996335263239\",\"15420764526732603133646176483042915906318651960194518136943858294265541434918\"],[\"3657954841783806502381750774780312041530173171470043250309926815017975476219\",\"3502207265482905042029962996793932548717468210237619905023157797841132512624\"],[\"1\",\"0\"]],\"c\":[\"1288521393482492105362792882426011805774869298603270001189992299082351112997\",\"3336108234609612516660580995781529303851605528785003185796473743343393403477\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AOJbPzKYeOn5sc0B6ZnHZXxwD6DkfKk5xHZ1XoTkbJF1\"}"; -pub const SUI_DATA_FROM_REACT_16: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImpKS0poeXJtbHE3T1UxU0NwZnlfX2F3MEZxVSIsIm5iZiI6MTcxNTY4Njg2NSwiaWF0IjoxNzE1Njg3MTY1LCJleHAiOjE3MTU2OTA3NjUsImp0aSI6Ijg4ZDVmNTg1OGMzNDIwMmY1OTAyOWE5ODM4YzhhOWMzYWVlMDZjNDMifQ.cjuamUo90ycOmkGffs4qe6Ozb0q-UhG6oG4pLf3a5zMgRUXr_PcKNj9GcHujqYzWFbVsiuYdoVwMmPsHeKmLnkuIDS4mwT0z-LhWvYrXdx2FksXyv0ECIBJNGHWNtf6JyhA_3XGYSqzn4sQncKxHK82aFAJZYaPfXCgKJJK0c9PFjONxY2nQoDV-IM89vm6x9vpNPjYxMxxE60p_5qceLLU9pgy4jgP2Eyco0sGfCFTry7zVqgYsMSinh_UIWk4naihDtgrZxAdNkoAA-4PQkWxrlTO8b68YQp8K4ncerUwmOJDs-0NUxDm8mTjwq47Qgf_UAcTxVN9_YpIqEoxdwQ\",\"userPassToIntFormat\":\"100102104119101105101121102\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":109,\"1\":20,\"2\":190,\"3\":101,\"4\":236,\"5\":16,\"6\":171,\"7\":49,\"8\":222,\"9\":170,\"10\":22,\"11\":241,\"12\":224,\"13\":116,\"14\":18,\"15\":124,\"16\":48,\"17\":1,\"18\":20,\"19\":126,\"20\":94,\"21\":16,\"22\":164,\"23\":173,\"24\":180,\"25\":226,\"26\":71,\"27\":184,\"28\":218,\"29\":162,\"30\":145,\"31\":87},\"secretKey\":{\"0\":131,\"1\":117,\"2\":15,\"3\":104,\"4\":243,\"5\":100,\"6\":1,\"7\":157,\"8\":31,\"9\":54,\"10\":163,\"11\":215,\"12\":45,\"13\":202,\"14\":70,\"15\":51,\"16\":77,\"17\":200,\"18\":206,\"19\":59,\"20\":210,\"21\":59,\"22\":129,\"23\":250,\"24\":53,\"25\":166,\"26\":201,\"27\":57,\"28\":9,\"29\":13,\"30\":255,\"31\":18,\"32\":109,\"33\":20,\"34\":190,\"35\":101,\"36\":236,\"37\":16,\"38\":171,\"39\":49,\"40\":222,\"41\":170,\"42\":22,\"43\":241,\"44\":224,\"45\":116,\"46\":18,\"47\":124,\"48\":48,\"49\":1,\"50\":20,\"51\":126,\"52\":94,\"53\":16,\"54\":164,\"55\":173,\"56\":180,\"57\":226,\"58\":71,\"59\":184,\"60\":218,\"61\":162,\"62\":145,\"63\":87}}},\"zkAddr\":\"0x3a26feb6fa552d6e2796e37cfcfaa19ff8d09b9b3e30060557f313ec82e7809a\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"17553248964460513660899064860794334313854327380740726458707730696116622715951\",\"19780935404993030841853448182973442738138094386982905919654095638585438825727\",\"1\"],\"b\":[[\"21560192083940754229490187081097411180154947135453319375957763951829010741758\",\"19864576266509862087012277908356289924851686435133221538927641836878678315039\"],[\"5332198541444016097635381835036279771892300735490162251066050727152100828695\",\"4562785582599067136108384927870755899035073041220030123445496806313655366742\"],[\"1\",\"0\"]],\"c\":[\"17180793399699270264610473764500109290307106335241771936808740744446379111802\",\"19531923144281240440166451089649574065952850605237982747209921274042428958350\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AG0UvmXsEKsx3qoW8eB0EnwwARR+XhCkrbTiR7jaopFX\"}"; -pub const SUI_DATA_FROM_REACT_17: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxPYUk4MkJHS1lSWXVETVRMVXU4Z0ktV3ZsayIsIm5iZiI6MTcxNTY4Njg1NywiaWF0IjoxNzE1Njg3MTU3LCJleHAiOjE3MTU2OTA3NTcsImp0aSI6ImMyOGE2MTEwYzMwYmQ0ZDkzMmEwOTNlOWVmZjllNzEyZjUzYWI2MjQifQ.fHYn7sAFbOtPneSX_YBA52ASidwosnl42uWF7RmroUU132sPO3Jmzf7tqZrqQFu04Y1G2LeGvTeHklUowVdWdKQkomV9bCeputcMRkDPD9-5-UJdpDY8eIAzfHzWN9nWyu5St0Iz0S0FIth6cesMmPUkCrq6pCUyHLWgrxUoICuYIbbtEO5ZVnF8lIeMjUTLXT4_9svFBRhugkD0nvHnQnWS8H0ijS53lCs8z7xVy0cm_MawsCMpApMQvWm-4CeIq69p3m2HXclXNmwSxg7oeGDKn-yqhPaXX3Pn4PfHKPj-XHXOR2rr9uG2lYi73yOyDve84wCXzV9kmiUnc0YGUQ\",\"userPassToIntFormat\":\"515253575654\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":100,\"1\":216,\"2\":222,\"3\":171,\"4\":27,\"5\":27,\"6\":171,\"7\":132,\"8\":172,\"9\":13,\"10\":174,\"11\":188,\"12\":196,\"13\":208,\"14\":35,\"15\":125,\"16\":10,\"17\":214,\"18\":5,\"19\":29,\"20\":118,\"21\":41,\"22\":114,\"23\":70,\"24\":166,\"25\":37,\"26\":189,\"27\":136,\"28\":37,\"29\":106,\"30\":245,\"31\":15},\"secretKey\":{\"0\":75,\"1\":60,\"2\":159,\"3\":196,\"4\":243,\"5\":180,\"6\":224,\"7\":198,\"8\":228,\"9\":147,\"10\":22,\"11\":104,\"12\":69,\"13\":182,\"14\":80,\"15\":232,\"16\":127,\"17\":195,\"18\":43,\"19\":2,\"20\":99,\"21\":206,\"22\":161,\"23\":47,\"24\":106,\"25\":44,\"26\":131,\"27\":5,\"28\":133,\"29\":110,\"30\":82,\"31\":140,\"32\":100,\"33\":216,\"34\":222,\"35\":171,\"36\":27,\"37\":27,\"38\":171,\"39\":132,\"40\":172,\"41\":13,\"42\":174,\"43\":188,\"44\":196,\"45\":208,\"46\":35,\"47\":125,\"48\":10,\"49\":214,\"50\":5,\"51\":29,\"52\":118,\"53\":41,\"54\":114,\"55\":70,\"56\":166,\"57\":37,\"58\":189,\"59\":136,\"60\":37,\"61\":106,\"62\":245,\"63\":15}}},\"zkAddr\":\"0x89045412e3f5c808e7bf0ea6d47008a6c75f14b48a7fea54f420b03d3298ef4e\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"257137064185145448465242836924275827726618300508610920187643303682623341809\",\"13136104385342155450873138185971548464179081219858145555616259274682267182602\",\"1\"],\"b\":[[\"9623367967771069752036280248035047299371597257306258748768218269896381701321\",\"12210765432002064938981141260402135327544184192147240766501813387730760651726\"],[\"15251118264052002493837427778759923199895437430037469672801786148252966111936\",\"12243121821747384937988506024826071890328897029202152518609157933400978560340\"],[\"1\",\"0\"]],\"c\":[\"4201350126073080124441494110984461007902792066210632786985402248838880518314\",\"10425614983366289743736253875955608779721351186796918402238008669517994775682\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AGTY3qsbG6uErA2uvMTQI30K1gUddilyRqYlvYglavUP\"}"; -pub const SUI_DATA_FROM_REACT_18: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlhhakktZ0NqbFVVY3ZBTFdmcDlyTURCelBzVSIsIm5iZiI6MTcxNTY4Njg0OSwiaWF0IjoxNzE1Njg3MTQ5LCJleHAiOjE3MTU2OTA3NDksImp0aSI6IjZmYmI3NmEzN2NjOTAwYTQ5NThlYmNlZmNmYmVhNjMzMzkyMzM2OTUifQ.RqLBHMZMuXbsZGW5YGDNbfTSGG5Ezv_XtJRvMbBIXytAqGoT70RrfZSwU3e8yXaq-o4RBoeypQIygj_Sjxq0JJXVRuypVqkbismASkWKWH77avFgRUe0Etvc8EFXupmwj1biRpURUukroVUyjktOI17m3DvFIIan7_rq3SQBNxLyjFZav517zaJaUVXdYMDAYIEVs1Es04G2kWTxBYQ6iu0jyHtuNcg9_kosGQEZjnp2HsnvegrRwloyjuFByMRv90bRuV6cc3f-3GPO23tcrhFzeoOQXUfcSdlqE3C92gb6E_3uBld414mNj2LelnagKtpvPjTCgX3tic2c7fB_CQ\",\"userPassToIntFormat\":\"989911510011710554\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":81,\"1\":243,\"2\":172,\"3\":238,\"4\":183,\"5\":132,\"6\":17,\"7\":7,\"8\":200,\"9\":125,\"10\":73,\"11\":248,\"12\":71,\"13\":220,\"14\":159,\"15\":138,\"16\":16,\"17\":207,\"18\":25,\"19\":103,\"20\":70,\"21\":23,\"22\":193,\"23\":72,\"24\":27,\"25\":94,\"26\":241,\"27\":155,\"28\":98,\"29\":155,\"30\":212,\"31\":118},\"secretKey\":{\"0\":89,\"1\":13,\"2\":132,\"3\":115,\"4\":95,\"5\":59,\"6\":196,\"7\":68,\"8\":136,\"9\":46,\"10\":22,\"11\":70,\"12\":5,\"13\":188,\"14\":76,\"15\":116,\"16\":156,\"17\":15,\"18\":226,\"19\":232,\"20\":167,\"21\":204,\"22\":143,\"23\":148,\"24\":230,\"25\":69,\"26\":18,\"27\":166,\"28\":234,\"29\":47,\"30\":178,\"31\":31,\"32\":81,\"33\":243,\"34\":172,\"35\":238,\"36\":183,\"37\":132,\"38\":17,\"39\":7,\"40\":200,\"41\":125,\"42\":73,\"43\":248,\"44\":71,\"45\":220,\"46\":159,\"47\":138,\"48\":16,\"49\":207,\"50\":25,\"51\":103,\"52\":70,\"53\":23,\"54\":193,\"55\":72,\"56\":27,\"57\":94,\"58\":241,\"59\":155,\"60\":98,\"61\":155,\"62\":212,\"63\":118}}},\"zkAddr\":\"0xa41d812b2137a9e701512dd1e77643b94c3eff566c5be50365d174d1db60a415\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"17614076016833085587577424708926810169376585820815427961767207039192652769013\",\"14135032500684844024372302628625185135058981148802759791768119531914068811069\",\"1\"],\"b\":[[\"12223738407851653989769057205672802523120105196291312843502064346721414495287\",\"633499823246797838323329834422571844397737716575556571535890211670105511423\"],[\"6003190178099558462113377195569012506764289704920013648574803015959961275195\",\"2773541228770509456407096233964565540804779880988894871588471857181885931620\"],[\"1\",\"0\"]],\"c\":[\"1069242590881057236271046634996302431045048055413724998035360474439616694142\",\"4170832142623397447640837445675045579300900045561776497865454715900704844006\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AFHzrO63hBEHyH1J+Efcn4oQzxlnRhfBSBte8Ztim9R2\"}"; -pub const SUI_DATA_FROM_REACT_19: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxyN2JvekNHNUw4UHlLVVNPRzNwMDZYYVM1USIsIm5iZiI6MTcxNTY4Njg0MSwiaWF0IjoxNzE1Njg3MTQxLCJleHAiOjE3MTU2OTA3NDEsImp0aSI6Ijc2MzdiMGMyM2ZiMWIwZTFjMGEyYWE3NWVkOGMxNjA1YzE1YWFiZjAifQ.uNMFOgl9xdG5wljwZrIDzWm3SS_F9OLhR9avDGRhHSxYNSzexcOHtGT7HY9zsWloN9LWFZxu2t3yG-jWduo5qYgyM-OXpdAXLzfXZwQSNxgtXl2yisxeBU18_7lPpmjMzTMUPCXtJxrB75VYoZAybkyGnFmC_tPD13MIShT04iUGkNLFPpaof4BGxnmCE4hNob-tVijFTH_EIdNXg0fr-rQ-qxd3vw7NVDIF0yDNxCeSYMz0GKuGPlvXk3SPtUzfUfZaJFau3QpfcrXhkNrUS0fW3HcXRLMhiVqNIJ5Y5wYJdq5IvEe_lElrv4NS4apswDNVI1s7B_iMDvcjFASD9Q\",\"userPassToIntFormat\":\"5255515057565453\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":223,\"1\":83,\"2\":48,\"3\":161,\"4\":204,\"5\":195,\"6\":149,\"7\":141,\"8\":132,\"9\":65,\"10\":55,\"11\":201,\"12\":245,\"13\":60,\"14\":139,\"15\":236,\"16\":39,\"17\":130,\"18\":130,\"19\":162,\"20\":215,\"21\":104,\"22\":235,\"23\":117,\"24\":152,\"25\":71,\"26\":252,\"27\":46,\"28\":73,\"29\":54,\"30\":170,\"31\":251},\"secretKey\":{\"0\":90,\"1\":130,\"2\":14,\"3\":79,\"4\":237,\"5\":213,\"6\":128,\"7\":240,\"8\":11,\"9\":61,\"10\":50,\"11\":225,\"12\":67,\"13\":212,\"14\":26,\"15\":215,\"16\":84,\"17\":207,\"18\":4,\"19\":3,\"20\":95,\"21\":124,\"22\":35,\"23\":123,\"24\":72,\"25\":189,\"26\":115,\"27\":153,\"28\":16,\"29\":105,\"30\":73,\"31\":216,\"32\":223,\"33\":83,\"34\":48,\"35\":161,\"36\":204,\"37\":195,\"38\":149,\"39\":141,\"40\":132,\"41\":65,\"42\":55,\"43\":201,\"44\":245,\"45\":60,\"46\":139,\"47\":236,\"48\":39,\"49\":130,\"50\":130,\"51\":162,\"52\":215,\"53\":104,\"54\":235,\"55\":117,\"56\":152,\"57\":71,\"58\":252,\"59\":46,\"60\":73,\"61\":54,\"62\":170,\"63\":251}}},\"zkAddr\":\"0x37c4424a1b9970b94dd7276aecae5b9d1c035c7e3c88f4f1155aa0e5127ef6e4\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"7945493796354284921600453177054285773255312631482061079984629835363646515586\",\"2166517138136751277833084326208436279446476764263036612847849710284540628729\",\"1\"],\"b\":[[\"14768147580014515274920059533450969526917243519129235569375547705391356814034\",\"10926704359346438742364088104571886636979515204481541507299552373423645137538\"],[\"18345707220306299341155061798987886250677895640406984732019863169577306401665\",\"13781450607771983148196301814354815025344242496715512941320154501577226245887\"],[\"1\",\"0\"]],\"c\":[\"16100487697721354409255314346417284275475569122937970611421991273969908317416\",\"20037727069966515075925458192010761910249599063237527691300280470015098486501\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AN9TMKHMw5WNhEE3yfU8i+wngoKi12jrdZhH/C5JNqr7\"}"; -pub const SUI_DATA_FROM_REACT_20: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJlMTgtZlBDdV9ZRndybE43TDhKV1BHX3hFbyIsIm5iZiI6MTcxNTY4NjgzMSwiaWF0IjoxNzE1Njg3MTMxLCJleHAiOjE3MTU2OTA3MzEsImp0aSI6IjdmZTFkZTM5NDVkMjliYTBhOWQ4MGFlODZiZGRmNjkyMDE1N2RlMDcifQ.RMM8wIiEzZ97DVdngkDhKapTMZq-R7woI2yjclLqTgnYZKTZ5N9y67zFJLDfcg017VyyRK18OS1OLsnUgnphi3ULotImnJ2292VDBd7kxhyq9QAqfHVDK2-MYNlJXy53UIr2xS9td1aoHUDZkvBy690IhV4nPrxLOUhI8c4gAvpkfHFmAvxYuQoUu69c_hSzREhrVOa979t5nZuJjNWwUcwgD40To1DM6Dxwy186basvY4AyWPHcI4ARFoyPEMRFUOtO05fUrwUH8O63Ay6K1DwxaLXDzx4T7O9X9nlrCj2uROdahsv-Dj24hruudSYxi4GH2uO6u0a1RlTIvWJ-1A\",\"userPassToIntFormat\":\"525451525655\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":66,\"1\":155,\"2\":237,\"3\":117,\"4\":45,\"5\":166,\"6\":245,\"7\":92,\"8\":78,\"9\":225,\"10\":218,\"11\":156,\"12\":7,\"13\":132,\"14\":164,\"15\":47,\"16\":114,\"17\":174,\"18\":4,\"19\":86,\"20\":18,\"21\":212,\"22\":182,\"23\":62,\"24\":50,\"25\":219,\"26\":104,\"27\":185,\"28\":183,\"29\":108,\"30\":38,\"31\":252},\"secretKey\":{\"0\":13,\"1\":127,\"2\":13,\"3\":29,\"4\":128,\"5\":121,\"6\":142,\"7\":51,\"8\":210,\"9\":28,\"10\":131,\"11\":160,\"12\":209,\"13\":42,\"14\":214,\"15\":198,\"16\":137,\"17\":147,\"18\":155,\"19\":40,\"20\":86,\"21\":167,\"22\":168,\"23\":10,\"24\":249,\"25\":180,\"26\":188,\"27\":132,\"28\":41,\"29\":146,\"30\":192,\"31\":28,\"32\":66,\"33\":155,\"34\":237,\"35\":117,\"36\":45,\"37\":166,\"38\":245,\"39\":92,\"40\":78,\"41\":225,\"42\":218,\"43\":156,\"44\":7,\"45\":132,\"46\":164,\"47\":47,\"48\":114,\"49\":174,\"50\":4,\"51\":86,\"52\":18,\"53\":212,\"54\":182,\"55\":62,\"56\":50,\"57\":219,\"58\":104,\"59\":185,\"60\":183,\"61\":108,\"62\":38,\"63\":252}}},\"zkAddr\":\"0x86ab13e3c90b7f5b52a0e7d045425f1a5ce4f2938d82fe32013b5c5dffc8aa40\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"13280060882937967421268531103181473070897547065707830941266439167277535861998\",\"9934433138500558951890280258062370504217382435917636186873727481367280202864\",\"1\"],\"b\":[[\"3838124130316726849360987686807592227651253623250263168834039482151640975443\",\"10050190797101422174255450354163308725608018844614813729840170282126147936409\"],[\"18360080471111693027482741715722945557865825591442098780536696036281663618095\",\"1378964582828950987975075563637558653759765511530268169302574447782691787466\"],[\"1\",\"0\"]],\"c\":[\"1373142722414479432483215105546507593017308819682036641663292686387425172376\",\"3353210342014729825799146687716012229927760750084040417279416030868174996451\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AEKb7XUtpvVcTuHanAeEpC9yrgRWEtS2PjLbaLm3bCb8\"}"; -pub const SUI_DATA_FROM_REACT_21: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Im12NUNKY1dsMXE1ek03Y0lyR1ZUdHF6SnFTNCIsIm5iZiI6MTcxNTY4NjgxOSwiaWF0IjoxNzE1Njg3MTE5LCJleHAiOjE3MTU2OTA3MTksImp0aSI6IjYxMDM2YmQwZWE3YjI5MDY4MjgwODYxMzMyODZhODZlNmY0ZmMwNGEifQ.VE2a8s2ZuyTVklFwSvh05y_mGrDMJXww-5Pu3-UUIQi3sBQnMzpnvWo3MIb32rXxwU6Obtx9izsR-Csk-U0QH4WuseGHnhHA90lACdeXNXHUWNktsY62_z2lkseTlJQV_ccNVctNgqornxmtV6gRvihLKkYCJt08umhAcRe8-Fh9iNmlCf5sMngaA-k0bvIbdnxkoP0KI9em7sgpTDB0FJFCgVAVYkzQTuJJlfuKjeF0lgpLnkjTOtgMyCpuZrrxf9GH6wY2VSme3Zk6xVJfl5cC6YugQFs-t56CEhPDrm-LIlLTD9JuNAKctlRRaTmkTembZAzweu6Wqh322MDx1g\",\"userPassToIntFormat\":\"100102100102100115106107\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":227,\"1\":142,\"2\":234,\"3\":83,\"4\":36,\"5\":125,\"6\":219,\"7\":233,\"8\":159,\"9\":30,\"10\":60,\"11\":195,\"12\":110,\"13\":130,\"14\":105,\"15\":107,\"16\":44,\"17\":46,\"18\":151,\"19\":154,\"20\":116,\"21\":131,\"22\":237,\"23\":231,\"24\":159,\"25\":119,\"26\":35,\"27\":130,\"28\":56,\"29\":90,\"30\":121,\"31\":26},\"secretKey\":{\"0\":34,\"1\":107,\"2\":197,\"3\":227,\"4\":209,\"5\":156,\"6\":36,\"7\":233,\"8\":231,\"9\":171,\"10\":100,\"11\":210,\"12\":113,\"13\":247,\"14\":59,\"15\":222,\"16\":214,\"17\":129,\"18\":238,\"19\":254,\"20\":13,\"21\":13,\"22\":3,\"23\":151,\"24\":9,\"25\":173,\"26\":77,\"27\":113,\"28\":126,\"29\":7,\"30\":203,\"31\":52,\"32\":227,\"33\":142,\"34\":234,\"35\":83,\"36\":36,\"37\":125,\"38\":219,\"39\":233,\"40\":159,\"41\":30,\"42\":60,\"43\":195,\"44\":110,\"45\":130,\"46\":105,\"47\":107,\"48\":44,\"49\":46,\"50\":151,\"51\":154,\"52\":116,\"53\":131,\"54\":237,\"55\":231,\"56\":159,\"57\":119,\"58\":35,\"59\":130,\"60\":56,\"61\":90,\"62\":121,\"63\":26}}},\"zkAddr\":\"0xb092062dc38ee15b239fedd8955547cae553068e350add6a186a900308ca1704\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"19083893384522082364200015848081882762611466511855277173108395395690822433582\",\"15765871630522826744343212165387977339454134778029147662517994756792436892191\",\"1\"],\"b\":[[\"3347275249816013439391836622904014049361323482158752310150932588414843416768\",\"9261935324040115069949005166058871304117632278716385673922763868694265924905\"],[\"10774327302040930015542399179222458502634829694095804484749135988841930351850\",\"409015645239595129631982791901837203813000443262394810220799589635024410401\"],[\"1\",\"0\"]],\"c\":[\"805618312212200473153836203801534856685701602304097276485035246177305246575\",\"12984127923817330198936709848850019846193356630613954592225359007088568774616\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extendedEphemeralPublicKey\":\"AOOO6lMkfdvpnx48w26CaWssLpeadIPt5593I4I4Wnka\"}"; - -pub const VALUE_PORTION_SIZE: usize = 126; - -pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"userPassToIntFormat\":\"9910010710611510499100106115107\",\"zkAddr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeralKeyPair\":{\"keypair\":{\"publicKey\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secretKey\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extendedEphemeralPublicKey\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zkProofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; +use tvm_types::BuilderData; +use tvm_types::Cell; +use tvm_types::SliceData; +use tvm_vm::executor::zk_stuff::error::ZkCryptoError; +use tvm_vm::int; +use tvm_vm::stack::integer::IntegerData; +use tvm_vm::stack::Stack; +use tvm_vm::stack::StackItem; +use tvm_vm::utils::pack_data_to_cell; + +use crate::test_framework::test_case_with_refs; +use crate::test_framework::Expects; + #[derive(Debug, Deserialize)] pub struct JwtData { jwt: String, @@ -103,40 +47,40 @@ pub struct JwtData { #[derive(Debug, Deserialize)] pub struct EphemeralKeyPair { - keypair: Keypair + keypair: Keypair, } #[derive(Debug, Deserialize)] pub struct Keypair { - publicKey: HashMap,//HashMap, // publicKey: Vec, - secretKey: HashMap // secretKey: Vec // HashMap, + publicKey: HashMap, // HashMap, // publicKey: Vec, + secretKey: HashMap, // secretKey: Vec // HashMap, } #[derive(Debug, Deserialize, Serialize)] pub struct ZkProofs { proofPoints: ProofPoints, - issBase64Details: IssBase64Details, - headerBase64: String, + iss_base64_details: iss_base64_details, + header_base64: String, } #[derive(Debug, Deserialize, Serialize)] pub struct ProofPoints { a: Vec, b: Vec>, - c: Vec + c: Vec, } #[derive(Debug, Deserialize, Serialize)] -pub struct IssBase64Details { +pub struct iss_base64_details { value: String, - indexMod4: i32 + index_mod4: i32, } #[derive(Debug, Deserialize)] pub struct JwtDataDecodedPart1 { alg: String, kid: String, - typ: String + typ: String, } #[derive(Debug, Deserialize)] @@ -149,7 +93,7 @@ pub struct JwtDataDecodedPart2 { nbf: u32, iat: u32, exp: u32, - jti: String + jti: String, } fn gen_keypair() -> ed25519_dalek::Keypair { @@ -157,22 +101,28 @@ fn gen_keypair() -> ed25519_dalek::Keypair { } #[test] -fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data taken from our react app for zklogin tests +fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" + // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" + // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 // in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, + 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); let mut eph_pubkey = Vec::new(); - // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + // replace by Alina's data (ephemeral public key place to byte array ), depends + // on iteration eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", eph_pubkey); println!("len eph_pubkey: {:?}", eph_pubkey.len()); @@ -181,8 +131,9 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -192,7 +143,7 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take println!("zk_seed = {:?}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -200,21 +151,21 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ - \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ + \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); println!("proof_and_jwt: {}", proof_and_jwt); - let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - + let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + println!("issAndheader_base64Details: {}", issAndheader_base64Details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid + // in this header is equal to one specified in line 143,... take kid from jwt if + // not equal let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -234,18 +185,18 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut public_inputs_as_bytes = vec![]; public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); @@ -254,13 +205,14 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - /** calcs poseidon **/ + /// calcs poseidon * println!("====== Start Poseidon ========"); let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + let issAndheader_base64Details_cell = + pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -275,17 +227,18 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take println!("code : {:?}", code); - test_case_with_refs(code.as_str(), vec![ modulus_cell.clone(), issAndHeaderBase64Details_cell, zk_seed_cell]) - .expect_stack(Stack::new() - .push(StackItem::Cell(public_inputs_cell.clone())) - ); - //.expect_success(); + test_case_with_refs( + code.as_str(), + vec![modulus_cell.clone(), issAndheader_base64Details_cell, zk_seed_cell], + ) + .expect_stack(Stack::new().push(StackItem::Cell(public_inputs_cell.clone()))); + //.expect_success(); - /** calcs vergrth16 **/ + /// calcs vergrth16 * println!("====== Start VERGRTH16 ========"); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); println!("proof_as_bytes : {:?}", proof_as_bytes); @@ -294,20 +247,20 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data take let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); let verification_key_id: u32 = 0; //valid key id - //let verification_key_id: u32 = 1; //invalid key id + // let verification_key_id: u32 = 1; //invalid key id let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] fn test_poseidon_plus_vrgrth16() { - /** Common data generation **/ - + /// Common data generation * let user_pass_salt = "206703048842351542647799591018316385612"; // Generate an ephemeral key pair. @@ -326,19 +279,19 @@ fn test_poseidon_plus_vrgrth16() { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed: {}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("proof_and_jwt: {}", proof_and_jwt); - let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("issAndheader_base64Details: {}", issAndheader_base64Details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -360,33 +313,33 @@ fn test_poseidon_plus_vrgrth16() { let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); println!("modulus: {:?}", modulus); println!("modulus hex: {:?}", hex::encode(&modulus)); - let max_epoch = 10; - //let max_epoch = 142; + // let max_epoch = 142; - /** calcs poseidon **/ + /// calcs poseidon * println!("====== Start Poseidon ========"); let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + let issAndheader_base64Details_cell = + pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); - //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut + // 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -399,17 +352,21 @@ fn test_poseidon_plus_vrgrth16() { code = code + &*"PUSHREF \n".to_string(); code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + test_case_with_refs( + code.as_str(), + vec![modulus_cell, issAndheader_base64Details_cell, zk_seed_cell], + ) + .expect_success(); - test_case_with_refs(code.as_str(), vec![ modulus_cell, issAndHeaderBase64Details_cell, zk_seed_cell]).expect_success(); - - /** calcs vergrth16 **/ + /// calcs vergrth16 * println!("====== Start Vergrth16 ========"); let pp = zk_login_inputs.get_proof(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -419,7 +376,7 @@ fn test_poseidon_plus_vrgrth16() { let y1 = proof.a.y.0.to_bits_le(); let y2 = proof.a.y.0.to_bits_be(); - //let y_ = -y; + // let y_ = -y; println!("proof.a: {:?}", proof.a); @@ -432,16 +389,16 @@ fn test_poseidon_plus_vrgrth16() { println!("proof.a.x.0.to_string(): {:?}", proof.a.x.0.to_string()); println!("y1: {:?}", y1); - for i in 0..y1.len(){ - print!("{}", y1[i] as i32); + for i in 0..y1.len() { + print!("{}", y1[i] as i32); } println!(""); println!("y2: {:?}", y2); - for i in 0..y2.len(){ - print!("{}", y2[i] as i32); + for i in 0..y2.len() { + print!("{}", y2[i] as i32); } println!(""); - //println!("y_: {:?}", y_); + // println!("y_: {:?}", y_); let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); @@ -460,13 +417,13 @@ fn test_poseidon_plus_vrgrth16() { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); - + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] fn test_eval_time_vrgrth16_new() { - //todo: later n must be extracted from 3d part of jwt + // todo: later n must be extracted from 3d part of jwt let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -474,13 +431,11 @@ fn test_eval_time_vrgrth16_new() { alg: "RS256".to_string(), }; - /* - { - "e": "AQAB", - "kty": "RSA", - "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" -} - */ + // { + // "e": "AQAB", + // "kty": "RSA", + // "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" + // } let mut all_jwk = HashMap::new(); all_jwk.insert( @@ -497,7 +452,7 @@ fn test_eval_time_vrgrth16_new() { println!("====================== Iter@ is {i} ========================="); // parse let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - //println!("{:?}", jwt_data); + // println!("{:?}", jwt_data); let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); println!("user_pass_salt is {user_pass_salt}"); @@ -505,7 +460,7 @@ fn test_eval_time_vrgrth16_new() { let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("ephemeral secret_key is {:?}", eph_secret_key); @@ -514,13 +469,13 @@ fn test_eval_time_vrgrth16_new() { let eph_pubkey_len = eph_pubkey.clone().len(); println!("len eph_pubkey: {:?}", eph_pubkey_len); - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 + // JwtDataDecodedPart1 let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); @@ -528,7 +483,7 @@ fn test_eval_time_vrgrth16_new() { let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 + // JwtDataDecodedPart2 let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); @@ -536,41 +491,48 @@ fn test_eval_time_vrgrth16_new() { let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); println!("time_for_vergrth16 is {time_for_vergrth16}"); println!("=========================================="); } - } #[test] -fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app for zklogin tests +fn test_vrgrth16_based_on_real_data_new() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" + // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" + // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 // in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, + 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); let mut eph_pubkey = Vec::new(); //vec![0x00]; - // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + // replace by Alina's data (ephemeral public key place to byte array ), depends + // on iteration eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", eph_pubkey); println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); @@ -578,8 +540,9 @@ fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -589,7 +552,7 @@ fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app println!("zk_seed = {:?}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -597,14 +560,15 @@ fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ - \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ + \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid + // in this header is equal to one specified in line 143,... take kid from jwt if + // not equal let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -624,19 +588,19 @@ fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -653,19 +617,19 @@ fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); let verification_key_id: u32 = 0; //valid key id - //let verification_key_id: u32 = 1; //invalid key id + // let verification_key_id: u32 = 1; //invalid key id let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] fn test_proof_serialization() { - let user_pass_salt = "206703048842351542647799591018316385612"; let zk_seed = gen_address_seed( @@ -673,20 +637,22 @@ fn test_proof_serialization() { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); - - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + ) + .unwrap(); + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("proof_and_jwt: {}", proof_and_jwt); let zk_login_inputs = tvm_vm::executor::zk_stuff::zk_login::ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + &*proof_and_jwt, + &*zk_seed.to_string(), + ) + .unwrap(); println!("zk_login_inputs: {:?}", zk_login_inputs); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); println!("proof.a: {:?}", proof.a); @@ -713,15 +679,14 @@ fn test_vrgrth16_fresh() { let xx = hex::encode(&xxx); println!("xxx {xx}"); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"20032491544466004395942516676927853848812757556091814296260914209848471949133\",\"2383319895045368406863089991961299436327009667970727469594098906910899823518\",\"1\"],\"b\":[[\"17524079199473031626933714849790290610990375813469214348846178898325828270802\",\"14967860363718375858883445892553389848174133418448836833724123534259346456965\"],[\"8012103671455598651673212917030479015077366694912593401917441922282850889728\",\"9619406946838713340504188077859322423191842838375117333667670119492063405148\"],[\"1\",\"0\"]],\"c\":[\"1155327534990006564455106296492790109069125857506281397147103620914309288350\",\"11642927414888703901346255147864200862372140915112720472429308471936285279899\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\"}"; + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"20032491544466004395942516676927853848812757556091814296260914209848471949133\",\"2383319895045368406863089991961299436327009667970727469594098906910899823518\",\"1\"],\"b\":[[\"17524079199473031626933714849790290610990375813469214348846178898325828270802\",\"14967860363718375858883445892553389848174133418448836833724123534259346456965\"],[\"8012103671455598651673212917030479015077366694912593401917441922282850889728\",\"9619406946838713340504188077859322423191842838375117333667670119492063405148\"],[\"1\",\"0\"]],\"c\":[\"1155327534990006564455106296492790109069125857506281397147103620914309288350\",\"11642927414888703901346255147864200862372140915112720472429308471936285279899\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\"}"; println!("proof_and_jwt: {}", proof_and_jwt); - let issAndHeaderBase64Details = "\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; - println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + let issAndheader_base64Details = "\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; + println!("issAndheader_base64Details: {}", issAndheader_base64Details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -743,33 +708,35 @@ fn test_vrgrth16_fresh() { let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); println!("modulus: {:?}", modulus); println!("modulus hex: {:?}", hex::encode(&modulus)); - let max_epoch = 142; - //let max_epoch = 10; + // let max_epoch = 10; - let mut eph_pubkey = vec![131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63]; + let mut eph_pubkey = vec![ + 131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, + 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63, + ]; println!("eph_pubkey : {:?}", eph_pubkey); println!("eph_pubkey len : {:?}", eph_pubkey.len()); let pp = zk_login_inputs.get_proof(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -794,12 +761,13 @@ fn test_vrgrth16_fresh() { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] fn test_poseidon_update() { - /** Common data generation **/ + /// Common data generation * let user_pass_salt = "206703048842351542647799591018316385612"; // Generate an ephemeral key pair. @@ -817,19 +785,19 @@ fn test_poseidon_update() { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed: {}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("proof_and_jwt: {}", proof_and_jwt); - let issAndHeaderBase64Details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - println!("issAndHeaderBase64Details: {}", issAndHeaderBase64Details); + let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("issAndheader_base64Details: {}", issAndheader_base64Details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -851,14 +819,13 @@ fn test_poseidon_update() { let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); println!("modulus: {:?}", modulus); @@ -868,9 +835,11 @@ fn test_poseidon_update() { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let issAndHeaderBase64Details_cell = pack_string_to_cell(&issAndHeaderBase64Details.clone(), &mut 0).unwrap(); + let issAndheader_base64Details_cell = + pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); - //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut + // 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -885,18 +854,23 @@ fn test_poseidon_update() { println!("code : {code}"); - test_case_with_refs(code.as_str(), vec![ modulus_cell, issAndHeaderBase64Details_cell, zk_seed_cell]).expect_success(); + test_case_with_refs( + code.as_str(), + vec![modulus_cell, issAndheader_base64Details_cell, zk_seed_cell], + ) + .expect_success(); } - #[test] fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { - println!("===================================== START VRGRTH16 TEST ====================================="); + println!( + "===================================== START VRGRTH16 TEST =====================================" + ); let user_pass_salt = "206703048842351542647799591018316385612"; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); @@ -904,24 +878,24 @@ fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed = {:?}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -943,19 +917,19 @@ fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); let max_epoch = 10; // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -978,70 +952,79 @@ fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); - + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); - println!("===================================== START CHKSIGNS TEST ====================================="); + println!( + "===================================== START CHKSIGNS TEST =====================================" + ); let pair = gen_keypair(); let binding = proof_cell.clone(); let first = binding.data(); - - /*let mut b = BuilderData::with_raw(first, len).unwrap();*/ + // let mut b = BuilderData::with_raw(first, len).unwrap(); let binding = public_inputs_cell.clone(); let second = binding.data(); - //b.append_raw(second, len); + // b.append_raw(second, len); let concatenated = [&first[..], &second[..]].concat(); println!("len concatenated = {}", concatenated.len()); - - //test cell with data and one not empty reference - let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - //b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); - //let cell_hash = test_cell.repr_hash(); - //sign hash of data cell + // test cell with data and one not empty reference + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + // b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); + // let cell_hash = test_cell.repr_hash(); + // sign hash of data cell let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - //put signature to separate slice + // put signature to separate slice let len = signature.len() * 8; let signature = SliceData::from_raw(signature, len); - //put public key to integer + // put public key to integer let pub_key = BuilderData::with_raw( pair.public.to_bytes().to_vec(), - ed25519_dalek::PUBLIC_KEY_LENGTH * 8 - ).unwrap(); + ed25519_dalek::PUBLIC_KEY_LENGTH * 8, + ) + .unwrap(); - //put hash to integer - //let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), 256).unwrap(); + // put hash to integer + // let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), + // 256).unwrap(); - test_case_with_refs(" + test_case_with_refs( + " PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) - .expect_stack(Stack::new().push(int!(-1))); + ", + vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], + ) + .expect_stack(Stack::new().push(int!(-1))); } - #[test] -fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for zklogin tests +fn test_vrgrth16_based_on_real_data() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" + // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" + // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 // in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, + 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); @@ -1053,8 +1036,9 @@ fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -1064,7 +1048,7 @@ fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for println!("zk_seed = {:?}", zk_seed); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -1072,14 +1056,15 @@ fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ - \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ + \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid + // in this header is equal to one specified in line 143,... take kid from jwt if + // not equal let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -1099,19 +1084,19 @@ fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -1129,22 +1114,21 @@ fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for let verification_key_id: u32 = 0; - //let verification_key_id: u32 = 1; + // let verification_key_id: u32 = 1; let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } - - -fn secretKeyFromIntegerMap(keyData: HashMap)->Vec{ +fn secret_key_from_integer_map(key_data: HashMap) -> Vec { let mut vec: Vec = Vec::new(); for i in 0..=31 { - if let Some(value) = keyData.get(&i.to_string()) { + if let Some(value) = key_data.get(&i.to_string()) { vec.push(value.clone()); } } @@ -1168,13 +1152,11 @@ fn pad_string_to_256(input: &str) -> String { } fn bits_to_decimal_and_reverse(bits: &str) -> Vec { - let byte_chunks: Vec<&str> = bits.as_bytes().chunks(8).map(|chunk| { - std::str::from_utf8(chunk).unwrap() - }).collect(); + let byte_chunks: Vec<&str> = + bits.as_bytes().chunks(8).map(|chunk| std::str::from_utf8(chunk).unwrap()).collect(); - let decimal_numbers: Vec = byte_chunks.iter() - .map(|byte| u8::from_str_radix(byte, 2).unwrap()) - .collect(); + let decimal_numbers: Vec = + byte_chunks.iter().map(|byte| u8::from_str_radix(byte, 2).unwrap()).collect(); decimal_numbers.into_iter().rev().collect() } @@ -1182,32 +1164,50 @@ fn bits_to_decimal_and_reverse(bits: &str) -> Vec { fn prepare_hex_representation(init_x: &str, y: BigUint) -> String { let mut binary_representation = pad_string_to_256(&to_binary_string(init_x)); - let P: BigUint = BigUint::from_bytes_be(&[ - 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]); + let p: BigUint = BigUint::from_bytes_be(&[ + 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, + ]); // Сравниваем y с p - y и меняем первый бит - if y > &P - &y { + if y > &p - &y { binary_representation.replace_range(0..1, "1"); } let reversed_byte_array = bits_to_decimal_and_reverse(&binary_representation); // Преобразуем массив байтов в hex-строку - let hex_string = reversed_byte_array.iter() - .map(|byte| format!("{:02x}", byte)) - .collect::(); + let hex_string = + reversed_byte_array.iter().map(|byte| format!("{:02x}", byte)).collect::(); hex_string } #[test] fn test_proof_stuff() { - let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 - , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 - , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + let sui_data = [ + SUI_DATA_FROM_REACT_1, + SUI_DATA_FROM_REACT_2, + SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, + SUI_DATA_FROM_REACT_5, + SUI_DATA_FROM_REACT_6, + SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, + SUI_DATA_FROM_REACT_9, + SUI_DATA_FROM_REACT_10, + SUI_DATA_FROM_REACT_11, + SUI_DATA_FROM_REACT_12, + SUI_DATA_FROM_REACT_13, + SUI_DATA_FROM_REACT_14, + SUI_DATA_FROM_REACT_15, + SUI_DATA_FROM_REACT_16, + SUI_DATA_FROM_REACT_17, + SUI_DATA_FROM_REACT_18, + SUI_DATA_FROM_REACT_19, + SUI_DATA_FROM_REACT_20, + SUI_DATA_FROM_REACT_21, + ]; for i in 0..sui_data.len() { let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); @@ -1223,13 +1223,13 @@ fn test_proof_stuff() { let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); println!("user_pass_salt is {user_pass_salt}"); - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 + // JwtDataDecodedPart1 let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); @@ -1237,7 +1237,7 @@ fn test_proof_stuff() { let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 + // JwtDataDecodedPart2 let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); @@ -1245,17 +1245,19 @@ fn test_proof_stuff() { let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -1263,33 +1265,34 @@ fn test_proof_stuff() { println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); println!("----------------------------------"); - /////////// - - let json_string = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - println!("json_string ={:?}", json_string);//jwt_data.zkProofs); - - + println!("json_string ={:?}", json_string); //jwt_data.zkProofs); let data: Value = serde_json::from_str(&*json_string).unwrap(); println!("data = {:?}", data); let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let a_y = + BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10) + .unwrap(); println!("a_x = {:?}", a_x); println!("a_y = {:?}", a_y); let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + let b1_y = + BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10) + .unwrap(); println!("b0_x = {:?}", b0_x); println!("b1_x = {:?}", b1_x); println!("b1_y = {:?}", b1_y); let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let c_y = + BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10) + .unwrap(); println!("c_x = {:?}", c_x); println!("c_y = {:?}", c_y); @@ -1309,40 +1312,58 @@ fn test_proof_stuff() { println!("==================="); } - - /* println!("Serialized proof"); - let json_string = r#"{"proofPoints":{"a":["8247215875293406890829839156897863742504615191361518281091302475904551111016","6872980335748205979379321982220498484242209225765686471076081944034292159666","1"],"b":[["21419680064642047510915171723230639588631899775315750803416713283740137406807","21566716915562037737681888858382287035712341650647439119820808127161946325890"],["17867714710686394159919998503724240212517838710399045289784307078087926404555","21812769875502013113255155836896615164559280911997219958031852239645061854221"],["1","0"]],"c":["7530826803702928198368421787278524256623871560746240215547076095911132653214","16244547936249959771862454850485726883972969173921727256151991751860694123976","1"]},"issBase64Details":{"value":"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1},"headerBase64":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"}"#; - - // Парсинг JSON-строки - let data: Value = serde_json::from_str(json_string).unwrap(); - - let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let hex_ax = prepare_hex_representation(a_x, a_y); - let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); - let hex_b1x = prepare_hex_representation(b1_x, b1_y); - let hex_cx = prepare_hex_representation(c_x, c_y); - - let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); - + // println!("Serialized proof"); + // let json_string = + // r#"{"proofPoints":{"a":[" + // 8247215875293406890829839156897863742504615191361518281091302475904551111016" + // ,"6872980335748205979379321982220498484242209225765686471076081944034292159666" + // ,"1"],"b":[[" + // 21419680064642047510915171723230639588631899775315750803416713283740137406807" + // ,"21566716915562037737681888858382287035712341650647439119820808127161946325890" + // ],["17867714710686394159919998503724240212517838710399045289784307078087926404555" + // ,"21812769875502013113255155836896615164559280911997219958031852239645061854221" + // ],["1","0"]],"c":[" + // 7530826803702928198368421787278524256623871560746240215547076095911132653214" + // ,"16244547936249959771862454850485726883972969173921727256151991751860694123976" + // ,"1"]},"iss_base64_details":{"value":" + // yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","index_mod4":1}," + // header_base64":" + // eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ" + // }"#; + // + // Парсинг JSON-строки + // let data: Value = serde_json::from_str(json_string).unwrap(); + // + // let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + // let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str(). + // unwrap().as_bytes(), 10).unwrap(); + // + // let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + // let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + // let b1_y = + // BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap(). + // as_bytes(), 10).unwrap(); + // + // let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + // let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str(). + // unwrap().as_bytes(), 10).unwrap(); + // + // let hex_ax = prepare_hex_representation(a_x, a_y); + // let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + // let hex_b1x = prepare_hex_representation(b1_x, b1_y); + // let hex_cx = prepare_hex_representation(c_x, c_y); + // + // let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + // // ????? ??????????? - println!("Serialized proof: {}", result); - println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); - */ + // println!("Serialized proof: {}", result); + // println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); } #[ignore] #[test] fn test_eval_time_vrgrth16() { - //todo: later n must be extracted from 3d part of jwt + // todo: later n must be extracted from 3d part of jwt let content: JWK = JWK { kty: "RSA".to_string(), @@ -1360,12 +1381,30 @@ fn test_eval_time_vrgrth16() { content, ); - //let sui_data = [SUI_DATA_FROM_REACT_1]; - let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 - , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 - , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + // let sui_data = [SUI_DATA_FROM_REACT_1]; + let sui_data = [ + SUI_DATA_FROM_REACT_1, + SUI_DATA_FROM_REACT_2, + SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, + SUI_DATA_FROM_REACT_5, + SUI_DATA_FROM_REACT_6, + SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, + SUI_DATA_FROM_REACT_9, + SUI_DATA_FROM_REACT_10, + SUI_DATA_FROM_REACT_11, + SUI_DATA_FROM_REACT_12, + SUI_DATA_FROM_REACT_13, + SUI_DATA_FROM_REACT_14, + SUI_DATA_FROM_REACT_15, + SUI_DATA_FROM_REACT_16, + SUI_DATA_FROM_REACT_17, + SUI_DATA_FROM_REACT_18, + SUI_DATA_FROM_REACT_19, + SUI_DATA_FROM_REACT_20, + SUI_DATA_FROM_REACT_21, + ]; let mut sum_ratio: u128 = 0; @@ -1373,7 +1412,7 @@ fn test_eval_time_vrgrth16() { println!("====================== Iter@ is {i} ========================="); // parse let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - //println!("{:?}", jwt_data); + // println!("{:?}", jwt_data); let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); println!("user_pass_salt is {user_pass_salt}"); @@ -1381,7 +1420,7 @@ fn test_eval_time_vrgrth16() { let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("ephemeral secret_key is {:?}", eph_secret_key); @@ -1390,44 +1429,47 @@ fn test_eval_time_vrgrth16() { let eph_pubkey_len = eph_pubkey.clone().len(); println!("len eph_pubkey: {:?}", eph_pubkey_len); - /*let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); - - let jwt_header = splitted_jwt_strings - .get(0) - .expect("split always returns at least one element"); - - let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( - "Could not find separator in jwt string.", - )).unwrap(); - - let decoded_jwt_header = base64::decode(jwt_header).unwrap(); - let decoded_jwt_body = base64::decode(jwt_body).unwrap(); - - let converted_jwt_header = String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); - let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 conversion failed"); - - let parsed_jwt_header = serde_json::from_str::(&converted_jwt_header).unwrap(); - let parsed_jwt_body = serde_json::from_str::(&converted_jwt_body).unwrap(); - - println!( - "{}", - serde_json::to_string_pretty(&parsed_jwt_header) - .expect("to_string_pretty always works on serde_json::Value") - ); - println!( - "{}", - serde_json::to_string_pretty(&parsed_jwt_body) - .expect("to_string_pretty always works on serde_json::Value") - );*/ - - - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + // let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); + // + // let jwt_header = splitted_jwt_strings + // .get(0) + // .expect("split always returns at least one element"); + // + // let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( + // "Could not find separator in jwt string.", + // )).unwrap(); + // + // let decoded_jwt_header = base64::decode(jwt_header).unwrap(); + // let decoded_jwt_body = base64::decode(jwt_body).unwrap(); + // + // let converted_jwt_header = + // String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); + // let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 + // conversion failed"); + // + // let parsed_jwt_header = + // serde_json::from_str::(&converted_jwt_header).unwrap(); + // let parsed_jwt_body = + // serde_json::from_str::(&converted_jwt_body).unwrap(); + // + // println!( + // "{}", + // serde_json::to_string_pretty(&parsed_jwt_header) + // .expect("to_string_pretty always works on serde_json::Value") + // ); + // println!( + // "{}", + // serde_json::to_string_pretty(&parsed_jwt_body) + // .expect("to_string_pretty always works on serde_json::Value") + // ); + + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 + // JwtDataDecodedPart1 let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); @@ -1435,81 +1477,85 @@ fn test_eval_time_vrgrth16() { let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 + // JwtDataDecodedPart2 let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); + // let key = DecodingKey::from_secret(&[]); + // let mut validation = Validation::new(Algorithm::HS256); + // validation.insecure_disable_signature_validation(); - //let key = DecodingKey::from_secret(&[]); - //let mut validation = Validation::new(Algorithm::HS256); - //validation.insecure_disable_signature_validation(); + // let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); + // let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion + // failed"); println!("jwt_string_3 is {:?}", jwt_string_3); + // JwtDataDecodedPart3 + // let jwt_data_decoded3: JwtDataDecodedPart3 = + // serde_json::from_str(&jwt_string_3).unwrap(); - //let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); - //let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion failed"); - //println!("jwt_string_3 is {:?}", jwt_string_3); - //JwtDataDecodedPart3 - //let jwt_data_decoded3: JwtDataDecodedPart3 = serde_json::from_str(&jwt_string_3).unwrap(); + // let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; + // println!("{:?}", encode(&jwt_data_1)); + // let jwt_string_3 = String::from_utf8(&jwt_data_3); - - //let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; - //println!("{:?}", encode(&jwt_data_1)); - //let jwt_string_3 = String::from_utf8(&jwt_data_3); - - //let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; - //let n = jwt_v_3["n"]; + // let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; + // let n = jwt_v_3["n"]; let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); let time_for_chcksgns = single_chcksgns(&eph_pubkey, &zk_login_inputs, &all_jwk); println!("time_for_vergrth16 is {time_for_vergrth16}"); println!("time_for_chcksgns is {time_for_chcksgns}"); - let current_ratio = time_for_vergrth16/time_for_chcksgns; + let current_ratio = time_for_vergrth16 / time_for_chcksgns; println!("current_ratio is {current_ratio}"); - sum_ratio = sum_ratio + current_ratio;/**/ + sum_ratio = sum_ratio + current_ratio; /**/ println!("sum_ratio is {sum_ratio}"); println!("=========================================="); } - let average_ratio = sum_ratio/(sui_data.len() as u128); + let average_ratio = sum_ratio / (sui_data.len() as u128); println!("average ratio is {average_ratio}"); } -fn prepare_proof_and_public_key_cells_for_stack(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> (Cell, Cell) { +fn prepare_proof_and_public_key_cells_for_stack( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, +) -> (Cell, Cell) { let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); println!("kid = {}", kid); println!("all_jwk = {:?}", all_jwk); - let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) + .unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -1528,12 +1574,15 @@ fn prepare_proof_and_public_key_cells_for_stack(eph_pubkey: &Vec, zk_login_i (proof_cell, public_inputs_cell) } +fn single_vrgrth16( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, +) -> u128 { + let (proof_cell, public_inputs_cell) = + prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - -fn single_vrgrth16(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { - let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - - //let verification_key_id: u32 = 2; + // let verification_key_id: u32 = 2; let verification_key_id: u32 = 0; let mut code = "PUSHREF \n".to_string(); @@ -1542,14 +1591,18 @@ fn single_vrgrth16(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jw code = code + "VERGRTH16"; let start: Instant = Instant::now(); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); start.elapsed().as_micros() } - - -fn single_chcksgns(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { - let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); +fn single_chcksgns( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, +) -> u128 { + let (proof_cell, public_inputs_cell) = + prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); let pair = gen_keypair(); @@ -1561,34 +1614,31 @@ fn single_chcksgns(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jw let concatenated = [&first[..], &second[..]].concat(); - let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - //put signature to separate slice + // put signature to separate slice let len = signature.len() * 8; let signature = SliceData::from_raw(signature, len); - //put public key to integer + // put public key to integer let pub_key = BuilderData::with_raw( pair.public.to_bytes().to_vec(), - ed25519_dalek::PUBLIC_KEY_LENGTH * 8 - ).unwrap(); + ed25519_dalek::PUBLIC_KEY_LENGTH * 8, + ) + .unwrap(); let start: Instant = Instant::now(); - test_case_with_refs(" + test_case_with_refs( + " PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) - .expect_stack(Stack::new().push(int!(-1))); + ", + vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], + ) + .expect_stack(Stack::new().push(int!(-1))); start.elapsed().as_micros() - } - - - - - - diff --git a/tvm_tests/src/test_zk_.rs b/tvm_tests/src/test_zk_.rs index d026baaf..fda5e630 100644 --- a/tvm_tests/src/test_zk_.rs +++ b/tvm_tests/src/test_zk_.rs @@ -1,139 +1,155 @@ -/* -use std::collections::HashMap; -use std::slice; -use ark_std::rand::rngs::StdRng; -use ark_std::rand::SeedableRng; -use base64ct::Encoding as bEncoding; -use fastcrypto::ed25519::Ed25519KeyPair; - - -use fastcrypto::traits::KeyPair; -use rand::Rng; -//use similar::DiffableStr; -use tvm_block::{ - GlobalCapabilities, MsgAddressInt, Serializable, ACTION_CHANGE_LIB, ACTION_COPYLEFT, - ACTION_RESERVE, ACTION_SEND_MSG, ACTION_SET_CODE, -}; -use tvm_assembler::compile_code_to_cell; -use tvm_types::{ - types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, - Sha256 -}; - -#[cfg(feature = "signature_no_check")] -use ton_vm::executor::BehaviorModifiers; -use tvm_vm::{ - boolean, - executor::serialize_currency_collection, - int, - stack::{ - integer::{ - serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, - IntegerData, - }, - serialization::{Deserializer, Serializer}, - Stack, StackItem, - }, - SmartContractInfo, - utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, -}; - -use tvm_vm::executor::zk::ZkCryptoError; -use tvm_assembler::CompileError; -use tvm_types::{BuilderData, Cell, SliceData}; - -use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, OIDCProvider, ZkLoginInputs}; -use fastcrypto_zkp::bn254::utils::gen_address_seed; - -pub const VALUE_PORTION_SIZE: usize = 126; - -#[test] -fn test_vergrth16() { - let user_pass_salt = "206703048842351542647799591018316385612"; - - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = vec![0x00]; - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - - println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); - let len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", len); - - // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "106294049240999307923", - "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); - - println!("zk_seed = {:?}", zk_seed); - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - let len = proof_and_jwt.bytes().len(); - println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), - alg: "RS256".to_string(), - }; - - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); - - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| { - ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); - - let max_epoch = 10; - - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); - - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - - let verification_key_id: u32 = 1; - - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; - - // ... run 'code', providing proof_cell, public_inputs_cell into stack.. -} - - - -*/ +// use std::collections::HashMap; +// use std::slice; +// use ark_std::rand::rngs::StdRng; +// use ark_std::rand::SeedableRng; +// use base64ct::Encoding as bEncoding; +// use fastcrypto::ed25519::Ed25519KeyPair; +// +// +// use fastcrypto::traits::KeyPair; +// use rand::Rng; +// use similar::DiffableStr; +// use tvm_block::{ +// GlobalCapabilities, MsgAddressInt, Serializable, ACTION_CHANGE_LIB, +// ACTION_COPYLEFT, ACTION_RESERVE, ACTION_SEND_MSG, ACTION_SET_CODE, +// }; +// use tvm_assembler::compile_code_to_cell; +// use tvm_types::{ +// types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, +// Sha256 +// }; +// +// #[cfg(feature = "signature_no_check")] +// use ton_vm::executor::BehaviorModifiers; +// use tvm_vm::{ +// boolean, +// executor::serialize_currency_collection, +// int, +// stack::{ +// integer::{ +// serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, +// IntegerData, +// }, +// serialization::{Deserializer, Serializer}, +// Stack, StackItem, +// }, +// SmartContractInfo, +// utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, +// }; +// +// use tvm_vm::executor::zk::ZkCryptoError; +// use tvm_assembler::CompileError; +// use tvm_types::{BuilderData, Cell, SliceData}; +// +// use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, +// OIDCProvider, ZkLoginInputs}; +// use fastcrypto_zkp::bn254::utils::gen_address_seed; +// +// pub const VALUE_PORTION_SIZE: usize = 126; +// +// #[test] +// fn test_vergrth16() { +// let user_pass_salt = "206703048842351542647799591018316385612"; +// +// Generate an ephemeral key pair. +// let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); +// let mut eph_pubkey = vec![0x00]; +// eph_pubkey.extend(ephemeral_kp.public().as_ref()); +// +// println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); +// let len = eph_pubkey.clone().len(); +// println!("len eph_pubkey: {:?}", len); +// +// Get the zklogin seed. +// This stuff is a kind of bound between smart contract and email (some +// account) It will be stored in smart contract (must be added during contract +// deployment) let zk_seed = gen_address_seed( +// user_pass_salt, +// "sub", +// "106294049240999307923", +// "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", +// ).unwrap(); +// +// println!("zk_seed = {:?}", zk_seed); +// +// let proof_and_jwt = +// "{\"proofPoints\":{\"a\":[\" +// 8247215875293406890829839156897863742504615191361518281091302475904551111016\ +// ",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\ +// ",\"1\"],\"b\":[[\" +// 21419680064642047510915171723230639588631899775315750803416713283740137406807\ +// ",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\ +// "],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\ +// ",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\ +// "],[\"1\",\"0\"]],\"c\":[\" +// 7530826803702928198368421787278524256623871560746240215547076095911132653214\ +// ",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\ +// ",\"1\"]},\"issBase64Details\":{\"value\":\" +// yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\" +// headerBase64\":\" +// eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\ +// "}"; let len = proof_and_jwt.bytes().len(); +// println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); +// +// let zk_login_inputs = ZkLoginInputs::from_json( +// &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// +// let content: JWK = JWK { +// kty: "RSA".to_string(), +// e: "AQAB".to_string(), +// n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), +// alg: "RS256".to_string(), +// }; +// +// let mut all_jwk = HashMap::new(); +// all_jwk.insert( +// JwkId::new( +// OIDCProvider::Google.get_config().iss, +// "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), +// ), +// content, +// ); +// +// let (iss, kid) = (zk_login_inputs.get_iss().to_string(), +// zk_login_inputs.get_kid().to_string()); let jwk = all_jwk +// .get(&JwkId::new(iss.clone(), kid.clone())) +// .ok_or_else(|| { +// ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) +// }).unwrap(); +// +// let max_epoch = 10; +// +// Decode modulus to bytes. +// let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { +// ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) +// }).unwrap(); +// +// let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); +// let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, +// &modulus, max_epoch).unwrap()]; +// +// let mut proof_as_bytes = vec![]; +// proof.serialize_compressed(&mut proof_as_bytes).unwrap(); +// println!("proof_as_bytes : {:?}", proof_as_bytes); +// +// let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); +// +// let mut public_inputs_as_bytes = vec![]; +// public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); +// println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); +// +// let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut +// 0).unwrap(); +// +// let verification_key_id: u32 = 1; +// +// let mut code = "PUSHREF \n".to_string(); +// code = code + "PUSHREF \n"; +// code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; +// code = code + "VERGRTH16"; +// +// ... run 'code', providing proof_cell, public_inputs_cell into stack.. +// } +// +// +// diff --git a/tvm_vm/src/executor/crypto.rs b/tvm_vm/src/executor/crypto.rs index bd2ccb0a..298ad2a7 100644 --- a/tvm_vm/src/executor/crypto.rs +++ b/tvm_vm/src/executor/crypto.rs @@ -10,6 +10,7 @@ // limitations under the License. use std::borrow::Cow; +use std::time::Instant; use ed25519::Signature; use ed25519_dalek::Verifier; @@ -31,9 +32,6 @@ use crate::stack::StackItem; use crate::types::Exception; use crate::types::Status; -use std::time::Instant; -use bls12_381::Bls12; - const PUBLIC_KEY_BITS: usize = PUBLIC_KEY_BYTES * 8; const SIGNATURE_BITS: usize = SIGNATURE_BYTES * 8; const PUBLIC_KEY_BYTES: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; @@ -153,27 +151,27 @@ fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Statu let signature = match Signature::try_from(&signature[..SIGNATURE_BYTES]) { Ok(signature) => signature, Err(err) => - { - #[allow(clippy::collapsible_else_if)] - if engine.check_capabilities(GlobalCapabilities::CapsTvmBugfixes2022 as u64) { + { + #[allow(clippy::collapsible_else_if)] + if engine.check_capabilities(GlobalCapabilities::CapsTvmBugfixes2022 as u64) { + engine.cc.stack.push(boolean!(false)); + return Ok(()); + } else { + if hash { engine.cc.stack.push(boolean!(false)); return Ok(()); } else { - if hash { - engine.cc.stack.push(boolean!(false)); - return Ok(()); - } else { - return err!(ExceptionCode::FatalError, "cannot load signature {}", err); - } + return err!(ExceptionCode::FatalError, "cannot load signature {}", err); } } + } }; let data = preprocess_signed_data(engine, data.as_ref()); #[cfg(feature = "signature_no_check")] - let result = + let result = engine.modifiers.chksig_always_succeed || pub_key.verify(&data, &signature).is_ok(); #[cfg(not(feature = "signature_no_check"))] - let result = pub_key.verify(&data, &signature).is_ok(); + let result = pub_key.verify(&data, &signature).is_ok(); let duration = start.elapsed(); @@ -184,7 +182,6 @@ fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Statu Ok(()) } - // CHKSIGNS (d s k – ?) // checks whether s is a valid Ed25519-signature of the data portion of Slice d // using public key k, similarly to CHKSIGNU. If the bit length of Slice d is diff --git a/tvm_vm/src/executor/engine/handlers.rs b/tvm_vm/src/executor/engine/handlers.rs index 032c9203..fcc86f18 100644 --- a/tvm_vm/src/executor/engine/handlers.rs +++ b/tvm_vm/src/executor/engine/handlers.rs @@ -44,13 +44,12 @@ use crate::executor::token::*; use crate::executor::tuple::*; use crate::executor::types::Instruction; use crate::executor::types::InstructionOptions; +use crate::executor::zk::*; use crate::stack::integer::behavior::Quiet; use crate::stack::integer::behavior::Signaling; use crate::types::Exception; use crate::types::Status; -use crate::executor::zk::*; - // ( - ) fn execute_nop(engine: &mut Engine) -> Status { engine.load_instruction(Instruction::new("NOP")) diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 4de0234d..53707bd5 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -1,58 +1,50 @@ -use crate::executor::Engine; -use crate::types::Status; +use std::str::FromStr; +use std::time::Instant; -use ark_bn254::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +pub use ark_bn254::Bn254; +use ark_bn254::Fq; +use ark_bn254::Fq2; +use ark_bn254::Fr; +pub use ark_bn254::Fr as Bn254Fr; +use ark_bn254::G1Affine; +use ark_bn254::G1Projective; +use ark_bn254::G2Affine; +use ark_bn254::G2Projective; use ark_ff::BigInteger; use ark_ff::PrimeField; +use ark_groth16::Groth16; +use ark_groth16::PreparedVerifyingKey; +use ark_groth16::VerifyingKey; +// use once_cell::sync::Lazy; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_snark::SNARK; +use derive_more::From; use num_bigint::BigUint; use schemars::JsonSchema; -use derive_more::From; -use serde::Serialize; use serde::Deserialize; - -use std::borrow::Cow; -use std::collections::HashMap; -use std::fmt::Error; - -use tvm_block::GlobalCapabilities; -use tvm_types::error; -use tvm_types::BuilderData; -use tvm_types::ExceptionCode; -use tvm_types::GasConsumer; -use tvm_types::UInt256; +use serde::Serialize; +use serde_json::Value; use tvm_types::SliceData; -use base64ct::{Base64UrlUnpadded,Encoding}; - -use std::str::FromStr; -use std::time::Instant; - -pub use ark_bn254::{Bn254, Fr as Bn254Fr}; -use ark_groth16::{Groth16, PreparedVerifyingKey, Proof, VerifyingKey}; -use ark_snark::SNARK; - - -use crate::error::TvmError; use crate::executor::engine::storage::fetch_stack; -use crate::executor::types::Instruction; -use crate::stack::integer::serialization::UnsignedIntegerBigEndianEncoding; -use crate::stack::integer::IntegerData; -use crate::stack::StackItem; -use crate::types::Exception; -use crate::utils::{bytes_to_string, unpack_string_from_cell}; -use crate::utils::pack_data_to_cell; -use crate::utils::unpack_data_from_cell; -//use once_cell::sync::Lazy; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use serde_json::Value; -use thiserror::Error; use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; use crate::executor::zk_stuff::curve_utils::Bn254FrElement; use crate::executor::zk_stuff::error::ZkCryptoError; use crate::executor::zk_stuff::utils::split_to_two_frs; -use crate::executor::zk_stuff::zk_login::{Claim, hash_ascii_str_to_field, hash_to_field, MAX_HEADER_LEN, MAX_ISS_LEN_B64, PACK_WIDTH}; +use crate::executor::zk_stuff::zk_login::hash_ascii_str_to_field; +use crate::executor::zk_stuff::zk_login::hash_to_field; +use crate::executor::zk_stuff::zk_login::MAX_HEADER_LEN; +use crate::executor::zk_stuff::zk_login::MAX_ISS_LEN_B64; +use crate::executor::zk_stuff::zk_login::PACK_WIDTH; +use crate::executor::Engine; +use crate::stack::integer::serialization::UnsignedIntegerBigEndianEncoding; +use crate::stack::integer::IntegerData; +use crate::stack::StackItem; use crate::stack::StackItem::Cell; - +use crate::types::Status; +use crate::utils::pack_data_to_cell; +use crate::utils::unpack_data_from_cell; +use crate::utils::unpack_string_from_cell; pub type ZkCryptoResult = Result; @@ -63,7 +55,8 @@ pub const SCALAR_SIZE: usize = 32; pub struct FieldElementWrapper(pub(crate) ark_bn254::Fr); impl FieldElementWrapper { - /// Deserialize 32 bytes into a BN254 field element using little-endian format. + /// Deserialize 32 bytes into a BN254 field element using little-endian + /// format. pub(crate) fn deserialize(bytes: &[u8]) -> ZkCryptoResult { if bytes.len() != SCALAR_SIZE { return Err(ZkCryptoError::InputLengthWrong(bytes.len())); @@ -73,8 +66,9 @@ impl FieldElementWrapper { .map(FieldElementWrapper) } - /// Deserialize a vector of bytes into a vector of BN254 field elements, assuming that each element - /// is serialized as a chunk of 32 bytes. See also [`FieldElement::deserialize`]. + /// Deserialize a vector of bytes into a vector of BN254 field elements, + /// assuming that each element is serialized as a chunk of 32 bytes. See + /// also [`FieldElement::deserialize`]. pub(crate) fn deserialize_vector( field_element_bytes: &[u8], ) -> ZkCryptoResult> { @@ -89,12 +83,11 @@ impl FieldElementWrapper { } } - pub type CircomG1 = Vec; -/// A G2 point in BN254 serialized as a vector of three vectors each being a vector of two strings -/// which are the canonical decimal representation of the coefficients of the projective coordinates -/// in Fq2. +/// A G2 point in BN254 serialized as a vector of three vectors each being a +/// vector of two strings which are the canonical decimal representation of the +/// coefficients of the projective coordinates in Fq2. pub type CircomG2 = Vec>; /// A struct that stores a Bn254 Fq field element as 32 bytes. @@ -107,10 +100,7 @@ impl std::str::FromStr for Bn254FqElementWrapper { fn from_str(s: &str) -> Result { let big_int = Fq::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; let be_bytes = big_int.into_bigint().to_bytes_be(); - be_bytes - .try_into() - .map_err(|_| ZkCryptoError::InvalidInput) - .map(Bn254FqElementWrapper) + be_bytes.try_into().map_err(|_| ZkCryptoError::InvalidInput).map(Bn254FqElementWrapper) } } @@ -125,8 +115,8 @@ impl std::fmt::Display for Bn254FqElementWrapper { // Bn254FqElement's serialized format is as a radix10 encoded string impl Serialize for Bn254FqElementWrapper { fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + where + S: serde::Serializer, { self.to_string().serialize(serializer) } @@ -134,8 +124,8 @@ impl Serialize for Bn254FqElementWrapper { impl<'de> Deserialize<'de> for Bn254FqElementWrapper { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, + where + D: serde::Deserializer<'de>, { let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) @@ -147,7 +137,8 @@ impl<'de> Deserialize<'de> for Bn254FqElementWrapper { pub struct Bn254FrElementWrapper(#[schemars(with = "String")] [u8; 32]); impl Bn254FrElementWrapper { - /// Returns the unpadded version of the field element. This returns with leading zeros removed. + /// Returns the unpadded version of the field element. This returns with + /// leading zeros removed. pub fn unpadded(&self) -> &[u8] { let mut buf = self.0.as_slice(); @@ -156,14 +147,11 @@ impl Bn254FrElementWrapper { } // If the value is '0' then just return a slice of length 1 of the final byte - if buf.is_empty() { - &self.0[31..] - } else { - buf - } + if buf.is_empty() { &self.0[31..] } else { buf } } - /// Returns the padded version of the field element. This returns with leading zeros preserved to 32 bytes. + /// Returns the padded version of the field element. This returns with + /// leading zeros preserved to 32 bytes. pub fn padded(&self) -> &[u8] { &self.0 } @@ -174,10 +162,7 @@ impl std::str::FromStr for Bn254FrElementWrapper { fn from_str(s: &str) -> Result { let big_int = Fr::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; let be_bytes = big_int.into_bigint().to_bytes_be(); - be_bytes - .try_into() - .map_err(|_| ZkCryptoError::InvalidInput) - .map(Bn254FrElementWrapper) + be_bytes.try_into().map_err(|_| ZkCryptoError::InvalidInput).map(Bn254FrElementWrapper) } } @@ -192,8 +177,8 @@ impl std::fmt::Display for Bn254FrElementWrapper { // Bn254FrElement's serialized format is as a radix10 encoded string impl Serialize for Bn254FrElementWrapper { fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + where + S: serde::Serializer, { self.to_string().serialize(serializer) } @@ -201,8 +186,8 @@ impl Serialize for Bn254FrElementWrapper { impl<'de> Deserialize<'de> for Bn254FrElementWrapper { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, + where + D: serde::Deserializer<'de>, { let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) @@ -223,9 +208,10 @@ impl From<&Bn254FrElementWrapper> for Fr { } } -/// Deserialize a G1 projective point in BN254 serialized as a vector of three strings into an affine -/// G1 point in arkworks format. Return an error if the input is not a vector of three strings or if -/// any of the strings cannot be parsed as a field element. +/// Deserialize a G1 projective point in BN254 serialized as a vector of three +/// strings into an affine G1 point in arkworks format. Return an error if the +/// input is not a vector of three strings or if any of the strings cannot be +/// parsed as a field element. pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result { if s.len() != 3 { return Err(ZkCryptoError::InvalidInput); @@ -241,10 +227,11 @@ pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result Result { if s.len() != 3 || s[0].len() != 2 || s[1].len() != 2 || s[2].len() != 2 { return Err(ZkCryptoError::InvalidInput); @@ -255,7 +242,7 @@ pub(crate) fn g2_affine_from_str_projective(s: &CircomG2) -> Result Result`. +/// A Groth16 proof in the BN254 construction. Thin wrapper around +/// `ark_groth16::Proof::`. #[derive(Debug, From)] pub struct ProofWrapper(pub(crate) ark_groth16::Proof); @@ -278,126 +265,123 @@ impl ProofWrapper { } } - -/** - Here there are third party zk login Groth16 verification keys taken for now for tests - todo: will be replaced by our keys later - todo: move all key data to json config file (?), use hash as id -**/ +/// Here there are third party zk login Groth16 verification keys taken for now +/// for tests todo: will be replaced by our keys later +/// todo: move all key data to json config file (?), use hash as id ///////////////////////////////////////////////////////////////////////////////////////////////////////// -//static GLOBAL_VERIFYING_KEY: Lazy> = Lazy::new(global_pvk); +// static GLOBAL_VERIFYING_KEY: Lazy> = Lazy::new(global_pvk); /// Corresponding to proofs generated from prover-dev. Used in devnet/testnet. -//static INSECURE_VERIFYING_KEY: Lazy> = Lazy::new(insecure_pvk); +// static INSECURE_VERIFYING_KEY: Lazy> = Lazy::new(insecure_pvk); -//static ZKP_VERIFYING_KEYS: Lazy>> = Lazy::new(keys); +// static ZKP_VERIFYING_KEYS: Lazy>> = Lazy::new(keys); -//todo: will contain our keys later, key ould be a hash of verification key -/*fn keys() -> HashMap> { - let mut h = HashMap::new(); - h.insert(0, insecure_pvk()); - h.insert(1, global_pvk()); - h -}*/ +// todo: will contain our keys later, key ould be a hash of verification key +// fn keys() -> HashMap> { +// let mut h = HashMap::new(); +// h.insert(0, insecure_pvk()); +// h.insert(1, global_pvk()); +// h +// } -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a +/// local setup and should not use in production. fn insecure_pvk() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ Bn254FqElementWrapper::from_str( "20491192805390485299153009773594534940189261866228447918068658471970481763042", - ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "9383485363053290200918347156157836566562967994039712273449902621266178545958", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ]) - .unwrap(); + .unwrap(); let vk_beta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "6375614351688725206403948262868962793625744043794305715222011528459656738731", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4252822878758300859123897981450591353533073413197771768651442665752259397132", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "10505242626370262277552901082094356697409835680220590971873171140371331206856", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "21847035105528745403288232691147584728191162732299865338377159692350059136679", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); let vk_gamma_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); let vk_delta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); // Create a vector of G1Affine elements from the IC let mut vk_gamma_abc_g1 = Vec::new(); @@ -406,22 +390,22 @@ fn insecure_pvk() -> PreparedVerifyingKey { Bn254FqElementWrapper::from_str( "20701306374481714853949730154526815782802808896228594855451770849676897643964", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "2766989084754673216772682210231588284954002353414778477810174100808747060165", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "501195541410525737371980194958674422793469475773065719916327137354779402600", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "13527631693157515024233848630878973193664410306029731429350155106228769355415", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], ] { @@ -441,102 +425,103 @@ fn insecure_pvk() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a +/// local setup and should not use in production. fn global_pvk() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ Bn254FqElementWrapper::from_str( "21529901943976716921335152104180790524318946701278905588288070441048877064089", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "7775817982019986089115946956794180159548389285968353014325286374017358010641", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ]) - .unwrap(); + .unwrap(); let vk_beta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "6600437987682835329040464538375790690815756241121776438004683031791078085074", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "16207344858883952201936462217289725998755030546200154201671892670464461194903", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "17943105074568074607580970189766801116106680981075272363121544016828311544390", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "18339640667362802607939727433487930605412455701857832124655129852540230493587", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); let vk_gamma_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); let vk_delta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "19260309516619721648285279557078789954438346514188902804737557357941293711874", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "2480422554560175324649200374556411861037961022026590718777465211464278308900", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "14489104692423540990601374549557603533921811847080812036788172274404299703364", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "12564378633583954025611992187142343628816140907276948128970903673042690269191", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); + .unwrap(); // Create a vector of G1Affine elements from the IC let mut vk_gamma_abc_g1 = Vec::new(); @@ -545,22 +530,22 @@ fn global_pvk() -> PreparedVerifyingKey { Bn254FqElementWrapper::from_str( "1607694606386445293170795095076356565829000940041894770459712091642365695804", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "18066827569413962196795937356879694709963206118612267170825707780758040578649", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "20653794344898475822834426774542692225449366952113790098812854265588083247207", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "3296759704176575765409730962060698204792513807296274014163938591826372646699", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], ] { @@ -581,249 +566,229 @@ fn global_pvk() -> PreparedVerifyingKey { } /////////////////////////////////// - -/* -{ - "protocol": "groth16", - "curve": "bn128", - "nPublic": 1, - "vk_alpha_1": [ - "16083174311393072332126484955039141051820368387551336007741432494536231879877", - "11995344593741129498206341608147577676708407993917230939676252851997423446210", - "1" - ], - "vk_beta_2": [ - [ - "7017589137241388812217334676878160715759313595646525247042913539379033763831", - "9588720105182136304988839277158105754318461657916765428451866781594135026063" - ], - [ - "2484424409632768920146683103978991861859052149379216050446911519906662584090", - "3390288516800701266276631045627865236740814264026178914799455551851945389106" - ], - [ - "1", - "0" - ] - ], - "vk_gamma_2": [ - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ], - [ - "1", - "0" - ] - ], - "vk_delta_2": [ - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ], - [ - "1", - "0" - ] - ], - "vk_alphabeta_12": [ - [ - [ - "21714733147969646607026510860825588717650100219981797829057062263408210680902", - "3537008011880168200043686742311687201724399812943751195896776782786770376237" - ], - [ - "17603627875319511470028150667626739231437882724082498094331281187463632527978", - "16387102395026382896078557475195975755625086402782579280728310209714363840057" - ], - [ - "10167039699419387719397961362130358913333446306472876910740079573026549091749", - "6683396731874395214442048077624848369375657254618428851285341246028721012664" - ] - ], - [ - [ - "12883624783449422144000099623629921455607648590216105687641263583110919278339", - "9384401935718213548370561215738644696157076909382807246189505166565439193274" - ], - [ - "11443428859064566845483530360939187689156386007731719272145725927626704316158", - "534441300427034362842952165392761749478350428105140492258092586110074096069" - ], - [ - "1626464416056203606908509147988281610862706785412523317944442421120459947696", - "14642919198945900947469533820505010212370261142917394368657515679029120182987" - ] - ] - ], - "IC": [ - [ - "11760611693671517707466601638901224388668992590928868758649168369215563295744", - "15842561259007247784907604255150260908812200067246900457940460682994649597353", - "1" - ], - [ - "9960247968913608540350443520882802417817484595360267448450266543686043480996", - "11040490439713280236989540698814598402024610465375008410116396264618122562865", - "1" - ] - ] -} - */ - - - -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a local setup and should not use in production. +// { +// "protocol": "groth16", +// "curve": "bn128", +// "nPublic": 1, +// "vk_alpha_1": [ +// "16083174311393072332126484955039141051820368387551336007741432494536231879877", +// "11995344593741129498206341608147577676708407993917230939676252851997423446210", +// "1" +// ], +// "vk_beta_2": [ +// [ +// "7017589137241388812217334676878160715759313595646525247042913539379033763831", +// "9588720105182136304988839277158105754318461657916765428451866781594135026063" +// ], +// [ +// "2484424409632768920146683103978991861859052149379216050446911519906662584090", +// "3390288516800701266276631045627865236740814264026178914799455551851945389106" +// ], +// [ +// "1", +// "0" +// ] +// ], +// "vk_gamma_2": [ +// [ +// "10857046999023057135944570762232829481370756359578518086990519993285655852781", +// "11559732032986387107991004021392285783925812861821192530917403151452391805634" +// ], +// [ +// "8495653923123431417604973247489272438418190587263600148770280649306958101930", +// "4082367875863433681332203403145435568316851327593401208105741076214120093531" +// ], +// [ +// "1", +// "0" +// ] +// ], +// "vk_delta_2": [ +// [ +// "10857046999023057135944570762232829481370756359578518086990519993285655852781", +// "11559732032986387107991004021392285783925812861821192530917403151452391805634" +// ], +// [ +// "8495653923123431417604973247489272438418190587263600148770280649306958101930", +// "4082367875863433681332203403145435568316851327593401208105741076214120093531" +// ], +// [ +// "1", +// "0" +// ] +// ], +// "vk_alphabeta_12": [ +// [ +// [ +// "21714733147969646607026510860825588717650100219981797829057062263408210680902", +// "3537008011880168200043686742311687201724399812943751195896776782786770376237" +// ], +// [ +// "17603627875319511470028150667626739231437882724082498094331281187463632527978", +// "16387102395026382896078557475195975755625086402782579280728310209714363840057" +// ], +// [ +// "10167039699419387719397961362130358913333446306472876910740079573026549091749", +// "6683396731874395214442048077624848369375657254618428851285341246028721012664" +// ] +// ], +// [ +// [ +// "12883624783449422144000099623629921455607648590216105687641263583110919278339", +// "9384401935718213548370561215738644696157076909382807246189505166565439193274" +// ], +// [ +// "11443428859064566845483530360939187689156386007731719272145725927626704316158", +// "534441300427034362842952165392761749478350428105140492258092586110074096069" +// ], +// [ +// "1626464416056203606908509147988281610862706785412523317944442421120459947696", +// "14642919198945900947469533820505010212370261142917394368657515679029120182987" +// ] +// ] +// ], +// "IC": [ +// [ +// "11760611693671517707466601638901224388668992590928868758649168369215563295744", +// "15842561259007247784907604255150260908812200067246900457940460682994649597353", +// "1" +// ], +// [ +// "9960247968913608540350443520882802417817484595360267448450266543686043480996", +// "11040490439713280236989540698814598402024610465375008410116396264618122562865", +// "1" +// ] +// ] +// } + +/// Load a fixed verifying key from zkLogin.vkey output. This is based on a +/// local setup and should not use in production. fn my_test_pvk_1() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ Bn254FqElementWrapper::from_str( "16083174311393072332126484955039141051820368387551336007741432494536231879877", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11995344593741129498206341608147577676708407993917230939676252851997423446210", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ]) - .unwrap(); - /* - "16083174311393072332126484955039141051820368387551336007741432494536231879877", - "11995344593741129498206341608147577676708407993917230939676252851997423446210", - */ - + .unwrap(); + // "16083174311393072332126484955039141051820368387551336007741432494536231879877", + // "11995344593741129498206341608147577676708407993917230939676252851997423446210", let vk_beta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "7017589137241388812217334676878160715759313595646525247042913539379033763831", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "9588720105182136304988839277158105754318461657916765428451866781594135026063", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "2484424409632768920146683103978991861859052149379216050446911519906662584090", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "3390288516800701266276631045627865236740814264026178914799455551851945389106", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); - /* - [ - "7017589137241388812217334676878160715759313595646525247042913539379033763831", - "9588720105182136304988839277158105754318461657916765428451866781594135026063" - ], - [ - "2484424409632768920146683103978991861859052149379216050446911519906662584090", - "3390288516800701266276631045627865236740814264026178914799455551851945389106" - ] - */ - - - - + .unwrap(); + // [ + // "7017589137241388812217334676878160715759313595646525247042913539379033763831", + // "9588720105182136304988839277158105754318461657916765428451866781594135026063" + // ], + // [ + // "2484424409632768920146683103978991861859052149379216050446911519906662584090", + // "3390288516800701266276631045627865236740814264026178914799455551851945389106" + // ] let vk_gamma_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); - - /* - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ] - */ - - + .unwrap(); + // [ + // "10857046999023057135944570762232829481370756359578518086990519993285655852781", + // "11559732032986387107991004021392285783925812861821192530917403151452391805634" + // ], + // [ + // "8495653923123431417604973247489272438418190587263600148770280649306958101930", + // "4082367875863433681332203403145435568316851327593401208105741076214120093531" + // ] let vk_delta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531", ) - .unwrap(), + .unwrap(), ], vec![ Bn254FqElementWrapper::from_str("1").unwrap(), Bn254FqElementWrapper::from_str("0").unwrap(), ], ]) - .unwrap(); - - /* - [ - "10857046999023057135944570762232829481370756359578518086990519993285655852781", - "11559732032986387107991004021392285783925812861821192530917403151452391805634" - ], - [ - "8495653923123431417604973247489272438418190587263600148770280649306958101930", - "4082367875863433681332203403145435568316851327593401208105741076214120093531" - ] - */ + .unwrap(); + + // [ + // "10857046999023057135944570762232829481370756359578518086990519993285655852781", + // "11559732032986387107991004021392285783925812861821192530917403151452391805634" + // ], + // [ + // "8495653923123431417604973247489272438418190587263600148770280649306958101930", + // "4082367875863433681332203403145435568316851327593401208105741076214120093531" + // ] // Create a vector of G1Affine elements from the IC let mut vk_gamma_abc_g1 = Vec::new(); @@ -832,22 +797,22 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { Bn254FqElementWrapper::from_str( "11760611693671517707466601638901224388668992590928868758649168369215563295744", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "15842561259007247784907604255150260908812200067246900457940460682994649597353", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], vec![ Bn254FqElementWrapper::from_str( "9960247968913608540350443520882802417817484595360267448450266543686043480996", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str( "11040490439713280236989540698814598402024610465375008410116396264618122562865", ) - .unwrap(), + .unwrap(), Bn254FqElementWrapper::from_str("1").unwrap(), ], ] { @@ -855,22 +820,18 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { vk_gamma_abc_g1.push(g1); } - /* - [ - [ - "11760611693671517707466601638901224388668992590928868758649168369215563295744", - "15842561259007247784907604255150260908812200067246900457940460682994649597353", - "1" - ], - [ - "9960247968913608540350443520882802417817484595360267448450266543686043480996", - "11040490439713280236989540698814598402024610465375008410116396264618122562865", - "1" - ] - ] - */ - - + // [ + // [ + // "11760611693671517707466601638901224388668992590928868758649168369215563295744", + // "15842561259007247784907604255150260908812200067246900457940460682994649597353", + // "1" + // ], + // [ + // "9960247968913608540350443520882802417817484595360267448450266543686043480996", + // "11040490439713280236989540698814598402024610465375008410116396264618122562865", + // "1" + // ] + // ] let vk = VerifyingKey { alpha_g1: vk_alpha_1, @@ -884,11 +845,10 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } - pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { let start = Instant::now(); engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16_NEW"))?; - fetch_stack(engine, 3); + fetch_stack(engine, 3)?; let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; println!("from vergrth16 vk_index: {:?}", vk_index); @@ -905,18 +865,18 @@ pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; let x: Vec = public_inputs.iter().map(|x| x.0).collect(); - let vk = if (vk_index == 0) { + let vk = if vk_index == 0 { insecure_pvk() - } else if (vk_index == 1) { + } else if vk_index == 1 { global_pvk() } else { my_test_pvk_1() }; - - //ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; + // ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); - //todo: add alternative for elliptic curve (may be we need bls curve also?), read from stack curve id + // todo: add alternative for elliptic curve (may be we need bls curve also?), + // read from stack curve id let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); @@ -926,12 +886,7 @@ pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { let succes = res.is_ok(); println!("res: {:?}", res); - let res = if (succes) { - boolean!(res.unwrap()) - } - else { - boolean!(false) - }; + let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; println!("res: {:?}", res); engine.cc.stack.push(res); @@ -942,12 +897,11 @@ pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let start = Instant::now(); engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16"))?; - fetch_stack(engine, 3); + fetch_stack(engine, 3)?; let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; println!("from vergrth16 vk_index: {:?}", vk_index); - let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; println!("from vergrth16 value public_inputs_as_bytes: {:?}", public_inputs_as_bytes); @@ -960,17 +914,18 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; let x: Vec = public_inputs.iter().map(|x| x.0).collect(); - let vk = if (vk_index == 0) { + let vk = if vk_index == 0 { insecure_pvk() - } else if (vk_index == 1) { + } else if vk_index == 1 { global_pvk() } else { my_test_pvk_1() }; - //ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; + // ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); - //todo: add alternative for elliptic curve (may be we need bls curve also?), read from stack curve id + // todo: add alternative for elliptic curve (may be we need bls curve also?), + // read from stack curve id let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); @@ -978,15 +933,9 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { println!("Time elapsed by vergrth16 is: {:?}", duration); - let succes = res.is_ok(); println!("res: {:?}", res); - let res = if (succes) { - boolean!(res.unwrap()) - } - else { - boolean!(false) - }; + let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; println!("res: {:?}", res); engine.cc.stack.push(res); @@ -1000,132 +949,125 @@ fn pop(barry: &[u8]) -> &[u8; 8] { pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; - //fetch_stack(engine, 4); - fetch_stack(engine, 5); + // fetch_stack(engine, 4); + fetch_stack(engine, 5)?; let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; println!("from poseidon value zkaddr: {:?}", zkaddr); - /*let epk_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; - let epk_as_bytes = unpack_data_from_cell(epk_slice, engine)?; - println!("from poseidon value epk_as_bytes: {:?}", hex::encode(epk_as_bytes.clone()));*/ + // let epk_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; + // let epk_as_bytes = unpack_data_from_cell(epk_slice, engine)?; + // println!("from poseidon value epk_as_bytes: {:?}", + // hex::encode(epk_as_bytes.clone())); - let header_and_iss_base64_slice = SliceData::load_cell_ref(engine.cmd.var(1 /*2*/).as_cell()?)?; + let header_and_iss_base64_slice = + SliceData::load_cell_ref(engine.cmd.var(1 /* 2 */).as_cell()?)?; let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; println!("from poseidon value header_and_iss_base64: {:?}", header_and_iss_base64); - let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2 /*3*/).as_cell()?)?; + let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2 /* 3 */).as_cell()?)?; let modulus = unpack_data_from_cell(modulus_slice, engine)?; - println!("from poseidon value modulus: {:?}",modulus); - + println!("from poseidon value modulus: {:?}", modulus); let eph_pub_key = engine - .cmd - .var(3 /*4*/) + .cmd + .var(3 /* 4 */) .as_integer()? - .as_builder::(/*PUBLIC_KEY_BITS*/ 256)?; + .as_builder::(/* PUBLIC_KEY_BITS */ 256)?; let eph_pub_key_bytes = eph_pub_key.data(); - println!("from poseidon value eph_pub_key_bytes: {:?}",eph_pub_key_bytes.len()); - println!("from poseidon value eph_pub_key_bytes: {:?}",eph_pub_key_bytes); + println!("from poseidon value eph_pub_key_bytes: {:?}", eph_pub_key_bytes.len()); + println!("from poseidon value eph_pub_key_bytes: {:?}", eph_pub_key_bytes); let max_epoch_ = engine - .cmd - .var(4 /*4*/) + .cmd + .var(4 /* 4 */) .as_integer()? - .as_builder::(/*PUBLIC_KEY_BITS*/ 64)?; + .as_builder::(/* PUBLIC_KEY_BITS */ 64)?; let max_epoch_bytes = pop(max_epoch_.data()); let max_epoch = u64::from_be_bytes(*max_epoch_bytes); - println!("from poseidon value max_epoch: {:?}",max_epoch); - - println!("from poseidon value max_epoch_bytes: {:?}",max_epoch_bytes.len()); - println!("from poseidon value max_epoch_bytes: {:?}",max_epoch_bytes); + println!("from poseidon value max_epoch: {:?}", max_epoch); + println!("from poseidon value max_epoch_bytes: {:?}", max_epoch_bytes.len()); + println!("from poseidon value max_epoch_bytes: {:?}", max_epoch_bytes); - //let max_epoch = 10; //todo: read from stack later - //let max_epoch = 142; + // let max_epoch = 10; //todo: read from stack later + // let max_epoch = 142; let public_inputs = calculate_poseidon_hash( &*zkaddr, &*header_and_iss_base64, - &eph_pub_key_bytes/*epk_as_bytes*/, + &eph_pub_key_bytes, // epk_as_bytes &modulus, - max_epoch - ).unwrap(); - + max_epoch, + ) + .unwrap(); let mut public_inputs_as_bytes = vec![]; public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); println!("from poseidon public_inputs_as_bytes : {:?}", public_inputs_as_bytes.clone()); - //println!("from poseidon public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + // println!("from poseidon public_inputs_as_bytes len : {:?}", + // public_inputs_as_bytes.len()); let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); engine.cc.stack.push(Cell(public_inputs_cell)); Ok(()) - } - pub fn calculate_poseidon_hash( - address_seed: &str, - header_and_iss_base64: &str, - eph_pk_bytes: &[u8], - modulus: &[u8], - max_epoch: u64) -> Result/**/ { - /*if header_base64.len() > MAX_HEADER_LEN as usize { - return Err(ZkCryptoError::GeneralError("Header too long".to_string())); - }*/ + address_seed: &str, + header_and_iss_base64: &str, + eph_pk_bytes: &[u8], + modulus: &[u8], + max_epoch: u64, +) -> Result /**/ { + // if header_base64.len() > MAX_HEADER_LEN as usize { + // return Err(ZkCryptoError::GeneralError("Header too long".to_string())); + // } - let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); - let addr_seed = (&address_seed).into(); + let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); + let addr_seed = (&address_seed).into(); - let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); + let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); - let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); + let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); - let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); + let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); - let header_base64 = v["headerBase64"].as_str().unwrap(); - println!("header_base64 {}", header_base64); + let header_base64 = v["headerBase64"].as_str().unwrap(); + println!("header_base64 {}", header_base64); - let issBase64Details = v["issBase64Details"].as_object().unwrap(); - println!("issBase64Details {:?}", issBase64Details); + let iss_base64_details = v["issBase64Details"].as_object().unwrap(); + println!("issBase64Details {:?}", iss_base64_details); - let index_mod_4 = issBase64Details["indexMod4"].as_i64().unwrap().to_string(); + let index_mod_4 = iss_base64_details["indexMod4"].as_i64().unwrap().to_string(); - println!("index_mod_4 {:?}", index_mod_4); + println!("index_mod_4 {:?}", index_mod_4); - let iss_base64_details_value = issBase64Details["value"].as_str().unwrap(); + let iss_base64_details_value = iss_base64_details["value"].as_str().unwrap(); - println!("iss_base64_details_value {:?}", iss_base64_details_value); + println!("iss_base64_details_value {:?}", iss_base64_details_value); - let index_mod_4_f = - (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); + let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); - let iss_base64_f = - hash_ascii_str_to_field(&iss_base64_details_value, MAX_ISS_LEN_B64).unwrap(); - let header_f = hash_ascii_str_to_field(&header_base64, MAX_HEADER_LEN).unwrap(); - let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); + let iss_base64_f = hash_ascii_str_to_field(&iss_base64_details_value, MAX_ISS_LEN_B64).unwrap(); + let header_f = hash_ascii_str_to_field(&header_base64, MAX_HEADER_LEN).unwrap(); + let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); - poseidon_zk_login(vec![ - first, - second, - addr_seed, - max_epoch_f, - iss_base64_f, - index_mod_4_f, - header_f, - modulus_f, - ]) + poseidon_zk_login(vec![ + first, + second, + addr_seed, + max_epoch_f, + iss_base64_f, + index_mod_4_f, + header_f, + modulus_f, + ]) } - - - - - diff --git a/tvm_vm/src/executor/zk_stuff/bn254/api.rs b/tvm_vm/src/executor/zk_stuff/bn254/api.rs index 687d373b..3e75317f 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/api.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/api.rs @@ -2,25 +2,28 @@ // SPDX-License-Identifier: Apache-2.0 use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; -use crate::executor::zk_stuff::bn254::{FieldElement, Proof, VerifyingKey}; +use crate::executor::zk_stuff::bn254::FieldElement; +use crate::executor::zk_stuff::bn254::Proof; +use crate::executor::zk_stuff::bn254::VerifyingKey; use crate::executor::zk_stuff::error::ZkCryptoError; //#[cfg(test)] //#[path = "unit_tests/api_tests.rs"] -//mod api_tests; +// mod api_tests; /// Size of scalars in the BN254 construction. pub const SCALAR_SIZE: usize = 32; -/// Deserialize bytes as an Arkwork representation of a verifying key, and return a vector of the -/// four components of a prepared verified key (see more at [`PreparedVerifyingKey`]). +/// Deserialize bytes as an Arkwork representation of a verifying key, and +/// return a vector of the four components of a prepared verified key (see more +/// at [`PreparedVerifyingKey`]). pub fn prepare_pvk_bytes(vk_bytes: &[u8]) -> Result>, ZkCryptoError> { PreparedVerifyingKey::from(&VerifyingKey::deserialize(vk_bytes)?).serialize() } -/// Verify Groth16 proof using the serialized form of the prepared verifying key (see more at -/// [`crate::bn254::verifier::PreparedVerifyingKey`]), serialized proof public input and serialized -/// proof points. +/// Verify Groth16 proof using the serialized form of the prepared verifying key +/// (see more at [`crate::bn254::verifier::PreparedVerifyingKey`]), serialized +/// proof public input and serialized proof points. pub fn verify_groth16_in_bytes( vk_gamma_abc_g1_bytes: &[u8], alpha_g1_beta_g2_bytes: &[u8], @@ -43,8 +46,8 @@ pub fn verify_groth16_in_bytes( verify_groth16(&pvk, proof_public_inputs_as_bytes, proof_points_as_bytes) } -/// Verify proof with a given verifying key in [struct PreparedVerifyingKey], serialized public inputs -/// and serialized proof points. +/// Verify proof with a given verifying key in [struct PreparedVerifyingKey], +/// serialized public inputs and serialized proof points. pub fn verify_groth16( pvk: &PreparedVerifyingKey, proof_public_inputs_as_bytes: &[u8], diff --git a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs index 81c45ab2..01f5ab5d 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs @@ -4,11 +4,14 @@ #![deny(unused_must_use, missing_debug_implementations)] //! Groth16 verifier over the BN254 elliptic curve construction. -use crate::executor::zk_stuff::bn254::api::SCALAR_SIZE; -use ark_bn254::{Bn254, Fr}; +use ark_bn254::Bn254; +use ark_bn254::Fr; use ark_serialize::CanonicalDeserialize; use derive_more::From; -use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; + +use crate::executor::zk_stuff::bn254::api::SCALAR_SIZE; +use crate::executor::zk_stuff::error::ZkCryptoError; +use crate::executor::zk_stuff::error::ZkCryptoResult; /// API that takes in serialized inputs pub mod api; @@ -20,25 +23,26 @@ pub mod verifier; pub mod poseidon; /// Zk login structs and utilities -//pub mod zk_login; +// pub mod zk_login; /// Zk login entrypoints -//pub mod zk_login_api; +// pub mod zk_login_api; /// Zk login utils -//pub mod utils; +// pub mod utils; - - -/// A field element in the BN254 construction. Thin wrapper around `api::Bn254Fr`. +/// A field element in the BN254 construction. Thin wrapper around +/// `api::Bn254Fr`. #[derive(Debug, From)] pub struct FieldElement(pub(crate) ark_bn254::Fr); -/// A Groth16 proof in the BN254 construction. Thin wrapper around `ark_groth16::Proof::`. +/// A Groth16 proof in the BN254 construction. Thin wrapper around +/// `ark_groth16::Proof::`. #[derive(Debug, From)] pub struct Proof(pub(crate) ark_groth16::Proof); -/// A Groth16 verifying key in the BN254 construction. Thin wrapper around `ark_groth16::VerifyingKey::`. +/// A Groth16 verifying key in the BN254 construction. Thin wrapper around +/// `ark_groth16::VerifyingKey::`. #[derive(Debug, From)] pub struct VerifyingKey(pub(crate) ark_groth16::VerifyingKey); @@ -52,18 +56,18 @@ impl Proof { } impl FieldElement { - /// Deserialize 32 bytes into a BN254 field element using little-endian format. + /// Deserialize 32 bytes into a BN254 field element using little-endian + /// format. pub(crate) fn deserialize(bytes: &[u8]) -> ZkCryptoResult { if bytes.len() != SCALAR_SIZE { return Err(ZkCryptoError::InputLengthWrong(bytes.len())); } - Fr::deserialize_compressed(bytes) - .map_err(|_| ZkCryptoError::InvalidInput) - .map(FieldElement) + Fr::deserialize_compressed(bytes).map_err(|_| ZkCryptoError::InvalidInput).map(FieldElement) } - /// Deserialize a vector of bytes into a vector of BN254 field elements, assuming that each element - /// is serialized as a chunk of 32 bytes. See also [`FieldElement::deserialize`]. + /// Deserialize a vector of bytes into a vector of BN254 field elements, + /// assuming that each element is serialized as a chunk of 32 bytes. See + /// also [`FieldElement::deserialize`]. pub(crate) fn deserialize_vector( field_element_bytes: &[u8], ) -> ZkCryptoResult> { diff --git a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs index 5f817ba2..aa0ea67f 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/constants.rs @@ -1,13 +1,27 @@ - - -use crate::executor::zk_stuff::Fr; use ff::PrimeField; use neptune::hash_type::HashType; use neptune::poseidon::PoseidonConstants; use neptune::Strength; use once_cell::sync::Lazy; use typenum::Unsigned; -use typenum::{U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9}; +use typenum::U1; +use typenum::U10; +use typenum::U11; +use typenum::U12; +use typenum::U13; +use typenum::U14; +use typenum::U15; +use typenum::U16; +use typenum::U2; +use typenum::U3; +use typenum::U4; +use typenum::U5; +use typenum::U6; +use typenum::U7; +use typenum::U8; +use typenum::U9; + +use crate::executor::zk_stuff::Fr; #[derive(Debug)] pub(crate) struct Constants { @@ -23,22 +37,14 @@ pub(crate) fn load_constants() -> Constants { let constants = constants_strings .iter() - .map(|c| { - c.iter() - .map(|ci| Fr::from_str_vartime(ci).unwrap()) - .collect() - }) + .map(|c| c.iter().map(|ci| Fr::from_str_vartime(ci).unwrap()).collect()) .collect(); let matrices = matrices_strings .iter() .map(|m| { m.iter() - .map(|mi| { - mi.iter() - .map(|mij| Fr::from_str_vartime(mij).unwrap()) - .collect() - }) + .map(|mi| mi.iter().map(|mij| Fr::from_str_vartime(mij).unwrap()).collect()) .collect() }) .collect(); @@ -47,9 +53,7 @@ pub(crate) fn load_constants() -> Constants { constants, matrices, full_rounds: 8, - partial_rounds: vec![ - 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, - ], + partial_rounds: vec![56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68], } } @@ -71,7 +75,8 @@ macro_rules! define_poseidon_constants { }}; } -// TODO: CONSTANTS are not needed after all constants are loaded because they are cloned into the POSEIDON_CONSTANTs. +// TODO: CONSTANTS are not needed after all constants are loaded because they +// are cloned into the POSEIDON_CONSTANTs. static CONSTANTS: Lazy = Lazy::new(load_constants); pub(crate) static POSEIDON_CONSTANTS_U1: Lazy> = Lazy::new(|| define_poseidon_constants!(CONSTANTS, U1)); diff --git a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs index 0194a3a9..dfc02fac 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs @@ -1,21 +1,25 @@ // Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::executor::zk_stuff::bn254::poseidon::constants::*; -use crate::executor::zk_stuff::{FrRepr}; +use std::cmp::Ordering; + use ark_bn254::Fr; -use ark_ff::{BigInteger, PrimeField}; +use ark_ff::BigInteger; +use ark_ff::PrimeField; use byte_slice_cast::AsByteSlice; -use crate::executor::zk_stuff::error::ZkCryptoError::{InputTooLong, InvalidInput}; -use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; - use ff::PrimeField as OtherPrimeField; use neptune::poseidon::HashMode::OptimizedStatic; use neptune::Poseidon; -use std::cmp::Ordering; -/// The output of the Poseidon hash function is a field element in BN254 which is 254 bits long, so -/// we need 32 bytes to represent it as an integer. +use crate::executor::zk_stuff::bn254::poseidon::constants::*; +use crate::executor::zk_stuff::error::ZkCryptoError; +use crate::executor::zk_stuff::error::ZkCryptoError::InputTooLong; +use crate::executor::zk_stuff::error::ZkCryptoError::InvalidInput; +use crate::executor::zk_stuff::error::ZkCryptoResult; +use crate::executor::zk_stuff::FrRepr; + +/// The output of the Poseidon hash function is a field element in BN254 which +/// is 254 bits long, so we need 32 bytes to represent it as an integer. pub const FIELD_ELEMENT_SIZE_IN_BYTES: usize = 32; /// The degree of the Merkle tree used to hash multiple elements. @@ -23,7 +27,8 @@ pub const MERKLE_TREE_DEGREE: usize = 16; mod constants; -/// Define a macro to calculate the poseidon hash of a vector of inputs using the neptune library. +/// Define a macro to calculate the poseidon hash of a vector of inputs using +/// the neptune library. macro_rules! define_poseidon_hash { ($inputs:expr, $poseidon_constants:expr) => {{ let mut poseidon = Poseidon::new(&$poseidon_constants); @@ -44,15 +49,16 @@ macro_rules! define_poseidon_hash { }}; } -/// Poseidon hash function over BN254. The input vector cannot be empty and must contain at most 16 -/// elements, otherwise an error is returned. +/// Poseidon hash function over BN254. The input vector cannot be empty and must +/// contain at most 16 elements, otherwise an error is returned. pub fn poseidon(inputs: Vec) -> Result { if inputs.is_empty() || inputs.len() > 16 { return Err(ZkCryptoError::InputLengthWrong(inputs.len())); } - // Instances of Poseidon and PoseidonConstants from neptune have different types depending on - // the number of inputs, so unfortunately we need to use a macro here. + // Instances of Poseidon and PoseidonConstants from neptune have different types + // depending on the number of inputs, so unfortunately we need to use a + // macro here. let result = match inputs.len() { 1 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U1), 2 => define_poseidon_hash!(inputs, POSEIDON_CONSTANTS_U2), @@ -75,11 +81,13 @@ pub fn poseidon(inputs: Vec) -> Result { Ok(fr_to_bn254fr(result)) } -/// Calculate the poseidon hash of the field element inputs. If there are no inputs, return an error. -/// If input length is <= 16, calculate H(inputs), if it is <= 32, calculate H(H(inputs[0..16]), -/// H(inputs[16..])), otherwise return an error. +/// Calculate the poseidon hash of the field element inputs. If there are no +/// inputs, return an error. If input length is <= 16, calculate H(inputs), if +/// it is <= 32, calculate H(H(inputs[0..16]), H(inputs[16..])), otherwise +/// return an error. /// -/// This functions must be equivalent with the one found in the zk_login circuit. +/// This functions must be equivalent with the one found in the zk_login +/// circuit. pub(crate) fn poseidon_zk_login(inputs: Vec) -> ZkCryptoResult { if inputs.is_empty() || inputs.len() > 32 { return Err(ZkCryptoError::InputLengthWrong(inputs.len())); @@ -87,8 +95,9 @@ pub(crate) fn poseidon_zk_login(inputs: Vec) -> ZkCryptoResult { poseidon_merkle_tree(inputs) } -/// Calculate the poseidon hash of the field element inputs. If the input length is <= 16, calculate -/// H(inputs), otherwise chunk the inputs into groups of 16, hash them and input the results recursively. +/// Calculate the poseidon hash of the field element inputs. If the input length +/// is <= 16, calculate H(inputs), otherwise chunk the inputs into groups of 16, +/// hash them and input the results recursively. pub fn poseidon_merkle_tree(inputs: Vec) -> Result { if inputs.len() <= MERKLE_TREE_DEGREE { poseidon(inputs) @@ -102,15 +111,18 @@ pub fn poseidon_merkle_tree(inputs: Vec) -> Result { } } -/// Calculate the poseidon hash of an array of inputs. Each input is interpreted as a BN254 field -/// element assuming a little-endian encoding. The field elements are then hashed using the poseidon -/// hash function ([poseidon_merkle_tree]) and the result is serialized as a little-endian integer (32 -/// bytes). +/// Calculate the poseidon hash of an array of inputs. Each input is interpreted +/// as a BN254 field element assuming a little-endian encoding. The field +/// elements are then hashed using the poseidon hash function +/// ([poseidon_merkle_tree]) and the result is serialized as a little-endian +/// integer (32 bytes). /// -/// If one of the inputs is in non-canonical form, e.g. it represents an integer greater than the -/// field size or is longer than 32 bytes, an error is returned. +/// If one of the inputs is in non-canonical form, e.g. it represents an integer +/// greater than the field size or is longer than 32 bytes, an error is +/// returned. /// -/// This function is used as an interface to the poseidon hash function in the sui-framework. +/// This function is used as an interface to the poseidon hash function in the +/// sui-framework. pub fn poseidon_bytes( inputs: &Vec>, ) -> Result<[u8; FIELD_ELEMENT_SIZE_IN_BYTES], ZkCryptoError> { @@ -119,23 +131,24 @@ pub fn poseidon_bytes( field_elements.push(canonical_le_bytes_to_field_element(input)?); } let output_as_field_element = poseidon_merkle_tree(field_elements)?; - Ok(field_element_to_canonical_le_bytes( - &output_as_field_element, - )) + Ok(field_element_to_canonical_le_bytes(&output_as_field_element)) } -/// Given a binary representation of a BN254 field element as an integer in little-endian encoding, -/// this function returns the corresponding field element. If the field element is not canonical (is -/// larger than the field size as an integer), an `FastCryptoError::InvalidInput` is returned. +/// Given a binary representation of a BN254 field element as an integer in +/// little-endian encoding, this function returns the corresponding field +/// element. If the field element is not canonical (is larger than the field +/// size as an integer), an `FastCryptoError::InvalidInput` is returned. /// -/// If more than 32 bytes is given, an `FastCryptoError::InputTooLong` is returned. +/// If more than 32 bytes is given, an `FastCryptoError::InputTooLong` is +/// returned. fn canonical_le_bytes_to_field_element(bytes: &[u8]) -> Result { match bytes.len().cmp(&FIELD_ELEMENT_SIZE_IN_BYTES) { Ordering::Less => Ok(Fr::from_le_bytes_mod_order(bytes)), Ordering::Equal => { let field_element = Fr::from_le_bytes_mod_order(bytes); - // Unfortunately, there doesn't seem to be a nice way to check if a modular reduction - // happened without doing the extra work of serializing the field element again. + // Unfortunately, there doesn't seem to be a nice way to check if a modular + // reduction happened without doing the extra work of serializing + // the field element again. let reduced_bytes = field_element.into_bigint().to_bytes_le(); if reduced_bytes != bytes { return Err(InvalidInput); @@ -146,8 +159,9 @@ fn canonical_le_bytes_to_field_element(bytes: &[u8]) -> Result [u8; FIELD_ELEMENT_SIZE_IN_BYTES] { let bytes = field_element.into_bigint().to_bytes_le(); <[u8; FIELD_ELEMENT_SIZE_IN_BYTES]>::try_from(bytes) @@ -156,151 +170,155 @@ fn field_element_to_canonical_le_bytes(field_element: &Fr) -> [u8; FIELD_ELEMENT /// Convert an ff field element to an arkworks-ff field element. fn fr_to_bn254fr(fr: crate::executor::zk_stuff::Fr) -> Fr { - // We use big-endian as in the definition of the BN254 prime field (see fastcrypto-zkp/src/lib.rs). + // We use big-endian as in the definition of the BN254 prime field (see + // fastcrypto-zkp/src/lib.rs). Fr::from_be_bytes_mod_order(fr.to_repr().as_byte_slice()) } /// Convert an arkworks-ff field element to an ff field element. fn bn254_to_fr(fr: Fr) -> crate::executor::zk_stuff::Fr { let mut bytes = [0u8; 32]; - // We use big-endian as in the definition of the BN254 prime field (see fastcrypto-zkp/src/lib.rs). + // We use big-endian as in the definition of the BN254 prime field (see + // fastcrypto-zkp/src/lib.rs). bytes.clone_from_slice(&fr.into_bigint().to_bytes_be()); crate::executor::zk_stuff::Fr::from_repr_vartime(FrRepr(bytes)) .expect("The bytes of fr are guaranteed to be canonical here") } -/* -#[cfg(test)] -mod test { - use crate::bn254::poseidon::poseidon_bytes; - use crate::bn254::poseidon::{poseidon, poseidon_merkle_tree}; - use crate::bn254::{poseidon::poseidon_zk_login, zk_login::Bn254Fr}; - use ark_bn254::Fr; - use ark_ff::{BigInteger, PrimeField}; - use lazy_static::lazy_static; - use proptest::arbitrary::Arbitrary; - use proptest::collection; - use std::str::FromStr; - - fn to_bigint_arr(vals: Vec) -> Vec { - vals.into_iter().map(Bn254Fr::from).collect() - } - - #[test] - fn poseidon_test() { - let input1 = Fr::from_str("134696963602902907403122104327765350261").unwrap(); - let input2 = Fr::from_str("17932473587154777519561053972421347139").unwrap(); - let input3 = Fr::from_str("10000").unwrap(); - let input4 = Fr::from_str( - "50683480294434968413708503290439057629605340925620961559740848568164438166", - ) - .unwrap(); - let hash = poseidon(vec![input1, input2, input3, input4]).unwrap(); - assert_eq!( - hash, - Fr::from_str( - "2272550810841985018139126931041192927190568084082399473943239080305281957330" - ) - .unwrap() - ); - } - #[test] - fn test_to_poseidon_hash() { - assert!(poseidon_merkle_tree(to_bigint_arr(vec![])).is_err()); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![1])) - .unwrap() - .to_string(), - "18586133768512220936620570745912940619677854269274689475585506675881198879027" - ); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![1, 2])) - .unwrap() - .to_string(), - "7853200120776062878684798364095072458815029376092732009249414926327459813530" - ); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - ])) - .unwrap() - .to_string(), - "4203130618016961831408770638653325366880478848856764494148034853759773445968" - ); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 - ])) - .unwrap() - .to_string(), - "9989051620750914585850546081941653841776809718687451684622678807385399211877" - ); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29 - ])) - .unwrap() - .to_string(), - "4123755143677678663754455867798672266093104048057302051129414708339780424023" - ); - assert_eq!( - poseidon_merkle_tree(to_bigint_arr(vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 - ])) - .unwrap() - .to_string(), - "15368023340287843142129781602124963668572853984788169144128906033251913623349" - ); - assert!(poseidon_zk_login(to_bigint_arr(vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32 - ])) - .is_err()); - } - - #[test] - fn test_hash_to_bytes() { - let inputs: Vec> = vec![vec![1u8]]; - let hash = poseidon_bytes(&inputs).unwrap(); - // 18586133768512220936620570745912940619677854269274689475585506675881198879027 in decimal - let expected = - hex::decode("33018202c57d898b84338b16d1a4960e133c6a4d656cfec1bd62a9ea00611729") - .unwrap(); - assert_eq!(hash.as_slice(), &expected); - - // 7853200120776062878684798364095072458815029376092732009249414926327459813530 in decimal - let inputs: Vec> = vec![vec![1u8], vec![2u8]]; - let hash = poseidon_bytes(&inputs).unwrap(); - let expected = - hex::decode("9a1817447a60199e51453274f217362acfe962966b4cf63d4190d6e7f5c05c11") - .unwrap(); - assert_eq!(hash.as_slice(), &expected); - - // Input larger than the modulus - let inputs = vec![vec![255; 32]]; - assert!(poseidon_bytes(&inputs).is_err()); - - // Input smaller than the modulus - let inputs = vec![vec![255; 31]]; - assert!(poseidon_bytes(&inputs).is_ok()); - } - - #[cfg(test)] - lazy_static! { - static ref POSEIDON_ARK: poseidon_ark::Poseidon = poseidon_ark::Poseidon::new(); - } - - proptest::proptest! { - #[test] - fn test_against_poseidon_ark(r in collection::vec(<[u8; 32]>::arbitrary(), 1..16)) { - - let inputs = r.into_iter().map(|ri| ark_bn254::Fr::from_le_bytes_mod_order(&ri)).collect::>(); - let expected = POSEIDON_ARK.hash(inputs.clone()).unwrap().into_bigint().to_bytes_le(); - - let actual = poseidon_bytes(&inputs.iter().map(|i| i.into_bigint().to_bytes_le().to_vec()).collect::>()).unwrap(); - assert_eq!(&actual, expected.as_slice()); - } - } -} -*/ +// #[cfg(test)] +// mod test { +// use crate::bn254::poseidon::poseidon_bytes; +// use crate::bn254::poseidon::{poseidon, poseidon_merkle_tree}; +// use crate::bn254::{poseidon::poseidon_zk_login, zk_login::Bn254Fr}; +// use ark_bn254::Fr; +// use ark_ff::{BigInteger, PrimeField}; +// use lazy_static::lazy_static; +// use proptest::arbitrary::Arbitrary; +// use proptest::collection; +// use std::str::FromStr; +// +// fn to_bigint_arr(vals: Vec) -> Vec { +// vals.into_iter().map(Bn254Fr::from).collect() +// } +// +// #[test] +// fn poseidon_test() { +// let input1 = +// Fr::from_str("134696963602902907403122104327765350261").unwrap(); let input2 +// = Fr::from_str("17932473587154777519561053972421347139").unwrap(); let input3 +// = Fr::from_str("10000").unwrap(); let input4 = Fr::from_str( +// "50683480294434968413708503290439057629605340925620961559740848568164438166", +// ) +// .unwrap(); +// let hash = poseidon(vec![input1, input2, input3, input4]).unwrap(); +// assert_eq!( +// hash, +// Fr::from_str( +// "2272550810841985018139126931041192927190568084082399473943239080305281957330" +// ) +// .unwrap() +// ); +// } +// #[test] +// fn test_to_poseidon_hash() { +// assert!(poseidon_merkle_tree(to_bigint_arr(vec![])).is_err()); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![1])) +// .unwrap() +// .to_string(), +// "18586133768512220936620570745912940619677854269274689475585506675881198879027" +// ); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![1, 2])) +// .unwrap() +// .to_string(), +// "7853200120776062878684798364095072458815029376092732009249414926327459813530" +// ); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![ +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +// ])) +// .unwrap() +// .to_string(), +// "4203130618016961831408770638653325366880478848856764494148034853759773445968" +// ); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![ +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +// ])) +// .unwrap() +// .to_string(), +// "9989051620750914585850546081941653841776809718687451684622678807385399211877" +// ); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![ +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +// 22, 23, 24, 25, 26, 27, 28, 29 +// ])) +// .unwrap() +// .to_string(), +// "4123755143677678663754455867798672266093104048057302051129414708339780424023" +// ); +// assert_eq!( +// poseidon_merkle_tree(to_bigint_arr(vec![ +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +// 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +// ])) +// .unwrap() +// .to_string(), +// "15368023340287843142129781602124963668572853984788169144128906033251913623349" +// ); +// assert!(poseidon_zk_login(to_bigint_arr(vec![ +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +// 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +// ])) +// .is_err()); +// } +// +// #[test] +// fn test_hash_to_bytes() { +// let inputs: Vec> = vec![vec![1u8]]; +// let hash = poseidon_bytes(&inputs).unwrap(); +// 18586133768512220936620570745912940619677854269274689475585506675881198879027 +// in decimal let expected = +// hex::decode(" +// 33018202c57d898b84338b16d1a4960e133c6a4d656cfec1bd62a9ea00611729") .unwrap(); +// assert_eq!(hash.as_slice(), &expected); +// +// 7853200120776062878684798364095072458815029376092732009249414926327459813530 +// in decimal let inputs: Vec> = vec![vec![1u8], vec![2u8]]; +// let hash = poseidon_bytes(&inputs).unwrap(); +// let expected = +// hex::decode(" +// 9a1817447a60199e51453274f217362acfe962966b4cf63d4190d6e7f5c05c11") .unwrap(); +// assert_eq!(hash.as_slice(), &expected); +// +// Input larger than the modulus +// let inputs = vec![vec![255; 32]]; +// assert!(poseidon_bytes(&inputs).is_err()); +// +// Input smaller than the modulus +// let inputs = vec![vec![255; 31]]; +// assert!(poseidon_bytes(&inputs).is_ok()); +// } +// +// #[cfg(test)] +// lazy_static! { +// static ref POSEIDON_ARK: poseidon_ark::Poseidon = +// poseidon_ark::Poseidon::new(); } +// +// proptest::proptest! { +// #[test] +// fn test_against_poseidon_ark(r in collection::vec(<[u8; 32]>::arbitrary(), +// 1..16)) { +// +// let inputs = r.into_iter().map(|ri| +// ark_bn254::Fr::from_le_bytes_mod_order(&ri)).collect::>(); +// let expected = +// POSEIDON_ARK.hash(inputs.clone()).unwrap().into_bigint().to_bytes_le(); +// +// let actual = poseidon_bytes(&inputs.iter().map(|i| +// i.into_bigint().to_bytes_le().to_vec()).collect::>()).unwrap(); +// assert_eq!(&actual, expected.as_slice()); +// } +// } +// } diff --git a/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs index 503ab539..482018c2 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs @@ -4,29 +4,41 @@ use std::borrow::Borrow; use std::ops::Neg; -use ark_bn254::{Bn254, Fq12, Fr, G1Affine, G2Affine}; +use ark_bn254::Bn254; +use ark_bn254::Fq12; +use ark_bn254::Fr; +use ark_bn254::G1Affine; +use ark_bn254::G2Affine; use ark_ec::bn::G2Prepared; use ark_ec::pairing::Pairing; -use ark_groth16::{Groth16, PreparedVerifyingKey as ArkPreparedVerifyingKey}; +use ark_groth16::Groth16; +use ark_groth16::PreparedVerifyingKey as ArkPreparedVerifyingKey; +use ark_serialize::CanonicalDeserialize; +use ark_serialize::CanonicalSerialize; use ark_snark::SNARK; use crate::executor::zk_stuff::bn254::api::SCALAR_SIZE; -use crate::executor::zk_stuff::bn254::{FieldElement, Proof, VerifyingKey}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use crate::executor::zk_stuff::error::{ZkCryptoError, ZkCryptoResult}; +use crate::executor::zk_stuff::bn254::FieldElement; +use crate::executor::zk_stuff::bn254::Proof; +use crate::executor::zk_stuff::bn254::VerifyingKey; +use crate::executor::zk_stuff::error::ZkCryptoError; +use crate::executor::zk_stuff::error::ZkCryptoResult; //#[cfg(test)] //#[path = "unit_tests/verifier_tests.rs"] -//mod verifier_tests; - -/// This is a helper function to store a pre-processed version of the verifying key. -/// This is roughly homologous to [`ark_groth16::data_structures::PreparedVerifyingKey`]. -/// Note that contrary to Arkworks, we don't store a "prepared" version of the gamma_g2_neg_pc, -/// delta_g2_neg_pc fields because they are very large and unpractical to use in the binary api. +// mod verifier_tests; + +/// This is a helper function to store a pre-processed version of the verifying +/// key. This is roughly homologous to +/// [`ark_groth16::data_structures::PreparedVerifyingKey`]. Note that contrary +/// to Arkworks, we don't store a "prepared" version of the gamma_g2_neg_pc, +/// delta_g2_neg_pc fields because they are very large and unpractical to use in +/// the binary api. #[derive(Clone, Debug, PartialEq, Eq)] pub struct PreparedVerifyingKey { /// The element vk.gamma_abc_g1, - /// aka the `[gamma^{-1} * (beta * a_i + alpha * b_i + c_i) * G]`, where i spans the public inputs + /// aka the `[gamma^{-1} * (beta * a_i + alpha * b_i + c_i) * G]`, where i + /// spans the public inputs pub vk_gamma_abc_g1: Vec, /// The element `e(alpha * G, beta * H)` in `E::GT`. pub alpha_g1_beta_g2: Fq12, @@ -57,8 +69,7 @@ impl PreparedVerifyingKey { let mut vk_gamma = Vec::new(); for g1 in &self.vk_gamma_abc_g1 { let mut g1_bytes = Vec::new(); - g1.serialize_compressed(&mut g1_bytes) - .map_err(|_| ZkCryptoError::InvalidInput)?; + g1.serialize_compressed(&mut g1_bytes).map_err(|_| ZkCryptoError::InvalidInput)?; vk_gamma.append(&mut g1_bytes); } res.push(vk_gamma); @@ -83,8 +94,8 @@ impl PreparedVerifyingKey { Ok(res) } - /// Deserialize the prepared verifying key from the serialized fields of vk_gamma_abc_g1, - /// alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc + /// Deserialize the prepared verifying key from the serialized fields of + /// vk_gamma_abc_g1, alpha_g1_beta_g2, gamma_g2_neg_pc, delta_g2_neg_pc pub fn deserialize>(bytes: &Vec) -> Result { if bytes.len() != 4 { return Err(ZkCryptoError::InputLengthWrong(bytes.len())); @@ -121,11 +132,11 @@ impl PreparedVerifyingKey { } impl From<&PreparedVerifyingKey> for ArkPreparedVerifyingKey { - /// Returns a [`ark_groth16::data_structures::PreparedVerifyingKey`] corresponding to this for - /// usage in the arkworks api. + /// Returns a [`ark_groth16::data_structures::PreparedVerifyingKey`] + /// corresponding to this for usage in the arkworks api. fn from(pvk: &PreparedVerifyingKey) -> Self { - // Note that not all the members are set here, but we set enough to be able to run - // Groth16::::verify_with_processed_vk. + // Note that not all the members are set here, but we set enough to be able to + // run Groth16::::verify_with_processed_vk. let mut ark_pvk = ArkPreparedVerifyingKey::default(); ark_pvk.vk.gamma_abc_g1 = pvk.vk_gamma_abc_g1.clone(); ark_pvk.alpha_g1_beta_g2 = pvk.alpha_g1_beta_g2; @@ -160,33 +171,31 @@ impl From<&ark_groth16::VerifyingKey> for PreparedVerifyingKey { } } } -/* -#[cfg(test)] -mod tests { - use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; - use crate::dummy_circuits::DummyCircuit; - use ark_bn254::{Bn254, Fr}; - use ark_groth16::Groth16; - use ark_snark::SNARK; - use ark_std::rand::thread_rng; - use ark_std::UniformRand; - - #[test] - fn test_serialization() { - const PUBLIC_SIZE: usize = 128; - let rng = &mut thread_rng(); - let c = DummyCircuit:: { - a: Some(::rand(rng)), - b: Some(::rand(rng)), - num_variables: PUBLIC_SIZE, - num_constraints: 10, - }; - let (_, vk) = Groth16::::circuit_specific_setup(c, rng).unwrap(); - let pvk = PreparedVerifyingKey::from(&vk); - - let serialized = pvk.serialize().unwrap(); - let deserialized = PreparedVerifyingKey::deserialize(&serialized).unwrap(); - assert_eq!(pvk, deserialized); - } -} -*/ +// #[cfg(test)] +// mod tests { +// use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; +// use crate::dummy_circuits::DummyCircuit; +// use ark_bn254::{Bn254, Fr}; +// use ark_groth16::Groth16; +// use ark_snark::SNARK; +// use ark_std::rand::thread_rng; +// use ark_std::UniformRand; +// +// #[test] +// fn test_serialization() { +// const PUBLIC_SIZE: usize = 128; +// let rng = &mut thread_rng(); +// let c = DummyCircuit:: { +// a: Some(::rand(rng)), +// b: Some(::rand(rng)), +// num_variables: PUBLIC_SIZE, +// num_constraints: 10, +// }; +// let (_, vk) = Groth16::::circuit_specific_setup(c, rng).unwrap(); +// let pvk = PreparedVerifyingKey::from(&vk); +// +// let serialized = pvk.serialize().unwrap(); +// let deserialized = PreparedVerifyingKey::deserialize(&serialized).unwrap(); +// assert_eq!(pvk, deserialized); +// } +// } diff --git a/tvm_vm/src/executor/zk_stuff/curve_utils.rs b/tvm_vm/src/executor/zk_stuff/curve_utils.rs index 52f4eadc..8ae4726a 100644 --- a/tvm_vm/src/executor/zk_stuff/curve_utils.rs +++ b/tvm_vm/src/executor/zk_stuff/curve_utils.rs @@ -1,23 +1,28 @@ -use ark_bn254::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_bn254::Fq; +use ark_bn254::Fq2; +use ark_bn254::Fr; +use ark_bn254::G1Affine; +use ark_bn254::G1Projective; +use ark_bn254::G2Affine; +use ark_bn254::G2Projective; use ark_ec::CurveGroup; use ark_ff::BigInteger; use ark_ff::PrimeField; -//use hex::serde; -//use fastcrypto::error::FastCryptoError; +// use hex::serde; +// use fastcrypto::error::FastCryptoError; use num_bigint::BigUint; use schemars::JsonSchema; - -use serde::Serialize; use serde::Deserialize; +use serde::Serialize; use crate::executor::zk_stuff::error::ZkCryptoError; -/// A G1 point in BN254 serialized as a vector of three strings which is the canonical decimal -/// representation of the projective coordinates in Fq. +/// A G1 point in BN254 serialized as a vector of three strings which is the +/// canonical decimal representation of the projective coordinates in Fq. pub type CircomG1 = Vec; -/// A G2 point in BN254 serialized as a vector of three vectors each being a vector of two strings -/// which are the canonical decimal representation of the coefficients of the projective coordinates -/// in Fq2. +/// A G2 point in BN254 serialized as a vector of three vectors each being a +/// vector of two strings which are the canonical decimal representation of the +/// coefficients of the projective coordinates in Fq2. pub type CircomG2 = Vec>; /// A struct that stores a Bn254 Fq field element as 32 bytes. @@ -30,10 +35,7 @@ impl std::str::FromStr for Bn254FqElement { fn from_str(s: &str) -> Result { let big_int = Fq::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; let be_bytes = big_int.into_bigint().to_bytes_be(); - be_bytes - .try_into() - .map_err(|_| ZkCryptoError::InvalidInput) - .map(Bn254FqElement) + be_bytes.try_into().map_err(|_| ZkCryptoError::InvalidInput).map(Bn254FqElement) } } @@ -48,8 +50,8 @@ impl std::fmt::Display for Bn254FqElement { // Bn254FqElement's serialized format is as a radix10 encoded string impl Serialize for Bn254FqElement { fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + where + S: serde::Serializer, { self.to_string().serialize(serializer) } @@ -57,8 +59,8 @@ impl Serialize for Bn254FqElement { impl<'de> Deserialize<'de> for Bn254FqElement { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, + where + D: serde::Deserializer<'de>, { let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) @@ -70,7 +72,8 @@ impl<'de> Deserialize<'de> for Bn254FqElement { pub struct Bn254FrElement(#[schemars(with = "String")] [u8; 32]); impl Bn254FrElement { - /// Returns the unpadded version of the field element. This returns with leading zeros removed. + /// Returns the unpadded version of the field element. This returns with + /// leading zeros removed. pub fn unpadded(&self) -> &[u8] { let mut buf = self.0.as_slice(); @@ -79,14 +82,11 @@ impl Bn254FrElement { } // If the value is '0' then just return a slice of length 1 of the final byte - if buf.is_empty() { - &self.0[31..] - } else { - buf - } + if buf.is_empty() { &self.0[31..] } else { buf } } - /// Returns the padded version of the field element. This returns with leading zeros preserved to 32 bytes. + /// Returns the padded version of the field element. This returns with + /// leading zeros preserved to 32 bytes. pub fn padded(&self) -> &[u8] { &self.0 } @@ -97,10 +97,7 @@ impl std::str::FromStr for Bn254FrElement { fn from_str(s: &str) -> Result { let big_int = Fr::from_str(s).map_err(|_| ZkCryptoError::InvalidInput)?; let be_bytes = big_int.into_bigint().to_bytes_be(); - be_bytes - .try_into() - .map_err(|_| ZkCryptoError::InvalidInput) - .map(Bn254FrElement) + be_bytes.try_into().map_err(|_| ZkCryptoError::InvalidInput).map(Bn254FrElement) } } @@ -115,8 +112,8 @@ impl std::fmt::Display for Bn254FrElement { // Bn254FrElement's serialized format is as a radix10 encoded string impl Serialize for Bn254FrElement { fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + where + S: serde::Serializer, { self.to_string().serialize(serializer) } @@ -124,8 +121,8 @@ impl Serialize for Bn254FrElement { impl<'de> Deserialize<'de> for Bn254FrElement { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, + where + D: serde::Deserializer<'de>, { let s = std::borrow::Cow::<'de, str>::deserialize(deserializer)?; std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom) @@ -146,9 +143,10 @@ impl From<&Bn254FrElement> for Fr { } } -/// Deserialize a G1 projective point in BN254 serialized as a vector of three strings into an affine -/// G1 point in arkworks format. Return an error if the input is not a vector of three strings or if -/// any of the strings cannot be parsed as a field element. +/// Deserialize a G1 projective point in BN254 serialized as a vector of three +/// strings into an affine G1 point in arkworks format. Return an error if the +/// input is not a vector of three strings or if any of the strings cannot be +/// parsed as a field element. pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result { if s.len() != 3 { return Err(ZkCryptoError::InvalidInput); @@ -156,10 +154,10 @@ pub(crate) fn g1_affine_from_str_projective(s: &CircomG1) -> Result Result Result { if s.len() != 3 || s[0].len() != 2 || s[1].len() != 2 || s[2].len() != 2 { return Err(ZkCryptoError::InvalidInput); @@ -184,7 +183,7 @@ pub(crate) fn g2_affine_from_str_projective(s: &CircomG2) -> Result = Result; @@ -50,5 +49,3 @@ pub enum ZkCryptoError { #[error("General cryptographic error")] GeneralOpaqueError, } - - diff --git a/tvm_vm/src/executor/zk_stuff/jwt_utils.rs b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs index 0af80ea0..ce495c7d 100644 --- a/tvm_vm/src/executor/zk_stuff/jwt_utils.rs +++ b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs @@ -1,11 +1,12 @@ -//extern crate serde_derive; +// extern crate serde_derive; -use crate::executor::zk_stuff::error::ZkCryptoError; use base64ct::Base64UrlUnpadded; use base64ct::Encoding; use schemars::JsonSchema; -use serde::Serialize; use serde::Deserialize; +use serde::Serialize; + +use crate::executor::zk_stuff::error::ZkCryptoError; /// Claims that be in the payload body. #[derive(Deserialize, Serialize, Debug)] diff --git a/tvm_vm/src/executor/zk_stuff/mod.rs b/tvm_vm/src/executor/zk_stuff/mod.rs index ef336769..6e3da482 100644 --- a/tvm_vm/src/executor/zk_stuff/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/mod.rs @@ -1,19 +1,14 @@ -use thiserror::Error; - -use ark_bn254::{Bn254}; // use ark_bn254::{Bn254, Fr}; -use ark_serialize::CanonicalDeserialize; use derive_more::From; - use ff::PrimeField; -//pub mod alphabet; +// pub mod alphabet; pub mod curve_utils; -//pub mod encodings; -pub mod error; -pub mod zk_login; -pub mod utils; +// pub mod encodings; pub mod bn254; +pub mod error; pub mod jwt_utils; +pub mod utils; +pub mod zk_login; /// Definition of the BN254 prime field. #[derive(PrimeField)] diff --git a/tvm_vm/src/executor/zk_stuff/utils.rs b/tvm_vm/src/executor/zk_stuff/utils.rs index 54e7a989..e2c0407c 100644 --- a/tvm_vm/src/executor/zk_stuff/utils.rs +++ b/tvm_vm/src/executor/zk_stuff/utils.rs @@ -1,27 +1,21 @@ +use std::str::FromStr; -use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; -use crate::executor::zk::Bn254Fr; -use crate::executor::zk_stuff::curve_utils::Bn254FrElement; -use crate::executor::zk_stuff::error::ZkCryptoError; -use fastcrypto::hash::{Blake2b256, HashFunction}; // use fastcrypto::rsa::Base64UrlUnpadded; // use fastcrypto::rsa::Encoding; use num_bigint::BigUint; - -use serde::{Deserialize, Serialize}; -use serde_json::json; -use std::str::FromStr; -use base64ct::{Base64UrlUnpadded, Encoding}; +use serde::Deserialize; +use serde::Serialize; use super::zk_login::hash_ascii_str_to_field; +use crate::executor::zk::Bn254Fr; +use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; +use crate::executor::zk_stuff::curve_utils::Bn254FrElement; +use crate::executor::zk_stuff::error::ZkCryptoError; -const ZK_LOGIN_AUTHENTICATOR_FLAG: u8 = 0x05; const MAX_KEY_CLAIM_NAME_LENGTH: u8 = 32; const MAX_KEY_CLAIM_VALUE_LENGTH: u8 = 115; const MAX_AUD_VALUE_LENGTH: u8 = 145; - - pub fn gen_address_seed( salt: &str, name: &str, // i.e. "sub" @@ -32,7 +26,8 @@ pub fn gen_address_seed( gen_address_seed_with_salt_hash(&salt_hash.to_string(), name, value, aud) } -/// Same as [`gen_address_seed`] but takes the poseidon hash of the salt as input instead of the salt. +/// Same as [`gen_address_seed`] but takes the poseidon hash of the salt as +/// input instead of the salt. pub(crate) fn gen_address_seed_with_salt_hash( salt_hash: &str, name: &str, // i.e. "sub" @@ -48,14 +43,16 @@ pub(crate) fn gen_address_seed_with_salt_hash( .to_string()) } - -/// Given a 33-byte public key bytes (flag || pk_bytes), returns the two Bn254Fr split at the 128 bit index. +/// Given a 33-byte public key bytes (flag || pk_bytes), returns the two Bn254Fr +/// split at the 128 bit index. pub fn split_to_two_frs(eph_pk_bytes: &[u8]) -> Result<(Bn254Fr, Bn254Fr), ZkCryptoError> { - // Split the bytes deterministically such that the first element contains the first 128 - // bits of the hash, and the second element contains the latter ones. + // Split the bytes deterministically such that the first element contains the + // first 128 bits of the hash, and the second element contains the latter + // ones. let (first_half, second_half) = eph_pk_bytes.split_at(eph_pk_bytes.len() - 16); let first_bigint = BigUint::from_bytes_be(first_half); - // TODO: this is not safe if the buffer is large. Can we use a fixed size array for eph_pk_bytes? + // TODO: this is not safe if the buffer is large. Can we use a fixed size array + // for eph_pk_bytes? let second_bigint = BigUint::from_bytes_be(second_half); let eph_public_key_0 = Bn254Fr::from(first_bigint); @@ -63,8 +60,6 @@ pub fn split_to_two_frs(eph_pk_bytes: &[u8]) -> Result<(Bn254Fr, Bn254Fr), ZkCry Ok((eph_public_key_0, eph_public_key_1)) } - - /// The response struct for the test issuer JWT token. #[derive(Debug, Serialize, Deserialize)] pub struct TestIssuerJWTResponse { diff --git a/tvm_vm/src/executor/zk_stuff/zk_login.rs b/tvm_vm/src/executor/zk_stuff/zk_login.rs index bf3223ce..2b664c20 100644 --- a/tvm_vm/src/executor/zk_stuff/zk_login.rs +++ b/tvm_vm/src/executor/zk_stuff/zk_login.rs @@ -1,42 +1,47 @@ +use std::cmp::Ordering::Equal; +use std::cmp::Ordering::Greater; +use std::cmp::Ordering::Less; +use std::str::FromStr; -use crate::executor::zk_stuff::{error::ZkCryptoResult, jwt_utils::JWTHeader}; - -use serde_json::Value; - -use super::utils::split_to_two_frs; -use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; -use crate::executor::zk_stuff::curve_utils::{ - g1_affine_from_str_projective, g2_affine_from_str_projective, Bn254FrElement, CircomG1, - CircomG2, -}; -pub use ark_bn254::{Bn254, Fr as Bn254Fr}; +pub use ark_bn254::Bn254; +pub use ark_bn254::Fr as Bn254Fr; pub use ark_ff::ToConstraintField; use ark_ff::Zero; use ark_groth16::Proof; -pub use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use crate::executor::zk_stuff::error::ZkCryptoError; +pub use ark_serialize::CanonicalDeserialize; +pub use ark_serialize::CanonicalSerialize; use itertools::Itertools; use num_bigint::BigUint; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::FromStr; -use ark_ec::AffineRepr; +use serde::Deserialize; +use serde::Serialize; +use serde_json::Value; +use super::utils::split_to_two_frs; +use crate::executor::zk_stuff::bn254::poseidon::poseidon_zk_login; +use crate::executor::zk_stuff::curve_utils::g1_affine_from_str_projective; +use crate::executor::zk_stuff::curve_utils::g2_affine_from_str_projective; +use crate::executor::zk_stuff::curve_utils::Bn254FrElement; +use crate::executor::zk_stuff::curve_utils::CircomG1; +use crate::executor::zk_stuff::curve_utils::CircomG2; +use crate::executor::zk_stuff::error::ZkCryptoError; +use crate::executor::zk_stuff::error::ZkCryptoResult; +use crate::executor::zk_stuff::jwt_utils::JWTHeader; //#[cfg(test)] //#[path = "unit_tests/zk_login_tests.rs"] -//mod zk_login_tests; +// mod zk_login_tests; -#[cfg(feature = "e2e")] -#[cfg(test)] -#[path = "unit_tests/zk_login_e2e_tests.rs"] -mod zk_login_e2e_tests; +//#[cfg(feature = "e2e")] +//#[cfg(test)] +//#[path = "unit_tests/zk_login_e2e_tests.rs"] +// mod zk_login_e2e_tests; pub const MAX_HEADER_LEN: u8 = 248; pub const PACK_WIDTH: u8 = 248; pub const ISS: &str = "iss"; -pub const BASE64_URL_CHARSET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +pub const BASE64_URL_CHARSET: &str = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; pub const MAX_EXT_ISS_LEN: u8 = 165; pub const MAX_ISS_LEN_B64: u8 = 4 * (1 + MAX_EXT_ISS_LEN / 3); @@ -68,10 +73,7 @@ pub struct ProviderConfig { impl ProviderConfig { /// Create a new provider config. pub fn new(iss: &str, jwk_endpoint: &str) -> Self { - Self { - iss: iss.to_string(), - jwk_endpoint: jwk_endpoint.to_string(), - } + Self { iss: iss.to_string(), jwk_endpoint: jwk_endpoint.to_string() } } } @@ -90,7 +92,8 @@ pub enum OIDCProvider { Apple, /// See https://slack.com/.well-known/openid-configuration Slack, - /// This is a test issuer maintained by Mysten that will return a JWT non-interactively. + /// This is a test issuer maintained by Mysten that will return a JWT + /// non-interactively. TestIssuer, } @@ -208,47 +211,44 @@ impl JWK { if reader.alg != "RS256" || reader.kty != "RSA" || trimmed_e != "AQAB" { return Err(ZkCryptoError::InvalidInput); } - Ok(Self { - kty: reader.kty, - e: trimmed_e, - n: trim(reader.n), - alg: reader.alg, - }) + Ok(Self { kty: reader.kty, e: trimmed_e, n: trim(reader.n), alg: reader.alg }) } } -/// Trim trailing '=' so that it is considered a valid base64 url encoding string by base64ct library. +/// Trim trailing '=' so that it is considered a valid base64 url encoding +/// string by base64ct library. fn trim(str: String) -> String { str.trim_end_matches('=').to_owned() } -/*/// Fetch JWKs from the given provider and return a list of JwkId -> JWK. -pub async fn fetch_jwks( - provider: &OIDCProvider, - client: &Client, -) -> Result, ZkCryptoError> { - let response = client - .get(provider.get_config().jwk_endpoint) - .send() - .await - .map_err(|e| { - ZkCryptoError::GeneralError(format!( - "Failed to get JWK {:?} {:?}", - e.to_string(), - provider - )) - })?; - let bytes = response.bytes().await.map_err(|e| { - ZkCryptoError::GeneralError(format!( - "Failed to get bytes {:?} {:?}", - e.to_string(), - provider - )) - })?; - parse_jwks(&bytes, provider) -}*/ - -/// Parse the JWK bytes received from the given provider and return a list of JwkId -> JWK. +// /// Fetch JWKs from the given provider and return a list of JwkId -> JWK. +// pub async fn fetch_jwks( +// provider: &OIDCProvider, +// client: &Client, +// ) -> Result, ZkCryptoError> { +// let response = client +// .get(provider.get_config().jwk_endpoint) +// .send() +// .await +// .map_err(|e| { +// ZkCryptoError::GeneralError(format!( +// "Failed to get JWK {:?} {:?}", +// e.to_string(), +// provider +// )) +// })?; +// let bytes = response.bytes().await.map_err(|e| { +// ZkCryptoError::GeneralError(format!( +// "Failed to get bytes {:?} {:?}", +// e.to_string(), +// provider +// )) +// })?; +// parse_jwks(&bytes, provider) +// } + +/// Parse the JWK bytes received from the given provider and return a list of +/// JwkId -> JWK. pub fn parse_jwks( json_bytes: &[u8], provider: &OIDCProvider, @@ -270,9 +270,7 @@ pub fn parse_jwks( return Ok(ret); } } - Err(ZkCryptoError::GeneralError( - "Invalid JWK response".to_string(), - )) + Err(ZkCryptoError::GeneralError("Invalid JWK response".to_string())) } /// A claim consists of value and index_mod_4. @@ -292,7 +290,8 @@ pub struct JWTDetails { } impl JWTDetails { - /// Read in the Claim and header string. Parse and validate kid, header, iss as JWT details. + /// Read in the Claim and header string. Parse and validate kid, header, iss + /// as JWT details. pub fn new(header_base64: &str, claim: &Claim) -> Result { let header = JWTHeader::new(header_base64)?; let ext_claim = decode_base64_url(&claim.value, &claim.index_mod_4)?; @@ -304,7 +303,8 @@ impl JWTDetails { } } -/// All inputs required for the zk login proof verification and other public inputs. +/// All inputs required for the zk login proof verification and other public +/// inputs. #[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ZkLoginInputs { @@ -328,7 +328,8 @@ pub struct ZkLoginInputsReader { } impl ZkLoginInputs { - /// Parse the proving service response and pass in the address seed. Initialize the jwt details struct. + /// Parse the proving service response and pass in the address seed. + /// Initialize the jwt details struct. pub fn from_json(value: &str, address_seed: &str) -> Result { let reader: ZkLoginInputsReader = serde_json::from_str(value).map_err(|_| ZkCryptoError::InvalidInput)?; @@ -377,7 +378,8 @@ impl ZkLoginInputs { &self.address_seed } - /// Calculate the poseidon hash from selected fields from inputs, along with the ephemeral pubkey. + /// Calculate the poseidon hash from selected fields from inputs, along with + /// the ephemeral pubkey. pub fn calculate_all_inputs_hash( &self, eph_pk_bytes: &[u8], @@ -435,7 +437,6 @@ impl ZkLoginProof { println!(""); - let bb = g2_affine_from_str_projective(&self.b)?; println!("&self.b bb {:?}", bb); println!("&self.b bb.x {:?}", bb.x); @@ -446,7 +447,6 @@ impl ZkLoginProof { println!("-bb.y {:?}", bby_); - // let aa = g1_affine_from_str_projective(&self.a)?; // println!("&self.a aa {:?}", aa); // println!("&self.a aa.y {:?}", aa.y); @@ -469,16 +469,15 @@ impl ZkLoginProof { } } -/// Parse the extended claim json value to its claim value, using the expected claim key. +/// Parse the extended claim json value to its claim value, using the expected +/// claim key. fn verify_extended_claim( extended_claim: &str, expected_key: &str, ) -> Result { // Last character of each extracted_claim must be '}' or ',' if !(extended_claim.ends_with('}') || extended_claim.ends_with(',')) { - return Err(ZkCryptoError::GeneralError( - "Invalid extended claim".to_string(), - )); + return Err(ZkCryptoError::GeneralError("Invalid extended claim".to_string())); } let json_str = format!("{{{}}}", &extended_claim[..extended_claim.len() - 1]); @@ -493,12 +492,11 @@ fn verify_extended_claim( Ok(value.to_string()) } -/// Parse the base64 string, add paddings based on offset, and convert to a bytearray. +/// Parse the base64 string, add paddings based on offset, and convert to a +/// bytearray. fn decode_base64_url(s: &str, i: &u8) -> Result { if s.len() < 2 { - return Err(ZkCryptoError::GeneralError( - "Base64 string smaller than 2".to_string(), - )); + return Err(ZkCryptoError::GeneralError("Base64 string smaller than 2".to_string())); } let mut bits = base64_to_bitarray(s)?; match i { @@ -510,9 +508,7 @@ fn decode_base64_url(s: &str, i: &u8) -> Result { bits.drain(..4); } _ => { - return Err(ZkCryptoError::GeneralError( - "Invalid first_char_offset".to_string(), - )); + return Err(ZkCryptoError::GeneralError("Invalid first_char_offset".to_string())); } } @@ -526,16 +522,12 @@ fn decode_base64_url(s: &str, i: &u8) -> Result { bits.drain(bits.len() - 4..); } _ => { - return Err(ZkCryptoError::GeneralError( - "Invalid last_char_offset".to_string(), - )); + return Err(ZkCryptoError::GeneralError("Invalid last_char_offset".to_string())); } } if bits.len() % 8 != 0 { - return Err(ZkCryptoError::GeneralError( - "Invalid bits length".to_string(), - )); + return Err(ZkCryptoError::GeneralError("Invalid bits length".to_string())); } Ok(std::str::from_utf8(&bitarray_to_bytearray(&bits)?) @@ -543,8 +535,10 @@ fn decode_base64_url(s: &str, i: &u8) -> Result { .to_owned()) } -/// Map a base64 string to a bit array by taking each char's index and covert it to binary form with one bit per u8 -/// element in the output. Returns [ZkCryptoError::InvalidInput] if one of the characters is not in the base64 charset. +/// Map a base64 string to a bit array by taking each char's index and covert it +/// to binary form with one bit per u8 element in the output. Returns +/// [ZkCryptoError::InvalidInput] if one of the characters is not in the base64 +/// charset. fn base64_to_bitarray(input: &str) -> ZkCryptoResult> { input .chars() @@ -559,8 +553,8 @@ fn base64_to_bitarray(input: &str) -> ZkCryptoResult> { .collect() } -/// Convert a bitarray (each bit is represented by a u8) to a byte array by taking each 8 bits as a -/// byte in big-endian format. +/// Convert a bitarray (each bit is represented by a u8) to a byte array by +/// taking each 8 bits as a byte in big-endian format. fn bitarray_to_bytearray(bits: &[u8]) -> ZkCryptoResult> { if bits.len() % 8 != 0 { return Err(ZkCryptoError::InvalidInput); @@ -584,10 +578,7 @@ pub fn hash_ascii_str_to_field(str: &str, max_size: u8) -> Result Result, ZkCryptoError> { - let arr: Vec = str - .chars() - .map(|c| BigUint::from_slice(&([c as u32]))) - .collect(); + let arr: Vec = str.chars().map(|c| BigUint::from_slice(&([c as u32]))).collect(); pad_with_zeroes(arr, max_len) } @@ -600,10 +591,10 @@ fn pad_with_zeroes(in_arr: Vec, out_count: u8) -> Result, Ok(padded) } -/// Maps a stream of bigints to a single field element. First we convert the base from -/// inWidth to packWidth. Then we compute the poseidon hash of the "packed" input. -/// input is the input vector containing equal-width big ints. inWidth is the width of -/// each input element. +/// Maps a stream of bigints to a single field element. First we convert the +/// base from inWidth to packWidth. Then we compute the poseidon hash of the +/// "packed" input. input is the input vector containing equal-width big ints. +/// inWidth is the width of each input element. pub fn hash_to_field( input: &[BigUint], in_width: u16, @@ -654,4 +645,3 @@ fn big_int_array_to_bits(integers: &[BigUint], intended_size: usize) -> ZkCrypto .flatten_ok() .collect() } - From aff4c35ed2833493eb2886137f4ff65b1366c14f Mon Sep 17 00:00:00 2001 From: alinat Date: Thu, 3 Oct 2024 23:05:46 +0300 Subject: [PATCH 04/19] fix warning and tests --- tvm_tests/Cargo.toml | 2 - tvm_tests/src/main.rs | 3 +- tvm_tests/src/test_framework.rs | 21 +- tvm_tests/src/test_zk.rs | 2564 +++++++++++----------- tvm_tests/src/test_zk_.rs | 155 -- tvm_vm/Cargo.toml | 2 +- tvm_vm/src/executor/zk.rs | 4 +- tvm_vm/src/executor/zk_stuff/mod.rs | 5 +- tvm_vm/src/executor/zk_stuff/zk_login.rs | 9 - 9 files changed, 1265 insertions(+), 1500 deletions(-) delete mode 100644 tvm_tests/src/test_zk_.rs diff --git a/tvm_tests/Cargo.toml b/tvm_tests/Cargo.toml index 383a64bd..79ad1358 100644 --- a/tvm_tests/Cargo.toml +++ b/tvm_tests/Cargo.toml @@ -19,8 +19,6 @@ pprof = { features = [ 'criterion', 'flamegraph' ], version = '0.11' } pretty_assertions = '1.3' criterion = '0.4' - - ed25519 = '1.2' ed25519-dalek = '1.0' anyhow = "1.0.79" diff --git a/tvm_tests/src/main.rs b/tvm_tests/src/main.rs index 27bae108..1ebbd25e 100644 --- a/tvm_tests/src/main.rs +++ b/tvm_tests/src/main.rs @@ -1,5 +1,6 @@ mod test_framework; + +#[cfg(test)] mod test_zk; -mod test_zk_; fn main() {} diff --git a/tvm_tests/src/test_framework.rs b/tvm_tests/src/test_framework.rs index ff06673a..868438d7 100644 --- a/tvm_tests/src/test_framework.rs +++ b/tvm_tests/src/test_framework.rs @@ -71,10 +71,10 @@ fn logger_init() { if log::log_enabled!(log::Level::Info) { return; } - let log_level = - if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { log::LevelFilter::Info }; + let log_level = log::LevelFilter::Info; + /*if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { log::LevelFilter::Info };*/ let encoder_boxed = Box::new(log4rs::encode::pattern::PatternEncoder::new("{m}")); - let config = if cfg!(feature = "log_file") { + /*let config = if cfg!(feature = "log_file") { let file = log4rs::append::file::FileAppender::builder() .encoder(encoder_boxed) .build("log/log.txt") @@ -90,6 +90,14 @@ fn logger_init() { .appender(log4rs::config::Appender::builder().build("console", Box::new(console))) .build(log4rs::config::Root::builder().appender("console").build(log_level)) .unwrap() + };*/ + let config = { + let console = + log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed).build(); + log4rs::config::Config::builder() + .appender(log4rs::config::Appender::builder().build("console", Box::new(console))) + .build(log4rs::config::Root::builder().appender("console").build(log_level)) + .unwrap() }; log4rs::init_config(config).ok(); } @@ -436,7 +444,7 @@ impl TestCase { executor.set_index_provider(index_provider) } let execution_result = executor.execute(); - if cfg!(feature = "fift_check") + /*if cfg!(feature = "fift_check") && args.stack.is_empty() && args.ctrls.is_empty() && !args.skip_fift_check @@ -450,7 +458,8 @@ impl TestCase { &execution_result, gas, ) - } + }*/ + TestCase { executor: Some(executor), compilation_result: Ok(bytecode), @@ -480,7 +489,7 @@ impl TestCase { vec![library.clone()], ); let execution_result = executor.execute(); - if cfg!(feature = "fift_check") && stack.is_none() && ctrls.is_none() { + if /*cfg!(feature = "fift_check") &&*/ stack.is_none() && ctrls.is_none() { compare_with_fift( code.clone(), library, diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index ecec6747..1f5809db 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -1,149 +1,178 @@ -// Copyright (C) 2019-2023 TON Labs. All Rights Reserved. -// -// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not -// use this file except in compliance with the License. -// -// 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 TON DEV software governing permissions and -// limitations under the License. - -use std::collections::HashMap; -use std::iter::repeat; -use std::time::Instant; - -use base64ct::Encoding as bEncoding; -use ed25519::signature::Signer; -use fastcrypto_zkp::bn254::zk_login::CanonicalSerialize; -use fastcrypto_zkp::bn254::zk_login::JwkId; -use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; -use fastcrypto_zkp::bn254::zk_login::JWK; -use num_bigint::BigUint; -use serde::Deserialize; -use serde_derive::Serialize; -use tvm_types::BuilderData; -use tvm_types::Cell; -use tvm_types::SliceData; -use tvm_vm::executor::zk_stuff::error::ZkCryptoError; -use tvm_vm::int; -use tvm_vm::stack::integer::IntegerData; -use tvm_vm::stack::Stack; -use tvm_vm::stack::StackItem; -use tvm_vm::utils::pack_data_to_cell; - -use crate::test_framework::test_case_with_refs; -use crate::test_framework::Expects; - -#[derive(Debug, Deserialize)] -pub struct JwtData { - jwt: String, - userPassToIntFormat: String, - ephemeralKeyPair: EphemeralKeyPair, - zkAddr: String, - zkProofs: ZkProofs, - extendedEphemeralPublicKey: String, -} +#[cfg(test)] +mod tests { + use num_traits::Zero; + use std::iter::repeat; + + use std::collections::HashMap; + + use std::str::FromStr; + use std::time::Instant; + use ark_std::rand::rngs::StdRng; + use ark_std::rand::SeedableRng; + use base64ct::Encoding as bEncoding; + use fastcrypto::ed25519::Ed25519KeyPair; + use base64::decode; + use ark_ff::biginteger::BigInteger; + use ed25519::signature::Signer; + + use fastcrypto::traits::{KeyPair, ToFromBytes}; + + + /*#[cfg(feature = "signature_no_check")]*/ + // use ton_vm::executor::BehaviorModifiers; + use tvm_vm::{ + int, + stack::{ + integer::{ + IntegerData, + }, + Stack, StackItem, + }, + utils::{pack_string_to_cell, pack_data_to_cell}, + }; -#[derive(Debug, Deserialize)] -pub struct EphemeralKeyPair { - keypair: Keypair, -} + use tvm_vm::executor::zk_stuff::error::ZkCryptoError; + use tvm_types::{BuilderData, Cell, SliceData}; + use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, OIDCProvider, ZkLoginInputs}; + use fastcrypto_zkp::bn254::utils::{gen_address_seed, get_zk_login_address}; + use fastcrypto_zkp::zk_login_utils::Bn254FrElement; + use num_bigint::BigUint; + + use serde::{Deserialize}; + use serde_derive::Serialize; + use serde_json::Value; + use crate::test_framework::{Expects, test_case_with_refs}; + + pub const SUI_DATA_FROM_REACT_1: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJ4bW5KVzMxcnV6S01HaXIwMVlQR1lMMHhEWSIsIm5iZiI6MTcxNTY4NzAzNiwiaWF0IjoxNzE1Njg3MzM2LCJleHAiOjE3MTU2OTA5MzYsImp0aSI6IjliNjAxZDI1ZjAwMzY0MGMyODg5YTJhMDQ3Nzg5MzgyY2IxY2ZlODcifQ.rTa9KA9HoYm04Agj71D0kDkvsCZ35SeeihBGbABYckBRxaUlCy6LQ-sEaVOTgvnL_DgVn7hx8g3sSmnhJ9kHzj5e6gtUoxoWAe8PuGyK2bmqhmPrQMeEps9f6m2EToQCIA_Id4fGCjSCktjJBi47QHT_Dhe6isHdKk1pgSshOyvCF1VjIvyyeGY5iWQ4cIRBMQNlNBT11o6T01SY6B9DtiiFN_0-ok5taIjQgtMNG6Cwr3tCnqXftuGGQrHlx15y8VgCPODYi-wOtvUbzI2yfx53PmRD_L8O50cMNCrCRE3yYR5MNOu1LlQ_EACy5UFsCJR35xRz84nv-6Iyrufx1g\",\"user_pass_to_int_format\":\"981021191041055255531141165751\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":155,\"1\":147,\"2\":37,\"3\":82,\"4\":183,\"5\":109,\"6\":227,\"7\":144,\"8\":85,\"9\":248,\"10\":20,\"11\":45,\"12\":92,\"13\":103,\"14\":160,\"15\":221,\"16\":101,\"17\":44,\"18\":30,\"19\":86,\"20\":96,\"21\":85,\"22\":24,\"23\":224,\"24\":106,\"25\":63,\"26\":13,\"27\":130,\"28\":8,\"29\":119,\"30\":247,\"31\":67},\"secret_key\":{\"0\":192,\"1\":16,\"2\":35,\"3\":54,\"4\":100,\"5\":14,\"6\":88,\"7\":217,\"8\":164,\"9\":21,\"10\":154,\"11\":233,\"12\":248,\"13\":208,\"14\":188,\"15\":4,\"16\":52,\"17\":244,\"18\":125,\"19\":103,\"20\":99,\"21\":26,\"22\":225,\"23\":60,\"24\":140,\"25\":75,\"26\":228,\"27\":157,\"28\":137,\"29\":220,\"30\":1,\"31\":65,\"32\":155,\"33\":147,\"34\":37,\"35\":82,\"36\":183,\"37\":109,\"38\":227,\"39\":144,\"40\":85,\"41\":248,\"42\":20,\"43\":45,\"44\":92,\"45\":103,\"46\":160,\"47\":221,\"48\":101,\"49\":44,\"50\":30,\"51\":86,\"52\":96,\"53\":85,\"54\":24,\"55\":224,\"56\":106,\"57\":63,\"58\":13,\"59\":130,\"60\":8,\"61\":119,\"62\":247,\"63\":67}}},\"zk_addr\":\"0x290623ea2fe67e77502c931e015e910720b59cf99994bfe872da851245a6adb8\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"4240296169193969312736577528388333411353554120022978085193148043577551744781\",\"5805161066003598301896048908428560240907086333477483881772048922050706263054\",\"1\"],\"b\":[[\"12834391737669124973917765536412427456985620342194191639017091262766903638891\",\"17565396762846717347409742387259908749145765976354144805005547481529916658455\"],[\"10704310067924910937030159163683742097178285875135929496314190235513445131794\",\"5158907077493606386023392148737817037260820737072162547798816810512684527243\"],[\"1\",\"0\"]],\"c\":[\"1422540522119231707130773229384414857146368773886805969586218853559909475064\",\"8843079196273712399340537238369227864378150337693574970239878271571912585171\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AJuTJVK3beOQVfgULVxnoN1lLB5WYFUY4Go/DYIId/dD\"}"; + pub const SUI_DATA_FROM_REACT_2: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjJKd0VMbjJfUV9Rd0VsTC1rWTFPRnFqdXZCMCIsIm5iZiI6MTcxNTY4NzAyOSwiaWF0IjoxNzE1Njg3MzI5LCJleHAiOjE3MTU2OTA5MjksImp0aSI6ImU2YjM1ZjJmNmFkNjIzOWEwMDAxMTJiMWI5YWI2MWQ0MjRkMGM1OTIifQ.QcrEDE9qmPZKX83nU3Tx2BN8fsinb_mmXkO1Qf7Uv1QTd0NjirSeu7C4Vn9WDNWDaIR-BgCfhOlkwMQPljcahqC4AN43N_66tvbEsXjtEdFejslXrGG4D_BEKvtmD7_WkW388LyU2PxKgtdDfpYFgmuT6wTM2TO5dTbrGrDyn88q3pkPfefC5a8Wi1V6zECfFdSV-pKQlxtPaImi7s3CKAUMDu1n-jcT-Ho2aTgrWKAzhXE56tgEWOpXQO06eJsWCSOqoZSLYtatTrZr4d38U7QRQiNlH-ydHv4zXt1tixLLJ0wvPx-dQaCnCl1kW1orYkJGFfHgjx6A9z5Ol4afuw\",\"user_pass_to_int_format\":\"101119106102103\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":194,\"1\":38,\"2\":203,\"3\":255,\"4\":219,\"5\":127,\"6\":105,\"7\":129,\"8\":234,\"9\":222,\"10\":71,\"11\":169,\"12\":108,\"13\":94,\"14\":28,\"15\":48,\"16\":111,\"17\":221,\"18\":113,\"19\":110,\"20\":5,\"21\":226,\"22\":19,\"23\":230,\"24\":232,\"25\":67,\"26\":255,\"27\":179,\"28\":6,\"29\":10,\"30\":209,\"31\":63},\"secret_key\":{\"0\":44,\"1\":32,\"2\":251,\"3\":184,\"4\":109,\"5\":252,\"6\":105,\"7\":67,\"8\":208,\"9\":111,\"10\":86,\"11\":214,\"12\":192,\"13\":135,\"14\":169,\"15\":48,\"16\":162,\"17\":36,\"18\":216,\"19\":145,\"20\":232,\"21\":64,\"22\":17,\"23\":14,\"24\":29,\"25\":56,\"26\":39,\"27\":118,\"28\":143,\"29\":250,\"30\":31,\"31\":66,\"32\":194,\"33\":38,\"34\":203,\"35\":255,\"36\":219,\"37\":127,\"38\":105,\"39\":129,\"40\":234,\"41\":222,\"42\":71,\"43\":169,\"44\":108,\"45\":94,\"46\":28,\"47\":48,\"48\":111,\"49\":221,\"50\":113,\"51\":110,\"52\":5,\"53\":226,\"54\":19,\"55\":230,\"56\":232,\"57\":67,\"58\":255,\"59\":179,\"60\":6,\"61\":10,\"62\":209,\"63\":63}}},\"zk_addr\":\"0x9d28c04a423b33d6901065b2e23440d80c963e2d8cf60619aed131cf302a3345\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"10113442204684515220664612836724727112601024759319365467272456423129044788607\",\"1622056145268645528934658046911045406324940175278473377024147189407527440953\",\"1\"],\"b\":[[\"16638441944380099215425740101953753038808466958852552979180365845498468757656\",\"15160836857346434734063515954042830497610079883703780011464867547889770445695\"],[\"18562910453341688699790780964434211467815845944672185772065803860963710445937\",\"8200691834141582017549140597895023392490964486044036655696113278873832146838\"],[\"1\",\"0\"]],\"c\":[\"4229037146526046139176767312447148765936834700862335953317784850097077554287\",\"14155516063621997063825085002662503289554536312724791903045026922766401869119\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AMImy//bf2mB6t5HqWxeHDBv3XFuBeIT5uhD/7MGCtE/\"}"; + pub const SUI_DATA_FROM_REACT_3: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkFadlVHUkI5MU5VZmdnYVV5bUdCQU9kSmM2ayIsIm5iZiI6MTcxNTY4NzAyMiwiaWF0IjoxNzE1Njg3MzIyLCJleHAiOjE3MTU2OTA5MjIsImp0aSI6ImZiNGNhMzdjOGE5MjEzOTFjZTE2ZDQwNmE2NmVmYjA1MTQxNTg5YjYifQ.C7zNP2sxRMF62irwNjO2y_JVMjYLqGk6sAWy0rKoXswa7SA6KhPrWocMAB2GKaQW-CeqUzMJdypgJz1RcMzmOWg30cv4diEgqBSM1I1ocOI5ivRE2Atj8g-Oj2uAm_DBvuJBLzTA6wfb34QTasOTZqLsMyoaQavxUprzPi-1z-MUE-darDjZ-IkWu7SctdEzNhSuUfQPJo_sbN5_38dQm300plXK-9iJgDxMWmT4NPO91hSQaGKbBm_euMI-fBAfYwARMnlaTETvSiCNSAyzphNrBi9kU49BFi5X04GoIkSW4zFwb74OeFbL49_14AZZ9Z2Mw7EPQ9sAAjzanxPUfA\",\"user_pass_to_int_format\":\"98118101102104106100\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":219,\"1\":225,\"2\":68,\"3\":197,\"4\":249,\"5\":59,\"6\":249,\"7\":200,\"8\":218,\"9\":242,\"10\":184,\"11\":214,\"12\":247,\"13\":159,\"14\":9,\"15\":162,\"16\":60,\"17\":174,\"18\":162,\"19\":13,\"20\":111,\"21\":5,\"22\":61,\"23\":179,\"24\":155,\"25\":167,\"26\":207,\"27\":6,\"28\":174,\"29\":163,\"30\":23,\"31\":23},\"secret_key\":{\"0\":28,\"1\":117,\"2\":37,\"3\":14,\"4\":166,\"5\":188,\"6\":125,\"7\":36,\"8\":70,\"9\":193,\"10\":162,\"11\":142,\"12\":79,\"13\":218,\"14\":210,\"15\":131,\"16\":217,\"17\":32,\"18\":88,\"19\":246,\"20\":195,\"21\":214,\"22\":135,\"23\":80,\"24\":27,\"25\":198,\"26\":131,\"27\":31,\"28\":3,\"29\":240,\"30\":199,\"31\":129,\"32\":219,\"33\":225,\"34\":68,\"35\":197,\"36\":249,\"37\":59,\"38\":249,\"39\":200,\"40\":218,\"41\":242,\"42\":184,\"43\":214,\"44\":247,\"45\":159,\"46\":9,\"47\":162,\"48\":60,\"49\":174,\"50\":162,\"51\":13,\"52\":111,\"53\":5,\"54\":61,\"55\":179,\"56\":155,\"57\":167,\"58\":207,\"59\":6,\"60\":174,\"61\":163,\"62\":23,\"63\":23}}},\"zk_addr\":\"0xeccbb76b41c1fd5e19950f0c005e5d2a2596b9cc510e98b6f69bb3cf590b3cf8\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"11651445672013969095011012560101085321682180365624939394143647198080899422642\",\"1099774502834574451399947043208869188329872135932897351612210181871486714260\",\"1\"],\"b\":[[\"4095258550782358133185755302461547336434190495389756275789648565352453295275\",\"11290282088300413285686821769617771231670721476484846359206004074570380534935\"],[\"10130196410049440247754977520268298700433580296307256932070052957562923587210\",\"18578315450133100598244014262861961858129311260491371986249505812898194068790\"],[\"1\",\"0\"]],\"c\":[\"3621803486710965065098877836422521469652420656514094958857631583114966034063\",\"10775419351495516109888010278620848514990288696189982169937651175162131341248\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"ANvhRMX5O/nI2vK41vefCaI8rqINbwU9s5unzwauoxcX\"}"; + pub const SUI_DATA_FROM_REACT_4: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Inh4VjZnc3RReGY2WW5Kb0QyMXMtZkNWdm9ESSIsIm5iZiI6MTcxNTY4NzAxNSwiaWF0IjoxNzE1Njg3MzE1LCJleHAiOjE3MTU2OTA5MTUsImp0aSI6ImQzOWJjMTUyOWVhODMwNTRiNGU0MDRlNDRhMmE4ZWRjOTJlZWFiYWYifQ.u23WQFEtc4TldMtNqrU7DiYdL33X2QySNxueCW79LQHc00P7g-Pu7xPX0XK_TLxP6ReZEdpdCmjfG6g--XBYXh313FKcqVhcrtKdBE06jf5acAf4fQ3TVzG5CFWqjISRhLL0eGjX20DZm8drrSFYTgfWPl9ANo6TV2IFF6BR9TOO_flxzmXPRVvER9ZA4QO52JCqagVYBw4bFZcUebiN_KXYuXOYWzUAiHM7lKUdVKoCte9JDKnTfRNg3r-i5tt5Oiovswwh9jubQd5c8nCQckQ8Fj9T5nPmlfPtF282kfd76xlHckvL94mM3HUKNuFrxeiFX07f_5Ff7NxvQ3QPgw\",\"user_pass_to_int_format\":\"118102101104106\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":25,\"1\":68,\"2\":102,\"3\":77,\"4\":86,\"5\":118,\"6\":203,\"7\":106,\"8\":41,\"9\":192,\"10\":205,\"11\":144,\"12\":20,\"13\":158,\"14\":42,\"15\":167,\"16\":18,\"17\":30,\"18\":27,\"19\":103,\"20\":51,\"21\":222,\"22\":226,\"23\":224,\"24\":168,\"25\":111,\"26\":16,\"27\":214,\"28\":128,\"29\":165,\"30\":10,\"31\":183},\"secret_key\":{\"0\":204,\"1\":128,\"2\":233,\"3\":135,\"4\":233,\"5\":64,\"6\":127,\"7\":97,\"8\":231,\"9\":135,\"10\":123,\"11\":149,\"12\":126,\"13\":145,\"14\":173,\"15\":252,\"16\":33,\"17\":141,\"18\":251,\"19\":181,\"20\":223,\"21\":9,\"22\":77,\"23\":32,\"24\":19,\"25\":187,\"26\":3,\"27\":180,\"28\":110,\"29\":49,\"30\":114,\"31\":167,\"32\":25,\"33\":68,\"34\":102,\"35\":77,\"36\":86,\"37\":118,\"38\":203,\"39\":106,\"40\":41,\"41\":192,\"42\":205,\"43\":144,\"44\":20,\"45\":158,\"46\":42,\"47\":167,\"48\":18,\"49\":30,\"50\":27,\"51\":103,\"52\":51,\"53\":222,\"54\":226,\"55\":224,\"56\":168,\"57\":111,\"58\":16,\"59\":214,\"60\":128,\"61\":165,\"62\":10,\"63\":183}}},\"zk_addr\":\"0x9440174050c8a69f3736aade438d256444387d7f99afaf9b5a9f29c6f0fba0c3\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"12337032776119704699956096862904448418119911526311506121881119564201699892276\",\"21261432927871679671381948020842646421823600661053961908567605147368225372658\",\"1\"],\"b\":[[\"361501104451650926380087094710685809078127996371826342961671838349546013669\",\"6224896865231367783073876006741593926823975323893517814398563485217838362592\"],[\"17991862631010087641911530148948529285385885925990265147692471125933697566220\",\"3919918348467391624469564417209140189505145619892305626999747602773689849635\"],[\"1\",\"0\"]],\"c\":[\"2974798412198231516644318932878285282801453498857240613838304706754188993145\",\"18411763423260631630440151338922210964792206590205572668118109635459867927504\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"ABlEZk1WdstqKcDNkBSeKqcSHhtnM97i4KhvENaApQq3\"}"; + pub const SUI_DATA_FROM_REACT_5: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlZXM0VrSmp5ZXM0M2pvNENXU0FyU1pORHk5ayIsIm5iZiI6MTcxNTY4NzAwNywiaWF0IjoxNzE1Njg3MzA3LCJleHAiOjE3MTU2OTA5MDcsImp0aSI6IjMwNDczMjk0MmI3MDQzOTUzN2M3OTE4YTIyZDMxODA1YTVjYzkzZTYifQ.sa6ee8fcMhF3JgGQcl03IY0alries0KC7SRH-HVUnA5cqTVYomJ6fr0NTDJmYXNKOeIcaT85LLN0ALsKtEQdZjhu1g4m16kbS-5MybFIXT85JIPhBOz7zYldrbiy-Me8XRNWPkR3X_lV9pwqvYJTnZ0ley5dDITRvIXE1w2ZmjGNDlDxG3aM2XOQDICQ1ztsCZkn20ShuvG7tZHq7cp7K0hd6JdX0fFRY85eSIeapW7NnnWdvJi2xvuiCcwqm8sshldcJI5uU9xikhoN2WA7c8fJ5rtshqp5-RtTOfbzLn2a6m0WeDE0JqUd8jbh6_T8mGtYYeYMAWfWb-jVPa8aNg\",\"user_pass_to_int_format\":\"118981041155255\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":76,\"1\":252,\"2\":245,\"3\":48,\"4\":8,\"5\":126,\"6\":211,\"7\":60,\"8\":249,\"9\":241,\"10\":111,\"11\":107,\"12\":148,\"13\":35,\"14\":224,\"15\":237,\"16\":179,\"17\":74,\"18\":84,\"19\":7,\"20\":130,\"21\":96,\"22\":198,\"23\":40,\"24\":23,\"25\":4,\"26\":50,\"27\":62,\"28\":191,\"29\":222,\"30\":119,\"31\":195},\"secret_key\":{\"0\":217,\"1\":194,\"2\":91,\"3\":84,\"4\":244,\"5\":214,\"6\":113,\"7\":57,\"8\":79,\"9\":43,\"10\":104,\"11\":85,\"12\":61,\"13\":225,\"14\":26,\"15\":139,\"16\":139,\"17\":206,\"18\":110,\"19\":48,\"20\":118,\"21\":99,\"22\":130,\"23\":122,\"24\":59,\"25\":6,\"26\":224,\"27\":144,\"28\":146,\"29\":25,\"30\":147,\"31\":225,\"32\":76,\"33\":252,\"34\":245,\"35\":48,\"36\":8,\"37\":126,\"38\":211,\"39\":60,\"40\":249,\"41\":241,\"42\":111,\"43\":107,\"44\":148,\"45\":35,\"46\":224,\"47\":237,\"48\":179,\"49\":74,\"50\":84,\"51\":7,\"52\":130,\"53\":96,\"54\":198,\"55\":40,\"56\":23,\"57\":4,\"58\":50,\"59\":62,\"60\":191,\"61\":222,\"62\":119,\"63\":195}}},\"zk_addr\":\"0x71444450505074fe9d9205f02747fb34f49dda22eb33eaf7929bb8561ffd45f2\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"4549343359411304649846201661164616647369749072820883051997393354186530425088\",\"3937997833930688873121017483900547354352969510911658484353113904856895725039\",\"1\"],\"b\":[[\"737118397015523176881783675037843258491735390512712007670938320351154476838\",\"18093386738096496776241258608856280732173952478987786488484944779094702670649\"],[\"17783469782238073070748856104623185946400565050372789961482242728023613389739\",\"15824649467012100671772283318060553156148444804907193757065241285355958322525\"],[\"1\",\"0\"]],\"c\":[\"15112690010634489290938122084488710379345235713605729023472643459768097669053\",\"21568492795931010980780236148561695295582527237009199544419907898465140630575\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AEz89TAIftM8+fFva5Qj4O2zSlQHgmDGKBcEMj6/3nfD\"}"; + pub const SUI_DATA_FROM_REACT_6: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjMySWx6VWJuSFY4MV9QTTBJSDBSZmFveVN1TSIsIm5iZiI6MTcxNTY4NzAwMCwiaWF0IjoxNzE1Njg3MzAwLCJleHAiOjE3MTU2OTA5MDAsImp0aSI6ImRhOTU5NmIwMTljOTQ2NWE4MzA0MWIxMDA3OTI2OGU3NDgwY2ZjMDkifQ.HFkMZFhHu6BGBbWhC1NwCvJ9_bKOL8jOdOHuRG21mKh-CaJPffnGtaVNcwEJjf4jOVVPPZNfcJPWOd7KoT_R2Giw7An2dUcJFvVJHUv4h55u4DinU50R7h7ACyEl5GwbKCI-cgxORbcoUdQRukDt1zJHe1eeWm1S8URlE2f4U0w2tPPaE_NmChIRyvU_CjB0dLwxzIWU74pvnbkLSSD2pTWhGbLT1yNhfMTh6yukLyEt2kWvNdZOgGbDfIU6xFjxJLtnPrm5WGiOiWyBmMuDput47-ns4821l3KogdIbWr6TLWW0PMwyJuHnif5pV7wJI9JL5XdFv8KZ0IReAYOIEg\",\"user_pass_to_int_format\":\"1021035256\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":169,\"1\":238,\"2\":219,\"3\":251,\"4\":231,\"5\":87,\"6\":175,\"7\":233,\"8\":185,\"9\":44,\"10\":161,\"11\":207,\"12\":48,\"13\":166,\"14\":79,\"15\":104,\"16\":225,\"17\":53,\"18\":68,\"19\":236,\"20\":49,\"21\":204,\"22\":99,\"23\":208,\"24\":2,\"25\":134,\"26\":101,\"27\":212,\"28\":221,\"29\":142,\"30\":69,\"31\":196},\"secret_key\":{\"0\":94,\"1\":128,\"2\":26,\"3\":130,\"4\":137,\"5\":40,\"6\":61,\"7\":27,\"8\":79,\"9\":58,\"10\":100,\"11\":117,\"12\":200,\"13\":118,\"14\":156,\"15\":202,\"16\":165,\"17\":34,\"18\":238,\"19\":237,\"20\":90,\"21\":63,\"22\":84,\"23\":119,\"24\":86,\"25\":2,\"26\":221,\"27\":177,\"28\":224,\"29\":4,\"30\":233,\"31\":99,\"32\":169,\"33\":238,\"34\":219,\"35\":251,\"36\":231,\"37\":87,\"38\":175,\"39\":233,\"40\":185,\"41\":44,\"42\":161,\"43\":207,\"44\":48,\"45\":166,\"46\":79,\"47\":104,\"48\":225,\"49\":53,\"50\":68,\"51\":236,\"52\":49,\"53\":204,\"54\":99,\"55\":208,\"56\":2,\"57\":134,\"58\":101,\"59\":212,\"60\":221,\"61\":142,\"62\":69,\"63\":196}}},\"zk_addr\":\"0xb1dfac568641e785f1fbd385f43f9ab5751f30e942ffd0618ea3cacf2feb884f\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"12140334820013650239749561964826061158522594132954339836339110630367427672527\",\"21543355833919541708094668850466443067263177907229807762067953508321817783804\",\"1\"],\"b\":[[\"11929519532343982399968491980281874410531815035766070083344475081372092452425\",\"13741260533480647813301201467326069876472210148610447598292633272004546481630\"],[\"14605296808789442404291984821803068302067977919075239981788942874792752578522\",\"20230214791286972912596895174545361255719543417377972941442631629070781210055\"],[\"1\",\"0\"]],\"c\":[\"6046227686259383004231849145260526357580306829730644608118177932582255490991\",\"1343314209137088066016224766407952045954639818725548553059063245802388749310\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AKnu2/vnV6/puSyhzzCmT2jhNUTsMcxj0AKGZdTdjkXE\"}"; + pub const SUI_DATA_FROM_REACT_7: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjhJNGF5NDF5THpHWnk4czNCUGR3QzItR2Q5ayIsIm5iZiI6MTcxNTY4Njk5MywiaWF0IjoxNzE1Njg3MjkzLCJleHAiOjE3MTU2OTA4OTMsImp0aSI6ImFjYmJiNmQ3NGY0ZmU3MjMxYzc2ZDQxNzE0ZDM4NDJiNzZlNDU4YzIifQ.nsmqj7tDDv7wJSn47YfaFBXabPYVBjZosGzH_bPHZZToPfvdQyXZrO5CXbaJmojxTPRmzZ2bPI39K9GMX7Y8gaOqk_LYHR7eemVaEj0wNpPPtmUFmHmyrL8nPkTN0a-87L2eu6t7yBZtEiT5e2Jz46RBu9rQL138seOvK3vm0YwhtnLGxhZQnoAKu076qZ_ItlsRn9PqM-sd83bqQoG_SPQVCZL6spWoFunXtj1FeKE-3gRRD8BopORDhFp4xytWDamd1XgIdCNp0a8u7mvElPZCjc3ZUAtFYBWwvfI9r2wN5X4gbNe_pbfpBmgg-2zxwt6c32IhNXlrDQkLxJYqkg\",\"user_pass_to_int_format\":\"9899115100106104\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":35,\"1\":64,\"2\":69,\"3\":29,\"4\":242,\"5\":9,\"6\":183,\"7\":224,\"8\":98,\"9\":254,\"10\":210,\"11\":82,\"12\":213,\"13\":2,\"14\":137,\"15\":66,\"16\":71,\"17\":61,\"18\":80,\"19\":154,\"20\":135,\"21\":100,\"22\":176,\"23\":189,\"24\":187,\"25\":96,\"26\":245,\"27\":194,\"28\":163,\"29\":250,\"30\":15,\"31\":37},\"secret_key\":{\"0\":117,\"1\":94,\"2\":35,\"3\":85,\"4\":116,\"5\":80,\"6\":126,\"7\":55,\"8\":166,\"9\":193,\"10\":94,\"11\":109,\"12\":238,\"13\":86,\"14\":132,\"15\":192,\"16\":225,\"17\":240,\"18\":26,\"19\":65,\"20\":211,\"21\":18,\"22\":195,\"23\":36,\"24\":225,\"25\":158,\"26\":143,\"27\":141,\"28\":21,\"29\":174,\"30\":139,\"31\":13,\"32\":35,\"33\":64,\"34\":69,\"35\":29,\"36\":242,\"37\":9,\"38\":183,\"39\":224,\"40\":98,\"41\":254,\"42\":210,\"43\":82,\"44\":213,\"45\":2,\"46\":137,\"47\":66,\"48\":71,\"49\":61,\"50\":80,\"51\":154,\"52\":135,\"53\":100,\"54\":176,\"55\":189,\"56\":187,\"57\":96,\"58\":245,\"59\":194,\"60\":163,\"61\":250,\"62\":15,\"63\":37}}},\"zk_addr\":\"0x2130548addf21464dba0598e4306193fc658433793260241bd224fa5a186eea1\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"11563763779979887221682129962776185026792805331576343366100386476995832665737\",\"11230623338801856741023013148077980370341441565413488652841279984753971030674\",\"1\"],\"b\":[[\"459996434316864652818633810305056376561329097756558823429320916262609240883\",\"9149790799426074072032368390512074348954812141386022619414187192076850710684\"],[\"21136831034524197906636931934376551157061262869485003235799208746070603082410\",\"7423352680736750974836973800304252036668418183885087029886854244313632685127\"],[\"1\",\"0\"]],\"c\":[\"13616579662900237409901679872544397096722160915603059752960265571802149963290\",\"17724386432768174493966206493099783171212386514205046762827409640509581679264\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"ACNARR3yCbfgYv7SUtUCiUJHPVCah2Swvbtg9cKj+g8l\"}"; + pub const SUI_DATA_FROM_REACT_8: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjlzWGhqc0xVZlNmdE12bl9iYmQtWkEwZnY5OCIsIm5iZiI6MTcxNTY4Njk4NiwiaWF0IjoxNzE1Njg3Mjg2LCJleHAiOjE3MTU2OTA4ODYsImp0aSI6IjhiNDUzYjUzNTY4MGU3OWZkZWUyOGE3NDVmMzgzMDBkMmNmYjNmODQifQ.a2fpzvW0PxyOcvE8P6WEtIs_mdfTQ9kJb4MIUC5T5uRYJ9ySqSa2qT-MICspGYBuNzCtWIvI6KHY9cIWE2XF3yv7d7gTk_IkhXJud0s5hMhsIxWuNXla_-HducNufaXxXxWYJ2g8dy2xsIMnPr5OC-r4dAX3DM3AchB8qA-RYJdtgwlLytyANp6I35BRT7ewXyDDdlqMLnz5dv4xh1y1wrXFL7VDyzV2XVTK3ap12Cev9IZtHnSGsDgl-vEXj1OYIyiaDgtDhA7rfLXWRTQEeVnRpF-v3AIwZmRu1qaXFoqUbMaSQpFotwb6m8fMQ1q9efOK1Xrv8dL3jBDcUA3w3w\",\"user_pass_to_int_format\":\"98118115106\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":52,\"1\":224,\"2\":199,\"3\":19,\"4\":180,\"5\":128,\"6\":181,\"7\":171,\"8\":55,\"9\":210,\"10\":168,\"11\":100,\"12\":198,\"13\":241,\"14\":150,\"15\":156,\"16\":226,\"17\":233,\"18\":32,\"19\":175,\"20\":153,\"21\":53,\"22\":23,\"23\":58,\"24\":196,\"25\":29,\"26\":16,\"27\":170,\"28\":245,\"29\":46,\"30\":71,\"31\":177},\"secret_key\":{\"0\":47,\"1\":184,\"2\":41,\"3\":167,\"4\":98,\"5\":225,\"6\":50,\"7\":146,\"8\":173,\"9\":129,\"10\":201,\"11\":41,\"12\":181,\"13\":239,\"14\":8,\"15\":249,\"16\":159,\"17\":200,\"18\":159,\"19\":80,\"20\":194,\"21\":79,\"22\":41,\"23\":26,\"24\":200,\"25\":82,\"26\":74,\"27\":200,\"28\":38,\"29\":172,\"30\":84,\"31\":187,\"32\":52,\"33\":224,\"34\":199,\"35\":19,\"36\":180,\"37\":128,\"38\":181,\"39\":171,\"40\":55,\"41\":210,\"42\":168,\"43\":100,\"44\":198,\"45\":241,\"46\":150,\"47\":156,\"48\":226,\"49\":233,\"50\":32,\"51\":175,\"52\":153,\"53\":53,\"54\":23,\"55\":58,\"56\":196,\"57\":29,\"58\":16,\"59\":170,\"60\":245,\"61\":46,\"62\":71,\"63\":177}}},\"zk_addr\":\"0xd704fd1fa5b1d8603b91081d104c08a025e9a952cd6b5b44324fcca2ed432737\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"12104554633236481277286668189930576438264898269322388260846346074721767290773\",\"12396613925509861793005815245783240999567113519994130032649036118285018908597\",\"1\"],\"b\":[[\"1950992742588131071369658940220202257834946772534232957497529743913085624908\",\"13592611568444679350754388983552527571019415309901710535712414143531288069409\"],[\"16680699225604481493782973126773355417557338915104879244979908308676269902149\",\"7242446539394843603528008588061352122030003516933411896066602483137632866329\"],[\"1\",\"0\"]],\"c\":[\"17095909781059243761149234557016161052123209525874162987135833613569429453315\",\"8531296608559822287633863219696197152375138627859243631029781182381653695377\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"ADTgxxO0gLWrN9KoZMbxlpzi6SCvmTUXOsQdEKr1Lkex\"}"; + pub const SUI_DATA_FROM_REACT_9: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImRLMlRMdjktRXFnaGR3SWQzMzlPNXZmN1JENCIsIm5iZiI6MTcxNTY4Njk3OSwiaWF0IjoxNzE1Njg3Mjc5LCJleHAiOjE3MTU2OTA4NzksImp0aSI6IjQxYTgwZTI3N2U5NzIxYjcwZDkyMjRkMWY5MzRlNjJhYTYwNzcyZGEifQ.NLM6YIR61HOzlEVS1ianwnFoG6OfSeLyuGpjH-Wt7eiWt27fHbDhOWTo-2ysx7cXuAl3gV8ZzMta24QSpjIiiaooGdurX92cWuDcARyewX5_4UuwBWBTXe66irHuqjwIOB2WwyN6PuOwvM6Y_IcL9vPwg76iJoupbeCHXBswiRVzVyBQus1k9SGigU8_ZuwGYoTLPd68MX7Z68NrK7mCF04Xaijs__zwJigIhVOK3TXN2Xy84Ha76mrXJRJZuWErrSNWagVO-dxb2oMT8vm5ND9aJ4q4NaIeGa8PIN2X1cfg9A6LZVBsGIc9JV2FG39yK4T2XAH6tn_HtoMzy_Vuvg\",\"user_pass_to_int_format\":\"10011898115106104\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":78,\"1\":247,\"2\":200,\"3\":7,\"4\":84,\"5\":131,\"6\":33,\"7\":223,\"8\":6,\"9\":241,\"10\":100,\"11\":90,\"12\":91,\"13\":2,\"14\":31,\"15\":23,\"16\":138,\"17\":130,\"18\":115,\"19\":150,\"20\":202,\"21\":79,\"22\":12,\"23\":132,\"24\":168,\"25\":153,\"26\":155,\"27\":131,\"28\":31,\"29\":69,\"30\":170,\"31\":112},\"secret_key\":{\"0\":98,\"1\":144,\"2\":57,\"3\":245,\"4\":40,\"5\":191,\"6\":248,\"7\":149,\"8\":147,\"9\":12,\"10\":229,\"11\":76,\"12\":157,\"13\":3,\"14\":241,\"15\":94,\"16\":134,\"17\":124,\"18\":226,\"19\":177,\"20\":31,\"21\":140,\"22\":224,\"23\":58,\"24\":57,\"25\":95,\"26\":235,\"27\":246,\"28\":120,\"29\":89,\"30\":33,\"31\":149,\"32\":78,\"33\":247,\"34\":200,\"35\":7,\"36\":84,\"37\":131,\"38\":33,\"39\":223,\"40\":6,\"41\":241,\"42\":100,\"43\":90,\"44\":91,\"45\":2,\"46\":31,\"47\":23,\"48\":138,\"49\":130,\"50\":115,\"51\":150,\"52\":202,\"53\":79,\"54\":12,\"55\":132,\"56\":168,\"57\":153,\"58\":155,\"59\":131,\"60\":31,\"61\":69,\"62\":170,\"63\":112}}},\"zk_addr\":\"0x4493e2aab6fcd5d7259e066291ed6f42f6e0b732ecbd38bbaf8a98546a7d0cba\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"6187760498712900389422022394560825973187662358740291343829568808375698843239\",\"3663904360488418820404220406786944885702547623862334490191838865255632801941\",\"1\"],\"b\":[[\"17208058907245387104889127891010282196539728213379257608213444054211064433036\",\"9822512703540345824827246410723992174766686970531763618190197664729418117984\"],[\"9555481236549941306688205540885297760448987185399187813240300069134845655152\",\"17967781633941820778916846359708064205041390458485667635199415296702341964940\"],[\"1\",\"0\"]],\"c\":[\"12374452924342055287727719327288397498526425907741014437332085255604038084453\",\"7084903967634108603521121616612807600817728267672878238097194166039392876060\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AE73yAdUgyHfBvFkWlsCHxeKgnOWyk8MhKiZm4MfRapw\"}"; + pub const SUI_DATA_FROM_REACT_10: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZjdk1UaEZFdjFzVTBGVGR1M3Z5TmxlVUd0MCIsIm5iZiI6MTcxNTY4Njk3MiwiaWF0IjoxNzE1Njg3MjcyLCJleHAiOjE3MTU2OTA4NzIsImp0aSI6ImFiMDMwNTMzZjQyOWJmOGFhMDNmYzZhYjAxZjg2MGQ3MTg5ZDBlNjkifQ.f11q7mTu1uScsGvj4-KgVHHEhfAqk53JbAIC0PT8-CU40D4fSWbBoyXrUUQw6zly4KsyqazAFJ_1JqjiFvYFOhCAsoGWpgiA-hnL4QK-uxqUV4ule7Wt9xs8QVPivYxTrK2jmDgPGosvTUmlrGeyZk2XwilO3mbTe5wN-zMkUF0zUTdlIBTPrKbXMS1PklWTjUgDa1bXb-hOaFILkfZ4UgQI3PYHjZul3Rm_UUHHHVRkLgt0M449CGjuKSsIFvVkslfL319_71DLo7W0sYkJkWGOa482vTvyHgR9SjalUPV4TzPhpe_6DZZlKna7MXgq4FWOS9710PC6_HAXF2n-ag\",\"user_pass_to_int_format\":\"11898100104102106115\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":146,\"1\":239,\"2\":26,\"3\":188,\"4\":228,\"5\":23,\"6\":17,\"7\":118,\"8\":183,\"9\":248,\"10\":93,\"11\":219,\"12\":0,\"13\":213,\"14\":164,\"15\":161,\"16\":140,\"17\":200,\"18\":97,\"19\":183,\"20\":135,\"21\":18,\"22\":103,\"23\":137,\"24\":234,\"25\":122,\"26\":246,\"27\":20,\"28\":155,\"29\":72,\"30\":212,\"31\":15},\"secret_key\":{\"0\":107,\"1\":202,\"2\":67,\"3\":226,\"4\":108,\"5\":41,\"6\":149,\"7\":181,\"8\":238,\"9\":3,\"10\":97,\"11\":189,\"12\":216,\"13\":94,\"14\":143,\"15\":210,\"16\":192,\"17\":213,\"18\":224,\"19\":200,\"20\":253,\"21\":67,\"22\":168,\"23\":88,\"24\":140,\"25\":106,\"26\":235,\"27\":247,\"28\":54,\"29\":146,\"30\":251,\"31\":123,\"32\":146,\"33\":239,\"34\":26,\"35\":188,\"36\":228,\"37\":23,\"38\":17,\"39\":118,\"40\":183,\"41\":248,\"42\":93,\"43\":219,\"44\":0,\"45\":213,\"46\":164,\"47\":161,\"48\":140,\"49\":200,\"50\":97,\"51\":183,\"52\":135,\"53\":18,\"54\":103,\"55\":137,\"56\":234,\"57\":122,\"58\":246,\"59\":20,\"60\":155,\"61\":72,\"62\":212,\"63\":15}}},\"zk_addr\":\"0xb86a18deea59af2850ab3800e2d46f63cfbea3bae309359089945d55949aef84\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"2575938484642353074459611431508941853614856803645537593538048270397701877180\",\"18525747234426619072147704335372433454079655655225636793928970068265541595508\",\"1\"],\"b\":[[\"5146896444986257903458872614168031344366471557324420746422302593221564486610\",\"19134791144810013840937258347062701987554745426617919650818846823708095832550\"],[\"3133101512761334334340993079649721452024653991833325456466256722050883608250\",\"21877263483512108853787895465249721341909931993800128255134630466114688578666\"],[\"1\",\"0\"]],\"c\":[\"3069457366306376197755607218741517434199413283376424243014529567457206056402\",\"4929625283757609606431630951067242799347282963225969540629139985267066740824\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AJLvGrzkFxF2t/hd2wDVpKGMyGG3hxJniep69hSbSNQP\"}"; + pub const SUI_DATA_FROM_REACT_11: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkJ4RzlwNFhoV1B4WEt3NVRRdG9FbDljZzI5NCIsIm5iZiI6MTcxNTY4Njk0MSwiaWF0IjoxNzE1Njg3MjQxLCJleHAiOjE3MTU2OTA4NDEsImp0aSI6IjMyYmMxN2VjNWY3ZTQ5ZWRkOTM2MzVkZjE5MDk2N2E3NTg5Y2ZmNTgifQ.w3cT9MVhKTvnmAlmKClFFG6hjB2zrwHonYuN6l5S2unwyR6P_tGE42KhaFSNCY-imysy8k42awfmAafXwftKClLvqzk1T6bi5Li6caVd6-la8wj_FxNWkE5Cy-N4grOiEYJtV5SZezFzifmL6LOstv-Nc4X2b9Z6utuGOWYq3W9LNPveD0v5GnBCR6JRtHJkI6e5yZnMwDDE5o1P-LZbGuFXP75P6jseGem956the_WbrwIsnnTdFgjgjbXn_1gkh4SYGQ1ig0NVKcs75hUhKuQi7V6VqycuyXTgACOCsIfh2guoKha-APZUeul3z33zNbsqUcgkWwl6CkvDSdGWiQ\",\"user_pass_to_int_format\":\"1145652515748\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":153,\"1\":152,\"2\":146,\"3\":133,\"4\":135,\"5\":137,\"6\":8,\"7\":27,\"8\":197,\"9\":109,\"10\":12,\"11\":221,\"12\":49,\"13\":15,\"14\":10,\"15\":1,\"16\":64,\"17\":236,\"18\":222,\"19\":97,\"20\":181,\"21\":214,\"22\":200,\"23\":214,\"24\":130,\"25\":247,\"26\":204,\"27\":212,\"28\":49,\"29\":33,\"30\":169,\"31\":172},\"secret_key\":{\"0\":159,\"1\":96,\"2\":35,\"3\":206,\"4\":32,\"5\":121,\"6\":5,\"7\":32,\"8\":37,\"9\":203,\"10\":15,\"11\":252,\"12\":99,\"13\":107,\"14\":57,\"15\":211,\"16\":139,\"17\":123,\"18\":6,\"19\":233,\"20\":56,\"21\":15,\"22\":35,\"23\":224,\"24\":243,\"25\":148,\"26\":44,\"27\":114,\"28\":112,\"29\":161,\"30\":226,\"31\":255,\"32\":153,\"33\":152,\"34\":146,\"35\":133,\"36\":135,\"37\":137,\"38\":8,\"39\":27,\"40\":197,\"41\":109,\"42\":12,\"43\":221,\"44\":49,\"45\":15,\"46\":10,\"47\":1,\"48\":64,\"49\":236,\"50\":222,\"51\":97,\"52\":181,\"53\":214,\"54\":200,\"55\":214,\"56\":130,\"57\":247,\"58\":204,\"59\":212,\"60\":49,\"61\":33,\"62\":169,\"63\":172}}},\"zk_addr\":\"0x41c25944949f0e3bf80fea41d9ab27acfa26e0b25ecd7e468235b2284e5b0c09\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"10607121052143170357142710430122120898934487918266599021712929788471219763472\",\"13359690919698524885136984693561112109891470903700041135375248695741012306373\",\"1\"],\"b\":[[\"3247989990207989646120856507929936403874972366284220250880918537588838028173\",\"20347831818628957019286012207626379731554938194907710010892594024137236752987\"],[\"18217798786390957788883983024823206348636485136705276787854998111125834676541\",\"11824109578691812603938426242725149605448845948255194504928078330266973720614\"],[\"1\",\"0\"]],\"c\":[\"16499583001208064509247079494271177710897656329498349773613236383353749984739\",\"1944718879141050229961827816471755841829876012643055740792265283564642185697\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AJmYkoWHiQgbxW0M3TEPCgFA7N5htdbI1oL3zNQxIams\"}"; + pub const SUI_DATA_FROM_REACT_12: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IndNcWhEa3BxQllkSlowQVBwXzUtbVZDLUU2OCIsIm5iZiI6MTcxNTY4NjkzMywiaWF0IjoxNzE1Njg3MjMzLCJleHAiOjE3MTU2OTA4MzMsImp0aSI6IjEwNGRhZTE1ZWMwODRjODU3MzBjYTRiZGI1MThiZTkwZDdkMTQ3NmEifQ.KBzhI2UOTstRFpgkZiFFlCmhy-E0PwoWdfWhXem6Kr0HjOgCfr-a5TGVRyMf0b7-Tnf712tMPf4N7-uPSoyaBsmtiYmAudj8whha2obUVhzWjghiURrbYkiCBWys5Z4v3SnVKDqXPsUFmNucBSA3l6DIWbhLT4WqTszGY-Qc_cKhR-7y5i3t90lhGNmwrvCR72jAXaF-xbBvsaiMXxhfCS5fnMFNRibIE3tRx1r3mkx59etA8E3xQAu8LPzFyC0ecEKL0K6a5ZWNWBFPbGSzAhSK9D3ak1gzON6rhccCPpLRErk2MIhUQq4HBnOywg5Lf1w0onxhkJtU6docO2VVAA\",\"user_pass_to_int_format\":\"11099104102117\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":173,\"1\":37,\"2\":48,\"3\":14,\"4\":54,\"5\":38,\"6\":225,\"7\":52,\"8\":254,\"9\":178,\"10\":32,\"11\":56,\"12\":162,\"13\":128,\"14\":135,\"15\":55,\"16\":10,\"17\":222,\"18\":131,\"19\":175,\"20\":166,\"21\":161,\"22\":145,\"23\":219,\"24\":44,\"25\":231,\"26\":183,\"27\":245,\"28\":141,\"29\":178,\"30\":237,\"31\":92},\"secret_key\":{\"0\":108,\"1\":38,\"2\":149,\"3\":222,\"4\":132,\"5\":184,\"6\":128,\"7\":164,\"8\":27,\"9\":101,\"10\":217,\"11\":92,\"12\":24,\"13\":245,\"14\":209,\"15\":31,\"16\":88,\"17\":174,\"18\":237,\"19\":144,\"20\":78,\"21\":127,\"22\":73,\"23\":195,\"24\":194,\"25\":229,\"26\":208,\"27\":176,\"28\":220,\"29\":60,\"30\":229,\"31\":253,\"32\":173,\"33\":37,\"34\":48,\"35\":14,\"36\":54,\"37\":38,\"38\":225,\"39\":52,\"40\":254,\"41\":178,\"42\":32,\"43\":56,\"44\":162,\"45\":128,\"46\":135,\"47\":55,\"48\":10,\"49\":222,\"50\":131,\"51\":175,\"52\":166,\"53\":161,\"54\":145,\"55\":219,\"56\":44,\"57\":231,\"58\":183,\"59\":245,\"60\":141,\"61\":178,\"62\":237,\"63\":92}}},\"zk_addr\":\"0xe5433ade6e56883e0cc13044783fc6e0d835db866e8ef69d305622f4dbfd7730\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"20315021530892971959830664693110327999639349964485536174303351139810441711270\",\"9363226245552972448215999928614529638129956136095863617353608229521342156596\",\"1\"],\"b\":[[\"13215029653817105228530429395766730210769586389024965762310641194113200165202\",\"7799676398333409903573594921069872917500921399080042730183754684502821618481\"],[\"13048821293399627652827197503115267831066766008561767009809325017447715880491\",\"331361016081752781071859245948286166830568341165278760117629920699739892753\"],[\"1\",\"0\"]],\"c\":[\"7347702391542317289078324477957712035210582056186479239076715504548941012834\",\"795883936884678581860170407596096541519605830081875833581950897247827301651\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AK0lMA42JuE0/rIgOKKAhzcK3oOvpqGR2yznt/WNsu1c\"}"; + pub const SUI_DATA_FROM_REACT_13: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjVqNVBySXFpYW9xaUNFWkR0eklNazY2MUotRSIsIm5iZiI6MTcxNTY4NjkyNCwiaWF0IjoxNzE1Njg3MjI0LCJleHAiOjE3MTU2OTA4MjQsImp0aSI6IjJmYzk0MmM1MDBiMmJmNGE5YzZiZjUwN2Y0MjU4NTg3MGM4YmQ5N2QifQ.GU70HImKkqZyGmWAC_onzc-ccUhALeT7ebQ0LrE0QGqjCZyCnonjOeDhatB4Q1GQCVQ-KPWKCdg4NNPCPvKwLYAjwNF0sorwS5h6jKKVvRgT_t12dbDzrPKJE7xW0_0kfmfj7lKGZp_W4HNVxd_hlPiwJb56X0ZVkt3pwpkwBe8MU-Nzb3QyrJtDRJDDb4v_bVdOJSyUNEtssFvAgFB4diGI_GFQzZpbQnBeciST-lS7rGHpItnlwe0mRNf3e34S7A7wUOo_YTvy-TKTViSekMdkMKt9hgGkti9c4dYwI8NMExe4wtnLFVOh6XZ0FtrdnVGrYZFMWTJjNGizUmFMZQ\",\"user_pass_to_int_format\":\"525451555057114102\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":221,\"1\":11,\"2\":223,\"3\":171,\"4\":2,\"5\":140,\"6\":112,\"7\":100,\"8\":233,\"9\":182,\"10\":68,\"11\":219,\"12\":126,\"13\":215,\"14\":96,\"15\":164,\"16\":201,\"17\":227,\"18\":132,\"19\":169,\"20\":157,\"21\":120,\"22\":187,\"23\":16,\"24\":40,\"25\":208,\"26\":174,\"27\":209,\"28\":89,\"29\":163,\"30\":255,\"31\":62},\"secret_key\":{\"0\":5,\"1\":6,\"2\":91,\"3\":164,\"4\":51,\"5\":203,\"6\":161,\"7\":246,\"8\":61,\"9\":156,\"10\":92,\"11\":96,\"12\":69,\"13\":141,\"14\":93,\"15\":73,\"16\":208,\"17\":85,\"18\":37,\"19\":52,\"20\":167,\"21\":121,\"22\":63,\"23\":221,\"24\":215,\"25\":165,\"26\":48,\"27\":232,\"28\":136,\"29\":10,\"30\":71,\"31\":92,\"32\":221,\"33\":11,\"34\":223,\"35\":171,\"36\":2,\"37\":140,\"38\":112,\"39\":100,\"40\":233,\"41\":182,\"42\":68,\"43\":219,\"44\":126,\"45\":215,\"46\":96,\"47\":164,\"48\":201,\"49\":227,\"50\":132,\"51\":169,\"52\":157,\"53\":120,\"54\":187,\"55\":16,\"56\":40,\"57\":208,\"58\":174,\"59\":209,\"60\":89,\"61\":163,\"62\":255,\"63\":62}}},\"zk_addr\":\"0x0934ba96e39b32a66b83afdd089d9534b91336d0c72324acb72b718e2d8adcd8\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"3292113297742390468701372446942400025026948502434627571571387058022780524172\",\"4608365882159831859997420943605862565647863626478617897572911626264555729258\",\"1\"],\"b\":[[\"5662407938030293510048180382159430467791189346676904212329490391470516566946\",\"14655907382794614210872210515582570998106075620115645016125280695488094003217\"],[\"3337061425406207163991320131711738442766654603337106758166291266688030689117\",\"4469383376673348053098454774700074508703514397281065469277327859575940584146\"],[\"1\",\"0\"]],\"c\":[\"6592007510647447256322156763481821378802835999285873915184749854236303252416\",\"16208563039085392733361585085996378606127672981771155339865393880548209917912\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AN0L36sCjHBk6bZE237XYKTJ44SpnXi7ECjQrtFZo/8+\"}"; + pub const SUI_DATA_FROM_REACT_14: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjN6eHc2SUFERzVXcjJDR244SGczS1Q3Nm1qOCIsIm5iZiI6MTcxNTY4NjkwNSwiaWF0IjoxNzE1Njg3MjA1LCJleHAiOjE3MTU2OTA4MDUsImp0aSI6IjNkOTM4NmFlODMxZDVhYjdiZTI1NjcxMDhmZjhkMTM1N2YzNDZjOTUifQ.R3s_OfTiDlMMSFsEfp4xM6rLoJ99GALalEE1TVG8aneruEWuI1qxz241YmX9r9-49t1ja5BfO0eh3Fu_p6lg1O32sNSLR626Mvrv1Ph60syPQN01Tam4RCV_YBK3b2Pj-rWeJq3WSCGQg2rab2QyHy3Al9VPdXlkbaaH69QzRSXFyNojixgo92cPhABxbAxI1a5pYmzwwfkDDO0FY5uRUt3w4wuBhx9gQ6g_kboF03pIzQ5kvGUYBPGax66faTzulAGdTADmU9xgG6denQoZWn3Lh6dfdQX8KXkn9jVY8gMIY_rbobc8nkIMmslsjjio7BXb90-YD_WJT5so5Cre3A\",\"user_pass_to_int_format\":\"1031021041155552\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":97,\"1\":100,\"2\":35,\"3\":169,\"4\":212,\"5\":9,\"6\":238,\"7\":108,\"8\":186,\"9\":80,\"10\":106,\"11\":26,\"12\":209,\"13\":87,\"14\":84,\"15\":117,\"16\":235,\"17\":25,\"18\":81,\"19\":248,\"20\":137,\"21\":197,\"22\":146,\"23\":139,\"24\":214,\"25\":127,\"26\":143,\"27\":179,\"28\":137,\"29\":79,\"30\":181,\"31\":216},\"secret_key\":{\"0\":70,\"1\":76,\"2\":130,\"3\":97,\"4\":75,\"5\":0,\"6\":7,\"7\":122,\"8\":166,\"9\":56,\"10\":85,\"11\":179,\"12\":143,\"13\":55,\"14\":136,\"15\":47,\"16\":75,\"17\":211,\"18\":125,\"19\":145,\"20\":130,\"21\":206,\"22\":118,\"23\":212,\"24\":87,\"25\":200,\"26\":130,\"27\":38,\"28\":65,\"29\":93,\"30\":37,\"31\":44,\"32\":97,\"33\":100,\"34\":35,\"35\":169,\"36\":212,\"37\":9,\"38\":238,\"39\":108,\"40\":186,\"41\":80,\"42\":106,\"43\":26,\"44\":209,\"45\":87,\"46\":84,\"47\":117,\"48\":235,\"49\":25,\"50\":81,\"51\":248,\"52\":137,\"53\":197,\"54\":146,\"55\":139,\"56\":214,\"57\":127,\"58\":143,\"59\":179,\"60\":137,\"61\":79,\"62\":181,\"63\":216}}},\"zk_addr\":\"0x87b9236aadcbc8de1a2bce17bb104cbae2f8c955f89808ee2d258cf2bc1cce1f\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"18415333747085688267133796133445868671450647215619171648016630248725573444572\",\"13021999644739913954648136527237689315935942107782566659768353668730521796833\",\"1\"],\"b\":[[\"10379715945772584677584721710592153467187645980157575584584703890180885281296\",\"21114541349211062821701871386552875726196087055162878583823021987759476907947\"],[\"21741245524391086016724288544952241247835975701957615054057894483829435111137\",\"19675246006347690391662817422022652459552259504790883596539945355325572896761\"],[\"1\",\"0\"]],\"c\":[\"6388980351498388564470364481867721519510272532387680761911853865824806443040\",\"2927953057998420964296253396822428516251336255094433794401337892358172944522\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AGFkI6nUCe5sulBqGtFXVHXrGVH4icWSi9Z/j7OJT7XY\"}"; + pub const SUI_DATA_FROM_REACT_15: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjRtbk1TajFjTmdlSUU4Unk3Z2dBOWNRVWRLSSIsIm5iZiI6MTcxNTY4Njg3MywiaWF0IjoxNzE1Njg3MTczLCJleHAiOjE3MTU2OTA3NzMsImp0aSI6ImVmYzU3YjVmMGEzZmEwZGI2ZTQzNWFhZjI4OTEwNjY2YjM0NWViNmEifQ.YRFPl_szPP8iBid__ACAj4Etr4YDZEmeawFTas_MFw7rR_sD_tQ268F2g9O4VOU3VWSWT-LCG1gp_NdRVvb5SFBzuMIYp4YrUEvzJdaO_ab1a2Xp_EVVEmjMwNHVpnFZjS9El0e0oOmaw_PQgC2soauJkfLvRhayx-_Vps7htHm94PW1aHBOxwr2HpR58mjzT4JyutyiioCLgLqhnvGW4N6CBlx6iLNfITk0wwsAOHRcdjW_hk0hHarjMy3U2VdbcPkmq1OIg8ZDQo2jbUGEWevUC6zrGeNWYjp38f3Wo1NUqf7_ne0YeJEBtyK5r9BuDxdr6YRyUXKnpxJpr9cZ-Q\",\"user_pass_to_int_format\":\"5256515057\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":226,\"1\":91,\"2\":63,\"3\":50,\"4\":152,\"5\":120,\"6\":233,\"7\":249,\"8\":177,\"9\":205,\"10\":1,\"11\":233,\"12\":153,\"13\":199,\"14\":101,\"15\":124,\"16\":112,\"17\":15,\"18\":160,\"19\":228,\"20\":124,\"21\":169,\"22\":57,\"23\":196,\"24\":118,\"25\":117,\"26\":94,\"27\":132,\"28\":228,\"29\":108,\"30\":145,\"31\":117},\"secret_key\":{\"0\":168,\"1\":100,\"2\":5,\"3\":144,\"4\":15,\"5\":220,\"6\":219,\"7\":42,\"8\":52,\"9\":1,\"10\":7,\"11\":203,\"12\":43,\"13\":71,\"14\":99,\"15\":90,\"16\":8,\"17\":66,\"18\":137,\"19\":155,\"20\":200,\"21\":27,\"22\":69,\"23\":112,\"24\":209,\"25\":173,\"26\":109,\"27\":93,\"28\":152,\"29\":210,\"30\":96,\"31\":194,\"32\":226,\"33\":91,\"34\":63,\"35\":50,\"36\":152,\"37\":120,\"38\":233,\"39\":249,\"40\":177,\"41\":205,\"42\":1,\"43\":233,\"44\":153,\"45\":199,\"46\":101,\"47\":124,\"48\":112,\"49\":15,\"50\":160,\"51\":228,\"52\":124,\"53\":169,\"54\":57,\"55\":196,\"56\":118,\"57\":117,\"58\":94,\"59\":132,\"60\":228,\"61\":108,\"62\":145,\"63\":117}}},\"zk_addr\":\"0xc2e01f23756fd4fc3e8ee98f96751729c911acc1b8abc4e5d8f732a0b6a69602\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"6734924940747627006546678824977458478287976951246203795880487352562116664933\",\"14763323532227801517600705873776227782564830701170466315373208681644431001874\",\"1\"],\"b\":[[\"19846719805329609703868726781640931109590522837532762309497922458996335263239\",\"15420764526732603133646176483042915906318651960194518136943858294265541434918\"],[\"3657954841783806502381750774780312041530173171470043250309926815017975476219\",\"3502207265482905042029962996793932548717468210237619905023157797841132512624\"],[\"1\",\"0\"]],\"c\":[\"1288521393482492105362792882426011805774869298603270001189992299082351112997\",\"3336108234609612516660580995781529303851605528785003185796473743343393403477\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AOJbPzKYeOn5sc0B6ZnHZXxwD6DkfKk5xHZ1XoTkbJF1\"}"; + pub const SUI_DATA_FROM_REACT_16: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImpKS0poeXJtbHE3T1UxU0NwZnlfX2F3MEZxVSIsIm5iZiI6MTcxNTY4Njg2NSwiaWF0IjoxNzE1Njg3MTY1LCJleHAiOjE3MTU2OTA3NjUsImp0aSI6Ijg4ZDVmNTg1OGMzNDIwMmY1OTAyOWE5ODM4YzhhOWMzYWVlMDZjNDMifQ.cjuamUo90ycOmkGffs4qe6Ozb0q-UhG6oG4pLf3a5zMgRUXr_PcKNj9GcHujqYzWFbVsiuYdoVwMmPsHeKmLnkuIDS4mwT0z-LhWvYrXdx2FksXyv0ECIBJNGHWNtf6JyhA_3XGYSqzn4sQncKxHK82aFAJZYaPfXCgKJJK0c9PFjONxY2nQoDV-IM89vm6x9vpNPjYxMxxE60p_5qceLLU9pgy4jgP2Eyco0sGfCFTry7zVqgYsMSinh_UIWk4naihDtgrZxAdNkoAA-4PQkWxrlTO8b68YQp8K4ncerUwmOJDs-0NUxDm8mTjwq47Qgf_UAcTxVN9_YpIqEoxdwQ\",\"user_pass_to_int_format\":\"100102104119101105101121102\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":109,\"1\":20,\"2\":190,\"3\":101,\"4\":236,\"5\":16,\"6\":171,\"7\":49,\"8\":222,\"9\":170,\"10\":22,\"11\":241,\"12\":224,\"13\":116,\"14\":18,\"15\":124,\"16\":48,\"17\":1,\"18\":20,\"19\":126,\"20\":94,\"21\":16,\"22\":164,\"23\":173,\"24\":180,\"25\":226,\"26\":71,\"27\":184,\"28\":218,\"29\":162,\"30\":145,\"31\":87},\"secret_key\":{\"0\":131,\"1\":117,\"2\":15,\"3\":104,\"4\":243,\"5\":100,\"6\":1,\"7\":157,\"8\":31,\"9\":54,\"10\":163,\"11\":215,\"12\":45,\"13\":202,\"14\":70,\"15\":51,\"16\":77,\"17\":200,\"18\":206,\"19\":59,\"20\":210,\"21\":59,\"22\":129,\"23\":250,\"24\":53,\"25\":166,\"26\":201,\"27\":57,\"28\":9,\"29\":13,\"30\":255,\"31\":18,\"32\":109,\"33\":20,\"34\":190,\"35\":101,\"36\":236,\"37\":16,\"38\":171,\"39\":49,\"40\":222,\"41\":170,\"42\":22,\"43\":241,\"44\":224,\"45\":116,\"46\":18,\"47\":124,\"48\":48,\"49\":1,\"50\":20,\"51\":126,\"52\":94,\"53\":16,\"54\":164,\"55\":173,\"56\":180,\"57\":226,\"58\":71,\"59\":184,\"60\":218,\"61\":162,\"62\":145,\"63\":87}}},\"zk_addr\":\"0x3a26feb6fa552d6e2796e37cfcfaa19ff8d09b9b3e30060557f313ec82e7809a\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"17553248964460513660899064860794334313854327380740726458707730696116622715951\",\"19780935404993030841853448182973442738138094386982905919654095638585438825727\",\"1\"],\"b\":[[\"21560192083940754229490187081097411180154947135453319375957763951829010741758\",\"19864576266509862087012277908356289924851686435133221538927641836878678315039\"],[\"5332198541444016097635381835036279771892300735490162251066050727152100828695\",\"4562785582599067136108384927870755899035073041220030123445496806313655366742\"],[\"1\",\"0\"]],\"c\":[\"17180793399699270264610473764500109290307106335241771936808740744446379111802\",\"19531923144281240440166451089649574065952850605237982747209921274042428958350\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AG0UvmXsEKsx3qoW8eB0EnwwARR+XhCkrbTiR7jaopFX\"}"; + pub const SUI_DATA_FROM_REACT_17: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxPYUk4MkJHS1lSWXVETVRMVXU4Z0ktV3ZsayIsIm5iZiI6MTcxNTY4Njg1NywiaWF0IjoxNzE1Njg3MTU3LCJleHAiOjE3MTU2OTA3NTcsImp0aSI6ImMyOGE2MTEwYzMwYmQ0ZDkzMmEwOTNlOWVmZjllNzEyZjUzYWI2MjQifQ.fHYn7sAFbOtPneSX_YBA52ASidwosnl42uWF7RmroUU132sPO3Jmzf7tqZrqQFu04Y1G2LeGvTeHklUowVdWdKQkomV9bCeputcMRkDPD9-5-UJdpDY8eIAzfHzWN9nWyu5St0Iz0S0FIth6cesMmPUkCrq6pCUyHLWgrxUoICuYIbbtEO5ZVnF8lIeMjUTLXT4_9svFBRhugkD0nvHnQnWS8H0ijS53lCs8z7xVy0cm_MawsCMpApMQvWm-4CeIq69p3m2HXclXNmwSxg7oeGDKn-yqhPaXX3Pn4PfHKPj-XHXOR2rr9uG2lYi73yOyDve84wCXzV9kmiUnc0YGUQ\",\"user_pass_to_int_format\":\"515253575654\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":100,\"1\":216,\"2\":222,\"3\":171,\"4\":27,\"5\":27,\"6\":171,\"7\":132,\"8\":172,\"9\":13,\"10\":174,\"11\":188,\"12\":196,\"13\":208,\"14\":35,\"15\":125,\"16\":10,\"17\":214,\"18\":5,\"19\":29,\"20\":118,\"21\":41,\"22\":114,\"23\":70,\"24\":166,\"25\":37,\"26\":189,\"27\":136,\"28\":37,\"29\":106,\"30\":245,\"31\":15},\"secret_key\":{\"0\":75,\"1\":60,\"2\":159,\"3\":196,\"4\":243,\"5\":180,\"6\":224,\"7\":198,\"8\":228,\"9\":147,\"10\":22,\"11\":104,\"12\":69,\"13\":182,\"14\":80,\"15\":232,\"16\":127,\"17\":195,\"18\":43,\"19\":2,\"20\":99,\"21\":206,\"22\":161,\"23\":47,\"24\":106,\"25\":44,\"26\":131,\"27\":5,\"28\":133,\"29\":110,\"30\":82,\"31\":140,\"32\":100,\"33\":216,\"34\":222,\"35\":171,\"36\":27,\"37\":27,\"38\":171,\"39\":132,\"40\":172,\"41\":13,\"42\":174,\"43\":188,\"44\":196,\"45\":208,\"46\":35,\"47\":125,\"48\":10,\"49\":214,\"50\":5,\"51\":29,\"52\":118,\"53\":41,\"54\":114,\"55\":70,\"56\":166,\"57\":37,\"58\":189,\"59\":136,\"60\":37,\"61\":106,\"62\":245,\"63\":15}}},\"zk_addr\":\"0x89045412e3f5c808e7bf0ea6d47008a6c75f14b48a7fea54f420b03d3298ef4e\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"257137064185145448465242836924275827726618300508610920187643303682623341809\",\"13136104385342155450873138185971548464179081219858145555616259274682267182602\",\"1\"],\"b\":[[\"9623367967771069752036280248035047299371597257306258748768218269896381701321\",\"12210765432002064938981141260402135327544184192147240766501813387730760651726\"],[\"15251118264052002493837427778759923199895437430037469672801786148252966111936\",\"12243121821747384937988506024826071890328897029202152518609157933400978560340\"],[\"1\",\"0\"]],\"c\":[\"4201350126073080124441494110984461007902792066210632786985402248838880518314\",\"10425614983366289743736253875955608779721351186796918402238008669517994775682\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AGTY3qsbG6uErA2uvMTQI30K1gUddilyRqYlvYglavUP\"}"; + pub const SUI_DATA_FROM_REACT_18: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IlhhakktZ0NqbFVVY3ZBTFdmcDlyTURCelBzVSIsIm5iZiI6MTcxNTY4Njg0OSwiaWF0IjoxNzE1Njg3MTQ5LCJleHAiOjE3MTU2OTA3NDksImp0aSI6IjZmYmI3NmEzN2NjOTAwYTQ5NThlYmNlZmNmYmVhNjMzMzkyMzM2OTUifQ.RqLBHMZMuXbsZGW5YGDNbfTSGG5Ezv_XtJRvMbBIXytAqGoT70RrfZSwU3e8yXaq-o4RBoeypQIygj_Sjxq0JJXVRuypVqkbismASkWKWH77avFgRUe0Etvc8EFXupmwj1biRpURUukroVUyjktOI17m3DvFIIan7_rq3SQBNxLyjFZav517zaJaUVXdYMDAYIEVs1Es04G2kWTxBYQ6iu0jyHtuNcg9_kosGQEZjnp2HsnvegrRwloyjuFByMRv90bRuV6cc3f-3GPO23tcrhFzeoOQXUfcSdlqE3C92gb6E_3uBld414mNj2LelnagKtpvPjTCgX3tic2c7fB_CQ\",\"user_pass_to_int_format\":\"989911510011710554\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":81,\"1\":243,\"2\":172,\"3\":238,\"4\":183,\"5\":132,\"6\":17,\"7\":7,\"8\":200,\"9\":125,\"10\":73,\"11\":248,\"12\":71,\"13\":220,\"14\":159,\"15\":138,\"16\":16,\"17\":207,\"18\":25,\"19\":103,\"20\":70,\"21\":23,\"22\":193,\"23\":72,\"24\":27,\"25\":94,\"26\":241,\"27\":155,\"28\":98,\"29\":155,\"30\":212,\"31\":118},\"secret_key\":{\"0\":89,\"1\":13,\"2\":132,\"3\":115,\"4\":95,\"5\":59,\"6\":196,\"7\":68,\"8\":136,\"9\":46,\"10\":22,\"11\":70,\"12\":5,\"13\":188,\"14\":76,\"15\":116,\"16\":156,\"17\":15,\"18\":226,\"19\":232,\"20\":167,\"21\":204,\"22\":143,\"23\":148,\"24\":230,\"25\":69,\"26\":18,\"27\":166,\"28\":234,\"29\":47,\"30\":178,\"31\":31,\"32\":81,\"33\":243,\"34\":172,\"35\":238,\"36\":183,\"37\":132,\"38\":17,\"39\":7,\"40\":200,\"41\":125,\"42\":73,\"43\":248,\"44\":71,\"45\":220,\"46\":159,\"47\":138,\"48\":16,\"49\":207,\"50\":25,\"51\":103,\"52\":70,\"53\":23,\"54\":193,\"55\":72,\"56\":27,\"57\":94,\"58\":241,\"59\":155,\"60\":98,\"61\":155,\"62\":212,\"63\":118}}},\"zk_addr\":\"0xa41d812b2137a9e701512dd1e77643b94c3eff566c5be50365d174d1db60a415\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"17614076016833085587577424708926810169376585820815427961767207039192652769013\",\"14135032500684844024372302628625185135058981148802759791768119531914068811069\",\"1\"],\"b\":[[\"12223738407851653989769057205672802523120105196291312843502064346721414495287\",\"633499823246797838323329834422571844397737716575556571535890211670105511423\"],[\"6003190178099558462113377195569012506764289704920013648574803015959961275195\",\"2773541228770509456407096233964565540804779880988894871588471857181885931620\"],[\"1\",\"0\"]],\"c\":[\"1069242590881057236271046634996302431045048055413724998035360474439616694142\",\"4170832142623397447640837445675045579300900045561776497865454715900704844006\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AFHzrO63hBEHyH1J+Efcn4oQzxlnRhfBSBte8Ztim9R2\"}"; + pub const SUI_DATA_FROM_REACT_19: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IkxyN2JvekNHNUw4UHlLVVNPRzNwMDZYYVM1USIsIm5iZiI6MTcxNTY4Njg0MSwiaWF0IjoxNzE1Njg3MTQxLCJleHAiOjE3MTU2OTA3NDEsImp0aSI6Ijc2MzdiMGMyM2ZiMWIwZTFjMGEyYWE3NWVkOGMxNjA1YzE1YWFiZjAifQ.uNMFOgl9xdG5wljwZrIDzWm3SS_F9OLhR9avDGRhHSxYNSzexcOHtGT7HY9zsWloN9LWFZxu2t3yG-jWduo5qYgyM-OXpdAXLzfXZwQSNxgtXl2yisxeBU18_7lPpmjMzTMUPCXtJxrB75VYoZAybkyGnFmC_tPD13MIShT04iUGkNLFPpaof4BGxnmCE4hNob-tVijFTH_EIdNXg0fr-rQ-qxd3vw7NVDIF0yDNxCeSYMz0GKuGPlvXk3SPtUzfUfZaJFau3QpfcrXhkNrUS0fW3HcXRLMhiVqNIJ5Y5wYJdq5IvEe_lElrv4NS4apswDNVI1s7B_iMDvcjFASD9Q\",\"user_pass_to_int_format\":\"5255515057565453\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":223,\"1\":83,\"2\":48,\"3\":161,\"4\":204,\"5\":195,\"6\":149,\"7\":141,\"8\":132,\"9\":65,\"10\":55,\"11\":201,\"12\":245,\"13\":60,\"14\":139,\"15\":236,\"16\":39,\"17\":130,\"18\":130,\"19\":162,\"20\":215,\"21\":104,\"22\":235,\"23\":117,\"24\":152,\"25\":71,\"26\":252,\"27\":46,\"28\":73,\"29\":54,\"30\":170,\"31\":251},\"secret_key\":{\"0\":90,\"1\":130,\"2\":14,\"3\":79,\"4\":237,\"5\":213,\"6\":128,\"7\":240,\"8\":11,\"9\":61,\"10\":50,\"11\":225,\"12\":67,\"13\":212,\"14\":26,\"15\":215,\"16\":84,\"17\":207,\"18\":4,\"19\":3,\"20\":95,\"21\":124,\"22\":35,\"23\":123,\"24\":72,\"25\":189,\"26\":115,\"27\":153,\"28\":16,\"29\":105,\"30\":73,\"31\":216,\"32\":223,\"33\":83,\"34\":48,\"35\":161,\"36\":204,\"37\":195,\"38\":149,\"39\":141,\"40\":132,\"41\":65,\"42\":55,\"43\":201,\"44\":245,\"45\":60,\"46\":139,\"47\":236,\"48\":39,\"49\":130,\"50\":130,\"51\":162,\"52\":215,\"53\":104,\"54\":235,\"55\":117,\"56\":152,\"57\":71,\"58\":252,\"59\":46,\"60\":73,\"61\":54,\"62\":170,\"63\":251}}},\"zk_addr\":\"0x37c4424a1b9970b94dd7276aecae5b9d1c035c7e3c88f4f1155aa0e5127ef6e4\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"7945493796354284921600453177054285773255312631482061079984629835363646515586\",\"2166517138136751277833084326208436279446476764263036612847849710284540628729\",\"1\"],\"b\":[[\"14768147580014515274920059533450969526917243519129235569375547705391356814034\",\"10926704359346438742364088104571886636979515204481541507299552373423645137538\"],[\"18345707220306299341155061798987886250677895640406984732019863169577306401665\",\"13781450607771983148196301814354815025344242496715512941320154501577226245887\"],[\"1\",\"0\"]],\"c\":[\"16100487697721354409255314346417284275475569122937970611421991273969908317416\",\"20037727069966515075925458192010761910249599063237527691300280470015098486501\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AN9TMKHMw5WNhEE3yfU8i+wngoKi12jrdZhH/C5JNqr7\"}"; + pub const SUI_DATA_FROM_REACT_20: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJlMTgtZlBDdV9ZRndybE43TDhKV1BHX3hFbyIsIm5iZiI6MTcxNTY4NjgzMSwiaWF0IjoxNzE1Njg3MTMxLCJleHAiOjE3MTU2OTA3MzEsImp0aSI6IjdmZTFkZTM5NDVkMjliYTBhOWQ4MGFlODZiZGRmNjkyMDE1N2RlMDcifQ.RMM8wIiEzZ97DVdngkDhKapTMZq-R7woI2yjclLqTgnYZKTZ5N9y67zFJLDfcg017VyyRK18OS1OLsnUgnphi3ULotImnJ2292VDBd7kxhyq9QAqfHVDK2-MYNlJXy53UIr2xS9td1aoHUDZkvBy690IhV4nPrxLOUhI8c4gAvpkfHFmAvxYuQoUu69c_hSzREhrVOa979t5nZuJjNWwUcwgD40To1DM6Dxwy186basvY4AyWPHcI4ARFoyPEMRFUOtO05fUrwUH8O63Ay6K1DwxaLXDzx4T7O9X9nlrCj2uROdahsv-Dj24hruudSYxi4GH2uO6u0a1RlTIvWJ-1A\",\"user_pass_to_int_format\":\"525451525655\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":66,\"1\":155,\"2\":237,\"3\":117,\"4\":45,\"5\":166,\"6\":245,\"7\":92,\"8\":78,\"9\":225,\"10\":218,\"11\":156,\"12\":7,\"13\":132,\"14\":164,\"15\":47,\"16\":114,\"17\":174,\"18\":4,\"19\":86,\"20\":18,\"21\":212,\"22\":182,\"23\":62,\"24\":50,\"25\":219,\"26\":104,\"27\":185,\"28\":183,\"29\":108,\"30\":38,\"31\":252},\"secret_key\":{\"0\":13,\"1\":127,\"2\":13,\"3\":29,\"4\":128,\"5\":121,\"6\":142,\"7\":51,\"8\":210,\"9\":28,\"10\":131,\"11\":160,\"12\":209,\"13\":42,\"14\":214,\"15\":198,\"16\":137,\"17\":147,\"18\":155,\"19\":40,\"20\":86,\"21\":167,\"22\":168,\"23\":10,\"24\":249,\"25\":180,\"26\":188,\"27\":132,\"28\":41,\"29\":146,\"30\":192,\"31\":28,\"32\":66,\"33\":155,\"34\":237,\"35\":117,\"36\":45,\"37\":166,\"38\":245,\"39\":92,\"40\":78,\"41\":225,\"42\":218,\"43\":156,\"44\":7,\"45\":132,\"46\":164,\"47\":47,\"48\":114,\"49\":174,\"50\":4,\"51\":86,\"52\":18,\"53\":212,\"54\":182,\"55\":62,\"56\":50,\"57\":219,\"58\":104,\"59\":185,\"60\":183,\"61\":108,\"62\":38,\"63\":252}}},\"zk_addr\":\"0x86ab13e3c90b7f5b52a0e7d045425f1a5ce4f2938d82fe32013b5c5dffc8aa40\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"13280060882937967421268531103181473070897547065707830941266439167277535861998\",\"9934433138500558951890280258062370504217382435917636186873727481367280202864\",\"1\"],\"b\":[[\"3838124130316726849360987686807592227651253623250263168834039482151640975443\",\"10050190797101422174255450354163308725608018844614813729840170282126147936409\"],[\"18360080471111693027482741715722945557865825591442098780536696036281663618095\",\"1378964582828950987975075563637558653759765511530268169302574447782691787466\"],[\"1\",\"0\"]],\"c\":[\"1373142722414479432483215105546507593017308819682036641663292686387425172376\",\"3353210342014729825799146687716012229927760750084040417279416030868174996451\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AEKb7XUtpvVcTuHanAeEpC9yrgRWEtS2PjLbaLm3bCb8\"}"; + pub const SUI_DATA_FROM_REACT_21: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Im12NUNKY1dsMXE1ek03Y0lyR1ZUdHF6SnFTNCIsIm5iZiI6MTcxNTY4NjgxOSwiaWF0IjoxNzE1Njg3MTE5LCJleHAiOjE3MTU2OTA3MTksImp0aSI6IjYxMDM2YmQwZWE3YjI5MDY4MjgwODYxMzMyODZhODZlNmY0ZmMwNGEifQ.VE2a8s2ZuyTVklFwSvh05y_mGrDMJXww-5Pu3-UUIQi3sBQnMzpnvWo3MIb32rXxwU6Obtx9izsR-Csk-U0QH4WuseGHnhHA90lACdeXNXHUWNktsY62_z2lkseTlJQV_ccNVctNgqornxmtV6gRvihLKkYCJt08umhAcRe8-Fh9iNmlCf5sMngaA-k0bvIbdnxkoP0KI9em7sgpTDB0FJFCgVAVYkzQTuJJlfuKjeF0lgpLnkjTOtgMyCpuZrrxf9GH6wY2VSme3Zk6xVJfl5cC6YugQFs-t56CEhPDrm-LIlLTD9JuNAKctlRRaTmkTembZAzweu6Wqh322MDx1g\",\"user_pass_to_int_format\":\"100102100102100115106107\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":227,\"1\":142,\"2\":234,\"3\":83,\"4\":36,\"5\":125,\"6\":219,\"7\":233,\"8\":159,\"9\":30,\"10\":60,\"11\":195,\"12\":110,\"13\":130,\"14\":105,\"15\":107,\"16\":44,\"17\":46,\"18\":151,\"19\":154,\"20\":116,\"21\":131,\"22\":237,\"23\":231,\"24\":159,\"25\":119,\"26\":35,\"27\":130,\"28\":56,\"29\":90,\"30\":121,\"31\":26},\"secret_key\":{\"0\":34,\"1\":107,\"2\":197,\"3\":227,\"4\":209,\"5\":156,\"6\":36,\"7\":233,\"8\":231,\"9\":171,\"10\":100,\"11\":210,\"12\":113,\"13\":247,\"14\":59,\"15\":222,\"16\":214,\"17\":129,\"18\":238,\"19\":254,\"20\":13,\"21\":13,\"22\":3,\"23\":151,\"24\":9,\"25\":173,\"26\":77,\"27\":113,\"28\":126,\"29\":7,\"30\":203,\"31\":52,\"32\":227,\"33\":142,\"34\":234,\"35\":83,\"36\":36,\"37\":125,\"38\":219,\"39\":233,\"40\":159,\"41\":30,\"42\":60,\"43\":195,\"44\":110,\"45\":130,\"46\":105,\"47\":107,\"48\":44,\"49\":46,\"50\":151,\"51\":154,\"52\":116,\"53\":131,\"54\":237,\"55\":231,\"56\":159,\"57\":119,\"58\":35,\"59\":130,\"60\":56,\"61\":90,\"62\":121,\"63\":26}}},\"zk_addr\":\"0xb092062dc38ee15b239fedd8955547cae553068e350add6a186a900308ca1704\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"19083893384522082364200015848081882762611466511855277173108395395690822433582\",\"15765871630522826744343212165387977339454134778029147662517994756792436892191\",\"1\"],\"b\":[[\"3347275249816013439391836622904014049361323482158752310150932588414843416768\",\"9261935324040115069949005166058871304117632278716385673922763868694265924905\"],[\"10774327302040930015542399179222458502634829694095804484749135988841930351850\",\"409015645239595129631982791901837203813000443262394810220799589635024410401\"],[\"1\",\"0\"]],\"c\":[\"805618312212200473153836203801534856685701602304097276485035246177305246575\",\"12984127923817330198936709848850019846193356630613954592225359007088568774616\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AOOO6lMkfdvpnx48w26CaWssLpeadIPt5593I4I4Wnka\"}"; + + //pub const VALUE_PORTION_SIZE: usize = 126; + + pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"user_pass_to_int_format\":\"9910010710611510499100106115107\",\"zk_addr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secret_key\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extended_ephemeral_public_key\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; + + #[derive(Debug, Deserialize)] + pub struct JwtData { + pub jwt: String, + pub user_pass_to_int_format: String, + pub ephemeral_key_pair: EphemeralKeyPair, + pub zk_addr: String, + pub zk_proofs: ZkProofs, + pub extended_ephemeral_public_key: String, + } -#[derive(Debug, Deserialize)] -pub struct Keypair { - publicKey: HashMap, // HashMap, // publicKey: Vec, - secretKey: HashMap, // secretKey: Vec // HashMap, -} + #[derive(Debug, Deserialize)] + pub struct EphemeralKeyPair { + pub keypair: Keypair, + } -#[derive(Debug, Deserialize, Serialize)] -pub struct ZkProofs { - proofPoints: ProofPoints, - iss_base64_details: iss_base64_details, - header_base64: String, -} + #[derive(Debug, Deserialize)] + pub struct Keypair { + pub public_key: HashMap, + pub secret_key: HashMap, + } -#[derive(Debug, Deserialize, Serialize)] -pub struct ProofPoints { - a: Vec, - b: Vec>, - c: Vec, -} + #[derive(Debug, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct ZkProofs { + pub proof_points: ProofPoints, + pub iss_base64_details: IssBase64Details, + pub header_base64: String, + } -#[derive(Debug, Deserialize, Serialize)] -pub struct iss_base64_details { - value: String, - index_mod4: i32, -} + #[derive(Debug, Deserialize, Serialize)] + pub struct ProofPoints { + pub a: Vec, + pub b: Vec>, + pub c: Vec, + } -#[derive(Debug, Deserialize)] -pub struct JwtDataDecodedPart1 { - alg: String, - kid: String, - typ: String, -} + #[derive(Debug, Deserialize, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct IssBase64Details { + pub value: String, + pub index_mod4: i32, + } -#[derive(Debug, Deserialize)] -pub struct JwtDataDecodedPart2 { - iss: String, - azp: String, - aud: String, - sub: String, - nonce: String, - nbf: u32, - iat: u32, - exp: u32, - jti: String, -} + #[derive(Debug, Deserialize)] + pub struct JwtDataDecodedPart1 { + pub alg: String, + pub kid: String, + pub typ: String, + } -fn gen_keypair() -> ed25519_dalek::Keypair { - ed25519_dalek::Keypair::generate(&mut rand::thread_rng()) -} + #[derive(Debug, Deserialize)] + pub struct JwtDataDecodedPart2 { + pub iss: String, + pub azp: String, + pub aud: String, + pub sub: String, + pub nonce: String, + pub nbf: u32, + pub iat: u32, + pub exp: u32, + pub jti: String, + } + + fn gen_keypair() -> ed25519_dalek::Keypair { + ed25519_dalek::Keypair::generate(&mut rand::thread_rng()) + } + + #[test] + fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); -#[test] -fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { - // real data taken from our react app for zklogin tests - // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} - // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. - // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" - // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" - // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 - // in ascii 535455565748 - let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations - - // Generate an ephemeral key pair. - let secret_key = [ - 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, - 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, - ]; - - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); - // replace by Alina's data (ephemeral public key place to byte array ), depends - // on iteration - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - println!("eph_pubkey: {:?}", eph_pubkey); - println!("len eph_pubkey: {:?}", eph_pubkey.len()); - - let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); - println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); - - // Get the zklogin seed. - // This stuff is a kind of bound between smart contract and email (some - // account) It will be stored in smart contract (must be added during - // contract deployment) - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt - "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt - ).unwrap(); - - println!("zk_seed = {:?}", zk_seed); - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -151,408 +180,389 @@ fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ - \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - let len = proof_and_jwt.bytes().len(); - println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - - println!("proof_and_jwt: {}", proof_and_jwt); - - let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - - println!("issAndheader_base64Details: {}", issAndheader_base64Details); - - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid - // in this header is equal to one specified in line 143,... take kid from jwt if - // not equal - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data - alg: "RS256".to_string(), - }; + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + println!("proof_and_jwt: {}", proof_and_jwt); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - let max_epoch = 142; // data from the react test - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("HERE public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("HERE public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - /// calcs poseidon * + let max_epoch = 142; // data from the react test - println!("====== Start Poseidon ========"); + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - let issAndheader_base64Details_cell = - pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("HERE public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("HERE public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - let max_epoch_ = 142; + println!("====== Start Poseidon ========"); - let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); - code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - println!("code : {:?}", code); + let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - test_case_with_refs( - code.as_str(), - vec![modulus_cell.clone(), issAndheader_base64Details_cell, zk_seed_cell], - ) - .expect_stack(Stack::new().push(StackItem::Cell(public_inputs_cell.clone()))); - //.expect_success(); + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); - /// calcs vergrth16 * + let max_epoch_ = 142; - println!("====== Start VERGRTH16 ========"); + let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("code : {:?}", code); - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + test_case_with_refs(code.as_str(), vec![modulus_cell.clone(), iss_and_header_base64details_cell, zk_seed_cell]) + .expect_stack(Stack::new() + .push(StackItem::Cell(public_inputs_cell.clone())) + ); + //.expect_success(); - let verification_key_id: u32 = 0; //valid key id - // let verification_key_id: u32 = 1; //invalid key id + println!("====== Start VERGRTH16 ========"); - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); -} + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); -#[test] -fn test_poseidon_plus_vrgrth16() { - /// Common data generation * - let user_pass_salt = "206703048842351542647799591018316385612"; + let verification_key_id: u32 = 0; //valid key id + //let verification_key_id: u32 = 1; //invalid key id - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); - eph_pubkey.extend(ephemeral_kp.public().as_ref()); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - println!("eph_pubkey: {:?}", eph_pubkey); - println!("len eph_pubkey: {:?}", eph_pubkey.len()); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + } - let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); - println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + #[test] + fn test_poseidon_plus_vrgrth16() { + let user_pass_salt = "206703048842351542647799591018316385612"; - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "106294049240999307923", - "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ) - .unwrap(); + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + eph_pubkey.extend(ephemeral_kp.public().as_ref()); - println!("zk_seed: {}", zk_seed); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); - println!("proof_and_jwt: {}", proof_and_jwt); + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); - let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - println!("issAndheader_base64Details: {}", issAndheader_base64Details); + println!("zk_seed: {}", zk_seed); - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), - alg: "RS256".to_string(), - }; + println!("proof_and_jwt: {}", proof_and_jwt); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - println!("modulus: {:?}", modulus); + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - println!("modulus hex: {:?}", hex::encode(&modulus)); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - let max_epoch = 10; + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - // let max_epoch = 142; + println!("modulus: {:?}", modulus); - /// calcs poseidon * + println!("modulus hex: {:?}", hex::encode(&modulus)); - println!("====== Start Poseidon ========"); - let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + let max_epoch = 10; - let issAndheader_base64Details_cell = - pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); + //let max_epoch = 142; - // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut - // 0).unwrap(); + println!("====== Start Poseidon ========"); - let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let max_epoch_ = 142; + let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); - code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); - test_case_with_refs( - code.as_str(), - vec![modulus_cell, issAndheader_base64Details_cell, zk_seed_cell], - ) - .expect_success(); + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); - /// calcs vergrth16 * + let max_epoch_ = 142; - println!("====== Start Vergrth16 ========"); + let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); - let pp = zk_login_inputs.get_proof(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + test_case_with_refs(code.as_str(), vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell]).expect_success(); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); + println!("====== Start Vergrth16 ========"); - let y1 = proof.a.y.0.to_bits_le(); - let y2 = proof.a.y.0.to_bits_be(); - // let y_ = -y; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - println!("proof.a: {:?}", proof.a); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); - println!("proof.a.y: {:?}", proof.a.y); + let y1 = proof.a.y.0.to_bits_le(); + let y2 = proof.a.y.0.to_bits_be(); + //let y_ = -y; - println!("proof.a.y.0: {:?}", proof.a.y.0); + println!("proof.a: {:?}", proof.a); - println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); + println!("proof.a.y: {:?}", proof.a.y); - println!("proof.a.x.0.to_string(): {:?}", proof.a.x.0.to_string()); + println!("proof.a.y.0: {:?}", proof.a.y.0); - println!("y1: {:?}", y1); - for i in 0..y1.len() { - print!("{}", y1[i] as i32); - } - println!(""); - println!("y2: {:?}", y2); - for i in 0..y2.len() { - print!("{}", y2[i] as i32); - } - println!(""); - // println!("y_: {:?}", y_); + println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + println!("proof.a.x.0.to_string(): {:?}", proof.a.x.0.to_string()); - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); + println!("y1: {:?}", y1); + for i in 0..y1.len() { + print!("{}", y1[i] as i32); + } + println!(""); + println!("y2: {:?}", y2); + for i in 0..y2.len() { + print!("{}", y2[i] as i32); + } + println!(""); + //println!("y_: {:?}", y_); - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - let verification_key_id: u32 = 1; + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); -} + let verification_key_id: u32 = 1; -#[test] -fn test_eval_time_vrgrth16_new() { - // todo: later n must be extracted from 3d part of jwt - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ".to_string(), - alg: "RS256".to_string(), - }; + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - // { - // "e": "AQAB", - // "kty": "RSA", - // "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" - // } + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + } - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "0e345fd7e4a97271dffa991f5a893cd16b8e0827".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + #[test] + fn test_eval_time_vrgrth16_new() { + //todo: later n must be extracted from 3d part of jwt + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ".to_string(), + alg: "RS256".to_string(), + }; + + /* + { + "e": "AQAB", + "kty": "RSA", + "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" + } + */ - let sui_data = [SUI_DATA_FROM_REACT_1_NEW]; + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "0e345fd7e4a97271dffa991f5a893cd16b8e0827".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - for i in 0..sui_data.len() { - println!("====================== Iter@ is {i} ========================="); - // parse - let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - // println!("{:?}", jwt_data); + let sui_data = [SUI_DATA_FROM_REACT_1_NEW]; - let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); - println!("user_pass_salt is {user_pass_salt}"); + for i in 0..sui_data.len() { + println!("====================== Iter@ is {i} ========================="); + // parse + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + //println!("{:?}", jwt_data); - let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); + let user_pass_salt = jwt_data.user_pass_to_int_format.as_str(); + println!("user_pass_salt is {user_pass_salt}"); - let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new(); //vec![0x00]; - eph_pubkey.extend(ephemeral_kp.public().as_ref()); + let eph_secret_key = secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); - println!("ephemeral secret_key is {:?}", eph_secret_key); - println!("ephemeral public_key is {:?}", eph_pubkey); + let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); - let eph_pubkey_len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", eph_pubkey_len); + println!("ephemeral secret_key is {:?}", eph_secret_key); + println!("ephemeral public_key is {:?}", eph_pubkey); - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); - let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + let eph_pubkey_len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", eph_pubkey_len); - let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); - println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); - // JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); - println!("kid: {:?}", jwt_data_decoded1.kid); + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); - let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); - println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); - // JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); - println!("aud: {:?}", jwt_data_decoded2.aud); - println!("sub: {:?}", jwt_data_decoded2.sub); + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); + println!("azp: {:?}", jwt_data_decoded2.azp); + println!("exp: {:?}", jwt_data_decoded2.exp); + println!("nonce: {:?}", jwt_data_decoded2.nonce); + println!("iss: {:?}", jwt_data_decoded2.iss); + println!("iat: {:?}", jwt_data_decoded2.iat); + println!("jti: {:?}", jwt_data_decoded2.jti); + println!("nbf: {:?}", jwt_data_decoded2.nbf); - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail - * alina.t@gosh.sh) from jwt */ - jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ) - .unwrap(); - println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); - let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); - let zk_login_inputs = - ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); - println!("time_for_vergrth16 is {time_for_vergrth16}"); + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); - println!("=========================================="); + let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); + println!("time_for_vergrth16 is {time_for_vergrth16}"); + + println!("=========================================="); + } } -} -#[test] -fn test_vrgrth16_based_on_real_data_new() { - // real data taken from our react app for zklogin tests - // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} - // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. - // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" - // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" - // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 - // in ascii 535455565748 - let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations - - // Generate an ephemeral key pair. - let secret_key = [ - 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, - 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, - ]; - - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); //vec![0x00]; - // replace by Alina's data (ephemeral public key place to byte array ), depends - // on iteration - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - println!("eph_pubkey: {:?}", eph_pubkey); - println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); - let len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", len); - - // Get the zklogin seed. - // This stuff is a kind of bound between smart contract and email (some - // account) It will be stored in smart contract (must be added during - // contract deployment) - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt - "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt - ).unwrap(); - - println!("zk_seed = {:?}", zk_seed); - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + #[test] + fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); //vec![0x00]; + // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -560,495 +570,470 @@ fn test_vrgrth16_based_on_real_data_new() { \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ - \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - let len = proof_and_jwt.bytes().len(); - println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid - // in this header is equal to one specified in line 143,... take kid from jwt if - // not equal - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data - alg: "RS256".to_string(), - }; + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - let max_epoch = 142; // data from the react test + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + let verification_key_id: u32 = 0; //valid key id + //let verification_key_id: u32 = 1; //invalid key id - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + } - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + #[test] + fn test_proof_serialization() { + let user_pass_salt = "206703048842351542647799591018316385612"; - let verification_key_id: u32 = 0; //valid key id - // let verification_key_id: u32 = 1; //invalid key id + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); -} + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; -#[test] -fn test_proof_serialization() { - let user_pass_salt = "206703048842351542647799591018316385612"; - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "106294049240999307923", - "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ) - .unwrap(); + println!("proof_and_jwt: {}", proof_and_jwt); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let zk_login_inputs = tvm_vm::executor::zk_stuff::zk_login::ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - println!("proof_and_jwt: {}", proof_and_jwt); + println!("zk_login_inputs: {:?}", zk_login_inputs); - let zk_login_inputs = tvm_vm::executor::zk_stuff::zk_login::ZkLoginInputs::from_json( - &*proof_and_jwt, - &*zk_seed.to_string(), - ) - .unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - println!("zk_login_inputs: {:?}", zk_login_inputs); + println!("proof.a: {:?}", proof.a); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); + } - println!("proof.a: {:?}", proof.a); + #[test] + fn test_vrgrth16_fresh() { + // Initial password was 567890 + let user_pass_salt = "535455565748"; - println!("proof.a.y.0.to_string(): {:?}", proof.a.y.0.to_string()); -} + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); -#[test] -fn test_vrgrth16_fresh() { - // Initial password was 567890 - let user_pass_salt = "535455565748"; + println!("zk_seed {zk_seed}"); - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt - "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt - ).unwrap(); + let iss = "https://accounts.google.com"; - println!("zk_seed {zk_seed}"); + let xxx = get_zk_login_address(&Bn254FrElement::from_str(&zk_seed).unwrap(), iss).unwrap(); + let xx = hex::encode(&xxx); + println!("xxx {xx}"); - let iss = "https://accounts.google.com"; + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"20032491544466004395942516676927853848812757556091814296260914209848471949133\",\"2383319895045368406863089991961299436327009667970727469594098906910899823518\",\"1\"],\"b\":[[\"17524079199473031626933714849790290610990375813469214348846178898325828270802\",\"14967860363718375858883445892553389848174133418448836833724123534259346456965\"],[\"8012103671455598651673212917030479015077366694912593401917441922282850889728\",\"9619406946838713340504188077859322423191842838375117333667670119492063405148\"],[\"1\",\"0\"]],\"c\":[\"1155327534990006564455106296492790109069125857506281397147103620914309288350\",\"11642927414888703901346255147864200862372140915112720472429308471936285279899\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\"}"; - let xxx = get_zk_login_address(&Bn254FrElement::from_str(&zk_seed).unwrap(), iss).unwrap(); - let xx = hex::encode(&xxx); - println!("xxx {xx}"); + println!("proof_and_jwt: {}", proof_and_jwt); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"20032491544466004395942516676927853848812757556091814296260914209848471949133\",\"2383319895045368406863089991961299436327009667970727469594098906910899823518\",\"1\"],\"b\":[[\"17524079199473031626933714849790290610990375813469214348846178898325828270802\",\"14967860363718375858883445892553389848174133418448836833724123534259346456965\"],[\"8012103671455598651673212917030479015077366694912593401917441922282850889728\",\"9619406946838713340504188077859322423191842838375117333667670119492063405148\"],[\"1\",\"0\"]],\"c\":[\"1155327534990006564455106296492790109069125857506281397147103620914309288350\",\"11642927414888703901346255147864200862372140915112720472429308471936285279899\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\"}"; + let iss_and_header_base64details = "\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; + println!("iss_and_header_base64details: {}", iss_and_header_base64details); - println!("proof_and_jwt: {}", proof_and_jwt); + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - let issAndheader_base64Details = "\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; - println!("issAndheader_base64Details: {}", issAndheader_base64Details); + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "pi22xDdK2fz5gclIbDIGghLDYiRO56eW2GUcboeVlhbAuhuT5mlEYIevkxdPOg5n6qICePZiQSxkwcYMIZyLkZhSJ2d2M6Szx2gDtnAmee6o_tWdroKu0DjqwG8pZU693oLaIjLku3IK20lTs6-2TeH-pUYMjEqiFMhn-hb7wnvH_FuPTjgz9i0rEdw_Hf3Wk6CMypaUHi31y6twrMWq1jEbdQNl50EwH-RQmQ9bs3Wm9V9t-2-_Jzg3AT0Ny4zEDU7WXgN2DevM8_FVje4IgztNy29XUkeUctHsr-431_Iu23JIy6U4Kxn36X3RlVUKEkOMpkDD3kd81JPW4Ger_w".parse().unwrap(), + alg: "RS256".to_string(), + }; - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "b2620d5e7f132b52afe8875cdf3776c064249d04".to_string(), + ), + content, + ); - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "pi22xDdK2fz5gclIbDIGghLDYiRO56eW2GUcboeVlhbAuhuT5mlEYIevkxdPOg5n6qICePZiQSxkwcYMIZyLkZhSJ2d2M6Szx2gDtnAmee6o_tWdroKu0DjqwG8pZU693oLaIjLku3IK20lTs6-2TeH-pUYMjEqiFMhn-hb7wnvH_FuPTjgz9i0rEdw_Hf3Wk6CMypaUHi31y6twrMWq1jEbdQNl50EwH-RQmQ9bs3Wm9V9t-2-_Jzg3AT0Ny4zEDU7WXgN2DevM8_FVje4IgztNy29XUkeUctHsr-431_Iu23JIy6U4Kxn36X3RlVUKEkOMpkDD3kd81JPW4Ger_w".parse().unwrap(), - alg: "RS256".to_string(), - }; + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "b2620d5e7f132b52afe8875cdf3776c064249d04".to_string(), - ), - content, - ); + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + println!("modulus: {:?}", modulus); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + println!("modulus hex: {:?}", hex::encode(&modulus)); - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); - println!("modulus: {:?}", modulus); + let max_epoch = 142; - println!("modulus hex: {:?}", hex::encode(&modulus)); + //let max_epoch = 10; - let max_epoch = 142; + let eph_pubkey = vec![131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63]; - // let max_epoch = 10; + println!("eph_pubkey : {:?}", eph_pubkey); + println!("eph_pubkey len : {:?}", eph_pubkey.len()); - let mut eph_pubkey = vec![ - 131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, - 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63, - ]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - println!("eph_pubkey : {:?}", eph_pubkey); - println!("eph_pubkey len : {:?}", eph_pubkey.len()); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); - let pp = zk_login_inputs.get_proof(); + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - println!("proof_as_bytes hex: {:?}", hex::encode(&proof_as_bytes)); + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + let verification_key_id: u32 = 0; - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - println!("public_inputs_as_bytes hex: {:?}", hex::encode(&public_inputs_as_bytes)); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + } - let verification_key_id: u32 = 0; + #[test] + fn test_poseidon_update() { + let user_pass_salt = "206703048842351542647799591018316385612"; - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + println!("eph_pubkey: {:?}", eph_pubkey); + println!("len eph_pubkey: {:?}", eph_pubkey.len()); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); -} + let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); + println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); -#[test] -fn test_poseidon_update() { - /// Common data generation * - let user_pass_salt = "206703048842351542647799591018316385612"; + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - println!("eph_pubkey: {:?}", eph_pubkey); - println!("len eph_pubkey: {:?}", eph_pubkey.len()); + println!("zk_seed: {}", zk_seed); - let eph_pubkey_hex_number = "0x".to_owned() + &hex::encode(eph_pubkey.clone()); - println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "106294049240999307923", - "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ) - .unwrap(); + println!("proof_and_jwt: {}", proof_and_jwt); - println!("zk_seed: {}", zk_seed); + let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - println!("proof_and_jwt: {}", proof_and_jwt); + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; - let issAndheader_base64Details = "{\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - println!("issAndheader_base64Details: {}", issAndheader_base64Details); + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), - alg: "RS256".to_string(), - }; + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + println!("modulus: {:?}", modulus); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + println!("modulus hex: {:?}", hex::encode(&modulus)); - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + println!("====== Start Poseidon ========"); - println!("modulus: {:?}", modulus); + let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - println!("modulus hex: {:?}", hex::encode(&modulus)); + let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - println!("====== Start Poseidon ========"); + //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); - let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); - let issAndheader_base64Details_cell = - pack_string_to_cell(&issAndheader_base64Details.clone(), &mut 0).unwrap(); + let max_epoch = "142"; //"200142"; - // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut - // 0).unwrap(); + let mut code = format!("PUSHINT {max_epoch} \n").to_string(); + code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); - let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + println!("code : {code}"); - let max_epoch = "142"; //"200142"; + test_case_with_refs(code.as_str(), vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell]).expect_success(); + } - let mut code = format!("PUSHINT {max_epoch} \n").to_string(); - code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); - println!("code : {code}"); + #[test] + fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { + println!("===================================== START VRGRTH16 TEST ====================================="); - test_case_with_refs( - code.as_str(), - vec![modulus_cell, issAndheader_base64Details_cell, zk_seed_cell], - ) - .expect_success(); -} + let user_pass_salt = "206703048842351542647799591018316385612"; + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); -#[test] -fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { - println!( - "===================================== START VRGRTH16 TEST =====================================" - ); - - let user_pass_salt = "206703048842351542647799591018316385612"; - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); //vec![0x00]; - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - - println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); - let len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", len); - - // Get the zklogin seed. - // This stuff is a kind of bound between smart contract and email (some - // account) It will be stored in smart contract (must be added during - // contract deployment) - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "106294049240999307923", - "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ) - .unwrap(); - - println!("zk_seed = {:?}", zk_seed); - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - let len = proof_and_jwt.bytes().len(); - println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), - alg: "RS256".to_string(), - }; + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "106294049240999307923", + "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + + + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let max_epoch = 10; - let max_epoch = 10; + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + let verification_key_id: u32 = 1; - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - let verification_key_id: u32 = 1; + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); + println!("===================================== START CHKSIGNS TEST ====================================="); - println!( - "===================================== START CHKSIGNS TEST =====================================" - ); + let pair = gen_keypair(); - let pair = gen_keypair(); + let binding = proof_cell.clone(); + let first = binding.data(); - let binding = proof_cell.clone(); - let first = binding.data(); - // let mut b = BuilderData::with_raw(first, len).unwrap(); - let binding = public_inputs_cell.clone(); - let second = binding.data(); - // b.append_raw(second, len); + /*let mut b = BuilderData::with_raw(first, len).unwrap();*/ + let binding = public_inputs_cell.clone(); + let second = binding.data(); + //b.append_raw(second, len); - let concatenated = [&first[..], &second[..]].concat(); - println!("len concatenated = {}", concatenated.len()); + let concatenated = [&first[..], &second[..]].concat(); + println!("len concatenated = {}", concatenated.len()); - // test cell with data and one not empty reference - let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - // b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); - // let cell_hash = test_cell.repr_hash(); - // sign hash of data cell - let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - // put signature to separate slice - let len = signature.len() * 8; - let signature = SliceData::from_raw(signature, len); + //test cell with data and one not empty reference + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + //b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); + //let cell_hash = test_cell.repr_hash(); + //sign hash of data cell + let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - // put public key to integer - let pub_key = BuilderData::with_raw( - pair.public.to_bytes().to_vec(), - ed25519_dalek::PUBLIC_KEY_LENGTH * 8, - ) - .unwrap(); + //put signature to separate slice + let len = signature.len() * 8; + let signature = SliceData::from_raw(signature, len); - // put hash to integer - // let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), - // 256).unwrap(); + //put public key to integer + let pub_key = BuilderData::with_raw( + pair.public.to_bytes().to_vec(), + ed25519_dalek::PUBLIC_KEY_LENGTH * 8, + ).unwrap(); - test_case_with_refs( - " + //put hash to integer + //let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), 256).unwrap(); + + test_case_with_refs(" PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", - vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], - ) - .expect_stack(Stack::new().push(int!(-1))); -} + ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) + .expect_stack(Stack::new().push(int!(-1))); + } + + + #[test] + fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for zklogin tests + // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} + // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} + // Initial password was 567890 + // in ascii 535455565748 + + let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations + + // Generate an ephemeral key pair. + let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + + // Generate an ephemeral key pair. + let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); + let mut eph_pubkey = Vec::new(); //vec![0x00]; // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + eph_pubkey.extend(ephemeral_kp.public().as_ref()); -#[test] -fn test_vrgrth16_based_on_real_data() { - // real data taken from our react app for zklogin tests - // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} - // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. - // com","sub":"112897468626716626103", "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08" - // ,"nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":" - // 27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial password was 567890 - // in ascii 535455565748 - - let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations - - // Generate an ephemeral key pair. - let secret_key = [ - 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, - 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, - ]; - - // Generate an ephemeral key pair. - let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new(); //vec![0x00]; // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration - eph_pubkey.extend(ephemeral_kp.public().as_ref()); - - println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); - let len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", len); - - // Get the zklogin seed. - // This stuff is a kind of bound between smart contract and email (some - // account) It will be stored in smart contract (must be added during - // contract deployment) - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt - "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt - ).unwrap(); - - println!("zk_seed = {:?}", zk_seed); - - let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ + println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); + let len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", len); + + // Get the zklogin seed. + //This stuff is a kind of bound between smart contract and email (some account) + //It will be stored in smart contract (must be added during contract deployment) + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + "112897468626716626103", // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + "232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", // Alina's data (fixed by app id ) from jwt + ).unwrap(); + + println!("zk_seed = {:?}", zk_seed); + + let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"2352077003566407045854435506409565889408960755152253285189640818725808263237\",\ \"9548308350778027075240385782578683112366097953461273569343148999989145049123\",\"1\"],\ \"b\":[[\"2172697685172701179756462481453772004245591587568555358926512547679273443868\",\ \"11300889616992175665271080883374830731684409375838395487979439153562369168807\"],\ @@ -1056,589 +1041,524 @@ fn test_vrgrth16_based_on_real_data() { \"12892936063156115176399929981646174277274895601746717550262309650970826515227\"],[\"1\",\"0\"]],\ \"c\":[\"21276833037675249246843718004583052134371270695679878402069223253610209272159\",\ \"8637596258221986824049981569842218428861929142818091935707054543971817804456\",\"1\"]},\ - \"iss_base64_details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"index_mod4\":1},\ - \"header_base64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - let len = proof_and_jwt.bytes().len(); - println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - - let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid - // in this header is equal to one specified in line 143,... take kid from jwt if - // not equal - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data - alg: "RS256".to_string(), - }; + \"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\ + \"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; + let len = proof_and_jwt.bytes().len(); + println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); + + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); +// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "uBHF-esPKiNlFaAvpdpejD4vpONW9FL0rgLDg1z8Q-x_CiHCvJCpiSehD41zmDOhzXP_fbMMSGpGL7R3duiz01nK5r_YmRw3RXeB0kcS7Z9H8MN6IJcde9MWbqkMabCDduFgdr6gvH0QbTipLB1qJK_oI_IBfRgjk6G0bGrKz3PniQw5TZ92r0u1LM-1XdBIb3aTYTGDW9KlOsrTTuKq0nj-anW5TXhecuxqSveFM4Hwlw7pw34ydBunFjFWDx4VVJqGNSqWCfcERxOulizIFruZIHJGkgunZnB4DF7mCZOttx2dwT9j7s3GfLJf0xoGumqpOMvecuipfTPeIdAzcQ".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); + + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); + + let max_epoch = 142; // data from the react test + + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "a3b762f871cdb3bae0044c649622fc1396eda3e3".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - let max_epoch = 142; // data from the react test + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + let verification_key_id: u32 = 0; - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + //let verification_key_id: u32 = 1; - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + } - let verification_key_id: u32 = 0; - // let verification_key_id: u32 = 1; + fn secret_key_from_integer_map(key_data: HashMap) -> Vec { + let mut vec: Vec = Vec::new(); + for i in 0..=31 { + if let Some(value) = key_data.get(&i.to_string()) { + vec.push(value.clone()); + } + } + return vec; + } - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; + fn to_binary_string(value: &str) -> String { + let big_value = BigUint::parse_bytes(value.as_bytes(), 10).unwrap(); + big_value.to_str_radix(2) + } - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); -} + fn pad_string_to_256(input: &str) -> String { + let current_length = input.len(); -fn secret_key_from_integer_map(key_data: HashMap) -> Vec { - let mut vec: Vec = Vec::new(); - for i in 0..=31 { - if let Some(value) = key_data.get(&i.to_string()) { - vec.push(value.clone()); + if current_length >= 256 { + return input.to_string(); } + + let zeros_to_add = 256 - current_length; + format!("{}{}", repeat('0').take(zeros_to_add).collect::(), input) } - return vec; -} -fn to_binary_string(value: &str) -> String { - let big_value = BigUint::parse_bytes(value.as_bytes(), 10).unwrap(); - big_value.to_str_radix(2) -} + fn bits_to_decimal_and_reverse(bits: &str) -> Vec { + let byte_chunks: Vec<&str> = bits.as_bytes().chunks(8).map(|chunk| { + std::str::from_utf8(chunk).unwrap() + }).collect(); -fn pad_string_to_256(input: &str) -> String { - let current_length = input.len(); + let decimal_numbers: Vec = byte_chunks.iter() + .map(|byte| u8::from_str_radix(byte, 2).unwrap()) + .collect(); - if current_length >= 256 { - return input.to_string(); + decimal_numbers.into_iter().rev().collect() } - let zeros_to_add = 256 - current_length; - format!("{}{}", repeat('0').take(zeros_to_add).collect::(), input) -} - -fn bits_to_decimal_and_reverse(bits: &str) -> Vec { - let byte_chunks: Vec<&str> = - bits.as_bytes().chunks(8).map(|chunk| std::str::from_utf8(chunk).unwrap()).collect(); + fn prepare_hex_representation(init_x: &str, y: BigUint) -> String { + let mut binary_representation = pad_string_to_256(&to_binary_string(init_x)); - let decimal_numbers: Vec = - byte_chunks.iter().map(|byte| u8::from_str_radix(byte, 2).unwrap()).collect(); + let p: BigUint = BigUint::from_bytes_be(&[ + 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]); - decimal_numbers.into_iter().rev().collect() -} + // Сравниваем y с p - y и меняем первый бит + if y > &p - &y { + binary_representation.replace_range(0..1, "1"); + } -fn prepare_hex_representation(init_x: &str, y: BigUint) -> String { - let mut binary_representation = pad_string_to_256(&to_binary_string(init_x)); + let reversed_byte_array = bits_to_decimal_and_reverse(&binary_representation); - let p: BigUint = BigUint::from_bytes_be(&[ - 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, - ]); + // Преобразуем массив байтов в hex-строку + let hex_string = reversed_byte_array.iter() + .map(|byte| format!("{:02x}", byte)) + .collect::(); - // Сравниваем y с p - y и меняем первый бит - if y > &p - &y { - binary_representation.replace_range(0..1, "1"); + hex_string } - let reversed_byte_array = bits_to_decimal_and_reverse(&binary_representation); + #[test] + fn test_proof_stuff() { + let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 + , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 + , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + + for i in 0..sui_data.len() { + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + let json_string = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); + print!("{:?}, \n", json_string); + print!("{:?}, \n", jwt_data.zk_addr); + print!("{:?}, \n", jwt_data.extended_ephemeral_public_key); + } - // Преобразуем массив байтов в hex-строку - let hex_string = - reversed_byte_array.iter().map(|byte| format!("{:02x}", byte)).collect::(); + for i in 0..sui_data.len() { + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - hex_string -} + ////// -#[test] -fn test_proof_stuff() { - let sui_data = [ - SUI_DATA_FROM_REACT_1, - SUI_DATA_FROM_REACT_2, - SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, - SUI_DATA_FROM_REACT_5, - SUI_DATA_FROM_REACT_6, - SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, - SUI_DATA_FROM_REACT_9, - SUI_DATA_FROM_REACT_10, - SUI_DATA_FROM_REACT_11, - SUI_DATA_FROM_REACT_12, - SUI_DATA_FROM_REACT_13, - SUI_DATA_FROM_REACT_14, - SUI_DATA_FROM_REACT_15, - SUI_DATA_FROM_REACT_16, - SUI_DATA_FROM_REACT_17, - SUI_DATA_FROM_REACT_18, - SUI_DATA_FROM_REACT_19, - SUI_DATA_FROM_REACT_20, - SUI_DATA_FROM_REACT_21, - ]; - - for i in 0..sui_data.len() { - let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - let json_string = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - print!("{:?}, \n", json_string); - } + let user_pass_salt = jwt_data.user_pass_to_int_format.as_str(); + println!("user_pass_salt is {user_pass_salt}"); - for i in 0..sui_data.len() { - let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); - ////// + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); - println!("user_pass_salt is {user_pass_salt}"); + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); + println!("alg: {:?}", jwt_data_decoded1.alg); + println!("typ: {:?}", jwt_data_decoded1.typ); - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); - let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); - println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); - // JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); - println!("kid: {:?}", jwt_data_decoded1.kid); + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); - let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); - let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); - println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - // JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); - println!("aud: {:?}", jwt_data_decoded2.aud); - println!("sub: {:?}", jwt_data_decoded2.sub); + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail - * alina.t@gosh.sh) from jwt */ - jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ) - .unwrap(); + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); - let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + println!("----------------------------------"); - let zk_login_inputs = - ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + /////////// - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - println!("----------------------------------"); - /////////// + let json_string = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); + println!("json_string ={:?}", json_string);//jwt_data.zk_proofs); + - let json_string = serde_json::to_string(&jwt_data.zkProofs).unwrap(); - println!("json_string ={:?}", json_string); //jwt_data.zkProofs); + let data: Value = serde_json::from_str(&*json_string).unwrap(); + println!("data = {:?}", data); - let data: Value = serde_json::from_str(&*json_string).unwrap(); - println!("data = {:?}", data); + let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("a_x = {:?}", a_x); + println!("a_y = {:?}", a_y); - let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - let a_y = - BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10) - .unwrap(); - println!("a_x = {:?}", a_x); - println!("a_y = {:?}", a_y); + let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("b0_x = {:?}", b0_x); + println!("b1_x = {:?}", b1_x); + println!("b1_y = {:?}", b1_y); - let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - let b1_y = - BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10) - .unwrap(); - println!("b0_x = {:?}", b0_x); - println!("b1_x = {:?}", b1_x); - println!("b1_y = {:?}", b1_y); + let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + println!("c_x = {:?}", c_x); + println!("c_y = {:?}", c_y); + + let hex_ax = prepare_hex_representation(a_x, a_y); + let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + let hex_b1x = prepare_hex_representation(b1_x, b1_y); + let hex_cx = prepare_hex_representation(c_x, c_y); + + let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + + println!("Serialized proof _ 0: {:?}", result); + + println!("Serialized proof _ 1: {:?}", hex::encode(&proof_as_bytes)); + + assert_eq!(result, hex::encode(&proof_as_bytes)); + + println!("==================="); + } - let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - let c_y = - BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10) - .unwrap(); - println!("c_x = {:?}", c_x); - println!("c_y = {:?}", c_y); - let hex_ax = prepare_hex_representation(a_x, a_y); - let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); - let hex_b1x = prepare_hex_representation(b1_x, b1_y); - let hex_cx = prepare_hex_representation(c_x, c_y); + /* println!("Serialized proof"); + let json_string = r#"{"proofPoints":{"a":["8247215875293406890829839156897863742504615191361518281091302475904551111016","6872980335748205979379321982220498484242209225765686471076081944034292159666","1"],"b":[["21419680064642047510915171723230639588631899775315750803416713283740137406807","21566716915562037737681888858382287035712341650647439119820808127161946325890"],["17867714710686394159919998503724240212517838710399045289784307078087926404555","21812769875502013113255155836896615164559280911997219958031852239645061854221"],["1","0"]],"c":["7530826803702928198368421787278524256623871560746240215547076095911132653214","16244547936249959771862454850485726883972969173921727256151991751860694123976","1"]},"issBase64Details":{"value":"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1},"headerBase64":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"}"#; - let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + // Парсинг JSON-строки + let data: Value = serde_json::from_str(json_string).unwrap(); - println!("Serialized proof _ 0: {:?}", result); + let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - println!("Serialized proof _ 1: {:?}", hex::encode(&proof_as_bytes)); + let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); - assert_eq!(result, hex::encode(&proof_as_bytes)); + let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - println!("==================="); + let hex_ax = prepare_hex_representation(a_x, a_y); + let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + let hex_b1x = prepare_hex_representation(b1_x, b1_y); + let hex_cx = prepare_hex_representation(c_x, c_y); + + let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + + // ????? ??????????? + println!("Serialized proof: {}", result); + println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); + */ } - // println!("Serialized proof"); - // let json_string = - // r#"{"proofPoints":{"a":[" - // 8247215875293406890829839156897863742504615191361518281091302475904551111016" - // ,"6872980335748205979379321982220498484242209225765686471076081944034292159666" - // ,"1"],"b":[[" - // 21419680064642047510915171723230639588631899775315750803416713283740137406807" - // ,"21566716915562037737681888858382287035712341650647439119820808127161946325890" - // ],["17867714710686394159919998503724240212517838710399045289784307078087926404555" - // ,"21812769875502013113255155836896615164559280911997219958031852239645061854221" - // ],["1","0"]],"c":[" - // 7530826803702928198368421787278524256623871560746240215547076095911132653214" - // ,"16244547936249959771862454850485726883972969173921727256151991751860694123976" - // ,"1"]},"iss_base64_details":{"value":" - // yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","index_mod4":1}," - // header_base64":" - // eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ" - // }"#; - // - // Парсинг JSON-строки - // let data: Value = serde_json::from_str(json_string).unwrap(); - // - // let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - // let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str(). - // unwrap().as_bytes(), 10).unwrap(); - // - // let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - // let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - // let b1_y = - // BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap(). - // as_bytes(), 10).unwrap(); - // - // let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - // let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str(). - // unwrap().as_bytes(), 10).unwrap(); - // - // let hex_ax = prepare_hex_representation(a_x, a_y); - // let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); - // let hex_b1x = prepare_hex_representation(b1_x, b1_y); - // let hex_cx = prepare_hex_representation(c_x, c_y); - // - // let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); - // - // ????? ??????????? - // println!("Serialized proof: {}", result); - // println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); -} + #[ignore] + #[test] + fn test_eval_time_vrgrth16() { + //todo: later n must be extracted from 3d part of jwt -#[ignore] -#[test] -fn test_eval_time_vrgrth16() { - // todo: later n must be extracted from 3d part of jwt + let content: JWK = JWK { + kty: "RSA".to_string(), + e: "AQAB".to_string(), + n: "xjWd1j8GmmWzuz732haG9HECXsSZBvxOBLph3FQhk_tplhWloI1ywx-RdopUZt1lndbOM9n99lZJkpQyNJ1sdy7JFgYLjqj-wtHdEaQlBGEQtmkW8zUjr_N3bmpsxGbPzOzlKe3qddtoxXvn9rI_RvHfJD1YY-6kayQeyPOBz_4ML1lvI_JHV-Bb1MSmSk3WaAh5PzeqleusmUT87Gqfu02cOPrY8cwugqo65D6-wzAEeVvceV8-c36TMoLU5csU05GBVplgd6Ouuw35ZsETG4si4QQJztC3KsZ4jhYM-aJ3jeFPt0r3cQooiXdZBp3JkXSpE-UUaOVPsXo7WiVmww".to_string(), // Alina's data + alg: "RS256".to_string(), + }; + + let mut all_jwk = HashMap::new(); + all_jwk.insert( + JwkId::new( + OIDCProvider::Google.get_config().iss, + "323b214ae6975a0f034ea77354dc0c25d03642dc".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), + ), + content, + ); - let content: JWK = JWK { - kty: "RSA".to_string(), - e: "AQAB".to_string(), - n: "xjWd1j8GmmWzuz732haG9HECXsSZBvxOBLph3FQhk_tplhWloI1ywx-RdopUZt1lndbOM9n99lZJkpQyNJ1sdy7JFgYLjqj-wtHdEaQlBGEQtmkW8zUjr_N3bmpsxGbPzOzlKe3qddtoxXvn9rI_RvHfJD1YY-6kayQeyPOBz_4ML1lvI_JHV-Bb1MSmSk3WaAh5PzeqleusmUT87Gqfu02cOPrY8cwugqo65D6-wzAEeVvceV8-c36TMoLU5csU05GBVplgd6Ouuw35ZsETG4si4QQJztC3KsZ4jhYM-aJ3jeFPt0r3cQooiXdZBp3JkXSpE-UUaOVPsXo7WiVmww".to_string(), // Alina's data - alg: "RS256".to_string(), - }; + //let sui_data = [SUI_DATA_FROM_REACT_1]; + let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 + , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 + , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; - let mut all_jwk = HashMap::new(); - all_jwk.insert( - JwkId::new( - OIDCProvider::Google.get_config().iss, - "323b214ae6975a0f034ea77354dc0c25d03642dc".to_string(), // Alina's data, fascrypto's was 6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), - ), - content, - ); - - // let sui_data = [SUI_DATA_FROM_REACT_1]; - let sui_data = [ - SUI_DATA_FROM_REACT_1, - SUI_DATA_FROM_REACT_2, - SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, - SUI_DATA_FROM_REACT_5, - SUI_DATA_FROM_REACT_6, - SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, - SUI_DATA_FROM_REACT_9, - SUI_DATA_FROM_REACT_10, - SUI_DATA_FROM_REACT_11, - SUI_DATA_FROM_REACT_12, - SUI_DATA_FROM_REACT_13, - SUI_DATA_FROM_REACT_14, - SUI_DATA_FROM_REACT_15, - SUI_DATA_FROM_REACT_16, - SUI_DATA_FROM_REACT_17, - SUI_DATA_FROM_REACT_18, - SUI_DATA_FROM_REACT_19, - SUI_DATA_FROM_REACT_20, - SUI_DATA_FROM_REACT_21, - ]; - - let mut sum_ratio: u128 = 0; - - for i in 0..sui_data.len() { - println!("====================== Iter@ is {i} ========================="); - // parse - let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - // println!("{:?}", jwt_data); - - let user_pass_salt = jwt_data.userPassToIntFormat.as_str(); - println!("user_pass_salt is {user_pass_salt}"); - - let eph_secret_key = secretKeyFromIntegerMap(jwt_data.ephemeralKeyPair.keypair.secretKey); - - let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new(); //vec![0x00]; - eph_pubkey.extend(ephemeral_kp.public().as_ref()); + let mut sum_ratio: u128 = 0; - println!("ephemeral secret_key is {:?}", eph_secret_key); - println!("ephemeral public_key is {:?}", eph_pubkey); - - let eph_pubkey_len = eph_pubkey.clone().len(); - println!("len eph_pubkey: {:?}", eph_pubkey_len); - - // let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); - // - // let jwt_header = splitted_jwt_strings - // .get(0) - // .expect("split always returns at least one element"); - // - // let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( - // "Could not find separator in jwt string.", - // )).unwrap(); - // - // let decoded_jwt_header = base64::decode(jwt_header).unwrap(); - // let decoded_jwt_body = base64::decode(jwt_body).unwrap(); - // - // let converted_jwt_header = - // String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); - // let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 - // conversion failed"); - // - // let parsed_jwt_header = - // serde_json::from_str::(&converted_jwt_header).unwrap(); - // let parsed_jwt_body = - // serde_json::from_str::(&converted_jwt_body).unwrap(); - // - // println!( - // "{}", - // serde_json::to_string_pretty(&parsed_jwt_header) - // .expect("to_string_pretty always works on serde_json::Value") - // ); - // println!( - // "{}", - // serde_json::to_string_pretty(&parsed_jwt_body) - // .expect("to_string_pretty always works on serde_json::Value") - // ); - - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); - let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); - - let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); - println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - - // JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); - println!("kid: {:?}", jwt_data_decoded1.kid); - - let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); - let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); - println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - - // JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); - println!("aud: {:?}", jwt_data_decoded2.aud); - println!("sub: {:?}", jwt_data_decoded2.sub); - - // let key = DecodingKey::from_secret(&[]); - // let mut validation = Validation::new(Algorithm::HS256); - // validation.insecure_disable_signature_validation(); - - // let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); - // let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion - // failed"); println!("jwt_string_3 is {:?}", jwt_string_3); - // JwtDataDecodedPart3 - // let jwt_data_decoded3: JwtDataDecodedPart3 = - // serde_json::from_str(&jwt_string_3).unwrap(); - - // let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; - // println!("{:?}", encode(&jwt_data_1)); - // let jwt_string_3 = String::from_utf8(&jwt_data_3); - - // let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; - // let n = jwt_v_3["n"]; + for i in 0..sui_data.len() { + println!("====================== Iter@ is {i} ========================="); + // parse + let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); + //println!("{:?}", jwt_data); + + let user_pass_salt = jwt_data.user_pass_to_int_format.as_str(); + println!("user_pass_salt is {user_pass_salt}"); + + println!("{:?}", jwt_data.ephemeral_key_pair.keypair.public_key); + let eph_secret_key = secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); + + let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); + let mut eph_pubkey = Vec::new();//vec![0x00]; + eph_pubkey.extend(ephemeral_kp.public().as_ref()); + + println!("ephemeral secret_key is {:?}", eph_secret_key); + println!("ephemeral public_key is {:?}", eph_pubkey); + + let eph_pubkey_len = eph_pubkey.clone().len(); + println!("len eph_pubkey: {:?}", eph_pubkey_len); + + /*let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); + + let jwt_header = splitted_jwt_strings + .get(0) + .expect("split always returns at least one element"); + + let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( + "Could not find separator in jwt string.", + )).unwrap(); + + let decoded_jwt_header = base64::decode(jwt_header).unwrap(); + let decoded_jwt_body = base64::decode(jwt_body).unwrap(); + + let converted_jwt_header = String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); + let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 conversion failed"); + + let parsed_jwt_header = serde_json::from_str::(&converted_jwt_header).unwrap(); + let parsed_jwt_body = serde_json::from_str::(&converted_jwt_body).unwrap(); + + println!( + "{}", + serde_json::to_string_pretty(&parsed_jwt_header) + .expect("to_string_pretty always works on serde_json::Value") + ); + println!( + "{}", + serde_json::to_string_pretty(&parsed_jwt_body) + .expect("to_string_pretty always works on serde_json::Value") + );*/ + + + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); + + let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); + println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" + + //JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + println!("kid: {:?}", jwt_data_decoded1.kid); + + let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); + let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); + println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" + + //JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + println!("aud: {:?}", jwt_data_decoded2.aud); + println!("sub: {:?}", jwt_data_decoded2.sub); + + + //let key = DecodingKey::from_secret(&[]); + //let mut validation = Validation::new(Algorithm::HS256); + //validation.insecure_disable_signature_validation(); + + //let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); + //let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion failed"); + //println!("jwt_string_3 is {:?}", jwt_string_3); + //JwtDataDecodedPart3 + //let jwt_data_decoded3: JwtDataDecodedPart3 = serde_json::from_str(&jwt_string_3).unwrap(); - let zk_seed = gen_address_seed( - user_pass_salt, - "sub", - jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail - * alina.t@gosh.sh) from jwt */ - jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ) - .unwrap(); - println!("jwt_data.zkProofs = {:?}", jwt_data.zkProofs); - let proof_and_jwt = serde_json::to_string(&jwt_data.zkProofs).unwrap(); + //let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; + //println!("{:?}", encode(&jwt_data_1)); + //let jwt_string_3 = String::from_utf8(&jwt_data_3); - let zk_login_inputs = - ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + //let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; + //let n = jwt_v_3["n"]; - let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); - let time_for_chcksgns = single_chcksgns(&eph_pubkey, &zk_login_inputs, &all_jwk); - println!("time_for_vergrth16 is {time_for_vergrth16}"); - println!("time_for_chcksgns is {time_for_chcksgns}"); + let zk_seed = gen_address_seed( + user_pass_salt, + "sub", + jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt + ).unwrap(); - let current_ratio = time_for_vergrth16 / time_for_chcksgns; - println!("current_ratio is {current_ratio}"); + println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); + let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - sum_ratio = sum_ratio + current_ratio; /**/ - println!("sum_ratio is {sum_ratio}"); - println!("=========================================="); + let zk_login_inputs = ZkLoginInputs::from_json( + &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + + let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); + let time_for_chcksgns = single_chcksgns(&eph_pubkey, &zk_login_inputs, &all_jwk); + println!("time_for_vergrth16 is {time_for_vergrth16}"); + println!("time_for_chcksgns is {time_for_chcksgns}"); + + let current_ratio = time_for_vergrth16 / time_for_chcksgns; + println!("current_ratio is {current_ratio}"); + + sum_ratio = sum_ratio + current_ratio;/**/ + println!("sum_ratio is {sum_ratio}"); + println!("=========================================="); + } + let average_ratio = sum_ratio / (sui_data.len() as u128); + + println!("average ratio is {average_ratio}"); } - let average_ratio = sum_ratio / (sui_data.len() as u128); - println!("average ratio is {average_ratio}"); -} + fn prepare_proof_and_public_key_cells_for_stack(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> (Cell, Cell) { + let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + println!("kid = {}", kid); + println!("all_jwk = {:?}", all_jwk); -fn prepare_proof_and_public_key_cells_for_stack( - eph_pubkey: &Vec, - zk_login_inputs: &ZkLoginInputs, - all_jwk: &HashMap, -) -> (Cell, Cell) { - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); - println!("kid = {}", kid); - println!("all_jwk = {:?}", all_jwk); - let jwk = all_jwk - .get(&JwkId::new(iss.clone(), kid.clone())) - .ok_or_else(|| ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid))) - .unwrap(); + let jwk = all_jwk + .get(&JwkId::new(iss.clone(), kid.clone())) + .ok_or_else(|| { + ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) + }).unwrap(); - let max_epoch = 142; // data from the react test + let max_epoch = 142; // data from the react test - // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) - .map_err(|_| ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string())) - .unwrap(); + // Decode modulus to bytes. + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }).unwrap(); - let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = - &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); + let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; - let mut proof_as_bytes = vec![]; - proof.serialize_compressed(&mut proof_as_bytes).unwrap(); - println!("proof_as_bytes : {:?}", proof_as_bytes); - println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); + let mut proof_as_bytes = vec![]; + proof.serialize_compressed(&mut proof_as_bytes).unwrap(); + println!("proof_as_bytes : {:?}", proof_as_bytes); + println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); - let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); + let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); - println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); + println!("public_inputs_as_bytes len : {:?}", public_inputs_as_bytes.len()); - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - (proof_cell, public_inputs_cell) -} + (proof_cell, public_inputs_cell) + } -fn single_vrgrth16( - eph_pubkey: &Vec, - zk_login_inputs: &ZkLoginInputs, - all_jwk: &HashMap, -) -> u128 { - let (proof_cell, public_inputs_cell) = - prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - - // let verification_key_id: u32 = 2; - let verification_key_id: u32 = 0; - - let mut code = "PUSHREF \n".to_string(); - code = code + "PUSHREF \n"; - code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; - code = code + "VERGRTH16"; - - let start: Instant = Instant::now(); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) - .expect_success(); - start.elapsed().as_micros() -} -fn single_chcksgns( - eph_pubkey: &Vec, - zk_login_inputs: &ZkLoginInputs, - all_jwk: &HashMap, -) -> u128 { - let (proof_cell, public_inputs_cell) = - prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); + fn single_vrgrth16(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { + let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - let pair = gen_keypair(); + //let verification_key_id: u32 = 2; + let verification_key_id: u32 = 0; - let binding = proof_cell.clone(); - let first = binding.data(); + let mut code = "PUSHREF \n".to_string(); + code = code + "PUSHREF \n"; + code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; + code = code + "VERGRTH16"; - let binding = public_inputs_cell.clone(); - let second = binding.data(); + let start: Instant = Instant::now(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + start.elapsed().as_micros() + } + + + fn single_chcksgns(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { + let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); + + let pair = gen_keypair(); - let concatenated = [&first[..], &second[..]].concat(); + let binding = proof_cell.clone(); + let first = binding.data(); - let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); + let binding = public_inputs_cell.clone(); + let second = binding.data(); - // put signature to separate slice - let len = signature.len() * 8; - let signature = SliceData::from_raw(signature, len); + let concatenated = [&first[..], &second[..]].concat(); - // put public key to integer - let pub_key = BuilderData::with_raw( - pair.public.to_bytes().to_vec(), - ed25519_dalek::PUBLIC_KEY_LENGTH * 8, - ) - .unwrap(); + let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - let start: Instant = Instant::now(); - test_case_with_refs( - " + //put signature to separate slice + let len = signature.len() * 8; + let signature = SliceData::from_raw(signature, len); + + //put public key to integer + let pub_key = BuilderData::with_raw( + pair.public.to_bytes().to_vec(), + ed25519_dalek::PUBLIC_KEY_LENGTH * 8, + ).unwrap(); + + let start: Instant = Instant::now(); + test_case_with_refs(" PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", - vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], - ) - .expect_stack(Stack::new().push(int!(-1))); - start.elapsed().as_micros() + ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) + .expect_stack(Stack::new().push(int!(-1))); + start.elapsed().as_micros() + } } + + + + + + + diff --git a/tvm_tests/src/test_zk_.rs b/tvm_tests/src/test_zk_.rs deleted file mode 100644 index fda5e630..00000000 --- a/tvm_tests/src/test_zk_.rs +++ /dev/null @@ -1,155 +0,0 @@ -// use std::collections::HashMap; -// use std::slice; -// use ark_std::rand::rngs::StdRng; -// use ark_std::rand::SeedableRng; -// use base64ct::Encoding as bEncoding; -// use fastcrypto::ed25519::Ed25519KeyPair; -// -// -// use fastcrypto::traits::KeyPair; -// use rand::Rng; -// use similar::DiffableStr; -// use tvm_block::{ -// GlobalCapabilities, MsgAddressInt, Serializable, ACTION_CHANGE_LIB, -// ACTION_COPYLEFT, ACTION_RESERVE, ACTION_SEND_MSG, ACTION_SET_CODE, -// }; -// use tvm_assembler::compile_code_to_cell; -// use tvm_types::{ -// types::ExceptionCode, AccountId, HashmapE, HashmapType, IBitstring, Result, -// Sha256 -// }; -// -// #[cfg(feature = "signature_no_check")] -// use ton_vm::executor::BehaviorModifiers; -// use tvm_vm::{ -// boolean, -// executor::serialize_currency_collection, -// int, -// stack::{ -// integer::{ -// serialization::{Encoding, UnsignedIntegerBigEndianEncoding}, -// IntegerData, -// }, -// serialization::{Deserializer, Serializer}, -// Stack, StackItem, -// }, -// SmartContractInfo, -// utils::{pack_string_to_cell, pack_data_to_cell, unpack_string_from_cell}, -// }; -// -// use tvm_vm::executor::zk::ZkCryptoError; -// use tvm_assembler::CompileError; -// use tvm_types::{BuilderData, Cell, SliceData}; -// -// use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, -// OIDCProvider, ZkLoginInputs}; -// use fastcrypto_zkp::bn254::utils::gen_address_seed; -// -// pub const VALUE_PORTION_SIZE: usize = 126; -// -// #[test] -// fn test_vergrth16() { -// let user_pass_salt = "206703048842351542647799591018316385612"; -// -// Generate an ephemeral key pair. -// let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); -// let mut eph_pubkey = vec![0x00]; -// eph_pubkey.extend(ephemeral_kp.public().as_ref()); -// -// println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); -// let len = eph_pubkey.clone().len(); -// println!("len eph_pubkey: {:?}", len); -// -// Get the zklogin seed. -// This stuff is a kind of bound between smart contract and email (some -// account) It will be stored in smart contract (must be added during contract -// deployment) let zk_seed = gen_address_seed( -// user_pass_salt, -// "sub", -// "106294049240999307923", -// "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", -// ).unwrap(); -// -// println!("zk_seed = {:?}", zk_seed); -// -// let proof_and_jwt = -// "{\"proofPoints\":{\"a\":[\" -// 8247215875293406890829839156897863742504615191361518281091302475904551111016\ -// ",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\ -// ",\"1\"],\"b\":[[\" -// 21419680064642047510915171723230639588631899775315750803416713283740137406807\ -// ",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\ -// "],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\ -// ",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\ -// "],[\"1\",\"0\"]],\"c\":[\" -// 7530826803702928198368421787278524256623871560746240215547076095911132653214\ -// ",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\ -// ",\"1\"]},\"issBase64Details\":{\"value\":\" -// yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\" -// headerBase64\":\" -// eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\ -// "}"; let len = proof_and_jwt.bytes().len(); -// println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); -// -// let zk_login_inputs = ZkLoginInputs::from_json( -// &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// -// let content: JWK = JWK { -// kty: "RSA".to_string(), -// e: "AQAB".to_string(), -// n: "oUriU8GqbRw-avcMn95DGW1cpZR1IoM6L7krfrWvLSSCcSX6Ig117o25Yk7QWBiJpaPV0FbP7Y5-DmThZ3SaF0AXW-3BsKPEXfFfeKVc6vBqk3t5mKlNEowjdvNTSzoOXO5UIHwsXaxiJlbMRalaFEUm-2CKgmXl1ss_yGh1OHkfnBiGsfQUndKoHiZuDzBMGw8Sf67am_Ok-4FShK0NuR3-q33aB_3Z7obC71dejSLWFOEcKUVCaw6DGVuLog3x506h1QQ1r0FXKOQxnmqrRgpoHqGSouuG35oZve1vgCU4vLZ6EAgBAbC0KL35I7_0wUDSMpiAvf7iZxzJVbspkQ".to_string(), -// alg: "RS256".to_string(), -// }; -// -// let mut all_jwk = HashMap::new(); -// all_jwk.insert( -// JwkId::new( -// OIDCProvider::Google.get_config().iss, -// "6f7254101f56e41cf35c9926de84a2d552b4c6f1".to_string(), -// ), -// content, -// ); -// -// let (iss, kid) = (zk_login_inputs.get_iss().to_string(), -// zk_login_inputs.get_kid().to_string()); let jwk = all_jwk -// .get(&JwkId::new(iss.clone(), kid.clone())) -// .ok_or_else(|| { -// ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) -// }).unwrap(); -// -// let max_epoch = 10; -// -// Decode modulus to bytes. -// let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { -// ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) -// }).unwrap(); -// -// let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); -// let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, -// &modulus, max_epoch).unwrap()]; -// -// let mut proof_as_bytes = vec![]; -// proof.serialize_compressed(&mut proof_as_bytes).unwrap(); -// println!("proof_as_bytes : {:?}", proof_as_bytes); -// -// let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); -// -// let mut public_inputs_as_bytes = vec![]; -// public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); -// println!("public_inputs_as_bytes : {:?}", public_inputs_as_bytes); -// -// let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut -// 0).unwrap(); -// -// let verification_key_id: u32 = 1; -// -// let mut code = "PUSHREF \n".to_string(); -// code = code + "PUSHREF \n"; -// code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; -// code = code + "VERGRTH16"; -// -// ... run 'code', providing proof_cell, public_inputs_cell into stack.. -// } -// -// -// diff --git a/tvm_vm/Cargo.toml b/tvm_vm/Cargo.toml index 52caf6d2..848e4742 100644 --- a/tvm_vm/Cargo.toml +++ b/tvm_vm/Cargo.toml @@ -53,7 +53,7 @@ num-bigint = { version = "0.4", default-features = false, features = ["rand"] } #fastcrypto-zkp = "0.1.3" fastcrypto = "0.1.8" #only temporary -neptune = { version = "13.0.0", default_features = false } +neptune = { version = "13.0.0", default-features = false } once_cell = "1.16" schemars = "0.8.10" diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 53707bd5..1fe9af52 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -845,7 +845,7 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } -pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { +/*pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { let start = Instant::now(); engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16_NEW"))?; fetch_stack(engine, 3)?; @@ -892,7 +892,7 @@ pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { engine.cc.stack.push(res); Ok(()) -} +}*/ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let start = Instant::now(); diff --git a/tvm_vm/src/executor/zk_stuff/mod.rs b/tvm_vm/src/executor/zk_stuff/mod.rs index 6e3da482..2a857c18 100644 --- a/tvm_vm/src/executor/zk_stuff/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/mod.rs @@ -1,4 +1,4 @@ -use derive_more::From; +//use derive_more::From; use ff::PrimeField; // pub mod alphabet; @@ -17,5 +17,6 @@ pub mod zk_login; #[PrimeFieldReprEndianness = "big"] pub struct Fr([u64; 4]); -#[derive(Debug, From)] +/*#[derive(Debug, From)] pub struct VerifyingKey(pub(crate) ark_groth16::VerifyingKey); +*/ diff --git a/tvm_vm/src/executor/zk_stuff/zk_login.rs b/tvm_vm/src/executor/zk_stuff/zk_login.rs index 2b664c20..e25b20f4 100644 --- a/tvm_vm/src/executor/zk_stuff/zk_login.rs +++ b/tvm_vm/src/executor/zk_stuff/zk_login.rs @@ -28,15 +28,6 @@ use crate::executor::zk_stuff::error::ZkCryptoError; use crate::executor::zk_stuff::error::ZkCryptoResult; use crate::executor::zk_stuff::jwt_utils::JWTHeader; -//#[cfg(test)] -//#[path = "unit_tests/zk_login_tests.rs"] -// mod zk_login_tests; - -//#[cfg(feature = "e2e")] -//#[cfg(test)] -//#[path = "unit_tests/zk_login_e2e_tests.rs"] -// mod zk_login_e2e_tests; - pub const MAX_HEADER_LEN: u8 = 248; pub const PACK_WIDTH: u8 = 248; pub const ISS: &str = "iss"; From 73c974e9eab2451287c2d66baa2b775ab607253b Mon Sep 17 00:00:00 2001 From: sehor05 Date: Fri, 4 Oct 2024 12:29:46 +0300 Subject: [PATCH 05/19] fmt + version --- Cargo.lock | 437 ++++++++++++-- Cargo.toml | 2 +- tvm_tests/src/test_framework.rs | 71 +-- tvm_tests/src/test_zk.rs | 869 +++++++++++++++++----------- tvm_vm/src/executor/zk.rs | 99 ++-- tvm_vm/src/executor/zk_stuff/mod.rs | 8 +- 6 files changed, 1015 insertions(+), 471 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2df7236e..6adda91b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,17 @@ dependencies = [ "syn 2.0.79", ] +[[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.24.1" @@ -188,7 +199,7 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "api_derive" -version = "2.2.8" +version = "2.2.9" dependencies = [ "api_info", "proc-macro2", @@ -199,7 +210,7 @@ dependencies = [ [[package]] name = "api_info" -version = "2.2.8" +version = "2.2.9" dependencies = [ "serde", "serde_derive", @@ -208,7 +219,7 @@ dependencies = [ [[package]] name = "api_test" -version = "2.2.8" +version = "2.2.9" dependencies = [ "api_derive", "api_info", @@ -534,6 +545,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.2.0" @@ -741,6 +758,29 @@ dependencies = [ "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", + "ec-gpu", + "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" + [[package]] name = "bstr" version = "1.10.0" @@ -944,6 +984,18 @@ dependencies = [ "vec_map", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "textwrap 0.16.1", +] + [[package]] name = "clap" version = "4.5.19" @@ -962,7 +1014,7 @@ checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.1", + "clap_lex 0.7.2", "strsim 0.11.1", ] @@ -978,6 +1030,15 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.7.2" @@ -1398,7 +1459,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] @@ -1439,6 +1500,17 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468 0.6.0", + "zeroize", +] + [[package]] name = "der" version = "0.7.9" @@ -1481,7 +1553,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] @@ -1791,12 +1863,137 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "fastcrypto" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9ea2139faa96e4d713803b7777b8fd2d5c245858b1644c08d3220f407149c6" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-secp256r1", + "ark-serialize", + "auto_ops", + "base64ct", + "bech32", + "bincode", + "blake2", + "blst", + "bs58", + "curve25519-dalek-ng", + "derive_more", + "digest 0.10.7", + "ecdsa", + "ed25519-consensus", + "elliptic-curve", + "eyre", + "fastcrypto-derive", + "generic-array", + "hex", + "hex-literal", + "hkdf", + "lazy_static", + "num-bigint 0.4.6", + "once_cell", + "p256", + "rand 0.8.5", + "readonly", + "rfc6979", + "rsa", + "schemars", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3", + "signature 2.2.0", + "static_assertions", + "thiserror", + "tokio", + "typenum", + "zeroize", +] + +[[package]] +name = "fastcrypto-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0c2af2157f416cb885e11d36cd0de2753f6d5384752d364075c835f5f8f891" +dependencies = [ + "convert_case 0.6.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "fastcrypto-zkp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2510946ae11008ca0c5d11e8acf7168914bcc5cf5d770eae8c03ad3d1526872" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-groth16", + "ark-relations", + "ark-serialize", + "ark-snark", + "blst", + "byte-slice-cast", + "derive_more", + "fastcrypto", + "ff", + "im", + "itertools 0.12.1", + "lazy_static", + "neptune", + "num-bigint 0.4.6", + "once_cell", + "reqwest", + "schemars", + "serde", + "serde_json", + "typenum", +] + [[package]] name = "fastrand" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +[[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_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 = "fiat-crypto" version = "0.2.9" @@ -2042,7 +2239,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.6", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -2401,6 +2598,17 @@ dependencies = [ "web-sys", ] +[[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", + "serde", +] + [[package]] name = "indexmap" version = "2.5.0" @@ -2431,7 +2639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88" dependencies = [ "ahash", - "indexmap 2.2.6", + "indexmap 2.5.0", "is-terminal", "itoa", "log", @@ -2552,6 +2760,16 @@ version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libloading" version = "0.8.5" @@ -2776,6 +2994,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + [[package]] name = "memmap2" version = "0.9.5" @@ -3431,7 +3658,7 @@ dependencies = [ "once_cell", "parking_lot", "smallvec", - "symbolic-demangle 12.9.2", + "symbolic-demangle 12.12.0", "tempfile", "thiserror", ] @@ -3485,6 +3712,15 @@ dependencies = [ "yansi", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -3679,7 +3915,7 @@ checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] @@ -3953,6 +4189,30 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.79", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -4086,13 +4346,24 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "serde_json" version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "itoa", "memchr", "ryu", @@ -4156,7 +4427,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] @@ -4165,7 +4436,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -4207,6 +4478,16 @@ dependencies = [ "digest 0.10.7", ] +[[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" @@ -4379,6 +4660,24 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "symbolic-common" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b55cdc318ede251d0957f07afe5fed912119b8c1bc5a7804151826db999e737" +dependencies = [ + "debugid", + "memmap2 0.5.10", + "stable_deref_trait", + "uuid", +] + [[package]] name = "symbolic-common" version = "12.12.0" @@ -4386,11 +4685,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366f1b4c6baf6cfefc234bbd4899535fca0b06c74443039a73f6dfb2fad88d77" dependencies = [ "debugid", - "memmap2", + "memmap2 0.9.5", "stable_deref_trait", "uuid", ] +[[package]] +name = "symbolic-demangle" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79be897be8a483a81fff6a3a4e195b4ac838ef73ca42d348b3f722da9902e489" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common 10.2.1", +] + [[package]] name = "symbolic-demangle" version = "12.12.0" @@ -4399,7 +4709,7 @@ checksum = "aba05ba5b9962ea5617baf556293720a8b2d0a282aa14ee4bf10e22efc7da8c8" dependencies = [ "cpp_demangle", "rustc-demangle", - "symbolic-common", + "symbolic-common 12.12.0", ] [[package]] @@ -4766,7 +5076,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", @@ -4906,7 +5216,7 @@ dependencies = [ [[package]] name = "tvm_abi" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "chrono", @@ -4923,7 +5233,7 @@ dependencies = [ [[package]] name = "tvm_api" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "byteorder", @@ -4944,7 +5254,7 @@ dependencies = [ [[package]] name = "tvm_assembler" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "clap 4.5.19", @@ -4961,7 +5271,7 @@ dependencies = [ [[package]] name = "tvm_block" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "base64 0.21.7", @@ -4982,7 +5292,7 @@ dependencies = [ [[package]] name = "tvm_block_json" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "failure", @@ -5004,7 +5314,7 @@ dependencies = [ [[package]] name = "tvm_cli" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "assert_cmd", @@ -5046,7 +5356,7 @@ dependencies = [ [[package]] name = "tvm_client" -version = "2.2.8" +version = "2.2.9" dependencies = [ "aes", "anyhow", @@ -5115,7 +5425,7 @@ dependencies = [ [[package]] name = "tvm_client_processing" -version = "2.2.8" +version = "2.2.9" dependencies = [ "api_derive", "api_info", @@ -5135,7 +5445,7 @@ dependencies = [ [[package]] name = "tvm_common" -version = "2.2.8" +version = "2.2.9" dependencies = [ "external-ip", "failure", @@ -5148,7 +5458,7 @@ dependencies = [ [[package]] name = "tvm_debugger" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "base64 0.21.7", @@ -5165,7 +5475,7 @@ dependencies = [ [[package]] name = "tvm_executor" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "failure", @@ -5179,7 +5489,7 @@ dependencies = [ [[package]] name = "tvm_sdk" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "api_derive", @@ -5204,7 +5514,7 @@ dependencies = [ [[package]] name = "tvm_struct" -version = "2.2.8" +version = "2.2.9" dependencies = [ "failure", "hex-literal", @@ -5213,9 +5523,47 @@ dependencies = [ "tvm_types", ] +[[package]] +name = "tvm_tests" +version = "2.2.9" +dependencies = [ + "anyhow", + "ark-ff", + "ark-std", + "base64 0.13.1", + "base64ct", + "criterion 0.4.0", + "diffy 0.2.2", + "ed25519 1.5.3", + "ed25519-dalek 1.0.1", + "fastcrypto", + "fastcrypto-zkp", + "hex", + "lazy_static", + "libloading 0.6.7", + "log", + "log4rs", + "num", + "num-bigint 0.4.6", + "num-traits", + "pprof 0.11.1", + "pretty_assertions", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "similar", + "tvm_assembler", + "tvm_block", + "tvm_types", + "tvm_vm", + "zstd 0.11.2+zstd.1.5.2", +] + [[package]] name = "tvm_tl_codegen" -version = "2.2.8" +version = "2.2.9" dependencies = [ "crc 1.8.1", "failure", @@ -5229,7 +5577,7 @@ dependencies = [ [[package]] name = "tvm_types" -version = "2.2.8" +version = "2.2.9" dependencies = [ "aes-ctr", "anyhow", @@ -5260,7 +5608,7 @@ dependencies = [ [[package]] name = "tvm_vm" -version = "2.2.8" +version = "2.2.9" dependencies = [ "anyhow", "ark-bls12-381", @@ -5289,7 +5637,7 @@ dependencies = [ "hex", "itertools 0.12.1", "lazy_static", - "libloading 0.8.4", + "libloading 0.8.5", "log", "log4rs", "neptune", @@ -5397,7 +5745,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "update_trusted_blocks" -version = "2.2.8" +version = "2.2.9" dependencies = [ "bincode", "serde", @@ -5932,13 +6280,32 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.1", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 28ad1564..48ab43b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ "tvm_tests" ] [workspace.package] -version = "2.2.8" +version = "2.2.9" rust-version = "1.76.0" authors = ["TVM Labs "] diff --git a/tvm_tests/src/test_framework.rs b/tvm_tests/src/test_framework.rs index 868438d7..ef362a23 100644 --- a/tvm_tests/src/test_framework.rs +++ b/tvm_tests/src/test_framework.rs @@ -72,25 +72,26 @@ fn logger_init() { return; } let log_level = log::LevelFilter::Info; - /*if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { log::LevelFilter::Info };*/ + // if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { + // log::LevelFilter::Info }; let encoder_boxed = Box::new(log4rs::encode::pattern::PatternEncoder::new("{m}")); - /*let config = if cfg!(feature = "log_file") { - let file = log4rs::append::file::FileAppender::builder() - .encoder(encoder_boxed) - .build("log/log.txt") - .unwrap(); - log4rs::config::Config::builder() - .appender(log4rs::config::Appender::builder().build("file", Box::new(file))) - .build(log4rs::config::Root::builder().appender("file").build(log_level)) - .unwrap() - } else { - let console = - log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed).build(); - log4rs::config::Config::builder() - .appender(log4rs::config::Appender::builder().build("console", Box::new(console))) - .build(log4rs::config::Root::builder().appender("console").build(log_level)) - .unwrap() - };*/ + // let config = if cfg!(feature = "log_file") { + // let file = log4rs::append::file::FileAppender::builder() + // .encoder(encoder_boxed) + // .build("log/log.txt") + // .unwrap(); + // log4rs::config::Config::builder() + // .appender(log4rs::config::Appender::builder().build("file", Box::new(file))) + // .build(log4rs::config::Root::builder().appender("file").build(log_level)) + // .unwrap() + // } else { + // let console = + // log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed). + // build(); log4rs::config::Config::builder() + // .appender(log4rs::config::Appender::builder().build("console", + // Box::new(console))) .build(log4rs::config::Root::builder().appender(" + // console").build(log_level)) .unwrap() + // }; let config = { let console = log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed).build(); @@ -444,21 +445,21 @@ impl TestCase { executor.set_index_provider(index_provider) } let execution_result = executor.execute(); - /*if cfg!(feature = "fift_check") - && args.stack.is_empty() - && args.ctrls.is_empty() - && !args.skip_fift_check - { - let gas = args.gas.map(|gas| gas.get_gas_remaining() as i32).unwrap_or(1000000); - compare_with_fift( - code, - args.library, - args.code, - &executor, - &execution_result, - gas, - ) - }*/ + // if cfg!(feature = "fift_check") + // && args.stack.is_empty() + // && args.ctrls.is_empty() + // && !args.skip_fift_check + // { + // let gas = args.gas.map(|gas| gas.get_gas_remaining() as + // i32).unwrap_or(1000000); compare_with_fift( + // code, + // args.library, + // args.code, + // &executor, + // &execution_result, + // gas, + // ) + // } TestCase { executor: Some(executor), @@ -489,7 +490,9 @@ impl TestCase { vec![library.clone()], ); let execution_result = executor.execute(); - if /*cfg!(feature = "fift_check") &&*/ stack.is_none() && ctrls.is_none() { + if + // cfg!(feature = "fift_check") && + stack.is_none() && ctrls.is_none() { compare_with_fift( code.clone(), library, diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index 1f5809db..d7c0dbc2 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -1,47 +1,46 @@ #[cfg(test)] mod tests { - use num_traits::Zero; - use std::iter::repeat; - use std::collections::HashMap; - + use std::iter::repeat; use std::str::FromStr; use std::time::Instant; + + use ark_ff::biginteger::BigInteger; use ark_std::rand::rngs::StdRng; use ark_std::rand::SeedableRng; - use base64ct::Encoding as bEncoding; - use fastcrypto::ed25519::Ed25519KeyPair; use base64::decode; - use ark_ff::biginteger::BigInteger; + use base64ct::Encoding as bEncoding; use ed25519::signature::Signer; - - use fastcrypto::traits::{KeyPair, ToFromBytes}; - - - /*#[cfg(feature = "signature_no_check")]*/ - // use ton_vm::executor::BehaviorModifiers; - use tvm_vm::{ - int, - stack::{ - integer::{ - IntegerData, - }, - Stack, StackItem, - }, - utils::{pack_string_to_cell, pack_data_to_cell}, - }; - - use tvm_vm::executor::zk_stuff::error::ZkCryptoError; - use tvm_types::{BuilderData, Cell, SliceData}; - use fastcrypto_zkp::bn254::zk_login::{CanonicalSerialize, JWK, JwkId, OIDCProvider, ZkLoginInputs}; - use fastcrypto_zkp::bn254::utils::{gen_address_seed, get_zk_login_address}; + use fastcrypto::ed25519::Ed25519KeyPair; + use fastcrypto::traits::KeyPair; + use fastcrypto::traits::ToFromBytes; + use fastcrypto_zkp::bn254::utils::gen_address_seed; + use fastcrypto_zkp::bn254::utils::get_zk_login_address; + use fastcrypto_zkp::bn254::zk_login::CanonicalSerialize; + use fastcrypto_zkp::bn254::zk_login::JwkId; + use fastcrypto_zkp::bn254::zk_login::OIDCProvider; + use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs; + use fastcrypto_zkp::bn254::zk_login::JWK; use fastcrypto_zkp::zk_login_utils::Bn254FrElement; use num_bigint::BigUint; - - use serde::{Deserialize}; + use num_traits::Zero; + use serde::Deserialize; use serde_derive::Serialize; use serde_json::Value; - use crate::test_framework::{Expects, test_case_with_refs}; + use tvm_types::BuilderData; + use tvm_types::Cell; + use tvm_types::SliceData; + use tvm_vm::executor::zk_stuff::error::ZkCryptoError; + // #[cfg(feature = "signature_no_check")] + // use ton_vm::executor::BehaviorModifiers; + use tvm_vm::{ + int, + stack::{integer::IntegerData, Stack, StackItem}, + utils::{pack_data_to_cell, pack_string_to_cell}, + }; + + use crate::test_framework::test_case_with_refs; + use crate::test_framework::Expects; pub const SUI_DATA_FROM_REACT_1: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJ4bW5KVzMxcnV6S01HaXIwMVlQR1lMMHhEWSIsIm5iZiI6MTcxNTY4NzAzNiwiaWF0IjoxNzE1Njg3MzM2LCJleHAiOjE3MTU2OTA5MzYsImp0aSI6IjliNjAxZDI1ZjAwMzY0MGMyODg5YTJhMDQ3Nzg5MzgyY2IxY2ZlODcifQ.rTa9KA9HoYm04Agj71D0kDkvsCZ35SeeihBGbABYckBRxaUlCy6LQ-sEaVOTgvnL_DgVn7hx8g3sSmnhJ9kHzj5e6gtUoxoWAe8PuGyK2bmqhmPrQMeEps9f6m2EToQCIA_Id4fGCjSCktjJBi47QHT_Dhe6isHdKk1pgSshOyvCF1VjIvyyeGY5iWQ4cIRBMQNlNBT11o6T01SY6B9DtiiFN_0-ok5taIjQgtMNG6Cwr3tCnqXftuGGQrHlx15y8VgCPODYi-wOtvUbzI2yfx53PmRD_L8O50cMNCrCRE3yYR5MNOu1LlQ_EACy5UFsCJR35xRz84nv-6Iyrufx1g\",\"user_pass_to_int_format\":\"981021191041055255531141165751\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":155,\"1\":147,\"2\":37,\"3\":82,\"4\":183,\"5\":109,\"6\":227,\"7\":144,\"8\":85,\"9\":248,\"10\":20,\"11\":45,\"12\":92,\"13\":103,\"14\":160,\"15\":221,\"16\":101,\"17\":44,\"18\":30,\"19\":86,\"20\":96,\"21\":85,\"22\":24,\"23\":224,\"24\":106,\"25\":63,\"26\":13,\"27\":130,\"28\":8,\"29\":119,\"30\":247,\"31\":67},\"secret_key\":{\"0\":192,\"1\":16,\"2\":35,\"3\":54,\"4\":100,\"5\":14,\"6\":88,\"7\":217,\"8\":164,\"9\":21,\"10\":154,\"11\":233,\"12\":248,\"13\":208,\"14\":188,\"15\":4,\"16\":52,\"17\":244,\"18\":125,\"19\":103,\"20\":99,\"21\":26,\"22\":225,\"23\":60,\"24\":140,\"25\":75,\"26\":228,\"27\":157,\"28\":137,\"29\":220,\"30\":1,\"31\":65,\"32\":155,\"33\":147,\"34\":37,\"35\":82,\"36\":183,\"37\":109,\"38\":227,\"39\":144,\"40\":85,\"41\":248,\"42\":20,\"43\":45,\"44\":92,\"45\":103,\"46\":160,\"47\":221,\"48\":101,\"49\":44,\"50\":30,\"51\":86,\"52\":96,\"53\":85,\"54\":24,\"55\":224,\"56\":106,\"57\":63,\"58\":13,\"59\":130,\"60\":8,\"61\":119,\"62\":247,\"63\":67}}},\"zk_addr\":\"0x290623ea2fe67e77502c931e015e910720b59cf99994bfe872da851245a6adb8\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"4240296169193969312736577528388333411353554120022978085193148043577551744781\",\"5805161066003598301896048908428560240907086333477483881772048922050706263054\",\"1\"],\"b\":[[\"12834391737669124973917765536412427456985620342194191639017091262766903638891\",\"17565396762846717347409742387259908749145765976354144805005547481529916658455\"],[\"10704310067924910937030159163683742097178285875135929496314190235513445131794\",\"5158907077493606386023392148737817037260820737072162547798816810512684527243\"],[\"1\",\"0\"]],\"c\":[\"1422540522119231707130773229384414857146368773886805969586218853559909475064\",\"8843079196273712399340537238369227864378150337693574970239878271571912585171\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AJuTJVK3beOQVfgULVxnoN1lLB5WYFUY4Go/DYIId/dD\"}"; pub const SUI_DATA_FROM_REACT_2: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6IjJKd0VMbjJfUV9Rd0VsTC1rWTFPRnFqdXZCMCIsIm5iZiI6MTcxNTY4NzAyOSwiaWF0IjoxNzE1Njg3MzI5LCJleHAiOjE3MTU2OTA5MjksImp0aSI6ImU2YjM1ZjJmNmFkNjIzOWEwMDAxMTJiMWI5YWI2MWQ0MjRkMGM1OTIifQ.QcrEDE9qmPZKX83nU3Tx2BN8fsinb_mmXkO1Qf7Uv1QTd0NjirSeu7C4Vn9WDNWDaIR-BgCfhOlkwMQPljcahqC4AN43N_66tvbEsXjtEdFejslXrGG4D_BEKvtmD7_WkW388LyU2PxKgtdDfpYFgmuT6wTM2TO5dTbrGrDyn88q3pkPfefC5a8Wi1V6zECfFdSV-pKQlxtPaImi7s3CKAUMDu1n-jcT-Ho2aTgrWKAzhXE56tgEWOpXQO06eJsWCSOqoZSLYtatTrZr4d38U7QRQiNlH-ydHv4zXt1tixLLJ0wvPx-dQaCnCl1kW1orYkJGFfHgjx6A9z5Ol4afuw\",\"user_pass_to_int_format\":\"101119106102103\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":194,\"1\":38,\"2\":203,\"3\":255,\"4\":219,\"5\":127,\"6\":105,\"7\":129,\"8\":234,\"9\":222,\"10\":71,\"11\":169,\"12\":108,\"13\":94,\"14\":28,\"15\":48,\"16\":111,\"17\":221,\"18\":113,\"19\":110,\"20\":5,\"21\":226,\"22\":19,\"23\":230,\"24\":232,\"25\":67,\"26\":255,\"27\":179,\"28\":6,\"29\":10,\"30\":209,\"31\":63},\"secret_key\":{\"0\":44,\"1\":32,\"2\":251,\"3\":184,\"4\":109,\"5\":252,\"6\":105,\"7\":67,\"8\":208,\"9\":111,\"10\":86,\"11\":214,\"12\":192,\"13\":135,\"14\":169,\"15\":48,\"16\":162,\"17\":36,\"18\":216,\"19\":145,\"20\":232,\"21\":64,\"22\":17,\"23\":14,\"24\":29,\"25\":56,\"26\":39,\"27\":118,\"28\":143,\"29\":250,\"30\":31,\"31\":66,\"32\":194,\"33\":38,\"34\":203,\"35\":255,\"36\":219,\"37\":127,\"38\":105,\"39\":129,\"40\":234,\"41\":222,\"42\":71,\"43\":169,\"44\":108,\"45\":94,\"46\":28,\"47\":48,\"48\":111,\"49\":221,\"50\":113,\"51\":110,\"52\":5,\"53\":226,\"54\":19,\"55\":230,\"56\":232,\"57\":67,\"58\":255,\"59\":179,\"60\":6,\"61\":10,\"62\":209,\"63\":63}}},\"zk_addr\":\"0x9d28c04a423b33d6901065b2e23440d80c963e2d8cf60619aed131cf302a3345\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"10113442204684515220664612836724727112601024759319365467272456423129044788607\",\"1622056145268645528934658046911045406324940175278473377024147189407527440953\",\"1\"],\"b\":[[\"16638441944380099215425740101953753038808466958852552979180365845498468757656\",\"15160836857346434734063515954042830497610079883703780011464867547889770445695\"],[\"18562910453341688699790780964434211467815845944672185772065803860963710445937\",\"8200691834141582017549140597895023392490964486044036655696113278873832146838\"],[\"1\",\"0\"]],\"c\":[\"4229037146526046139176767312447148765936834700862335953317784850097077554287\",\"14155516063621997063825085002662503289554536312724791903045026922766401869119\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AMImy//bf2mB6t5HqWxeHDBv3XFuBeIT5uhD/7MGCtE/\"}"; @@ -65,7 +64,7 @@ mod tests { pub const SUI_DATA_FROM_REACT_20: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJlMTgtZlBDdV9ZRndybE43TDhKV1BHX3hFbyIsIm5iZiI6MTcxNTY4NjgzMSwiaWF0IjoxNzE1Njg3MTMxLCJleHAiOjE3MTU2OTA3MzEsImp0aSI6IjdmZTFkZTM5NDVkMjliYTBhOWQ4MGFlODZiZGRmNjkyMDE1N2RlMDcifQ.RMM8wIiEzZ97DVdngkDhKapTMZq-R7woI2yjclLqTgnYZKTZ5N9y67zFJLDfcg017VyyRK18OS1OLsnUgnphi3ULotImnJ2292VDBd7kxhyq9QAqfHVDK2-MYNlJXy53UIr2xS9td1aoHUDZkvBy690IhV4nPrxLOUhI8c4gAvpkfHFmAvxYuQoUu69c_hSzREhrVOa979t5nZuJjNWwUcwgD40To1DM6Dxwy186basvY4AyWPHcI4ARFoyPEMRFUOtO05fUrwUH8O63Ay6K1DwxaLXDzx4T7O9X9nlrCj2uROdahsv-Dj24hruudSYxi4GH2uO6u0a1RlTIvWJ-1A\",\"user_pass_to_int_format\":\"525451525655\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":66,\"1\":155,\"2\":237,\"3\":117,\"4\":45,\"5\":166,\"6\":245,\"7\":92,\"8\":78,\"9\":225,\"10\":218,\"11\":156,\"12\":7,\"13\":132,\"14\":164,\"15\":47,\"16\":114,\"17\":174,\"18\":4,\"19\":86,\"20\":18,\"21\":212,\"22\":182,\"23\":62,\"24\":50,\"25\":219,\"26\":104,\"27\":185,\"28\":183,\"29\":108,\"30\":38,\"31\":252},\"secret_key\":{\"0\":13,\"1\":127,\"2\":13,\"3\":29,\"4\":128,\"5\":121,\"6\":142,\"7\":51,\"8\":210,\"9\":28,\"10\":131,\"11\":160,\"12\":209,\"13\":42,\"14\":214,\"15\":198,\"16\":137,\"17\":147,\"18\":155,\"19\":40,\"20\":86,\"21\":167,\"22\":168,\"23\":10,\"24\":249,\"25\":180,\"26\":188,\"27\":132,\"28\":41,\"29\":146,\"30\":192,\"31\":28,\"32\":66,\"33\":155,\"34\":237,\"35\":117,\"36\":45,\"37\":166,\"38\":245,\"39\":92,\"40\":78,\"41\":225,\"42\":218,\"43\":156,\"44\":7,\"45\":132,\"46\":164,\"47\":47,\"48\":114,\"49\":174,\"50\":4,\"51\":86,\"52\":18,\"53\":212,\"54\":182,\"55\":62,\"56\":50,\"57\":219,\"58\":104,\"59\":185,\"60\":183,\"61\":108,\"62\":38,\"63\":252}}},\"zk_addr\":\"0x86ab13e3c90b7f5b52a0e7d045425f1a5ce4f2938d82fe32013b5c5dffc8aa40\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"13280060882937967421268531103181473070897547065707830941266439167277535861998\",\"9934433138500558951890280258062370504217382435917636186873727481367280202864\",\"1\"],\"b\":[[\"3838124130316726849360987686807592227651253623250263168834039482151640975443\",\"10050190797101422174255450354163308725608018844614813729840170282126147936409\"],[\"18360080471111693027482741715722945557865825591442098780536696036281663618095\",\"1378964582828950987975075563637558653759765511530268169302574447782691787466\"],[\"1\",\"0\"]],\"c\":[\"1373142722414479432483215105546507593017308819682036641663292686387425172376\",\"3353210342014729825799146687716012229927760750084040417279416030868174996451\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AEKb7XUtpvVcTuHanAeEpC9yrgRWEtS2PjLbaLm3bCb8\"}"; pub const SUI_DATA_FROM_REACT_21: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Im12NUNKY1dsMXE1ek03Y0lyR1ZUdHF6SnFTNCIsIm5iZiI6MTcxNTY4NjgxOSwiaWF0IjoxNzE1Njg3MTE5LCJleHAiOjE3MTU2OTA3MTksImp0aSI6IjYxMDM2YmQwZWE3YjI5MDY4MjgwODYxMzMyODZhODZlNmY0ZmMwNGEifQ.VE2a8s2ZuyTVklFwSvh05y_mGrDMJXww-5Pu3-UUIQi3sBQnMzpnvWo3MIb32rXxwU6Obtx9izsR-Csk-U0QH4WuseGHnhHA90lACdeXNXHUWNktsY62_z2lkseTlJQV_ccNVctNgqornxmtV6gRvihLKkYCJt08umhAcRe8-Fh9iNmlCf5sMngaA-k0bvIbdnxkoP0KI9em7sgpTDB0FJFCgVAVYkzQTuJJlfuKjeF0lgpLnkjTOtgMyCpuZrrxf9GH6wY2VSme3Zk6xVJfl5cC6YugQFs-t56CEhPDrm-LIlLTD9JuNAKctlRRaTmkTembZAzweu6Wqh322MDx1g\",\"user_pass_to_int_format\":\"100102100102100115106107\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":227,\"1\":142,\"2\":234,\"3\":83,\"4\":36,\"5\":125,\"6\":219,\"7\":233,\"8\":159,\"9\":30,\"10\":60,\"11\":195,\"12\":110,\"13\":130,\"14\":105,\"15\":107,\"16\":44,\"17\":46,\"18\":151,\"19\":154,\"20\":116,\"21\":131,\"22\":237,\"23\":231,\"24\":159,\"25\":119,\"26\":35,\"27\":130,\"28\":56,\"29\":90,\"30\":121,\"31\":26},\"secret_key\":{\"0\":34,\"1\":107,\"2\":197,\"3\":227,\"4\":209,\"5\":156,\"6\":36,\"7\":233,\"8\":231,\"9\":171,\"10\":100,\"11\":210,\"12\":113,\"13\":247,\"14\":59,\"15\":222,\"16\":214,\"17\":129,\"18\":238,\"19\":254,\"20\":13,\"21\":13,\"22\":3,\"23\":151,\"24\":9,\"25\":173,\"26\":77,\"27\":113,\"28\":126,\"29\":7,\"30\":203,\"31\":52,\"32\":227,\"33\":142,\"34\":234,\"35\":83,\"36\":36,\"37\":125,\"38\":219,\"39\":233,\"40\":159,\"41\":30,\"42\":60,\"43\":195,\"44\":110,\"45\":130,\"46\":105,\"47\":107,\"48\":44,\"49\":46,\"50\":151,\"51\":154,\"52\":116,\"53\":131,\"54\":237,\"55\":231,\"56\":159,\"57\":119,\"58\":35,\"59\":130,\"60\":56,\"61\":90,\"62\":121,\"63\":26}}},\"zk_addr\":\"0xb092062dc38ee15b239fedd8955547cae553068e350add6a186a900308ca1704\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"19083893384522082364200015848081882762611466511855277173108395395690822433582\",\"15765871630522826744343212165387977339454134778029147662517994756792436892191\",\"1\"],\"b\":[[\"3347275249816013439391836622904014049361323482158752310150932588414843416768\",\"9261935324040115069949005166058871304117632278716385673922763868694265924905\"],[\"10774327302040930015542399179222458502634829694095804484749135988841930351850\",\"409015645239595129631982791901837203813000443262394810220799589635024410401\"],[\"1\",\"0\"]],\"c\":[\"805618312212200473153836203801534856685701602304097276485035246177305246575\",\"12984127923817330198936709848850019846193356630613954592225359007088568774616\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AOOO6lMkfdvpnx48w26CaWssLpeadIPt5593I4I4Wnka\"}"; - //pub const VALUE_PORTION_SIZE: usize = 126; + // pub const VALUE_PORTION_SIZE: usize = 126; pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"user_pass_to_int_format\":\"9910010710611510499100106115107\",\"zk_addr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secret_key\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extended_ephemeral_public_key\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; @@ -137,22 +136,28 @@ mod tests { } #[test] - fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { //real data taken from our react app for zklogin tests + fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 - // in ascii 535455565748 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp" + // :1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial + // password was 567890 in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, + 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); let mut eph_pubkey = Vec::new(); - // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + // replace by Alina's data (ephemeral public key place to byte array ), depends + // on iteration eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", eph_pubkey); println!("len eph_pubkey: {:?}", eph_pubkey.len()); @@ -161,8 +166,9 @@ mod tests { println!("eph_pubkey_hex_number: {:?}", eph_pubkey_hex_number); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -189,11 +195,10 @@ mod tests { let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ\"}"; - println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -210,21 +215,26 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut public_inputs_as_bytes = vec![]; public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); @@ -237,7 +247,8 @@ mod tests { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + let iss_and_header_base64details_cell = + pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -252,10 +263,11 @@ mod tests { println!("code : {:?}", code); - test_case_with_refs(code.as_str(), vec![modulus_cell.clone(), iss_and_header_base64details_cell, zk_seed_cell]) - .expect_stack(Stack::new() - .push(StackItem::Cell(public_inputs_cell.clone())) - ); + test_case_with_refs( + code.as_str(), + vec![modulus_cell.clone(), iss_and_header_base64details_cell, zk_seed_cell], + ) + .expect_stack(Stack::new().push(StackItem::Cell(public_inputs_cell.clone()))); //.expect_success(); println!("====== Start VERGRTH16 ========"); @@ -269,14 +281,15 @@ mod tests { let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); let verification_key_id: u32 = 0; //valid key id - //let verification_key_id: u32 = 1; //invalid key id + // let verification_key_id: u32 = 1; //invalid key id let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] @@ -299,7 +312,8 @@ mod tests { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed: {}", zk_seed); @@ -310,8 +324,8 @@ mod tests { let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -329,35 +343,40 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); println!("modulus: {:?}", modulus); println!("modulus hex: {:?}", hex::encode(&modulus)); - let max_epoch = 10; - //let max_epoch = 142; + // let max_epoch = 142; println!("====== Start Poseidon ========"); let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + let iss_and_header_base64details_cell = + pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut + // 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -370,13 +389,17 @@ mod tests { code = code + &*"PUSHREF \n".to_string(); code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); - - test_case_with_refs(code.as_str(), vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell]).expect_success(); + test_case_with_refs( + code.as_str(), + vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell], + ) + .expect_success(); println!("====== Start Vergrth16 ========"); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -386,7 +409,7 @@ mod tests { let y1 = proof.a.y.0.to_bits_le(); let y2 = proof.a.y.0.to_bits_be(); - //let y_ = -y; + // let y_ = -y; println!("proof.a: {:?}", proof.a); @@ -408,7 +431,7 @@ mod tests { print!("{}", y2[i] as i32); } println!(""); - //println!("y_: {:?}", y_); + // println!("y_: {:?}", y_); let proof_cell = pack_data_to_cell(&proof_as_bytes, &mut 0).unwrap(); @@ -427,12 +450,13 @@ mod tests { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] fn test_eval_time_vrgrth16_new() { - //todo: later n must be extracted from 3d part of jwt + // todo: later n must be extracted from 3d part of jwt let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -440,13 +464,11 @@ mod tests { alg: "RS256".to_string(), }; - /* - { - "e": "AQAB", - "kty": "RSA", - "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" - } - */ + // { + // "e": "AQAB", + // "kty": "RSA", + // "n": "rv95jmy91hibD7cb_BCA25jv5HrX7WoqHv-fh8wrOR5aYcM8Kvsc3mbzs2w1vCUlMRv7NdEGVBEnOZ6tHvUzGLon4ythd5XsX-wTvAtIHPkyHdo5zGpTgATO9CEn78Y-f1E8By63ttv14kXe_RMjt5aKttK4yqqUyzWUexSs7pET2zWiigd0_bGhJGYYEJlEk_JsOBFvloIBaycMfDjK--kgqnlRA8SWUkP3pEJIAo9oHzmvX6uXZTEJK10a1YNj0JVR4wZY3k60NaUX-KCroreU85iYgnecyxSdL-trpKdkg0-2OYks-_2Isymu7jPX-uKVyi-zKyaok3N64mERRQ" + // } let mut all_jwk = HashMap::new(); all_jwk.insert( @@ -463,15 +485,16 @@ mod tests { println!("====================== Iter@ is {i} ========================="); // parse let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - //println!("{:?}", jwt_data); + // println!("{:?}", jwt_data); let user_pass_salt = jwt_data.user_pass_to_int_format.as_str(); println!("user_pass_salt is {user_pass_salt}"); - let eph_secret_key = secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); + let eph_secret_key = + secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("ephemeral secret_key is {:?}", eph_secret_key); @@ -486,16 +509,18 @@ mod tests { let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + // JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = + serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + // JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = + serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); println!("azp: {:?}", jwt_data_decoded2.azp); @@ -506,19 +531,21 @@ mod tests { println!("jti: {:?}", jwt_data_decoded2.jti); println!("nbf: {:?}", jwt_data_decoded2.nbf); - let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()) + .unwrap(); let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); println!("time_for_vergrth16 is {time_for_vergrth16}"); @@ -528,22 +555,28 @@ mod tests { } #[test] - fn test_vrgrth16_based_on_real_data_new() { //real data taken from our react app for zklogin tests + fn test_vrgrth16_based_on_real_data_new() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 - // in ascii 535455565748 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp" + // :1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial + // password was 567890 in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, + 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); let mut eph_pubkey = Vec::new(); //vec![0x00]; - // replace by Alina's data (ephemeral public key place to byte array ), depends on iteration + // replace by Alina's data (ephemeral public key place to byte array ), depends + // on iteration eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", eph_pubkey); println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); @@ -551,8 +584,9 @@ mod tests { println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -575,9 +609,11 @@ mod tests { let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid + // in this header is equal to one specified in line 143,... take kid from jwt if + // not equal let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -594,22 +630,27 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -626,14 +667,15 @@ mod tests { let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); let verification_key_id: u32 = 0; //valid key id - //let verification_key_id: u32 = 1; //invalid key id + // let verification_key_id: u32 = 1; //invalid key id let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] @@ -645,16 +687,18 @@ mod tests { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); - + ) + .unwrap(); let proof_and_jwt = "{\"proofPoints\":{\"a\":[\"8247215875293406890829839156897863742504615191361518281091302475904551111016\",\"6872980335748205979379321982220498484242209225765686471076081944034292159666\",\"1\"],\"b\":[[\"21419680064642047510915171723230639588631899775315750803416713283740137406807\",\"21566716915562037737681888858382287035712341650647439119820808127161946325890\"],[\"17867714710686394159919998503724240212517838710399045289784307078087926404555\",\"21812769875502013113255155836896615164559280911997219958031852239645061854221\"],[\"1\",\"0\"]],\"c\":[\"7530826803702928198368421787278524256623871560746240215547076095911132653214\",\"16244547936249959771862454850485726883972969173921727256151991751860694123976\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; - println!("proof_and_jwt: {}", proof_and_jwt); let zk_login_inputs = tvm_vm::executor::zk_stuff::zk_login::ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + &*proof_and_jwt, + &*zk_seed.to_string(), + ) + .unwrap(); println!("zk_login_inputs: {:?}", zk_login_inputs); @@ -692,8 +736,8 @@ mod tests { let iss_and_header_base64details = "\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyNjIwZDVlN2YxMzJiNTJhZmU4ODc1Y2RmMzc3NmMwNjQyNDlkMDQiLCJ0eXAiOiJKV1QifQ\""; println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -711,35 +755,42 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); println!("modulus: {:?}", modulus); println!("modulus hex: {:?}", hex::encode(&modulus)); - let max_epoch = 142; - //let max_epoch = 10; + // let max_epoch = 10; - let eph_pubkey = vec![131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63]; + let eph_pubkey = vec![ + 131, 177, 23, 68, 46, 252, 168, 4, 146, 173, 66, 45, 69, 248, 80, 87, 25, 27, 251, 212, + 143, 3, 173, 66, 156, 56, 155, 83, 21, 226, 161, 63, + ]; println!("eph_pubkey : {:?}", eph_pubkey); println!("eph_pubkey len : {:?}", eph_pubkey.len()); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -764,7 +815,8 @@ mod tests { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } #[test] @@ -786,7 +838,8 @@ mod tests { "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed: {}", zk_seed); @@ -797,8 +850,8 @@ mod tests { let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("iss_and_header_base64details: {}", iss_and_header_base64details); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -816,18 +869,22 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); println!("modulus: {:?}", modulus); @@ -837,9 +894,11 @@ mod tests { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + let iss_and_header_base64details_cell = + pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - //let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut 0).unwrap(); + // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut + // 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); @@ -854,18 +913,23 @@ mod tests { println!("code : {code}"); - test_case_with_refs(code.as_str(), vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell]).expect_success(); + test_case_with_refs( + code.as_str(), + vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell], + ) + .expect_success(); } - #[test] fn test_vrgrth16_and_chcksigns_comparison_based_on_fascrypto_data() { - println!("===================================== START VRGRTH16 TEST ====================================="); + println!( + "===================================== START VRGRTH16 TEST =====================================" + ); let user_pass_salt = "206703048842351542647799591018316385612"; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("eph_pubkey: {:?}", hex::encode(eph_pubkey.clone())); @@ -873,14 +937,16 @@ mod tests { println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", "106294049240999307923", "25769832374-famecqrhe2gkebt5fvqms2263046lj96.apps.googleusercontent.com", - ).unwrap(); + ) + .unwrap(); println!("zk_seed = {:?}", zk_seed); @@ -888,9 +954,8 @@ mod tests { let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); - + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { kty: "RSA".to_string(), @@ -908,23 +973,28 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); let max_epoch = 10; // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -947,70 +1017,79 @@ mod tests { code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); - + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); - println!("===================================== START CHKSIGNS TEST ====================================="); + println!( + "===================================== START CHKSIGNS TEST =====================================" + ); let pair = gen_keypair(); let binding = proof_cell.clone(); let first = binding.data(); - - /*let mut b = BuilderData::with_raw(first, len).unwrap();*/ + // let mut b = BuilderData::with_raw(first, len).unwrap(); let binding = public_inputs_cell.clone(); let second = binding.data(); - //b.append_raw(second, len); + // b.append_raw(second, len); let concatenated = [&first[..], &second[..]].concat(); println!("len concatenated = {}", concatenated.len()); - - //test cell with data and one not empty reference + // test cell with data and one not empty reference let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - //b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); - //let cell_hash = test_cell.repr_hash(); - //sign hash of data cell + // b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); + // let cell_hash = test_cell.repr_hash(); + // sign hash of data cell let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - //put signature to separate slice + // put signature to separate slice let len = signature.len() * 8; let signature = SliceData::from_raw(signature, len); - //put public key to integer + // put public key to integer let pub_key = BuilderData::with_raw( pair.public.to_bytes().to_vec(), ed25519_dalek::PUBLIC_KEY_LENGTH * 8, - ).unwrap(); + ) + .unwrap(); - //put hash to integer - //let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), 256).unwrap(); + // put hash to integer + // let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), + // 256).unwrap(); - test_case_with_refs(" + test_case_with_refs( + " PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) - .expect_stack(Stack::new().push(int!(-1))); + ", + vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], + ) + .expect_stack(Stack::new().push(int!(-1))); } - #[test] - fn test_vrgrth16_based_on_real_data() { //real data taken from our react app for zklogin tests + fn test_vrgrth16_based_on_real_data() { + // real data taken from our react app for zklogin tests // {"alg":"RS256","kid":"a3b762f871cdb3bae0044c649622fc1396eda3e3","typ":"JWT"} // {"iss":"https://accounts.google.com","azp":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com", - // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com","sub":"112897468626716626103", - // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp":1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} - // Initial password was 567890 - // in ascii 535455565748 + // "aud":"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent. + // com","sub":"112897468626716626103", + // "nonce":"sS2DydHu3Ihp8ZCWCA4nzD79e08","nbf":1715600156,"iat":1715600456,"exp" + // :1715604056,"jti":"27d9a159279fc60df664c6ce8cb149a4244e5dd5"} Initial + // password was 567890 in ascii 535455565748 let user_pass_salt = "535455565748"; // Alina's data (password in ascii ), should be different for iterations // Generate an ephemeral key pair. - let secret_key = [222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14]; + let secret_key = [ + 222, 248, 61, 101, 214, 199, 113, 189, 223, 94, 151, 140, 235, 182, 203, 46, 143, 162, + 166, 87, 162, 250, 176, 4, 29, 19, 42, 221, 116, 33, 178, 14, + ]; // Generate an ephemeral key pair. let ephemeral_kp = Ed25519KeyPair::from_bytes(&secret_key).unwrap(); //Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32])); @@ -1022,8 +1101,9 @@ mod tests { println!("len eph_pubkey: {:?}", len); // Get the zklogin seed. - //This stuff is a kind of bound between smart contract and email (some account) - //It will be stored in smart contract (must be added during contract deployment) + // This stuff is a kind of bound between smart contract and email (some + // account) It will be stored in smart contract (must be added during + // contract deployment) let zk_seed = gen_address_seed( user_pass_salt, "sub", @@ -1046,9 +1126,11 @@ mod tests { let len = proof_and_jwt.bytes().len(); println!(" proof_and_jwt_bytes len (in bytes) = {:?}", len); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt, &*zk_seed.to_string()).unwrap(); -// summary from 132 to 146 : need to parse jwt, see jwt header to check that kid in this header is equal to one specified in line 143,... take kid from jwt if not equal + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); + // summary from 132 to 146 : need to parse jwt, see jwt header to check that kid + // in this header is equal to one specified in line 143,... take kid from jwt if + // not equal let content: JWK = JWK { kty: "RSA".to_string(), e: "AQAB".to_string(), @@ -1065,22 +1147,27 @@ mod tests { content, ); - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -1098,17 +1185,17 @@ mod tests { let verification_key_id: u32 = 0; - //let verification_key_id: u32 = 1; + // let verification_key_id: u32 = 1; let mut code = "PUSHREF \n".to_string(); code = code + "PUSHREF \n"; code = code + "PUSHINT " + &*verification_key_id.to_string() + "\n"; code = code + "VERGRTH16"; - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); } - fn secret_key_from_integer_map(key_data: HashMap) -> Vec { let mut vec: Vec = Vec::new(); for i in 0..=31 { @@ -1136,13 +1223,11 @@ mod tests { } fn bits_to_decimal_and_reverse(bits: &str) -> Vec { - let byte_chunks: Vec<&str> = bits.as_bytes().chunks(8).map(|chunk| { - std::str::from_utf8(chunk).unwrap() - }).collect(); + let byte_chunks: Vec<&str> = + bits.as_bytes().chunks(8).map(|chunk| std::str::from_utf8(chunk).unwrap()).collect(); - let decimal_numbers: Vec = byte_chunks.iter() - .map(|byte| u8::from_str_radix(byte, 2).unwrap()) - .collect(); + let decimal_numbers: Vec = + byte_chunks.iter().map(|byte| u8::from_str_radix(byte, 2).unwrap()).collect(); decimal_numbers.into_iter().rev().collect() } @@ -1151,8 +1236,9 @@ mod tests { let mut binary_representation = pad_string_to_256(&to_binary_string(init_x)); let p: BigUint = BigUint::from_bytes_be(&[ - 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]); + 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, + ]); // Сравниваем y с p - y и меняем первый бит if y > &p - &y { @@ -1162,20 +1248,37 @@ mod tests { let reversed_byte_array = bits_to_decimal_and_reverse(&binary_representation); // Преобразуем массив байтов в hex-строку - let hex_string = reversed_byte_array.iter() - .map(|byte| format!("{:02x}", byte)) - .collect::(); + let hex_string = + reversed_byte_array.iter().map(|byte| format!("{:02x}", byte)).collect::(); hex_string } #[test] fn test_proof_stuff() { - let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 - , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 - , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + let sui_data = [ + SUI_DATA_FROM_REACT_1, + SUI_DATA_FROM_REACT_2, + SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, + SUI_DATA_FROM_REACT_5, + SUI_DATA_FROM_REACT_6, + SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, + SUI_DATA_FROM_REACT_9, + SUI_DATA_FROM_REACT_10, + SUI_DATA_FROM_REACT_11, + SUI_DATA_FROM_REACT_12, + SUI_DATA_FROM_REACT_13, + SUI_DATA_FROM_REACT_14, + SUI_DATA_FROM_REACT_15, + SUI_DATA_FROM_REACT_16, + SUI_DATA_FROM_REACT_17, + SUI_DATA_FROM_REACT_18, + SUI_DATA_FROM_REACT_19, + SUI_DATA_FROM_REACT_20, + SUI_DATA_FROM_REACT_21, + ]; for i in 0..sui_data.len() { let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); @@ -1199,8 +1302,9 @@ mod tests { let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + // JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = + serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); println!("alg: {:?}", jwt_data_decoded1.alg); println!("typ: {:?}", jwt_data_decoded1.typ); @@ -1209,23 +1313,27 @@ mod tests { let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + // JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = + serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()) + .unwrap(); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); @@ -1235,31 +1343,36 @@ mod tests { println!("proof_as_bytes len: {:?}", proof_as_bytes.len()); println!("----------------------------------"); - /////////// - let json_string = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - println!("json_string ={:?}", json_string);//jwt_data.zk_proofs); - + println!("json_string ={:?}", json_string); //jwt_data.zk_proofs); let data: Value = serde_json::from_str(&*json_string).unwrap(); println!("data = {:?}", data); let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let a_y = + BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10) + .unwrap(); println!("a_x = {:?}", a_x); println!("a_y = {:?}", a_y); let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let b1_y = BigUint::parse_bytes( + data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), + 10, + ) + .unwrap(); println!("b0_x = {:?}", b0_x); println!("b1_x = {:?}", b1_x); println!("b1_y = {:?}", b1_y); let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); + let c_y = + BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10) + .unwrap(); println!("c_x = {:?}", c_x); println!("c_y = {:?}", c_y); @@ -1279,40 +1392,58 @@ mod tests { println!("==================="); } - - /* println!("Serialized proof"); - let json_string = r#"{"proofPoints":{"a":["8247215875293406890829839156897863742504615191361518281091302475904551111016","6872980335748205979379321982220498484242209225765686471076081944034292159666","1"],"b":[["21419680064642047510915171723230639588631899775315750803416713283740137406807","21566716915562037737681888858382287035712341650647439119820808127161946325890"],["17867714710686394159919998503724240212517838710399045289784307078087926404555","21812769875502013113255155836896615164559280911997219958031852239645061854221"],["1","0"]],"c":["7530826803702928198368421787278524256623871560746240215547076095911132653214","16244547936249959771862454850485726883972969173921727256151991751860694123976","1"]},"issBase64Details":{"value":"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1},"headerBase64":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"}"#; - - // Парсинг JSON-строки - let data: Value = serde_json::from_str(json_string).unwrap(); - - let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - let b1_y = BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str().unwrap().as_bytes(), 10).unwrap(); - - let hex_ax = prepare_hex_representation(a_x, a_y); - let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); - let hex_b1x = prepare_hex_representation(b1_x, b1_y); - let hex_cx = prepare_hex_representation(c_x, c_y); - - let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); - - // ????? ??????????? - println!("Serialized proof: {}", result); - println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); - */ + // println!("Serialized proof"); + // let json_string = + // r#"{"proofPoints":{"a":[" + // 8247215875293406890829839156897863742504615191361518281091302475904551111016" + // ,"6872980335748205979379321982220498484242209225765686471076081944034292159666" + // ,"1"],"b":[[" + // 21419680064642047510915171723230639588631899775315750803416713283740137406807" + // ,"21566716915562037737681888858382287035712341650647439119820808127161946325890" + // ],["17867714710686394159919998503724240212517838710399045289784307078087926404555" + // ,"21812769875502013113255155836896615164559280911997219958031852239645061854221" + // ],["1","0"]],"c":[" + // 7530826803702928198368421787278524256623871560746240215547076095911132653214" + // ,"16244547936249959771862454850485726883972969173921727256151991751860694123976" + // ,"1"]},"issBase64Details":{"value":" + // yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1}," + // headerBase64":" + // eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ" + // }"#; + // + // Парсинг JSON-строки + // let data: Value = serde_json::from_str(json_string).unwrap(); + // + // let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); + // let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str(). + // unwrap().as_bytes(), 10).unwrap(); + // + // let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); + // let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); + // let b1_y = + // BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str(). + // unwrap().as_bytes(), 10).unwrap(); + // + // let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); + // let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str(). + // unwrap().as_bytes(), 10).unwrap(); + // + // let hex_ax = prepare_hex_representation(a_x, a_y); + // let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); + // let hex_b1x = prepare_hex_representation(b1_x, b1_y); + // let hex_cx = prepare_hex_representation(c_x, c_y); + // + // let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); + // + // ????? ??????????? + // println!("Serialized proof: {}", result); + // println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); } #[ignore] #[test] fn test_eval_time_vrgrth16() { - //todo: later n must be extracted from 3d part of jwt + // todo: later n must be extracted from 3d part of jwt let content: JWK = JWK { kty: "RSA".to_string(), @@ -1330,12 +1461,30 @@ mod tests { content, ); - //let sui_data = [SUI_DATA_FROM_REACT_1]; - let sui_data = [SUI_DATA_FROM_REACT_1, SUI_DATA_FROM_REACT_2, SUI_DATA_FROM_REACT_3, - SUI_DATA_FROM_REACT_4, SUI_DATA_FROM_REACT_5, SUI_DATA_FROM_REACT_6, SUI_DATA_FROM_REACT_7, - SUI_DATA_FROM_REACT_8, SUI_DATA_FROM_REACT_9, SUI_DATA_FROM_REACT_10, SUI_DATA_FROM_REACT_11, SUI_DATA_FROM_REACT_12 - , SUI_DATA_FROM_REACT_13, SUI_DATA_FROM_REACT_14, SUI_DATA_FROM_REACT_15, SUI_DATA_FROM_REACT_16 - , SUI_DATA_FROM_REACT_17, SUI_DATA_FROM_REACT_18, SUI_DATA_FROM_REACT_19, SUI_DATA_FROM_REACT_20, SUI_DATA_FROM_REACT_21]; + // let sui_data = [SUI_DATA_FROM_REACT_1]; + let sui_data = [ + SUI_DATA_FROM_REACT_1, + SUI_DATA_FROM_REACT_2, + SUI_DATA_FROM_REACT_3, + SUI_DATA_FROM_REACT_4, + SUI_DATA_FROM_REACT_5, + SUI_DATA_FROM_REACT_6, + SUI_DATA_FROM_REACT_7, + SUI_DATA_FROM_REACT_8, + SUI_DATA_FROM_REACT_9, + SUI_DATA_FROM_REACT_10, + SUI_DATA_FROM_REACT_11, + SUI_DATA_FROM_REACT_12, + SUI_DATA_FROM_REACT_13, + SUI_DATA_FROM_REACT_14, + SUI_DATA_FROM_REACT_15, + SUI_DATA_FROM_REACT_16, + SUI_DATA_FROM_REACT_17, + SUI_DATA_FROM_REACT_18, + SUI_DATA_FROM_REACT_19, + SUI_DATA_FROM_REACT_20, + SUI_DATA_FROM_REACT_21, + ]; let mut sum_ratio: u128 = 0; @@ -1343,16 +1492,17 @@ mod tests { println!("====================== Iter@ is {i} ========================="); // parse let jwt_data: JwtData = serde_json::from_str(&sui_data[i]).unwrap(); - //println!("{:?}", jwt_data); + // println!("{:?}", jwt_data); let user_pass_salt = jwt_data.user_pass_to_int_format.as_str(); println!("user_pass_salt is {user_pass_salt}"); println!("{:?}", jwt_data.ephemeral_key_pair.keypair.public_key); - let eph_secret_key = secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); + let eph_secret_key = + secret_key_from_integer_map(jwt_data.ephemeral_key_pair.keypair.secret_key); let ephemeral_kp = Ed25519KeyPair::from_bytes(&eph_secret_key).unwrap(); - let mut eph_pubkey = Vec::new();//vec![0x00]; + let mut eph_pubkey = Vec::new(); //vec![0x00]; eph_pubkey.extend(ephemeral_kp.public().as_ref()); println!("ephemeral secret_key is {:?}", eph_secret_key); @@ -1361,36 +1511,39 @@ mod tests { let eph_pubkey_len = eph_pubkey.clone().len(); println!("len eph_pubkey: {:?}", eph_pubkey_len); - /*let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); - - let jwt_header = splitted_jwt_strings - .get(0) - .expect("split always returns at least one element"); - - let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( - "Could not find separator in jwt string.", - )).unwrap(); - - let decoded_jwt_header = base64::decode(jwt_header).unwrap(); - let decoded_jwt_body = base64::decode(jwt_body).unwrap(); - - let converted_jwt_header = String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); - let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 conversion failed"); - - let parsed_jwt_header = serde_json::from_str::(&converted_jwt_header).unwrap(); - let parsed_jwt_body = serde_json::from_str::(&converted_jwt_body).unwrap(); - - println!( - "{}", - serde_json::to_string_pretty(&parsed_jwt_header) - .expect("to_string_pretty always works on serde_json::Value") - ); - println!( - "{}", - serde_json::to_string_pretty(&parsed_jwt_body) - .expect("to_string_pretty always works on serde_json::Value") - );*/ - + // let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); + // + // let jwt_header = splitted_jwt_strings + // .get(0) + // .expect("split always returns at least one element"); + // + // let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( + // "Could not find separator in jwt string.", + // )).unwrap(); + // + // let decoded_jwt_header = base64::decode(jwt_header).unwrap(); + // let decoded_jwt_body = base64::decode(jwt_body).unwrap(); + // + // let converted_jwt_header = + // String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); + // let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 + // conversion failed"); + // + // let parsed_jwt_header = + // serde_json::from_str::(&converted_jwt_header).unwrap(); + // let parsed_jwt_body = + // serde_json::from_str::(&converted_jwt_body).unwrap(); + // + // println!( + // "{}", + // serde_json::to_string_pretty(&parsed_jwt_header) + // .expect("to_string_pretty always works on serde_json::Value") + // ); + // println!( + // "{}", + // serde_json::to_string_pretty(&parsed_jwt_body) + // .expect("to_string_pretty always works on serde_json::Value") + // ); let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); @@ -1398,50 +1551,54 @@ mod tests { let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); println!("jwt_string_1 is {:?}", jwt_string_1); // jwt_string_1 is "{\"alg\":\"RS256\",\"kid\":\"323b214ae6975a0f034ea77354dc0c25d03642dc\",\"typ\":\"JWT\"}" - //JwtDataDecodedPart1 - let jwt_data_decoded1: JwtDataDecodedPart1 = serde_json::from_str(&jwt_string_1).unwrap(); + // JwtDataDecodedPart1 + let jwt_data_decoded1: JwtDataDecodedPart1 = + serde_json::from_str(&jwt_string_1).unwrap(); println!("kid: {:?}", jwt_data_decoded1.kid); let jwt_data_2 = decode(jwt_data_vector[1]).expect("Base64 decoding failed"); let jwt_string_2 = String::from_utf8(jwt_data_2).expect("UTF-8 conversion failed"); println!("jwt_string_2 is {:?}", jwt_string_2); // "{\"iss\":\"https://accounts.google.com\",\"azp\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"aud\":\"232624085191-v1tq20fg1kdhhgvat6saj7jf0hd8233r.apps.googleusercontent.com\",\"sub\":\"112897468626716626103\",\"nonce\":\"bxmnJW31ruzKMGir01YPGYL0xDY\",\"nbf\":1715687036,\"iat\":1715687336,\"exp\":1715690936,\"jti\":\"9b601d25f003640c2889a2a047789382cb1cfe87\"}" - //JwtDataDecodedPart2 - let jwt_data_decoded2: JwtDataDecodedPart2 = serde_json::from_str(&jwt_string_2).unwrap(); + // JwtDataDecodedPart2 + let jwt_data_decoded2: JwtDataDecodedPart2 = + serde_json::from_str(&jwt_string_2).unwrap(); println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); + // let key = DecodingKey::from_secret(&[]); + // let mut validation = Validation::new(Algorithm::HS256); + // validation.insecure_disable_signature_validation(); - //let key = DecodingKey::from_secret(&[]); - //let mut validation = Validation::new(Algorithm::HS256); - //validation.insecure_disable_signature_validation(); - - //let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); - //let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion failed"); - //println!("jwt_string_3 is {:?}", jwt_string_3); - //JwtDataDecodedPart3 - //let jwt_data_decoded3: JwtDataDecodedPart3 = serde_json::from_str(&jwt_string_3).unwrap(); - + // let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); + // let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion + // failed"); println!("jwt_string_3 is {:?}", jwt_string_3); + // JwtDataDecodedPart3 + // let jwt_data_decoded3: JwtDataDecodedPart3 = + // serde_json::from_str(&jwt_string_3).unwrap(); - //let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; - //println!("{:?}", encode(&jwt_data_1)); - //let jwt_string_3 = String::from_utf8(&jwt_data_3); + // let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; + // println!("{:?}", encode(&jwt_data_1)); + // let jwt_string_3 = String::from_utf8(&jwt_data_3); - //let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; - //let n = jwt_v_3["n"]; + // let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; + // let n = jwt_v_3["n"]; let zk_seed = gen_address_seed( user_pass_salt, "sub", - jwt_data_decoded2.sub.as_str(), // Alina's data (stable id, fixed by gmail alina.t@gosh.sh) from jwt + jwt_data_decoded2.sub.as_str(), /* Alina's data (stable id, fixed by gmail + * alina.t@gosh.sh) from jwt */ jwt_data_decoded2.aud.as_str(), // Alina's data (fixed by app id ) from jwt - ).unwrap(); + ) + .unwrap(); println!("jwt_data.zk_proofs = {:?}", jwt_data.zk_proofs); let proof_and_jwt = serde_json::to_string(&jwt_data.zk_proofs).unwrap(); - let zk_login_inputs = ZkLoginInputs::from_json( - &*proof_and_jwt.to_string(), &*zk_seed.to_string()).unwrap(); + let zk_login_inputs = + ZkLoginInputs::from_json(&*proof_and_jwt.to_string(), &*zk_seed.to_string()) + .unwrap(); let time_for_vergrth16 = single_vrgrth16(&eph_pubkey, &zk_login_inputs, &all_jwk); let time_for_chcksgns = single_chcksgns(&eph_pubkey, &zk_login_inputs, &all_jwk); @@ -1451,7 +1608,7 @@ mod tests { let current_ratio = time_for_vergrth16 / time_for_chcksgns; println!("current_ratio is {current_ratio}"); - sum_ratio = sum_ratio + current_ratio;/**/ + sum_ratio = sum_ratio + current_ratio; /**/ println!("sum_ratio is {sum_ratio}"); println!("=========================================="); } @@ -1460,27 +1617,35 @@ mod tests { println!("average ratio is {average_ratio}"); } - fn prepare_proof_and_public_key_cells_for_stack(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> (Cell, Cell) { - let (iss, kid) = (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); + fn prepare_proof_and_public_key_cells_for_stack( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, + ) -> (Cell, Cell) { + let (iss, kid) = + (zk_login_inputs.get_iss().to_string(), zk_login_inputs.get_kid().to_string()); println!("kid = {}", kid); println!("all_jwk = {:?}", all_jwk); - let jwk = all_jwk .get(&JwkId::new(iss.clone(), kid.clone())) .ok_or_else(|| { ZkCryptoError::GeneralError(format!("JWK not found ({} - {})", iss, kid)) - }).unwrap(); + }) + .unwrap(); let max_epoch = 142; // data from the react test // Decode modulus to bytes. - let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n).map_err(|_| { - ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) - }).unwrap(); + let modulus = base64ct::Base64UrlUnpadded::decode_vec(&jwk.n) + .map_err(|_| { + ZkCryptoError::GeneralError("Invalid Base64 encoded jwk modulus".to_string()) + }) + .unwrap(); let proof = &zk_login_inputs.get_proof().as_arkworks().unwrap(); - let public_inputs = &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; + let public_inputs = + &[zk_login_inputs.calculate_all_inputs_hash(&eph_pubkey, &modulus, max_epoch).unwrap()]; let mut proof_as_bytes = vec![]; proof.serialize_compressed(&mut proof_as_bytes).unwrap(); @@ -1499,11 +1664,15 @@ mod tests { (proof_cell, public_inputs_cell) } + fn single_vrgrth16( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, + ) -> u128 { + let (proof_cell, public_inputs_cell) = + prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - fn single_vrgrth16(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { - let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - - //let verification_key_id: u32 = 2; + // let verification_key_id: u32 = 2; let verification_key_id: u32 = 0; let mut code = "PUSHREF \n".to_string(); @@ -1512,13 +1681,18 @@ mod tests { code = code + "VERGRTH16"; let start: Instant = Instant::now(); - test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]).expect_success(); + test_case_with_refs(code.as_str(), vec![proof_cell.clone(), public_inputs_cell.clone()]) + .expect_success(); start.elapsed().as_micros() } - - fn single_chcksgns(eph_pubkey: &Vec, zk_login_inputs: &ZkLoginInputs, all_jwk: &HashMap) -> u128 { - let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); + fn single_chcksgns( + eph_pubkey: &Vec, + zk_login_inputs: &ZkLoginInputs, + all_jwk: &HashMap, + ) -> u128 { + let (proof_cell, public_inputs_cell) = + prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); let pair = gen_keypair(); @@ -1533,32 +1707,29 @@ mod tests { let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); - //put signature to separate slice + // put signature to separate slice let len = signature.len() * 8; let signature = SliceData::from_raw(signature, len); - //put public key to integer + // put public key to integer let pub_key = BuilderData::with_raw( pair.public.to_bytes().to_vec(), ed25519_dalek::PUBLIC_KEY_LENGTH * 8, - ).unwrap(); + ) + .unwrap(); let start: Instant = Instant::now(); - test_case_with_refs(" + test_case_with_refs( + " PUSHREFSLICE PUSHREFSLICE PUSHREFSLICE PLDU 256 CHKSIGNS - ", vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()]) - .expect_stack(Stack::new().push(int!(-1))); + ", + vec![test_cell, signature.into_cell(), pub_key.into_cell().unwrap()], + ) + .expect_stack(Stack::new().push(int!(-1))); start.elapsed().as_micros() } } - - - - - - - diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 1fe9af52..143f55ba 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -845,54 +845,57 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } -/*pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { - let start = Instant::now(); - engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16_NEW"))?; - fetch_stack(engine, 3)?; - - let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; - println!("from vergrth16 vk_index: {:?}", vk_index); - - let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; - let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; - println!("from vergrth16 value public_inputs_as_bytes: {:?}", public_inputs_as_bytes); - - let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; - let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; - println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); - - let proof = ProofWrapper::deserialize(&proof_as_bytes)?; - let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; - let x: Vec = public_inputs.iter().map(|x| x.0).collect(); - - let vk = if vk_index == 0 { - insecure_pvk() - } else if vk_index == 1 { - global_pvk() - } else { - my_test_pvk_1() - }; - - // ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; - println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); - // todo: add alternative for elliptic curve (may be we need bls curve also?), - // read from stack curve id - let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) - .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); - - let duration = start.elapsed(); - - println!("Time elapsed by vergrth16 is: {:?}", duration); - - let succes = res.is_ok(); - println!("res: {:?}", res); - let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; - println!("res: {:?}", res); - - engine.cc.stack.push(res); - - Ok(()) -}*/ +// pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { +// let start = Instant::now(); +// engine.load_instruction(crate::executor::types::Instruction::new(" +// VERGRTH16_NEW"))?; fetch_stack(engine, 3)?; +// +// let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; +// println!("from vergrth16 vk_index: {:?}", vk_index); +// +// let public_inputs_slice = +// SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; +// let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, +// engine)?; println!("from vergrth16 value public_inputs_as_bytes: {:?}", +// public_inputs_as_bytes); +// +// let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; +// let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; +// println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); +// +// let proof = ProofWrapper::deserialize(&proof_as_bytes)?; +// let public_inputs = +// FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; +// let x: Vec = public_inputs.iter().map(|x| x.0).collect(); +// +// let vk = if vk_index == 0 { +// insecure_pvk() +// } else if vk_index == 1 { +// global_pvk() +// } else { +// my_test_pvk_1() +// }; +// +// ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; +// println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); +// todo: add alternative for elliptic curve (may be we need bls curve also?), +// read from stack curve id +// let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) +// .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); +// +// let duration = start.elapsed(); +// +// println!("Time elapsed by vergrth16 is: {:?}", duration); +// +// let succes = res.is_ok(); +// println!("res: {:?}", res); +// let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; +// println!("res: {:?}", res); +// +// engine.cc.stack.push(res); +// +// Ok(()) +// } pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let start = Instant::now(); diff --git a/tvm_vm/src/executor/zk_stuff/mod.rs b/tvm_vm/src/executor/zk_stuff/mod.rs index 2a857c18..bdf888a5 100644 --- a/tvm_vm/src/executor/zk_stuff/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/mod.rs @@ -1,4 +1,4 @@ -//use derive_more::From; +// use derive_more::From; use ff::PrimeField; // pub mod alphabet; @@ -17,6 +17,6 @@ pub mod zk_login; #[PrimeFieldReprEndianness = "big"] pub struct Fr([u64; 4]); -/*#[derive(Debug, From)] -pub struct VerifyingKey(pub(crate) ark_groth16::VerifyingKey); -*/ +// #[derive(Debug, From)] +// pub struct VerifyingKey(pub(crate) +// ark_groth16::VerifyingKey); From fd6133cb18ef36c05b4b2d2c38e5e1965b5d5df4 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 4 Oct 2024 14:44:28 +0300 Subject: [PATCH 06/19] remove commented not necessary stuff + update changelog --- CHANGELOG.md | 5 + tvm_vm/src/executor/zk.rs | 95 ------------ tvm_vm/src/executor/zk_stuff/bn254/api.rs | 7 - tvm_vm/src/executor/zk_stuff/bn254/mod.rs | 3 - .../executor/zk_stuff/bn254/poseidon/mod.rs | 141 ------------------ .../src/executor/zk_stuff/bn254/verifier.rs | 35 ----- tvm_vm/src/executor/zk_stuff/curve_utils.rs | 2 - tvm_vm/src/executor/zk_stuff/jwt_utils.rs | 2 - tvm_vm/src/executor/zk_stuff/utils.rs | 2 - 9 files changed, 5 insertions(+), 287 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fafe4a9..5c8fc6a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [2.2.98] – 2024-10-04 + +### New +- Add support of VERGRTH16 and POSEIDON instruction for zk-login. + ## [2.2.8] – 2024-08-19 ### Improved diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 143f55ba..75a887a7 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -566,101 +566,6 @@ fn global_pvk() -> PreparedVerifyingKey { } /////////////////////////////////// -// { -// "protocol": "groth16", -// "curve": "bn128", -// "nPublic": 1, -// "vk_alpha_1": [ -// "16083174311393072332126484955039141051820368387551336007741432494536231879877", -// "11995344593741129498206341608147577676708407993917230939676252851997423446210", -// "1" -// ], -// "vk_beta_2": [ -// [ -// "7017589137241388812217334676878160715759313595646525247042913539379033763831", -// "9588720105182136304988839277158105754318461657916765428451866781594135026063" -// ], -// [ -// "2484424409632768920146683103978991861859052149379216050446911519906662584090", -// "3390288516800701266276631045627865236740814264026178914799455551851945389106" -// ], -// [ -// "1", -// "0" -// ] -// ], -// "vk_gamma_2": [ -// [ -// "10857046999023057135944570762232829481370756359578518086990519993285655852781", -// "11559732032986387107991004021392285783925812861821192530917403151452391805634" -// ], -// [ -// "8495653923123431417604973247489272438418190587263600148770280649306958101930", -// "4082367875863433681332203403145435568316851327593401208105741076214120093531" -// ], -// [ -// "1", -// "0" -// ] -// ], -// "vk_delta_2": [ -// [ -// "10857046999023057135944570762232829481370756359578518086990519993285655852781", -// "11559732032986387107991004021392285783925812861821192530917403151452391805634" -// ], -// [ -// "8495653923123431417604973247489272438418190587263600148770280649306958101930", -// "4082367875863433681332203403145435568316851327593401208105741076214120093531" -// ], -// [ -// "1", -// "0" -// ] -// ], -// "vk_alphabeta_12": [ -// [ -// [ -// "21714733147969646607026510860825588717650100219981797829057062263408210680902", -// "3537008011880168200043686742311687201724399812943751195896776782786770376237" -// ], -// [ -// "17603627875319511470028150667626739231437882724082498094331281187463632527978", -// "16387102395026382896078557475195975755625086402782579280728310209714363840057" -// ], -// [ -// "10167039699419387719397961362130358913333446306472876910740079573026549091749", -// "6683396731874395214442048077624848369375657254618428851285341246028721012664" -// ] -// ], -// [ -// [ -// "12883624783449422144000099623629921455607648590216105687641263583110919278339", -// "9384401935718213548370561215738644696157076909382807246189505166565439193274" -// ], -// [ -// "11443428859064566845483530360939187689156386007731719272145725927626704316158", -// "534441300427034362842952165392761749478350428105140492258092586110074096069" -// ], -// [ -// "1626464416056203606908509147988281610862706785412523317944442421120459947696", -// "14642919198945900947469533820505010212370261142917394368657515679029120182987" -// ] -// ] -// ], -// "IC": [ -// [ -// "11760611693671517707466601638901224388668992590928868758649168369215563295744", -// "15842561259007247784907604255150260908812200067246900457940460682994649597353", -// "1" -// ], -// [ -// "9960247968913608540350443520882802417817484595360267448450266543686043480996", -// "11040490439713280236989540698814598402024610465375008410116396264618122562865", -// "1" -// ] -// ] -// } - /// Load a fixed verifying key from zkLogin.vkey output. This is based on a /// local setup and should not use in production. fn my_test_pvk_1() -> PreparedVerifyingKey { diff --git a/tvm_vm/src/executor/zk_stuff/bn254/api.rs b/tvm_vm/src/executor/zk_stuff/bn254/api.rs index 3e75317f..1bf3cb0e 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/api.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/api.rs @@ -1,16 +1,9 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; use crate::executor::zk_stuff::bn254::FieldElement; use crate::executor::zk_stuff::bn254::Proof; use crate::executor::zk_stuff::bn254::VerifyingKey; use crate::executor::zk_stuff::error::ZkCryptoError; -//#[cfg(test)] -//#[path = "unit_tests/api_tests.rs"] -// mod api_tests; - /// Size of scalars in the BN254 construction. pub const SCALAR_SIZE: usize = 32; diff --git a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs index 01f5ab5d..3d60a584 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs @@ -1,8 +1,5 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 #![warn(missing_docs, unreachable_pub)] #![deny(unused_must_use, missing_debug_implementations)] -//! Groth16 verifier over the BN254 elliptic curve construction. use ark_bn254::Bn254; use ark_bn254::Fr; diff --git a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs index dfc02fac..8433682b 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/poseidon/mod.rs @@ -1,6 +1,3 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - use std::cmp::Ordering; use ark_bn254::Fr; @@ -184,141 +181,3 @@ fn bn254_to_fr(fr: Fr) -> crate::executor::zk_stuff::Fr { crate::executor::zk_stuff::Fr::from_repr_vartime(FrRepr(bytes)) .expect("The bytes of fr are guaranteed to be canonical here") } -// #[cfg(test)] -// mod test { -// use crate::bn254::poseidon::poseidon_bytes; -// use crate::bn254::poseidon::{poseidon, poseidon_merkle_tree}; -// use crate::bn254::{poseidon::poseidon_zk_login, zk_login::Bn254Fr}; -// use ark_bn254::Fr; -// use ark_ff::{BigInteger, PrimeField}; -// use lazy_static::lazy_static; -// use proptest::arbitrary::Arbitrary; -// use proptest::collection; -// use std::str::FromStr; -// -// fn to_bigint_arr(vals: Vec) -> Vec { -// vals.into_iter().map(Bn254Fr::from).collect() -// } -// -// #[test] -// fn poseidon_test() { -// let input1 = -// Fr::from_str("134696963602902907403122104327765350261").unwrap(); let input2 -// = Fr::from_str("17932473587154777519561053972421347139").unwrap(); let input3 -// = Fr::from_str("10000").unwrap(); let input4 = Fr::from_str( -// "50683480294434968413708503290439057629605340925620961559740848568164438166", -// ) -// .unwrap(); -// let hash = poseidon(vec![input1, input2, input3, input4]).unwrap(); -// assert_eq!( -// hash, -// Fr::from_str( -// "2272550810841985018139126931041192927190568084082399473943239080305281957330" -// ) -// .unwrap() -// ); -// } -// #[test] -// fn test_to_poseidon_hash() { -// assert!(poseidon_merkle_tree(to_bigint_arr(vec![])).is_err()); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![1])) -// .unwrap() -// .to_string(), -// "18586133768512220936620570745912940619677854269274689475585506675881198879027" -// ); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![1, 2])) -// .unwrap() -// .to_string(), -// "7853200120776062878684798364095072458815029376092732009249414926327459813530" -// ); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![ -// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -// ])) -// .unwrap() -// .to_string(), -// "4203130618016961831408770638653325366880478848856764494148034853759773445968" -// ); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![ -// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 -// ])) -// .unwrap() -// .to_string(), -// "9989051620750914585850546081941653841776809718687451684622678807385399211877" -// ); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![ -// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, -// 22, 23, 24, 25, 26, 27, 28, 29 -// ])) -// .unwrap() -// .to_string(), -// "4123755143677678663754455867798672266093104048057302051129414708339780424023" -// ); -// assert_eq!( -// poseidon_merkle_tree(to_bigint_arr(vec![ -// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, -// 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 -// ])) -// .unwrap() -// .to_string(), -// "15368023340287843142129781602124963668572853984788169144128906033251913623349" -// ); -// assert!(poseidon_zk_login(to_bigint_arr(vec![ -// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, -// 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 -// ])) -// .is_err()); -// } -// -// #[test] -// fn test_hash_to_bytes() { -// let inputs: Vec> = vec![vec![1u8]]; -// let hash = poseidon_bytes(&inputs).unwrap(); -// 18586133768512220936620570745912940619677854269274689475585506675881198879027 -// in decimal let expected = -// hex::decode(" -// 33018202c57d898b84338b16d1a4960e133c6a4d656cfec1bd62a9ea00611729") .unwrap(); -// assert_eq!(hash.as_slice(), &expected); -// -// 7853200120776062878684798364095072458815029376092732009249414926327459813530 -// in decimal let inputs: Vec> = vec![vec![1u8], vec![2u8]]; -// let hash = poseidon_bytes(&inputs).unwrap(); -// let expected = -// hex::decode(" -// 9a1817447a60199e51453274f217362acfe962966b4cf63d4190d6e7f5c05c11") .unwrap(); -// assert_eq!(hash.as_slice(), &expected); -// -// Input larger than the modulus -// let inputs = vec![vec![255; 32]]; -// assert!(poseidon_bytes(&inputs).is_err()); -// -// Input smaller than the modulus -// let inputs = vec![vec![255; 31]]; -// assert!(poseidon_bytes(&inputs).is_ok()); -// } -// -// #[cfg(test)] -// lazy_static! { -// static ref POSEIDON_ARK: poseidon_ark::Poseidon = -// poseidon_ark::Poseidon::new(); } -// -// proptest::proptest! { -// #[test] -// fn test_against_poseidon_ark(r in collection::vec(<[u8; 32]>::arbitrary(), -// 1..16)) { -// -// let inputs = r.into_iter().map(|ri| -// ark_bn254::Fr::from_le_bytes_mod_order(&ri)).collect::>(); -// let expected = -// POSEIDON_ARK.hash(inputs.clone()).unwrap().into_bigint().to_bytes_le(); -// -// let actual = poseidon_bytes(&inputs.iter().map(|i| -// i.into_bigint().to_bytes_le().to_vec()).collect::>()).unwrap(); -// assert_eq!(&actual, expected.as_slice()); -// } -// } -// } diff --git a/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs index 482018c2..84f0fad7 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/verifier.rs @@ -1,6 +1,3 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - use std::borrow::Borrow; use std::ops::Neg; @@ -24,10 +21,6 @@ use crate::executor::zk_stuff::bn254::VerifyingKey; use crate::executor::zk_stuff::error::ZkCryptoError; use crate::executor::zk_stuff::error::ZkCryptoResult; -//#[cfg(test)] -//#[path = "unit_tests/verifier_tests.rs"] -// mod verifier_tests; - /// This is a helper function to store a pre-processed version of the verifying /// key. This is roughly homologous to /// [`ark_groth16::data_structures::PreparedVerifyingKey`]. Note that contrary @@ -171,31 +164,3 @@ impl From<&ark_groth16::VerifyingKey> for PreparedVerifyingKey { } } } -// #[cfg(test)] -// mod tests { -// use crate::executor::zk_stuff::bn254::verifier::PreparedVerifyingKey; -// use crate::dummy_circuits::DummyCircuit; -// use ark_bn254::{Bn254, Fr}; -// use ark_groth16::Groth16; -// use ark_snark::SNARK; -// use ark_std::rand::thread_rng; -// use ark_std::UniformRand; -// -// #[test] -// fn test_serialization() { -// const PUBLIC_SIZE: usize = 128; -// let rng = &mut thread_rng(); -// let c = DummyCircuit:: { -// a: Some(::rand(rng)), -// b: Some(::rand(rng)), -// num_variables: PUBLIC_SIZE, -// num_constraints: 10, -// }; -// let (_, vk) = Groth16::::circuit_specific_setup(c, rng).unwrap(); -// let pvk = PreparedVerifyingKey::from(&vk); -// -// let serialized = pvk.serialize().unwrap(); -// let deserialized = PreparedVerifyingKey::deserialize(&serialized).unwrap(); -// assert_eq!(pvk, deserialized); -// } -// } diff --git a/tvm_vm/src/executor/zk_stuff/curve_utils.rs b/tvm_vm/src/executor/zk_stuff/curve_utils.rs index 8ae4726a..75f55244 100644 --- a/tvm_vm/src/executor/zk_stuff/curve_utils.rs +++ b/tvm_vm/src/executor/zk_stuff/curve_utils.rs @@ -8,8 +8,6 @@ use ark_bn254::G2Projective; use ark_ec::CurveGroup; use ark_ff::BigInteger; use ark_ff::PrimeField; -// use hex::serde; -// use fastcrypto::error::FastCryptoError; use num_bigint::BigUint; use schemars::JsonSchema; use serde::Deserialize; diff --git a/tvm_vm/src/executor/zk_stuff/jwt_utils.rs b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs index ce495c7d..e797bdfc 100644 --- a/tvm_vm/src/executor/zk_stuff/jwt_utils.rs +++ b/tvm_vm/src/executor/zk_stuff/jwt_utils.rs @@ -1,5 +1,3 @@ -// extern crate serde_derive; - use base64ct::Base64UrlUnpadded; use base64ct::Encoding; use schemars::JsonSchema; diff --git a/tvm_vm/src/executor/zk_stuff/utils.rs b/tvm_vm/src/executor/zk_stuff/utils.rs index e2c0407c..43f400a6 100644 --- a/tvm_vm/src/executor/zk_stuff/utils.rs +++ b/tvm_vm/src/executor/zk_stuff/utils.rs @@ -1,7 +1,5 @@ use std::str::FromStr; -// use fastcrypto::rsa::Base64UrlUnpadded; -// use fastcrypto::rsa::Encoding; use num_bigint::BigUint; use serde::Deserialize; use serde::Serialize; From ac7d415fce267585ea40f2593cb01564620144c1 Mon Sep 17 00:00:00 2001 From: Alina Trepacheva Date: Fri, 4 Oct 2024 14:45:49 +0300 Subject: [PATCH 07/19] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c8fc6a9..14fe198e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. ## [2.2.98] – 2024-10-04 ### New -- Add support of VERGRTH16 and POSEIDON instruction for zk-login. +- Add support of VERGRTH16 and POSEIDON instructions for zk-login. ## [2.2.8] – 2024-08-19 From c88207afa71db1156f9de322be0b0b7728efb1a1 Mon Sep 17 00:00:00 2001 From: Alina Trepacheva Date: Fri, 4 Oct 2024 15:52:15 +0300 Subject: [PATCH 08/19] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14fe198e..71470079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [2.2.98] – 2024-10-04 +## [2.2.9] – 2024-10-04 ### New - Add support of VERGRTH16 and POSEIDON instructions for zk-login. From 6b9e4d46c3271e54bdd8c3131985b94225bbe8f3 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 04:54:38 +0300 Subject: [PATCH 09/19] remove println --- tvm_vm/src/executor/crypto.rs | 7 -- tvm_vm/src/executor/zk.rs | 140 +--------------------------------- 2 files changed, 4 insertions(+), 143 deletions(-) diff --git a/tvm_vm/src/executor/crypto.rs b/tvm_vm/src/executor/crypto.rs index 298ad2a7..dabb2574 100644 --- a/tvm_vm/src/executor/crypto.rs +++ b/tvm_vm/src/executor/crypto.rs @@ -108,8 +108,6 @@ fn preprocess_signed_data<'a>(_engine: &Engine, data: &'a [u8]) -> Cow<'a, [u8]> } fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Status { - let start = Instant::now(); - engine.load_instruction(Instruction::new(name))?; fetch_stack(engine, 3)?; let pub_key = engine @@ -173,12 +171,7 @@ fn check_signature(engine: &mut Engine, name: &'static str, hash: bool) -> Statu #[cfg(not(feature = "signature_no_check"))] let result = pub_key.verify(&data, &signature).is_ok(); - let duration = start.elapsed(); - - println!("Time elapsed by chcksign is: {:?}", duration); - engine.cc.stack.push(boolean!(result)); - println!("%%%result: {:?}", result); Ok(()) } diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 75a887a7..e308ab1f 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -582,8 +582,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { Bn254FqElementWrapper::from_str("1").unwrap(), ]) .unwrap(); - // "16083174311393072332126484955039141051820368387551336007741432494536231879877", - // "11995344593741129498206341608147577676708407993917230939676252851997423446210", let vk_beta_2 = g2_affine_from_str_projective(&vec![ vec![ @@ -612,14 +610,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { ], ]) .unwrap(); - // [ - // "7017589137241388812217334676878160715759313595646525247042913539379033763831", - // "9588720105182136304988839277158105754318461657916765428451866781594135026063" - // ], - // [ - // "2484424409632768920146683103978991861859052149379216050446911519906662584090", - // "3390288516800701266276631045627865236740814264026178914799455551851945389106" - // ] let vk_gamma_2 = g2_affine_from_str_projective(&vec![ vec![ @@ -649,15 +639,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { ]) .unwrap(); - // [ - // "10857046999023057135944570762232829481370756359578518086990519993285655852781", - // "11559732032986387107991004021392285783925812861821192530917403151452391805634" - // ], - // [ - // "8495653923123431417604973247489272438418190587263600148770280649306958101930", - // "4082367875863433681332203403145435568316851327593401208105741076214120093531" - // ] - let vk_delta_2 = g2_affine_from_str_projective(&vec![ vec![ Bn254FqElementWrapper::from_str( @@ -686,15 +667,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { ]) .unwrap(); - // [ - // "10857046999023057135944570762232829481370756359578518086990519993285655852781", - // "11559732032986387107991004021392285783925812861821192530917403151452391805634" - // ], - // [ - // "8495653923123431417604973247489272438418190587263600148770280649306958101930", - // "4082367875863433681332203403145435568316851327593401208105741076214120093531" - // ] - // Create a vector of G1Affine elements from the IC let mut vk_gamma_abc_g1 = Vec::new(); for e in [ @@ -725,19 +697,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { vk_gamma_abc_g1.push(g1); } - // [ - // [ - // "11760611693671517707466601638901224388668992590928868758649168369215563295744", - // "15842561259007247784907604255150260908812200067246900457940460682994649597353", - // "1" - // ], - // [ - // "9960247968913608540350443520882802417817484595360267448450266543686043480996", - // "11040490439713280236989540698814598402024610465375008410116396264618122562865", - // "1" - // ] - // ] - let vk = VerifyingKey { alpha_g1: vk_alpha_1, beta_g2: vk_beta_2, @@ -750,57 +709,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } -// pub(crate) fn execute_vergrth16_new(engine: &mut Engine) -> Status { -// let start = Instant::now(); -// engine.load_instruction(crate::executor::types::Instruction::new(" -// VERGRTH16_NEW"))?; fetch_stack(engine, 3)?; -// -// let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; -// println!("from vergrth16 vk_index: {:?}", vk_index); -// -// let public_inputs_slice = -// SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; -// let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, -// engine)?; println!("from vergrth16 value public_inputs_as_bytes: {:?}", -// public_inputs_as_bytes); -// -// let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; -// let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; -// println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); -// -// let proof = ProofWrapper::deserialize(&proof_as_bytes)?; -// let public_inputs = -// FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; -// let x: Vec = public_inputs.iter().map(|x| x.0).collect(); -// -// let vk = if vk_index == 0 { -// insecure_pvk() -// } else if vk_index == 1 { -// global_pvk() -// } else { -// my_test_pvk_1() -// }; -// -// ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; -// println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); -// todo: add alternative for elliptic curve (may be we need bls curve also?), -// read from stack curve id -// let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) -// .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); -// -// let duration = start.elapsed(); -// -// println!("Time elapsed by vergrth16 is: {:?}", duration); -// -// let succes = res.is_ok(); -// println!("res: {:?}", res); -// let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; -// println!("res: {:?}", res); -// -// engine.cc.stack.push(res); -// -// Ok(()) -// } pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let start = Instant::now(); @@ -808,15 +716,12 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { fetch_stack(engine, 3)?; let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; - println!("from vergrth16 vk_index: {:?}", vk_index); let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; - println!("from vergrth16 value public_inputs_as_bytes: {:?}", public_inputs_as_bytes); let proof_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; let proof_as_bytes = unpack_data_from_cell(proof_slice, engine)?; - println!("from vergrth16 value proof_as_bytes: {:?}", proof_as_bytes); let proof = ProofWrapper::deserialize(&proof_as_bytes)?; let public_inputs = FieldElementWrapper::deserialize_vector(&public_inputs_as_bytes)?; @@ -830,21 +735,14 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { my_test_pvk_1() }; - // ZKP_VERIFYING_KEYS.get(&vk_index).unwrap();//&GLOBAL_VERIFYING_KEY; - println!("vk data = {:?}", vk.alpha_g1_beta_g2.to_string()); // todo: add alternative for elliptic curve (may be we need bls curve also?), // read from stack curve id let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); - let duration = start.elapsed(); - - println!("Time elapsed by vergrth16 is: {:?}", duration); - let succes = res.is_ok(); - println!("res: {:?}", res); + let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; - println!("res: {:?}", res); engine.cc.stack.push(res); @@ -857,55 +755,37 @@ fn pop(barry: &[u8]) -> &[u8; 8] { pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; - // fetch_stack(engine, 4); fetch_stack(engine, 5)?; let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; - println!("from poseidon value zkaddr: {:?}", zkaddr); - // let epk_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; - // let epk_as_bytes = unpack_data_from_cell(epk_slice, engine)?; - // println!("from poseidon value epk_as_bytes: {:?}", - // hex::encode(epk_as_bytes.clone())); let header_and_iss_base64_slice = SliceData::load_cell_ref(engine.cmd.var(1 /* 2 */).as_cell()?)?; let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; - println!("from poseidon value header_and_iss_base64: {:?}", header_and_iss_base64); let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2 /* 3 */).as_cell()?)?; let modulus = unpack_data_from_cell(modulus_slice, engine)?; - println!("from poseidon value modulus: {:?}", modulus); let eph_pub_key = engine .cmd - .var(3 /* 4 */) + .var(3 ) .as_integer()? .as_builder::(/* PUBLIC_KEY_BITS */ 256)?; let eph_pub_key_bytes = eph_pub_key.data(); - println!("from poseidon value eph_pub_key_bytes: {:?}", eph_pub_key_bytes.len()); - println!("from poseidon value eph_pub_key_bytes: {:?}", eph_pub_key_bytes); let max_epoch_ = engine .cmd - .var(4 /* 4 */) + .var(4 ) .as_integer()? .as_builder::(/* PUBLIC_KEY_BITS */ 64)?; let max_epoch_bytes = pop(max_epoch_.data()); let max_epoch = u64::from_be_bytes(*max_epoch_bytes); - println!("from poseidon value max_epoch: {:?}", max_epoch); - - println!("from poseidon value max_epoch_bytes: {:?}", max_epoch_bytes.len()); - println!("from poseidon value max_epoch_bytes: {:?}", max_epoch_bytes); - - // let max_epoch = 10; //todo: read from stack later - // let max_epoch = 142; - let public_inputs = calculate_poseidon_hash( &*zkaddr, &*header_and_iss_base64, @@ -917,9 +797,6 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let mut public_inputs_as_bytes = vec![]; public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - println!("from poseidon public_inputs_as_bytes : {:?}", public_inputs_as_bytes.clone()); - // println!("from poseidon public_inputs_as_bytes len : {:?}", - // public_inputs_as_bytes.len()); let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); @@ -935,10 +812,7 @@ pub fn calculate_poseidon_hash( modulus: &[u8], max_epoch: u64, ) -> Result /**/ { - // if header_base64.len() > MAX_HEADER_LEN as usize { - // return Err(ZkCryptoError::GeneralError("Header too long".to_string())); - // } - + let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); let addr_seed = (&address_seed).into(); @@ -949,19 +823,13 @@ pub fn calculate_poseidon_hash( let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); let header_base64 = v["headerBase64"].as_str().unwrap(); - println!("header_base64 {}", header_base64); let iss_base64_details = v["issBase64Details"].as_object().unwrap(); - println!("issBase64Details {:?}", iss_base64_details); let index_mod_4 = iss_base64_details["indexMod4"].as_i64().unwrap().to_string(); - println!("index_mod_4 {:?}", index_mod_4); - let iss_base64_details_value = iss_base64_details["value"].as_str().unwrap(); - println!("iss_base64_details_value {:?}", iss_base64_details_value); - let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); let iss_base64_f = hash_ascii_str_to_field(&iss_base64_details_value, MAX_ISS_LEN_B64).unwrap(); From bf4d4799fe6a00463f518b8db05274fb08a27f5d Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 05:04:22 +0300 Subject: [PATCH 10/19] remove some extra comments in zk.rs --- tvm_vm/src/executor/zk.rs | 46 ++++++++++----------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index e308ab1f..bcea0774 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -51,6 +51,9 @@ pub type ZkCryptoResult = Result; /// Size of scalars in the BN254 construction. pub const SCALAR_SIZE: usize = 32; +const PUBLIC_KEY_BITS: usize = PUBLIC_KEY_BYTES * 8; +const PUBLIC_KEY_BYTES: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; + #[derive(Debug, From)] pub struct FieldElementWrapper(pub(crate) ark_bn254::Fr); @@ -265,28 +268,7 @@ impl ProofWrapper { } } -/// Here there are third party zk login Groth16 verification keys taken for now -/// for tests todo: will be replaced by our keys later -/// todo: move all key data to json config file (?), use hash as id - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -// static GLOBAL_VERIFYING_KEY: Lazy> = Lazy::new(global_pvk); - -/// Corresponding to proofs generated from prover-dev. Used in devnet/testnet. -// static INSECURE_VERIFYING_KEY: Lazy> = Lazy::new(insecure_pvk); - -// static ZKP_VERIFYING_KEYS: Lazy>> = Lazy::new(keys); - -// todo: will contain our keys later, key ould be a hash of verification key -// fn keys() -> HashMap> { -// let mut h = HashMap::new(); -// h.insert(0, insecure_pvk()); -// h.insert(1, global_pvk()); -// h -// } -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a -/// local setup and should not use in production. fn insecure_pvk() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ @@ -425,8 +407,7 @@ fn insecure_pvk() -> PreparedVerifyingKey { PreparedVerifyingKey::from(vk) } -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a -/// local setup and should not use in production. + fn global_pvk() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ @@ -564,10 +545,7 @@ fn global_pvk() -> PreparedVerifyingKey { // Convert the verifying key into the prepared form. PreparedVerifyingKey::from(vk) } -/////////////////////////////////// -/// Load a fixed verifying key from zkLogin.vkey output. This is based on a -/// local setup and should not use in production. fn my_test_pvk_1() -> PreparedVerifyingKey { // Convert the Circom G1/G2/GT to arkworks G1/G2/GT let vk_alpha_1 = g1_affine_from_str_projective(&vec![ @@ -735,8 +713,8 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { my_test_pvk_1() }; - // todo: add alternative for elliptic curve (may be we need bls curve also?), - // read from stack curve id + // todo: add alternative for elliptic curve (BLS), read from stack curve id + let res = Groth16::::verify_with_processed_vk(&vk, &x, &proof.0) .map_err(|e| ZkCryptoError::GeneralError(e.to_string())); @@ -760,28 +738,26 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; - let header_and_iss_base64_slice = SliceData::load_cell_ref(engine.cmd.var(1 /* 2 */).as_cell()?)?; let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; - let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2 /* 3 */).as_cell()?)?; + let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; let modulus = unpack_data_from_cell(modulus_slice, engine)?; let eph_pub_key = engine .cmd .var(3 ) .as_integer()? - .as_builder::(/* PUBLIC_KEY_BITS */ 256)?; + .as_builder::(PUBLIC_KEY_BITS)?; let eph_pub_key_bytes = eph_pub_key.data(); - let max_epoch_ = engine .cmd .var(4 ) .as_integer()? - .as_builder::(/* PUBLIC_KEY_BITS */ 64)?; + .as_builder::( 64)?; let max_epoch_bytes = pop(max_epoch_.data()); let max_epoch = u64::from_be_bytes(*max_epoch_bytes); @@ -789,7 +765,7 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let public_inputs = calculate_poseidon_hash( &*zkaddr, &*header_and_iss_base64, - &eph_pub_key_bytes, // epk_as_bytes + &eph_pub_key_bytes, &modulus, max_epoch, ) @@ -811,7 +787,7 @@ pub fn calculate_poseidon_hash( eph_pk_bytes: &[u8], modulus: &[u8], max_epoch: u64, -) -> Result /**/ { +) -> Result { let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); let addr_seed = (&address_seed).into(); From 38e92cd20a254a9d924c6b83a465cff93252c366 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 06:32:30 +0300 Subject: [PATCH 11/19] cut test_framework: leave only used stuff --- tvm_tests/src/test_framework.rs | 632 +--------------------- tvm_tests/src/test_zk.rs | 57 -- tvm_vm/src/executor/crypto.rs | 1 - tvm_vm/src/executor/zk.rs | 3 - tvm_vm/src/executor/zk_stuff/bn254/mod.rs | 2 +- tvm_vm/src/executor/zk_stuff/mod.rs | 7 +- 6 files changed, 6 insertions(+), 696 deletions(-) diff --git a/tvm_tests/src/test_framework.rs b/tvm_tests/src/test_framework.rs index ef362a23..dbaf1e4b 100644 --- a/tvm_tests/src/test_framework.rs +++ b/tvm_tests/src/test_framework.rs @@ -1,97 +1,30 @@ -// Copyright (C) 2019-2023 TON Labs. All Rights Reserved. -// -// Licensed under the SOFTWARE EVALUATION License (the "License"); you may not -// use this file except in compliance with the License. -// -// 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 TON DEV software governing permissions and -// limitations under the License. - #![allow(dead_code)] use std::convert::Into; -use std::ffi::CStr; -use std::os::raw::c_char; + use std::sync::Arc; -// use failure::{Error}; use tvm_assembler::compile_code; use tvm_assembler::CompileError; -use tvm_block::GlobalCapabilities; -// use failure::Error as Error; -use tvm_types::{ - types::ExceptionCode, BocWriter, BuilderData, Cell, HashmapE, HashmapType, Result, SliceData, -}; -use tvm_vm::error::tvm_exception_code; -use tvm_vm::error::tvm_exception_or_custom_code; -use tvm_vm::error::TvmError; + +use tvm_types::{Cell, BuilderData, HashmapE, Result, SliceData}; + use tvm_vm::executor::gas::gas_state::Gas; use tvm_vm::executor::BehaviorModifiers; use tvm_vm::executor::Engine; use tvm_vm::executor::IndexProvider; -use tvm_vm::int; -use tvm_vm::smart_contract_info::SmartContractInfo; -use tvm_vm::stack::integer::IntegerData; use tvm_vm::stack::savelist::SaveList; use tvm_vm::stack::Stack; -use tvm_vm::stack::StackItem; -use tvm_vm::types::Exception; pub type Bytecode = SliceData; #[allow(dead_code)] -pub mod create { - use super::*; - - pub fn cell>(data: T) -> StackItem { - let data = data.as_ref().to_vec(); - StackItem::Cell(BuilderData::with_bitstring(data).unwrap().into_cell().unwrap()) - } - - pub fn builder>(data: T) -> StackItem { - let builder = BuilderData::with_bitstring(data.as_ref().to_vec()).unwrap(); - StackItem::builder(builder) - } - - pub fn slice>(data: T) -> StackItem { - let data = data.as_ref().to_vec(); - let slice = SliceData::new(data); - StackItem::Slice(slice) - } - - pub fn tuple>(data: &T) -> StackItem { - let data = data.as_ref().to_vec(); - StackItem::tuple(data) - } -} fn logger_init() { - // do not init twice if log::log_enabled!(log::Level::Info) { return; } let log_level = log::LevelFilter::Info; - // if cfg!(feature = "verbose") { log::LevelFilter::Trace } else { - // log::LevelFilter::Info }; let encoder_boxed = Box::new(log4rs::encode::pattern::PatternEncoder::new("{m}")); - // let config = if cfg!(feature = "log_file") { - // let file = log4rs::append::file::FileAppender::builder() - // .encoder(encoder_boxed) - // .build("log/log.txt") - // .unwrap(); - // log4rs::config::Config::builder() - // .appender(log4rs::config::Appender::builder().build("file", Box::new(file))) - // .build(log4rs::config::Root::builder().appender("file").build(log_level)) - // .unwrap() - // } else { - // let console = - // log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed). - // build(); log4rs::config::Config::builder() - // .appender(log4rs::config::Appender::builder().build("console", - // Box::new(console))) .build(log4rs::config::Root::builder().appender(" - // console").build(log_level)) .unwrap() - // }; let config = { let console = log4rs::append::console::ConsoleAppender::builder().encoder(encoder_boxed).build(); @@ -134,161 +67,6 @@ impl TestCaseInputs { index_provider: None, } } - - pub fn with_ref(mut self, cell: Cell) -> TestCaseInputs { - assert!(self.refs.len() < 4); - self.refs.push(cell); - self - } - - pub fn with_refs(mut self, refs: Vec) -> TestCaseInputs { - self.refs = refs; - self - } - - pub fn with_root_data(self, root_data: Cell) -> TestCaseInputs { - self.with_ctrl(4, StackItem::Cell(root_data)) - } - - pub fn with_temp_data(self, temp_data: SmartContractInfo) -> TestCaseInputs { - self.with_ctrl(7, temp_data.into_temp_data_item()) - } - - // do not run with stack - use refs, then do PUSHREF* - pub fn with_stack(mut self, stack: Stack) -> TestCaseInputs { - self.stack = stack; - self - } - - pub fn with_capability(mut self, capability: tvm_block::GlobalCapabilities) -> TestCaseInputs { - self.skip_fift_check = true; - self.capabilities |= capability as u64; - self - } - - pub fn with_block_version(mut self, block_version: u32) -> TestCaseInputs { - self.skip_fift_check = true; - self.block_version = block_version; - self - } - - pub fn skip_fift_check(mut self, skip: bool) -> TestCaseInputs { - if skip { - self.skip_fift_check = skip; - } - self - } - - pub fn with_index_provider(mut self, index_provider: Arc) -> TestCaseInputs { - self.index_provider = Some(index_provider); - self - } - - pub fn with_ctrl(mut self, ctrl: usize, mut item: StackItem) -> TestCaseInputs { - self.ctrls.put(ctrl, &mut item).expect("test arguments must be valid"); - self - } - - pub fn with_gas(mut self, gas: Gas) -> TestCaseInputs { - self.gas = Some(gas); - self - } - - pub fn with_gas_limit(self, gas_limit: i64) -> TestCaseInputs { - self.with_gas(Gas::test_with_limit(gas_limit)) - } - - pub fn with_library(mut self, library: HashmapE) -> TestCaseInputs { - self.library = library; - self - } - - pub fn with_behavior_modifiers( - mut self, - behavior_modifiers: BehaviorModifiers, - ) -> TestCaseInputs { - self.skip_fift_check = true; - self.behavior_modifiers = Some(behavior_modifiers); - self - } - - pub fn expect_bytecode(self, bytecode: Vec) -> TestCaseInputs { - self.expect_bytecode_extended(bytecode, None) - } - - pub fn expect_bytecode_extended( - self, - bytecode: Vec, - message: Option<&str>, - ) -> TestCaseInputs { - let inputcode = SliceData::new(bytecode); - let compilation_result = compile_code(&self.code); - match compilation_result { - Ok(ref selfcode) => { - let mut selfcode = selfcode.clone(); - let mut bytevec = vec![]; - while selfcode.remaining_bits() != 0 { - bytevec.append(&mut selfcode.get_bytestring(0)); - if selfcode.remaining_references() > 0 { - selfcode = SliceData::load_cell(selfcode.reference(0).unwrap()).unwrap(); - } else { - break; - } - } - bytevec.push(0x80); - let selfcode = SliceData::new(bytevec); - if !selfcode.eq(&inputcode) { - match message { - Some(msg) => panic!( - "{}Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", - msg, inputcode, selfcode - ), - None => panic!( - "Bytecode did not match:\n Expected: <{:x?}>\n But was: <{:x?}>", - inputcode, selfcode - ), - } - }; - } - Err(e) => match message { - Some(msg) => panic!("{}{}", msg, e), - None => panic!("{}", e), - }, - } - self - } - - pub fn expect_compilation_failure(self, error: CompileError) -> TestCaseInputs { - self.expect_compilation_failure_extended(error, None) - } - - pub fn expect_compilation_failure_extended( - self, - error: CompileError, - message: Option<&str>, - ) -> TestCaseInputs { - let compilation_result = compile_code(&self.code); - match message { - None => { - let actual = compilation_result.expect_err(&format!("Error expected {}", error)); - assert_eq!( - error, actual, - "Expected (left): <{}>, but was (right): <{}>.", - error, actual - ) - } - Some(msg) => { - let actual = - compilation_result.expect_err(&format!("{}. Error expected {}", msg, error)); - assert_eq!( - error, actual, - "{}\nExpected (left): <{}>, but was (right): <{}>.", - msg, error, actual - ) - } - } - self - } } impl From for TestCase { @@ -324,92 +102,6 @@ impl TestCase { } } -fn compare_with_fift( - bytecode: SliceData, - library: HashmapE, - code: String, - executor: &Engine, - execution_result: &Result, - gas_remaining: i32, -) { - #[cfg(windows)] - let lib_name = "vm_run_shared.dll"; - #[cfg(not(windows))] - let lib_name = "./vm_run_shared.so"; - if let Ok(lib) = libloading::Library::new(lib_name) { - let mut data = vec![]; - assert!(bytecode.pos() == 0); - let mut roots = vec![bytecode.cell_opt().unwrap().clone()]; - if let Some(root) = library.data() { - roots.push(root.clone()); - } - let bag = BocWriter::with_roots(roots).unwrap(); - bag.write(&mut data).unwrap(); - // code is written to BOC and can be checked with FIFT - // "fift.boc" file>B B>boc *mut c_char, - > = lib.get(b"run_vm_boc_with_gas_and_commit").unwrap(); - let free_mem: libloading::Symbol *mut c_char> = - lib.get(b"free_mem").unwrap(); - let res = run_boc(data.as_ptr(), size as i32, gas_remaining); - fift_result = CStr::from_ptr(res).to_string_lossy().into_owned().trim().to_string(); - free_mem(res); - } - let tvm_result = match execution_result { - Ok(ref result) => { - let stack = executor.get_stack_result_fift(); - match stack.is_empty() { - true => format!( - "{} {}{}", - result, - executor.gas_used(), - executor.get_committed_state_fift() - ), - false => format!( - "{} {} {}{}", - stack, - result, - executor.gas_used(), - executor.get_committed_state_fift() - ), - } - } - Err(ref err) => { - if let Some(ExceptionCode::OutOfGas) = tvm_exception_code(err) { - let gas = executor.gas_used(); - format!( - "{} {} {}{}", - gas, - !(ExceptionCode::OutOfGas as i32), - gas, - executor.get_committed_state_fift() - ) - } else { - let err = tvm_exception_or_custom_code(err); - format!( - "0 {} {}{}", - err, - executor.gas_used(), - executor.get_committed_state_fift() - ) - } - } - }; - if tvm_result != fift_result { - log::info!("bytecode: {}\n", &StackItem::Slice(bytecode).dump_as_fift()); - log::info!("code:\n{}\n", code); - assert_eq!(tvm_result, fift_result); - } - } else { - panic!("no shared dll found") - } -} - impl TestCase { pub(super) fn new(args: TestCaseInputs) -> TestCase { match compile_code(&args.code) { @@ -445,21 +137,6 @@ impl TestCase { executor.set_index_provider(index_provider) } let execution_result = executor.execute(); - // if cfg!(feature = "fift_check") - // && args.stack.is_empty() - // && args.ctrls.is_empty() - // && !args.skip_fift_check - // { - // let gas = args.gas.map(|gas| gas.get_gas_remaining() as - // i32).unwrap_or(1000000); compare_with_fift( - // code, - // args.library, - // args.code, - // &executor, - // &execution_result, - // gas, - // ) - // } TestCase { executor: Some(executor), @@ -473,94 +150,13 @@ impl TestCase { } } - // TODO: call this from fn new - pub fn with_bytecode( - code: Bytecode, - ctrls: Option, - stack: Option, - library: HashmapE, - ) -> TestCase { - logger_init(); - - let mut executor = Engine::with_capabilities(0).setup_with_libraries( - code.clone(), - ctrls.clone(), - stack.clone(), - None, - vec![library.clone()], - ); - let execution_result = executor.execute(); - if - // cfg!(feature = "fift_check") && - stack.is_none() && ctrls.is_none() { - compare_with_fift( - code.clone(), - library, - format!("{:x}", code), - &executor, - &execution_result, - 1000000, - ) - } - log::trace!("bytecode: {}", code); - TestCase { executor: Some(executor), compilation_result: Ok(code), execution_result } - } - - pub fn get_root(&self) -> Option { - if let Some(ref eng) = self.executor { - if let StackItem::Cell(c) = eng.get_committed_state().get_root() { - return Some(c.clone()); - } - } - None - } - - pub fn get_actions(&self) -> Option { - if let Some(ref eng) = self.executor { - if let StackItem::Cell(c) = eng.get_committed_state().get_actions() { - return Some(c.clone()); - } - } - None - } } pub trait Expects { fn expect_stack(self, stack: &Stack) -> TestCase; fn expect_stack_extended(self, stack: &Stack, message: Option<&str>) -> TestCase; - fn expect_empty_stack(self) -> TestCase; - fn expect_int_stack(self, stack_contents: &[i32]) -> TestCase; - fn expect_item(self, stack_item: StackItem) -> TestCase; - fn expect_item_extended(self, stack_item: StackItem, message: Option<&str>) -> TestCase; fn expect_success(self) -> TestCase; fn expect_success_extended(self, message: Option<&str>) -> TestCase; - fn expect_ctrl(self, ctrl: usize, item: &StackItem) -> TestCase; - fn expect_ctrl_extended(self, ctrl: usize, item: &StackItem, message: Option<&str>) - -> TestCase; - fn expect_failure(self, exception_code: ExceptionCode) -> TestCase; - fn expect_custom_failure(self, custom_code: i32) -> TestCase; - fn expect_custom_failure_extended bool>( - self, - op: F, - exc_name: &str, - message: Option<&str>, - ) -> TestCase; - fn expect_failure_extended( - self, - exception_code: ExceptionCode, - message: Option<&str>, - ) -> TestCase; - fn expect_root_data(self, cell: Cell) -> TestCase; - fn expect_same_results(self, other: Self); - fn expect_gas( - self, - max_gas_limit: i64, - gas_limit: i64, - gas_credit: i64, - gas_remaining: i64, - ) -> TestCase; - fn expect_steps(self, steps: u32) -> TestCase; - fn stack(self) -> Stack; } impl> Expects for T { @@ -596,27 +192,6 @@ impl> Expects for T { test_case } - fn expect_empty_stack(self) -> TestCase { - self.expect_stack(&Stack::new()) - } - - // Order of items in array like in spec docs right item is top item - fn expect_int_stack(self, stack_contents: &[i32]) -> TestCase { - let mut stack = Stack::new(); - for element in stack_contents { - stack.push(int!(*element)); - } - self.expect_stack(&stack) - } - - fn expect_item(self, stack_item: StackItem) -> TestCase { - self.expect_item_extended(stack_item, None) - } - - fn expect_item_extended(self, stack_item: StackItem, message: Option<&str>) -> TestCase { - self.expect_stack_extended(Stack::new().push(stack_item), message) - } - fn expect_success(self) -> TestCase { self.expect_success_extended(None) } @@ -640,148 +215,6 @@ impl> Expects for T { test_case } - fn expect_ctrl(self, ctrl: usize, item: &StackItem) -> TestCase { - self.expect_ctrl_extended(ctrl, item, None) - } - - fn expect_ctrl_extended( - self, - ctrl: usize, - item: &StackItem, - message: Option<&str>, - ) -> TestCase { - let test_case: TestCase = self.into(); - let executor = test_case.executor(message); - match test_case.execution_result { - Ok(_) => executor.assert_ctrl(ctrl, item), - Err(ref e) => { - // print_failed_detail_extended(&test_case, e, message); - panic!("Execution error: {}", e); - } - }; - test_case - } - - fn expect_failure(self, exception_code: ExceptionCode) -> TestCase { - self.expect_failure_extended(exception_code, None) - } - - fn expect_custom_failure_extended bool>( - self, - op: F, - exc_name: &str, - message: Option<&str>, - ) -> TestCase { - let test_case: TestCase = self.into(); - let executor = test_case.executor(message); - match test_case.execution_result { - Ok(_) => { - log::info!( - target: "tvm", - "Expected failure: {}, however execution succeeded.", - exc_name - ); - print_stack(&test_case, executor); - match message { - None => panic!("Expected failure: {}, however execution succeeded.", exc_name), - Some(msg) => panic!( - "{}.\nExpected failure: {}, however execution succeeded.", - msg, exc_name - ), - } - } - Err(ref e) => { - if let Some(TvmError::TvmExceptionFull(e, msg2)) = e.downcast_ref() { - if op(e) { - match message { - Some(msg) => panic!( - "{} - {}\nNon expected exception: {}, expected: {}", - msg2, msg, e, exc_name - ), - None => panic!( - "{}\nNon expected exception: {}, expected: {}", - msg2, e, exc_name - ), - } - } - } else { - let code = e.downcast_ref::(); - match code { - Some(code) => { - let e = Exception::from(*code); - if op(&e) { - panic!("Non expected exception: {}, expected: {}", e, exc_name) - } - } - None => { - if op(&Exception::from(ExceptionCode::FatalError)) { - panic!("Non expected exception: {}, expected: {}", e, exc_name) - } - } - } - } - } - } - test_case - } - - fn expect_custom_failure(self, custom_code: i32) -> TestCase { - self.expect_custom_failure_extended( - |e| e.custom_code() != Some(custom_code), - "custom exception", - None, - ) - } - - fn expect_failure_extended( - self, - exception_code: ExceptionCode, - message: Option<&str>, - ) -> TestCase { - self.expect_custom_failure_extended( - |e| e.exception_code() != Some(exception_code), - &format!("{}", exception_code), - message, - ) - } - - fn expect_root_data(self, cell: Cell) -> TestCase { - self.expect_ctrl(4, &StackItem::Cell(cell)) - } - - fn expect_same_results(self, other: Self) { - let case1 = self.expect_success(); - let case2 = other.expect_success(); - let stack = case2.executor.unwrap().withdraw_stack(); - case1.expect_stack_extended(&stack, Some("results are not the same!")); - } - - fn expect_gas( - self, - max_gas_limit: i64, - gas_limit: i64, - gas_credit: i64, - gas_remaining: i64, - ) -> TestCase { - let test_case: TestCase = self.into(); - let gas = test_case.executor(None).get_gas(); - assert_eq!(gas.get_gas_limit_max(), max_gas_limit); - assert_eq!(gas.get_gas_limit(), gas_limit); - assert_eq!(gas.get_gas_credit(), gas_credit); - assert_eq!(gas.get_gas_remaining(), gas_remaining); - test_case - } - - fn expect_steps(self, steps: u32) -> TestCase { - let test_case: TestCase = self.into(); - assert_eq!(test_case.executor(None).steps(), steps); - test_case - } - - fn stack(self) -> Stack { - let test_case: TestCase = self.into(); - test_case.executor(None).stack().clone() - } } fn print_stack(test_case: &TestCase, executor: &Engine) { @@ -792,68 +225,11 @@ fn print_stack(test_case: &TestCase, executor: &Engine) { } } -// #[allow(dead_code)] -// fn print_failed_detail(case: &TestCase, exception: &Error) { -// print_failed_detail_extended(case, exception, None) -// } -// -// fn print_failed_detail_extended(case: &TestCase, exception: &Error, message: -// Option <&str>) { log::info!(target: "tvm", "exception: {:?}\n", exception); -// let msg2 = if let Some(TvmError::TvmExceptionFull(_e, msg2)) = -// exception.downcast_ref() { msg2.clone() -// } else { -// String::new() -// }; -// match message { -// Some(ref msg) => log::info!( -// target: "tvm", -// "{} failed with {} {}.\nBytecode: {:x?}\n", -// msg, exception, msg2, case.compilation_result -// ), -// None => log::info!( -// target: "tvm", -// "failed with {} {}.\nBytecode: {:x?}\n", -// exception, msg2, case.compilation_result -// ) -// } -// } - pub fn test_case_with_refs(code: &str, references: Vec) -> TestCaseInputs { TestCaseInputs::new(code.to_string(), Stack::new(), references, 0) } -pub fn test_case_with_ref(code: &str, reference: Cell) -> TestCaseInputs { - TestCaseInputs::new(code.to_string(), Stack::new(), vec![reference], 0) -} - pub fn test_case(code: impl ToString) -> TestCaseInputs { TestCaseInputs::new(code.to_string(), Stack::new(), vec![], 0) } -pub fn test_case_with_bytecode(code: Bytecode) -> TestCase { - TestCase::with_bytecode(code, None, None, Default::default()) -} - -#[allow(dead_code)] -pub fn test_single_argument_fail(cmd: &str, argument: isize) { - let code = format!("{} {}", cmd, argument); - test_case(code).expect_compilation_failure(CompileError::out_of_range(1, 1, cmd, "arg 0")); -} - -#[allow(dead_code)] -pub fn expect_exception(code: &str, exc_code: ExceptionCode) { - test_case(code).expect_failure(exc_code); -} - -#[allow(dead_code)] -pub fn expect_exception_with_capability( - code: &str, - exc_code: ExceptionCode, - capability: GlobalCapabilities, - check_fift: bool, -) { - test_case(code) - .with_capability(capability) - .skip_fift_check(!check_fift) - .expect_failure(exc_code); -} diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index d7c0dbc2..5a800dff 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -4,7 +4,6 @@ mod tests { use std::iter::repeat; use std::str::FromStr; use std::time::Instant; - use ark_ff::biginteger::BigInteger; use ark_std::rand::rngs::StdRng; use ark_std::rand::SeedableRng; @@ -31,8 +30,6 @@ mod tests { use tvm_types::Cell; use tvm_types::SliceData; use tvm_vm::executor::zk_stuff::error::ZkCryptoError; - // #[cfg(feature = "signature_no_check")] - // use ton_vm::executor::BehaviorModifiers; use tvm_vm::{ int, stack::{integer::IntegerData, Stack, StackItem}, @@ -64,8 +61,6 @@ mod tests { pub const SUI_DATA_FROM_REACT_20: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6ImJlMTgtZlBDdV9ZRndybE43TDhKV1BHX3hFbyIsIm5iZiI6MTcxNTY4NjgzMSwiaWF0IjoxNzE1Njg3MTMxLCJleHAiOjE3MTU2OTA3MzEsImp0aSI6IjdmZTFkZTM5NDVkMjliYTBhOWQ4MGFlODZiZGRmNjkyMDE1N2RlMDcifQ.RMM8wIiEzZ97DVdngkDhKapTMZq-R7woI2yjclLqTgnYZKTZ5N9y67zFJLDfcg017VyyRK18OS1OLsnUgnphi3ULotImnJ2292VDBd7kxhyq9QAqfHVDK2-MYNlJXy53UIr2xS9td1aoHUDZkvBy690IhV4nPrxLOUhI8c4gAvpkfHFmAvxYuQoUu69c_hSzREhrVOa979t5nZuJjNWwUcwgD40To1DM6Dxwy186basvY4AyWPHcI4ARFoyPEMRFUOtO05fUrwUH8O63Ay6K1DwxaLXDzx4T7O9X9nlrCj2uROdahsv-Dj24hruudSYxi4GH2uO6u0a1RlTIvWJ-1A\",\"user_pass_to_int_format\":\"525451525655\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":66,\"1\":155,\"2\":237,\"3\":117,\"4\":45,\"5\":166,\"6\":245,\"7\":92,\"8\":78,\"9\":225,\"10\":218,\"11\":156,\"12\":7,\"13\":132,\"14\":164,\"15\":47,\"16\":114,\"17\":174,\"18\":4,\"19\":86,\"20\":18,\"21\":212,\"22\":182,\"23\":62,\"24\":50,\"25\":219,\"26\":104,\"27\":185,\"28\":183,\"29\":108,\"30\":38,\"31\":252},\"secret_key\":{\"0\":13,\"1\":127,\"2\":13,\"3\":29,\"4\":128,\"5\":121,\"6\":142,\"7\":51,\"8\":210,\"9\":28,\"10\":131,\"11\":160,\"12\":209,\"13\":42,\"14\":214,\"15\":198,\"16\":137,\"17\":147,\"18\":155,\"19\":40,\"20\":86,\"21\":167,\"22\":168,\"23\":10,\"24\":249,\"25\":180,\"26\":188,\"27\":132,\"28\":41,\"29\":146,\"30\":192,\"31\":28,\"32\":66,\"33\":155,\"34\":237,\"35\":117,\"36\":45,\"37\":166,\"38\":245,\"39\":92,\"40\":78,\"41\":225,\"42\":218,\"43\":156,\"44\":7,\"45\":132,\"46\":164,\"47\":47,\"48\":114,\"49\":174,\"50\":4,\"51\":86,\"52\":18,\"53\":212,\"54\":182,\"55\":62,\"56\":50,\"57\":219,\"58\":104,\"59\":185,\"60\":183,\"61\":108,\"62\":38,\"63\":252}}},\"zk_addr\":\"0x86ab13e3c90b7f5b52a0e7d045425f1a5ce4f2938d82fe32013b5c5dffc8aa40\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"13280060882937967421268531103181473070897547065707830941266439167277535861998\",\"9934433138500558951890280258062370504217382435917636186873727481367280202864\",\"1\"],\"b\":[[\"3838124130316726849360987686807592227651253623250263168834039482151640975443\",\"10050190797101422174255450354163308725608018844614813729840170282126147936409\"],[\"18360080471111693027482741715722945557865825591442098780536696036281663618095\",\"1378964582828950987975075563637558653759765511530268169302574447782691787466\"],[\"1\",\"0\"]],\"c\":[\"1373142722414479432483215105546507593017308819682036641663292686387425172376\",\"3353210342014729825799146687716012229927760750084040417279416030868174996451\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AEKb7XUtpvVcTuHanAeEpC9yrgRWEtS2PjLbaLm3bCb8\"}"; pub const SUI_DATA_FROM_REACT_21: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6Im12NUNKY1dsMXE1ek03Y0lyR1ZUdHF6SnFTNCIsIm5iZiI6MTcxNTY4NjgxOSwiaWF0IjoxNzE1Njg3MTE5LCJleHAiOjE3MTU2OTA3MTksImp0aSI6IjYxMDM2YmQwZWE3YjI5MDY4MjgwODYxMzMyODZhODZlNmY0ZmMwNGEifQ.VE2a8s2ZuyTVklFwSvh05y_mGrDMJXww-5Pu3-UUIQi3sBQnMzpnvWo3MIb32rXxwU6Obtx9izsR-Csk-U0QH4WuseGHnhHA90lACdeXNXHUWNktsY62_z2lkseTlJQV_ccNVctNgqornxmtV6gRvihLKkYCJt08umhAcRe8-Fh9iNmlCf5sMngaA-k0bvIbdnxkoP0KI9em7sgpTDB0FJFCgVAVYkzQTuJJlfuKjeF0lgpLnkjTOtgMyCpuZrrxf9GH6wY2VSme3Zk6xVJfl5cC6YugQFs-t56CEhPDrm-LIlLTD9JuNAKctlRRaTmkTembZAzweu6Wqh322MDx1g\",\"user_pass_to_int_format\":\"100102100102100115106107\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":227,\"1\":142,\"2\":234,\"3\":83,\"4\":36,\"5\":125,\"6\":219,\"7\":233,\"8\":159,\"9\":30,\"10\":60,\"11\":195,\"12\":110,\"13\":130,\"14\":105,\"15\":107,\"16\":44,\"17\":46,\"18\":151,\"19\":154,\"20\":116,\"21\":131,\"22\":237,\"23\":231,\"24\":159,\"25\":119,\"26\":35,\"27\":130,\"28\":56,\"29\":90,\"30\":121,\"31\":26},\"secret_key\":{\"0\":34,\"1\":107,\"2\":197,\"3\":227,\"4\":209,\"5\":156,\"6\":36,\"7\":233,\"8\":231,\"9\":171,\"10\":100,\"11\":210,\"12\":113,\"13\":247,\"14\":59,\"15\":222,\"16\":214,\"17\":129,\"18\":238,\"19\":254,\"20\":13,\"21\":13,\"22\":3,\"23\":151,\"24\":9,\"25\":173,\"26\":77,\"27\":113,\"28\":126,\"29\":7,\"30\":203,\"31\":52,\"32\":227,\"33\":142,\"34\":234,\"35\":83,\"36\":36,\"37\":125,\"38\":219,\"39\":233,\"40\":159,\"41\":30,\"42\":60,\"43\":195,\"44\":110,\"45\":130,\"46\":105,\"47\":107,\"48\":44,\"49\":46,\"50\":151,\"51\":154,\"52\":116,\"53\":131,\"54\":237,\"55\":231,\"56\":159,\"57\":119,\"58\":35,\"59\":130,\"60\":56,\"61\":90,\"62\":121,\"63\":26}}},\"zk_addr\":\"0xb092062dc38ee15b239fedd8955547cae553068e350add6a186a900308ca1704\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"19083893384522082364200015848081882762611466511855277173108395395690822433582\",\"15765871630522826744343212165387977339454134778029147662517994756792436892191\",\"1\"],\"b\":[[\"3347275249816013439391836622904014049361323482158752310150932588414843416768\",\"9261935324040115069949005166058871304117632278716385673922763868694265924905\"],[\"10774327302040930015542399179222458502634829694095804484749135988841930351850\",\"409015645239595129631982791901837203813000443262394810220799589635024410401\"],[\"1\",\"0\"]],\"c\":[\"805618312212200473153836203801534856685701602304097276485035246177305246575\",\"12984127923817330198936709848850019846193356630613954592225359007088568774616\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjMyM2IyMTRhZTY5NzVhMGYwMzRlYTc3MzU0ZGMwYzI1ZDAzNjQyZGMiLCJ0eXAiOiJKV1QifQ\"},\"extended_ephemeral_public_key\":\"AOOO6lMkfdvpnx48w26CaWssLpeadIPt5593I4I4Wnka\"}"; - // pub const VALUE_PORTION_SIZE: usize = 126; - pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"user_pass_to_int_format\":\"9910010710611510499100106115107\",\"zk_addr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secret_key\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extended_ephemeral_public_key\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; #[derive(Debug, Deserialize)] @@ -1511,40 +1506,6 @@ mod tests { let eph_pubkey_len = eph_pubkey.clone().len(); println!("len eph_pubkey: {:?}", eph_pubkey_len); - // let splitted_jwt_strings: Vec<_> = jwt_data.jwt.split('.').collect(); - // - // let jwt_header = splitted_jwt_strings - // .get(0) - // .expect("split always returns at least one element"); - // - // let jwt_body = splitted_jwt_strings.get(1).ok_or(Box::::from( - // "Could not find separator in jwt string.", - // )).unwrap(); - // - // let decoded_jwt_header = base64::decode(jwt_header).unwrap(); - // let decoded_jwt_body = base64::decode(jwt_body).unwrap(); - // - // let converted_jwt_header = - // String::from_utf8(decoded_jwt_header).expect("UTF-8 conversion failed"); - // let converted_jwt_body = String::from_utf8(decoded_jwt_body).expect("UTF-8 - // conversion failed"); - // - // let parsed_jwt_header = - // serde_json::from_str::(&converted_jwt_header).unwrap(); - // let parsed_jwt_body = - // serde_json::from_str::(&converted_jwt_body).unwrap(); - // - // println!( - // "{}", - // serde_json::to_string_pretty(&parsed_jwt_header) - // .expect("to_string_pretty always works on serde_json::Value") - // ); - // println!( - // "{}", - // serde_json::to_string_pretty(&parsed_jwt_body) - // .expect("to_string_pretty always works on serde_json::Value") - // ); - let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); @@ -1566,24 +1527,6 @@ mod tests { println!("aud: {:?}", jwt_data_decoded2.aud); println!("sub: {:?}", jwt_data_decoded2.sub); - // let key = DecodingKey::from_secret(&[]); - // let mut validation = Validation::new(Algorithm::HS256); - // validation.insecure_disable_signature_validation(); - - // let jwt_data_3 = decode(jwt_data_vector[2]).expect("Base64 decoding failed"); - // let jwt_string_3 = String::from_utf8(jwt_data_3).expect("UTF-8 conversion - // failed"); println!("jwt_string_3 is {:?}", jwt_string_3); - // JwtDataDecodedPart3 - // let jwt_data_decoded3: JwtDataDecodedPart3 = - // serde_json::from_str(&jwt_string_3).unwrap(); - - // let jwt_data_3 = &decode(jwt_data.2).unwrap()[..]; - // println!("{:?}", encode(&jwt_data_1)); - // let jwt_string_3 = String::from_utf8(&jwt_data_3); - - // let jwt_v_3: Value = serde_json::from_str(&jwt_string_3)?; - // let n = jwt_v_3["n"]; - let zk_seed = gen_address_seed( user_pass_salt, "sub", diff --git a/tvm_vm/src/executor/crypto.rs b/tvm_vm/src/executor/crypto.rs index dabb2574..d4920238 100644 --- a/tvm_vm/src/executor/crypto.rs +++ b/tvm_vm/src/executor/crypto.rs @@ -10,7 +10,6 @@ // limitations under the License. use std::borrow::Cow; -use std::time::Instant; use ed25519::Signature; use ed25519_dalek::Verifier; diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index bcea0774..4d7f25d9 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -1,5 +1,4 @@ use std::str::FromStr; -use std::time::Instant; pub use ark_bn254::Bn254; use ark_bn254::Fq; @@ -15,7 +14,6 @@ use ark_ff::PrimeField; use ark_groth16::Groth16; use ark_groth16::PreparedVerifyingKey; use ark_groth16::VerifyingKey; -// use once_cell::sync::Lazy; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_snark::SNARK; use derive_more::From; @@ -689,7 +687,6 @@ fn my_test_pvk_1() -> PreparedVerifyingKey { pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { - let start = Instant::now(); engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16"))?; fetch_stack(engine, 3)?; diff --git a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs index 3d60a584..cc34044c 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs @@ -1,4 +1,4 @@ -#![warn(missing_docs, unreachable_pub)] +#![warn(unreachable_pub)] #![deny(unused_must_use, missing_debug_implementations)] use ark_bn254::Bn254; diff --git a/tvm_vm/src/executor/zk_stuff/mod.rs b/tvm_vm/src/executor/zk_stuff/mod.rs index bdf888a5..c75a564e 100644 --- a/tvm_vm/src/executor/zk_stuff/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/mod.rs @@ -1,9 +1,7 @@ -// use derive_more::From; + use ff::PrimeField; -// pub mod alphabet; pub mod curve_utils; -// pub mod encodings; pub mod bn254; pub mod error; pub mod jwt_utils; @@ -17,6 +15,3 @@ pub mod zk_login; #[PrimeFieldReprEndianness = "big"] pub struct Fr([u64; 4]); -// #[derive(Debug, From)] -// pub struct VerifyingKey(pub(crate) -// ark_groth16::VerifyingKey); From 64973e7e41a3b1aa10a51da5ba28ad7be4cb7787 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 08:04:32 +0300 Subject: [PATCH 12/19] update some dependencies in tvm_tests --- tvm_tests/Cargo.toml | 31 +++++++++++++------------- tvm_tests/src/test_zk.rs | 47 +--------------------------------------- 2 files changed, 16 insertions(+), 62 deletions(-) diff --git a/tvm_tests/Cargo.toml b/tvm_tests/Cargo.toml index 79ad1358..6e059f57 100644 --- a/tvm_tests/Cargo.toml +++ b/tvm_tests/Cargo.toml @@ -13,6 +13,20 @@ tvm_types.workspace = true tvm_assembler = {workspace = true, features = ['gosh']} tvm_vm = {workspace = true, features = ['gosh']} +num-bigint.workspace = true +serde_repr.workspace = true +serde_json.workspace = true +serde.workspace = true +serde_derive.workspace = true +num-traits.workspace = true +hex.workspace = true +anyhow.workspace = true +lazy_static.workspace = true +log.workspace = true +num.workspace = true + +base64 = "0.13" + libloading = '0.6' log4rs = '1.2' pprof = { features = [ 'criterion', 'flamegraph' ], version = '0.11' } @@ -21,15 +35,10 @@ criterion = '0.4' ed25519 = '1.2' ed25519-dalek = '1.0' -anyhow = "1.0.79" -hex = '0.4' -lazy_static = '1.4' -log = '0.4' -num = '0.4' - rand = '0.7' diffy = { optional = true, version = '0.2.2' } similar = { features = [ 'bytes' ], optional = true, version = '2.2.0' } + zstd = { default-features = false, optional = true, version = '0.11' } fastcrypto-zkp = "0.1.3" fastcrypto = "0.1.8" @@ -38,16 +47,6 @@ ark-ff = "0.4.2" base64ct ={ version = "1.5.3", features = ["alloc"]} -base64 = "0.13" - -serde = "1.0.197" -serde_derive = "1.0.197" -serde_json = "1.0.114" -serde_repr = "0.1.18" - -num-traits = "0.2.18" -num-bigint = "0.4.6" - [lints] workspace = true diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index 5a800dff..5ce14070 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -1387,52 +1387,6 @@ mod tests { println!("==================="); } - // println!("Serialized proof"); - // let json_string = - // r#"{"proofPoints":{"a":[" - // 8247215875293406890829839156897863742504615191361518281091302475904551111016" - // ,"6872980335748205979379321982220498484242209225765686471076081944034292159666" - // ,"1"],"b":[[" - // 21419680064642047510915171723230639588631899775315750803416713283740137406807" - // ,"21566716915562037737681888858382287035712341650647439119820808127161946325890" - // ],["17867714710686394159919998503724240212517838710399045289784307078087926404555" - // ,"21812769875502013113255155836896615164559280911997219958031852239645061854221" - // ],["1","0"]],"c":[" - // 7530826803702928198368421787278524256623871560746240215547076095911132653214" - // ,"16244547936249959771862454850485726883972969173921727256151991751860694123976" - // ,"1"]},"issBase64Details":{"value":" - // yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC","indexMod4":1}," - // headerBase64":" - // eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ" - // }"#; - // - // Парсинг JSON-строки - // let data: Value = serde_json::from_str(json_string).unwrap(); - // - // let a_x = data["proofPoints"]["a"][0].as_str().unwrap(); - // let a_y = BigUint::parse_bytes(data["proofPoints"]["a"][1].as_str(). - // unwrap().as_bytes(), 10).unwrap(); - // - // let b0_x = data["proofPoints"]["b"][0][0].as_str().unwrap(); - // let b1_x = data["proofPoints"]["b"][0][1].as_str().unwrap(); - // let b1_y = - // BigUint::parse_bytes(data["proofPoints"]["b"][1][1].as_str(). - // unwrap().as_bytes(), 10).unwrap(); - // - // let c_x = data["proofPoints"]["c"][0].as_str().unwrap(); - // let c_y = BigUint::parse_bytes(data["proofPoints"]["c"][1].as_str(). - // unwrap().as_bytes(), 10).unwrap(); - // - // let hex_ax = prepare_hex_representation(a_x, a_y); - // let hex_b0x = prepare_hex_representation(b0_x, BigUint::zero()); - // let hex_b1x = prepare_hex_representation(b1_x, b1_y); - // let hex_cx = prepare_hex_representation(c_x, c_y); - // - // let result = format!("{}{}{}{}", hex_ax, hex_b0x, hex_b1x, hex_cx); - // - // ????? ??????????? - // println!("Serialized proof: {}", result); - // println!("Serialized proof: 68490e184c1c5279d09fafc5e5c0b77d2a61fe6262ced81ff315c1813ec23b1257c1538b36c9822e94933c0fdb49d39502b7d63c47cc75cae7264f6afa1b5b2f82c3d7dc537cc07c2969bb4454a3d423d0e998f5787d4735eed757554654aeaf9ee6f79a85b302bdf25d83a9aeb4e06361459f51c86b1dca23172500034ca690"); } #[ignore] @@ -1506,6 +1460,7 @@ mod tests { let eph_pubkey_len = eph_pubkey.clone().len(); println!("len eph_pubkey: {:?}", eph_pubkey_len); + let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); From 3562abfc07fe489c2d0f682d4af5ecb9f21e5220 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 09:39:32 +0300 Subject: [PATCH 13/19] update some dependencies --- tvm_vm/Cargo.toml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tvm_vm/Cargo.toml b/tvm_vm/Cargo.toml index 848e4742..747d722a 100644 --- a/tvm_vm/Cargo.toml +++ b/tvm_vm/Cargo.toml @@ -28,9 +28,9 @@ tvm_block.workspace = true tvm_types.workspace = true serde_json.workspace = true +num-bigint.workspace = true #serde.workspace = true -#bellman = { git = "https://github.com/zkcrypto/bellman" } bls12_381 = "0.8" @@ -49,17 +49,15 @@ ark-r1cs-std = "0.4.0" ark-std = "0.4.0" -num-bigint = { version = "0.4", default-features = false, features = ["rand"] } -#fastcrypto-zkp = "0.1.3" +#num-bigint = { version = "0.4", default-features = false, features = ["rand"] } -fastcrypto = "0.1.8" #only temporary +fastcrypto = "0.1.8" neptune = { version = "13.0.0", default-features = false } once_cell = "1.16" schemars = "0.8.10" serde = { version = "1.0.156", features = ["derive"] } -#serde_derive = "1.0.200" -#serde_json = "1.0.93" + derive_more = "0.99.16" base64ct ={ version = "1.5.3", features = ["alloc"]} From 778b89807fc639fbe2d4a68ac49dffc5a2e60720 Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 09:41:19 +0300 Subject: [PATCH 14/19] more updates --- tvm_tests/Cargo.toml | 11 +++---- tvm_tests/src/test_zk.rs | 38 ++++++++++------------- tvm_vm/src/executor/zk_stuff/bn254/mod.rs | 8 ----- tvm_vm/src/executor/zk_stuff/zk_login.rs | 30 ------------------ 4 files changed, 21 insertions(+), 66 deletions(-) diff --git a/tvm_tests/Cargo.toml b/tvm_tests/Cargo.toml index 6e059f57..5e6f3818 100644 --- a/tvm_tests/Cargo.toml +++ b/tvm_tests/Cargo.toml @@ -24,27 +24,24 @@ anyhow.workspace = true lazy_static.workspace = true log.workspace = true num.workspace = true +ed25519.workspace = true +ed25519-dalek.workspace = true +rand.workspace = true -base64 = "0.13" +base64 = "0.13" libloading = '0.6' log4rs = '1.2' pprof = { features = [ 'criterion', 'flamegraph' ], version = '0.11' } pretty_assertions = '1.3' criterion = '0.4' - -ed25519 = '1.2' -ed25519-dalek = '1.0' -rand = '0.7' diffy = { optional = true, version = '0.2.2' } similar = { features = [ 'bytes' ], optional = true, version = '2.2.0' } - zstd = { default-features = false, optional = true, version = '0.11' } fastcrypto-zkp = "0.1.3" fastcrypto = "0.1.8" ark-std = "0.4.0" ark-ff = "0.4.2" - base64ct ={ version = "1.5.3", features = ["alloc"]} diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index 5ce14070..ad7fbbb1 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod tests { + use ed25519_dalek::Signer; use std::collections::HashMap; use std::iter::repeat; use std::str::FromStr; @@ -9,7 +10,7 @@ mod tests { use ark_std::rand::SeedableRng; use base64::decode; use base64ct::Encoding as bEncoding; - use ed25519::signature::Signer; + use rand::rngs::OsRng; use fastcrypto::ed25519::Ed25519KeyPair; use fastcrypto::traits::KeyPair; use fastcrypto::traits::ToFromBytes; @@ -63,6 +64,9 @@ mod tests { pub const SUI_DATA_FROM_REACT_1_NEW: &str = "{\"jwt\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMzI2MjQwODUxOTEtdjF0cTIwZmcxa2RoaGd2YXQ2c2FqN2pmMGhkODIzM3IuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTI4OTc0Njg2MjY3MTY2MjYxMDMiLCJub25jZSI6InZ0WGVzaFJyX2ZrVGR3SHpFQXY4a2wtbllHWSIsIm5iZiI6MTcyMTA2NzkzNiwiaWF0IjoxNzIxMDY4MjM2LCJleHAiOjE3MjEwNzE4MzYsImp0aSI6IjkzMjQ2YjIxNjg1NzM5YWE2MjI3MGY4NDllNTNmNDFhNTRiZGMxYWUifQ.HjDKI_m-uWUsgYzhc7Ovuy_bms0NEFdIoFUIjoG1axwxNKkZ1Hh-lXa1wyGDl0Zy1RM9fCblkMmyLY0Mm7-ACL1nqDA-EmWlIfytk6PPRu8YOFI_mMg-YmZmgGQTn1bJv0jUOo3yPaRa9hKceDfifFLS1tbWuOIyKZTCy2oH_TEcZo6O3UI2_ksOlf0tnfwtUmF-I2vhtlbH57AH6Uc0Kx4cSObrE4VV1Pj_rCwwEDGxxpAiSth8tCKM80mlzJ6Si3F11Epqj2vDLAX5IzZtn2gMj18MADlWsgmrxNbRh4-suVE_p7VIzlTuBfjmZps_5w6E62KPzovypo2ql3KISQ\",\"user_pass_to_int_format\":\"9910010710611510499100106115107\",\"zk_addr\":\"0x3a934c047196bdfdd751778f758cc2642a9cfa574ddb5d57025b67d109225e20\",\"ephemeral_key_pair\":{\"keypair\":{\"public_key\":{\"0\":141,\"1\":251,\"2\":140,\"3\":40,\"4\":213,\"5\":82,\"6\":20,\"7\":190,\"8\":208,\"9\":214,\"10\":244,\"11\":203,\"12\":156,\"13\":205,\"14\":36,\"15\":19,\"16\":24,\"17\":131,\"18\":176,\"19\":142,\"20\":74,\"21\":37,\"22\":199,\"23\":244,\"24\":70,\"25\":101,\"26\":194,\"27\":80,\"28\":211,\"29\":235,\"30\":171,\"31\":245},\"secret_key\":{\"0\":47,\"1\":220,\"2\":171,\"3\":167,\"4\":122,\"5\":143,\"6\":157,\"7\":242,\"8\":79,\"9\":81,\"10\":91,\"11\":236,\"12\":14,\"13\":127,\"14\":102,\"15\":140,\"16\":193,\"17\":217,\"18\":93,\"19\":88,\"20\":41,\"21\":18,\"22\":94,\"23\":40,\"24\":39,\"25\":63,\"26\":178,\"27\":120,\"28\":104,\"29\":214,\"30\":208,\"31\":207,\"32\":141,\"33\":251,\"34\":140,\"35\":40,\"36\":213,\"37\":82,\"38\":20,\"39\":190,\"40\":208,\"41\":214,\"42\":244,\"43\":203,\"44\":156,\"45\":205,\"46\":36,\"47\":19,\"48\":24,\"49\":131,\"50\":176,\"51\":142,\"52\":74,\"53\":37,\"54\":199,\"55\":244,\"56\":70,\"57\":101,\"58\":194,\"59\":80,\"60\":211,\"61\":235,\"62\":171,\"63\":245}}},\"maxEpoch\":142,\"extended_ephemeral_public_key\":\"AI37jCjVUhS+0Nb0y5zNJBMYg7COSiXH9EZlwlDT66v1\",\"zk_proofs\":{\"proofPoints\":{\"a\":[\"16813421039278654796395330442837655698730555183413337856642209109628683845443\",\"17226506757024740186126597704040151976665029813672291135146823263440625226230\",\"1\"],\"b\":[[\"19865189571716457271280707825159835672267817382424243521747870225851449993660\",\"8171164569532624421381183938498786515254461782830166752970857493983192858118\"],[\"19433278357078234147721454549239782691011759423461848201596076417708238357802\",\"20376887254972130170934329519774996610471771975828424380410011418190971129130\"],[\"1\",\"0\"]],\"c\":[\"12219856656033196506465767208555446381917939816812556286240154247316268622405\",\"17874973202272136490287260014626440020057757567816424198331948639084405340444\",\"1\"]},\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlMzQ1ZmQ3ZTRhOTcyNzFkZmZhOTkxZjVhODkzY2QxNmI4ZTA4MjciLCJ0eXAiOiJKV1QifQ\"}}"; + + + #[derive(Debug, Deserialize)] pub struct JwtData { pub jwt: String, @@ -126,10 +130,6 @@ mod tests { pub jti: String, } - fn gen_keypair() -> ed25519_dalek::Keypair { - ed25519_dalek::Keypair::generate(&mut rand::thread_rng()) - } - #[test] fn test_poseidon_plus_vrgrth16_based_on_real_data_super_new() { // real data taken from our react app for zklogin tests @@ -499,6 +499,8 @@ mod tests { println!("len eph_pubkey: {:?}", eph_pubkey_len); let jwt_data_vector: Vec<&str> = jwt_data.jwt.split(".").collect(); + println!("jwt_data_vector[0] {:?}", jwt_data_vector[0]); + let jwt_data_1 = decode(jwt_data_vector[0]).expect("Base64 decoding failed"); let jwt_string_1 = String::from_utf8(jwt_data_1).expect("UTF-8 conversion failed"); @@ -892,9 +894,6 @@ mod tests { let iss_and_header_base64details_cell = pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); - // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut - // 0).unwrap(); - let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); let max_epoch = "142"; //"200142"; @@ -1019,7 +1018,8 @@ mod tests { "===================================== START CHKSIGNS TEST =====================================" ); - let pair = gen_keypair(); + let mut csprng = OsRng; + let signing_key: ed25519_dalek::SigningKey = ed25519_dalek::SigningKey::generate(&mut csprng); let binding = proof_cell.clone(); let first = binding.data(); @@ -1034,10 +1034,8 @@ mod tests { // test cell with data and one not empty reference let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - // b.into_cell().unwrap();//crate::test_app_specific::gen_test_tree_of_cells(); - // let cell_hash = test_cell.repr_hash(); - // sign hash of data cell - let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); + + let signature = signing_key.sign(test_cell.data()).to_bytes().to_vec(); // put signature to separate slice let len = signature.len() * 8; @@ -1045,14 +1043,11 @@ mod tests { // put public key to integer let pub_key = BuilderData::with_raw( - pair.public.to_bytes().to_vec(), + signing_key.verifying_key().as_bytes().to_vec(), ed25519_dalek::PUBLIC_KEY_LENGTH * 8, ) .unwrap(); - // put hash to integer - // let hash = BuilderData::with_raw(cell_hash.as_slice().to_vec(), - // 256).unwrap(); test_case_with_refs( " @@ -1592,7 +1587,8 @@ mod tests { let (proof_cell, public_inputs_cell) = prepare_proof_and_public_key_cells_for_stack(eph_pubkey, zk_login_inputs, all_jwk); - let pair = gen_keypair(); + let mut csprng = OsRng; + let signing_key: ed25519_dalek::SigningKey = ed25519_dalek::SigningKey::generate(&mut csprng); let binding = proof_cell.clone(); let first = binding.data(); @@ -1602,8 +1598,8 @@ mod tests { let concatenated = [&first[..], &second[..]].concat(); - let test_cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); - let signature = pair.sign(test_cell.data()).to_bytes().to_vec(); + let test_cell: Cell = pack_data_to_cell(&concatenated, &mut 0).unwrap(); + let signature = signing_key.sign(test_cell.data()).to_bytes().to_vec(); // put signature to separate slice let len = signature.len() * 8; @@ -1611,7 +1607,7 @@ mod tests { // put public key to integer let pub_key = BuilderData::with_raw( - pair.public.to_bytes().to_vec(), + signing_key.verifying_key().as_bytes().to_vec(), ed25519_dalek::PUBLIC_KEY_LENGTH * 8, ) .unwrap(); diff --git a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs index cc34044c..37f66ec3 100644 --- a/tvm_vm/src/executor/zk_stuff/bn254/mod.rs +++ b/tvm_vm/src/executor/zk_stuff/bn254/mod.rs @@ -19,14 +19,6 @@ pub mod verifier; /// Poseidon hash function over BN254 pub mod poseidon; -/// Zk login structs and utilities -// pub mod zk_login; - -/// Zk login entrypoints -// pub mod zk_login_api; - -/// Zk login utils -// pub mod utils; /// A field element in the BN254 construction. Thin wrapper around /// `api::Bn254Fr`. diff --git a/tvm_vm/src/executor/zk_stuff/zk_login.rs b/tvm_vm/src/executor/zk_stuff/zk_login.rs index e25b20f4..23c39318 100644 --- a/tvm_vm/src/executor/zk_stuff/zk_login.rs +++ b/tvm_vm/src/executor/zk_stuff/zk_login.rs @@ -422,36 +422,6 @@ impl ZkLoginProof { /// Convert the Circom G1/G2/GT to arkworks G1/G2/GT pub fn as_arkworks(&self) -> Result, ZkCryptoError> { - println!(""); - println!("&self.a {:?}", &self.a); - println!("&self.b {:?}", &self.b); - - println!(""); - - let bb = g2_affine_from_str_projective(&self.b)?; - println!("&self.b bb {:?}", bb); - println!("&self.b bb.x {:?}", bb.x); - println!("&self.b bb.y {:?}", bb.y); - - let bby = bb.y; - let bby_ = -bby; - - println!("-bb.y {:?}", bby_); - - // let aa = g1_affine_from_str_projective(&self.a)?; - // println!("&self.a aa {:?}", aa); - // println!("&self.a aa.y {:?}", aa.y); - // - // let yy_ = -aa.y; - // println!("-aa.y {:?}", yy_); - // println!("-aa.y.to_string() {:?}", yy_.to_string()); - // - // println!("&self.a aa.y.to_string() {:?}", aa.y.to_string()); - // println!("&self.a aa.y.0 {:?}", aa.y.0); - // println!("&self.a aa.y.0.to_string() {:?}", aa.y.0.to_string()); - - println!(""); - return Ok(Proof { a: g1_affine_from_str_projective(&self.a)?, b: g2_affine_from_str_projective(&self.b)?, From 8f682f98b6dd775d949605df61d887ac3673706f Mon Sep 17 00:00:00 2001 From: alinat Date: Fri, 11 Oct 2024 10:55:59 +0300 Subject: [PATCH 15/19] update dependencies --- tvm_tests/Cargo.toml | 8 +++----- tvm_vm/Cargo.toml | 12 ++++-------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/tvm_tests/Cargo.toml b/tvm_tests/Cargo.toml index 5e6f3818..e01d7172 100644 --- a/tvm_tests/Cargo.toml +++ b/tvm_tests/Cargo.toml @@ -27,7 +27,9 @@ num.workspace = true ed25519.workspace = true ed25519-dalek.workspace = true rand.workspace = true - +diffy.workspace = true +zstd.workspace = true +similar.workspace = true base64 = "0.13" libloading = '0.6' @@ -35,15 +37,11 @@ log4rs = '1.2' pprof = { features = [ 'criterion', 'flamegraph' ], version = '0.11' } pretty_assertions = '1.3' criterion = '0.4' -diffy = { optional = true, version = '0.2.2' } -similar = { features = [ 'bytes' ], optional = true, version = '2.2.0' } -zstd = { default-features = false, optional = true, version = '0.11' } fastcrypto-zkp = "0.1.3" fastcrypto = "0.1.8" ark-std = "0.4.0" ark-ff = "0.4.2" base64ct ={ version = "1.5.3", features = ["alloc"]} - [lints] workspace = true diff --git a/tvm_vm/Cargo.toml b/tvm_vm/Cargo.toml index 747d722a..806184a5 100644 --- a/tvm_vm/Cargo.toml +++ b/tvm_vm/Cargo.toml @@ -23,13 +23,12 @@ rand.workspace = true similar = { features = ["bytes"], optional = true, version = "2.4.0" } thiserror.workspace = true zstd = { default-features = false, optional = true, version = "0.13.0" } -# + tvm_block.workspace = true tvm_types.workspace = true - serde_json.workspace = true num-bigint.workspace = true -#serde.workspace = true +serde.workspace = true bls12_381 = "0.8" @@ -48,15 +47,12 @@ ark-crypto-primitives = { version = "0.4.0", features = ["r1cs", "prf"] } ark-r1cs-std = "0.4.0" ark-std = "0.4.0" - -#num-bigint = { version = "0.4", default-features = false, features = ["rand"] } - fastcrypto = "0.1.8" neptune = { version = "13.0.0", default-features = false } once_cell = "1.16" schemars = "0.8.10" -serde = { version = "1.0.156", features = ["derive"] } +#serde = { version = "1.0.156", features = ["derive"] } derive_more = "0.99.16" base64ct ={ version = "1.5.3", features = ["alloc"]} @@ -72,7 +68,7 @@ log4rs = "1.2.0" pprof = { features = ["criterion", "flamegraph"], version = "0.13.0" } pretty_assertions = "1.4.0" -serde = { version = "1.0.156", features = ["derive"] } +#serde = { version = "1.0.156", features = ["derive"] } [features] fift_check = [] From fa958c30cedf3ee686c45a6df333605bcd898e1a Mon Sep 17 00:00:00 2001 From: alinat Date: Wed, 16 Oct 2024 12:13:50 +0300 Subject: [PATCH 16/19] change poseidon intruction api --- Cargo.lock | 126 ++++++++---------------------------- tvm_assembler/src/simple.rs | 2 +- tvm_tests/src/test_zk.rs | 68 ++++++++++++------- tvm_vm/src/executor/zk.rs | 110 ++++++++++++++++++++++++++++++- 4 files changed, 182 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 337c4f41..32a93eb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,7 +199,7 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "api_derive" -version = "2.2.10" +version = "2.2.11" dependencies = [ "api_info", "proc-macro2", @@ -210,7 +210,7 @@ dependencies = [ [[package]] name = "api_info" -version = "2.2.10" +version = "2.2.11" dependencies = [ "serde", "serde_derive", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "api_test" -version = "2.2.10" +version = "2.2.11" dependencies = [ "api_derive", "api_info", @@ -1385,19 +1385,6 @@ dependencies = [ "cipher 0.2.5", ] -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -1574,15 +1561,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "diffy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c27ec7cef89a63c063e06570bb861b7d35e406d6885551b346d77c459b34d3db" -dependencies = [ - "ansi_term", -] - [[package]] name = "diffy" version = "0.3.0" @@ -1662,19 +1640,10 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature 2.2.0", + "signature", "spki 0.7.3", ] -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature 1.6.4", -] - [[package]] name = "ed25519" version = "2.2.3" @@ -1682,7 +1651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8 0.10.2", - "signature 2.2.0", + "signature", ] [[package]] @@ -1700,28 +1669,14 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek 3.2.0", - "ed25519 1.5.3", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "ed25519-dalek" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", + "curve25519-dalek", + "ed25519", "rand_core 0.6.4", "serde", "sha2 0.10.8", @@ -1907,7 +1862,7 @@ dependencies = [ "serde_with", "sha2 0.10.8", "sha3", - "signature 2.2.0", + "signature", "static_assertions", "thiserror", "tokio", @@ -4074,7 +4029,7 @@ dependencies = [ "pkcs8 0.9.0", "rand_core 0.6.4", "sha2 0.10.8", - "signature 2.2.0", + "signature", "subtle", "zeroize", ] @@ -4503,12 +4458,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - [[package]] name = "signature" version = "2.2.0" @@ -5276,8 +5225,8 @@ dependencies = [ "anyhow", "base64 0.21.7", "crc 3.2.1", - "ed25519 2.2.3", - "ed25519-dalek 2.1.1", + "ed25519", + "ed25519-dalek", "failure", "hex", "log", @@ -5372,7 +5321,7 @@ dependencies = [ "chrono", "crc 3.2.1", "dirs", - "ed25519-dalek 2.1.1", + "ed25519-dalek", "failure", "futures", "graphql-parser", @@ -5420,7 +5369,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "zeroize", - "zstd 0.13.2", + "zstd", ] [[package]] @@ -5525,7 +5474,7 @@ dependencies = [ [[package]] name = "tvm_tests" -version = "2.2.9" +version = "2.2.11" dependencies = [ "anyhow", "ark-ff", @@ -5533,9 +5482,9 @@ dependencies = [ "base64 0.13.1", "base64ct", "criterion 0.4.0", - "diffy 0.2.2", - "ed25519 1.5.3", - "ed25519-dalek 1.0.1", + "diffy", + "ed25519", + "ed25519-dalek", "fastcrypto", "fastcrypto-zkp", "hex", @@ -5548,7 +5497,7 @@ dependencies = [ "num-traits", "pprof 0.11.1", "pretty_assertions", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_derive", "serde_json", @@ -5558,7 +5507,7 @@ dependencies = [ "tvm_block", "tvm_types", "tvm_vm", - "zstd 0.11.2+zstd.1.5.2", + "zstd", ] [[package]] @@ -5585,9 +5534,9 @@ dependencies = [ "blst", "crc 3.2.1", "criterion 0.5.1", - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", - "ed25519-dalek 2.1.1", + "curve25519-dalek", + "ed25519", + "ed25519-dalek", "failure", "hex", "lazy_static", @@ -5628,9 +5577,9 @@ dependencies = [ "byte-slice-cast", "criterion 0.5.1", "derive_more", - "diffy 0.3.0", - "ed25519 2.2.3", - "ed25519-dalek 2.1.1", + "diffy", + "ed25519", + "ed25519-dalek", "failure", "fastcrypto", "ff", @@ -5656,7 +5605,7 @@ dependencies = [ "tvm_block", "tvm_types", "typenum", - "zstd 0.13.2", + "zstd", ] [[package]] @@ -6194,7 +6143,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ - "curve25519-dalek 4.1.3", + "curve25519-dalek", "rand_core 0.6.4", "serde", "zeroize", @@ -6280,32 +6229,13 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - [[package]] name = "zstd" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 7.2.1", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", + "zstd-safe", ] [[package]] diff --git a/tvm_assembler/src/simple.rs b/tvm_assembler/src/simple.rs index 22395937..2aae0a29 100644 --- a/tvm_assembler/src/simple.rs +++ b/tvm_assembler/src/simple.rs @@ -843,7 +843,7 @@ impl Engine { CALCBKREWARD => 0xC7, 0x29 CALCMINSTAKE => 0xC7, 0x30 VERGRTH16 => 0xC7, 0x31 - POSEIDON_ZKLOGIN => 0xC7, 0x32 + POSEIDON => 0xC7, 0x32 } #[cfg(feature = "groth")] diff --git a/tvm_tests/src/test_zk.rs b/tvm_tests/src/test_zk.rs index ad7fbbb1..fe1304d1 100644 --- a/tvm_tests/src/test_zk.rs +++ b/tvm_tests/src/test_zk.rs @@ -192,6 +192,10 @@ mod tests { println!("iss_and_header_base64details: {}", iss_and_header_base64details); + let header_base_64 = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImEzYjc2MmY4NzFjZGIzYmFlMDA0NGM2NDk2MjJmYzEzOTZlZGEzZTMiLCJ0eXAiOiJKV1QifQ"; + let iss_base_64 = "yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC"; + let index_mod_4 = "1"; + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); let content: JWK = JWK { @@ -242,25 +246,26 @@ mod tests { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = - pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + let header_base_64_cell = pack_string_to_cell(&header_base_64, &mut 0).unwrap(); - let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); + let iss_base_64_cell = pack_string_to_cell(&iss_base_64, &mut 0).unwrap(); - let max_epoch_ = 142; + let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); - let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + let mut code = format!("PUSHINT {index_mod_4} \n").to_string(); + code = code + &*format!("PUSHINT {max_epoch} \n").to_string(); code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON \n".to_string();/**/ - println!("code : {:?}", code); + println!("code : {code}"); test_case_with_refs( code.as_str(), - vec![modulus_cell.clone(), iss_and_header_base64details_cell, zk_seed_cell], + vec![modulus_cell.clone(), iss_base_64_cell, header_base_64_cell, zk_seed_cell], ) .expect_stack(Stack::new().push(StackItem::Cell(public_inputs_cell.clone()))); //.expect_success(); @@ -319,6 +324,10 @@ mod tests { let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("iss_and_header_base64details: {}", iss_and_header_base64details); + let header_base_64 = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"; + let iss_base_64 = "yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC"; + let index_mod_4 = "1"; + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); @@ -367,26 +376,26 @@ mod tests { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = - pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + let header_base_64_cell = pack_string_to_cell(&header_base_64, &mut 0).unwrap(); - // let eph_pubkey_cell = pack_data_to_cell(&eph_pubkey.clone(), &mut - // 0).unwrap(); + let iss_base_64_cell = pack_string_to_cell(&iss_base_64, &mut 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); - let max_epoch_ = 142; - - let mut code = format!("PUSHINT {max_epoch_} \n").to_string(); + let mut code = format!("PUSHINT {index_mod_4} \n").to_string(); + code = code + &*format!("PUSHINT {max_epoch} \n").to_string(); code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON \n".to_string();/**/ + + println!("code : {code}"); test_case_with_refs( code.as_str(), - vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell], + vec![modulus_cell, iss_base_64_cell, header_base_64_cell, zk_seed_cell], ) .expect_success(); @@ -847,6 +856,10 @@ mod tests { let iss_and_header_base64details = "{\"issBase64Details\":{\"value\":\"yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC\",\"indexMod4\":1},\"headerBase64\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ\"}"; println!("iss_and_header_base64details: {}", iss_and_header_base64details); + let header_base_64 = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjZmNzI1NDEwMWY1NmU0MWNmMzVjOTkyNmRlODRhMmQ1NTJiNGM2ZjEiLCJ0eXAiOiJKV1QifQ"; + let iss_base_64 = "yJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLC"; + let index_mod_4 = "1"; + let zk_login_inputs = ZkLoginInputs::from_json(&*proof_and_jwt, &*zk_seed.to_string()).unwrap(); @@ -891,25 +904,36 @@ mod tests { let modulus_cell = pack_data_to_cell(&modulus.clone(), &mut 0).unwrap(); - let iss_and_header_base64details_cell = - pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap(); + /*let iss_and_header_base64details_cell = + pack_string_to_cell(&iss_and_header_base64details, &mut 0).unwrap();*/ + + let header_base_64_cell = + pack_string_to_cell(&header_base_64, &mut 0).unwrap(); + + let iss_base_64_cell = + pack_string_to_cell(&iss_base_64, &mut 0).unwrap(); let zk_seed_cell = pack_string_to_cell(&zk_seed.clone(), &mut 0).unwrap(); let max_epoch = "142"; //"200142"; - let mut code = format!("PUSHINT {max_epoch} \n").to_string(); + let mut code = format!("PUSHINT {index_mod_4} \n").to_string(); + code = code + &*format!("PUSHINT {max_epoch} \n").to_string(); code = code + &*format!("PUSHINT {eph_pubkey_hex_number} \n").to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); code = code + &*"PUSHREF \n".to_string(); - code = code + &*"POSEIDON_ZKLOGIN \n".to_string(); + code = code + &*"PUSHREF \n".to_string(); + //code = code + &*"PUSHREF \n".to_string(); + code = code + &*"POSEIDON \n".to_string();/**/ + + println!("code : {code}"); test_case_with_refs( code.as_str(), - vec![modulus_cell, iss_and_header_base64details_cell, zk_seed_cell], + vec![modulus_cell, /*&iss_and_header_base64details_cell*/ iss_base_64_cell, header_base_64_cell, zk_seed_cell], ) .expect_success(); } diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 4d7f25d9..2a4af24a 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -21,7 +21,6 @@ use num_bigint::BigUint; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use serde_json::Value; use tvm_types::SliceData; use crate::executor::engine::storage::fetch_stack; @@ -729,6 +728,111 @@ fn pop(barry: &[u8]) -> &[u8; 8] { } pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { + engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; + fetch_stack(engine, 7)?; + + let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; + let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; + + let header_base_64_slice = + SliceData::load_cell_ref(engine.cmd.var(1 ).as_cell()?)?; + let header_base_64 = unpack_string_from_cell(header_base_64_slice, engine)?; + + let iss_base_64_slice = + SliceData::load_cell_ref(engine.cmd.var(2 ).as_cell()?)?; + let iss_base_64 = unpack_string_from_cell(iss_base_64_slice, engine)?; + + let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(3).as_cell()?)?; + let modulus = unpack_data_from_cell(modulus_slice, engine)?; + + let eph_pub_key = engine + .cmd + .var(4 ) + .as_integer()? + .as_builder::(PUBLIC_KEY_BITS)?; + + let eph_pub_key_bytes = eph_pub_key.data(); + + let max_epoch_ = engine + .cmd + .var(5 ) + .as_integer()? + .as_builder::( 64)?; + + let index_mod_4 = engine.cmd.var(6).as_integer()?.into(0..=255)?.to_string(); + + let max_epoch_bytes = pop(max_epoch_.data()); + let max_epoch = u64::from_be_bytes(*max_epoch_bytes); + + let public_inputs = calculate_poseidon_hash( + &*zkaddr, + /*&*header_and_iss_base64,*/ + &header_base_64, + &iss_base_64, + &index_mod_4, + &eph_pub_key_bytes, + &modulus, + max_epoch, + ) + .unwrap(); + + let mut public_inputs_as_bytes = vec![]; + public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); + + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + + engine.cc.stack.push(Cell(public_inputs_cell)); + + Ok(()) +} + +pub fn calculate_poseidon_hash( + address_seed: &str, + header_base_64: &str, + iss_base_64: &str, + index_mod_4: &str, + /*header_and_iss_base64: &str,*/ + eph_pk_bytes: &[u8], + modulus: &[u8], + max_epoch: u64, +) -> Result { + + let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); + let addr_seed = (&address_seed).into(); + + let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); + + let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); + + /*let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); + + let header_base64 = v["headerBase64"].as_str().unwrap(); + + let iss_base64_details = v["issBase64Details"].as_object().unwrap(); + + let index_mod_4 = iss_base64_details["indexMod4"].as_i64().unwrap().to_string() + + let iss_base64_details_value = iss_base64_details["value"].as_str().unwrap();;*/ + + let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); + + let iss_base64_f = hash_ascii_str_to_field(/*&iss_base64_details_value*/&iss_base_64, MAX_ISS_LEN_B64).unwrap(); + let header_f = hash_ascii_str_to_field(/*&header_base64*/ &header_base_64, MAX_HEADER_LEN).unwrap(); + let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); + + poseidon_zk_login(vec![ + first, + second, + addr_seed, + max_epoch_f, + iss_base64_f, + index_mod_4_f, + header_f, + modulus_f, + ]) +} + +/*pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; fetch_stack(engine, 5)?; @@ -736,7 +840,7 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; let header_and_iss_base64_slice = - SliceData::load_cell_ref(engine.cmd.var(1 /* 2 */).as_cell()?)?; + SliceData::load_cell_ref(engine.cmd.var(1 ).as_cell()?)?; let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; @@ -819,4 +923,4 @@ pub fn calculate_poseidon_hash( header_f, modulus_f, ]) -} +}*/ From 129341e74216de71b4a5ec37e13910023e3293bf Mon Sep 17 00:00:00 2001 From: alinat Date: Wed, 16 Oct 2024 13:08:25 +0300 Subject: [PATCH 17/19] fix error handling --- tvm_vm/src/executor/zk.rs | 40 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 2a4af24a..7ab88a4e 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -21,6 +21,7 @@ use num_bigint::BigUint; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; + use tvm_types::SliceData; use crate::executor::engine::storage::fetch_stack; @@ -689,7 +690,7 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { engine.load_instruction(crate::executor::types::Instruction::new("VERGRTH16"))?; fetch_stack(engine, 3)?; - let vk_index = engine.cmd.var(0).as_small_integer().unwrap() as u32; + let vk_index = engine.cmd.var(0).as_small_integer()? as u32; let public_inputs_slice = SliceData::load_cell_ref(engine.cmd.var(1).as_cell()?)?; let public_inputs_as_bytes = unpack_data_from_cell(public_inputs_slice, engine)?; @@ -716,7 +717,7 @@ pub(crate) fn execute_vergrth16(engine: &mut Engine) -> Status { let succes = res.is_ok(); - let res = if succes { boolean!(res.unwrap()) } else { boolean!(false) }; + let res = if succes { boolean!(res?) } else { boolean!(false) }; engine.cc.stack.push(res); @@ -766,21 +767,18 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let public_inputs = calculate_poseidon_hash( &*zkaddr, - /*&*header_and_iss_base64,*/ &header_base_64, &iss_base_64, &index_mod_4, &eph_pub_key_bytes, &modulus, max_epoch, - ) - .unwrap(); + )?; let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); + public_inputs.serialize_compressed(&mut public_inputs_as_bytes)?; + let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0)?; engine.cc.stack.push(Cell(public_inputs_cell)); Ok(()) @@ -791,34 +789,22 @@ pub fn calculate_poseidon_hash( header_base_64: &str, iss_base_64: &str, index_mod_4: &str, - /*header_and_iss_base64: &str,*/ eph_pk_bytes: &[u8], modulus: &[u8], max_epoch: u64, ) -> Result { - let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); + let address_seed = Bn254FrElement::from_str(address_seed)?; let addr_seed = (&address_seed).into(); - let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); - - let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); + let (first, second) = split_to_two_frs(eph_pk_bytes)?; - /*let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); + let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string())?).into(); - let header_base64 = v["headerBase64"].as_str().unwrap(); - - let iss_base64_details = v["issBase64Details"].as_object().unwrap(); - - let index_mod_4 = iss_base64_details["indexMod4"].as_i64().unwrap().to_string() - - let iss_base64_details_value = iss_base64_details["value"].as_str().unwrap();;*/ - - let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); - - let iss_base64_f = hash_ascii_str_to_field(/*&iss_base64_details_value*/&iss_base_64, MAX_ISS_LEN_B64).unwrap(); - let header_f = hash_ascii_str_to_field(/*&header_base64*/ &header_base_64, MAX_HEADER_LEN).unwrap(); - let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); + let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4)?).into(); + let iss_base64_f = hash_ascii_str_to_field(&iss_base_64, MAX_ISS_LEN_B64)?; + let header_f = hash_ascii_str_to_field( &header_base_64, MAX_HEADER_LEN)?; + let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH)?; poseidon_zk_login(vec![ first, From 8af9f94af93f433f434fa3e4025ad68cbe62ff5c Mon Sep 17 00:00:00 2001 From: alinat Date: Wed, 16 Oct 2024 14:10:56 +0300 Subject: [PATCH 18/19] remove old code --- tvm_vm/src/executor/zk.rs | 97 +-------------------------------------- 1 file changed, 1 insertion(+), 96 deletions(-) diff --git a/tvm_vm/src/executor/zk.rs b/tvm_vm/src/executor/zk.rs index 7ab88a4e..79294ccf 100644 --- a/tvm_vm/src/executor/zk.rs +++ b/tvm_vm/src/executor/zk.rs @@ -763,6 +763,7 @@ pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { let index_mod_4 = engine.cmd.var(6).as_integer()?.into(0..=255)?.to_string(); let max_epoch_bytes = pop(max_epoch_.data()); + let max_epoch = u64::from_be_bytes(*max_epoch_bytes); let public_inputs = calculate_poseidon_hash( @@ -793,19 +794,14 @@ pub fn calculate_poseidon_hash( modulus: &[u8], max_epoch: u64, ) -> Result { - let address_seed = Bn254FrElement::from_str(address_seed)?; let addr_seed = (&address_seed).into(); - let (first, second) = split_to_two_frs(eph_pk_bytes)?; - let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string())?).into(); - let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4)?).into(); let iss_base64_f = hash_ascii_str_to_field(&iss_base_64, MAX_ISS_LEN_B64)?; let header_f = hash_ascii_str_to_field( &header_base_64, MAX_HEADER_LEN)?; let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH)?; - poseidon_zk_login(vec![ first, second, @@ -818,95 +814,4 @@ pub fn calculate_poseidon_hash( ]) } -/*pub(crate) fn execute_poseidon_zk_login(engine: &mut Engine) -> Status { - engine.load_instruction(crate::executor::types::Instruction::new("POSEIDON"))?; - fetch_stack(engine, 5)?; - - let zkaddr_slice = SliceData::load_cell_ref(engine.cmd.var(0).as_cell()?)?; - let zkaddr = unpack_string_from_cell(zkaddr_slice, engine)?; - - let header_and_iss_base64_slice = - SliceData::load_cell_ref(engine.cmd.var(1 ).as_cell()?)?; - let header_and_iss_base64 = unpack_string_from_cell(header_and_iss_base64_slice, engine)?; - - let modulus_slice = SliceData::load_cell_ref(engine.cmd.var(2).as_cell()?)?; - let modulus = unpack_data_from_cell(modulus_slice, engine)?; - - let eph_pub_key = engine - .cmd - .var(3 ) - .as_integer()? - .as_builder::(PUBLIC_KEY_BITS)?; - - let eph_pub_key_bytes = eph_pub_key.data(); - - let max_epoch_ = engine - .cmd - .var(4 ) - .as_integer()? - .as_builder::( 64)?; - - let max_epoch_bytes = pop(max_epoch_.data()); - let max_epoch = u64::from_be_bytes(*max_epoch_bytes); - - let public_inputs = calculate_poseidon_hash( - &*zkaddr, - &*header_and_iss_base64, - &eph_pub_key_bytes, - &modulus, - max_epoch, - ) - .unwrap(); - - let mut public_inputs_as_bytes = vec![]; - public_inputs.serialize_compressed(&mut public_inputs_as_bytes).unwrap(); - - let public_inputs_cell = pack_data_to_cell(&public_inputs_as_bytes, &mut 0).unwrap(); - - engine.cc.stack.push(Cell(public_inputs_cell)); - - Ok(()) -} - -pub fn calculate_poseidon_hash( - address_seed: &str, - header_and_iss_base64: &str, - eph_pk_bytes: &[u8], - modulus: &[u8], - max_epoch: u64, -) -> Result { - - let address_seed = Bn254FrElement::from_str(address_seed).unwrap(); - let addr_seed = (&address_seed).into(); - - let (first, second) = split_to_two_frs(eph_pk_bytes).unwrap(); - let max_epoch_f = (&Bn254FrElement::from_str(&max_epoch.to_string()).unwrap()).into(); - - let v: Value = serde_json::from_str(header_and_iss_base64).unwrap(); - - let header_base64 = v["headerBase64"].as_str().unwrap(); - - let iss_base64_details = v["issBase64Details"].as_object().unwrap(); - - let index_mod_4 = iss_base64_details["indexMod4"].as_i64().unwrap().to_string(); - - let iss_base64_details_value = iss_base64_details["value"].as_str().unwrap(); - - let index_mod_4_f = (&Bn254FrElement::from_str(&index_mod_4).unwrap()).into(); - - let iss_base64_f = hash_ascii_str_to_field(&iss_base64_details_value, MAX_ISS_LEN_B64).unwrap(); - let header_f = hash_ascii_str_to_field(&header_base64, MAX_HEADER_LEN).unwrap(); - let modulus_f = hash_to_field(&[BigUint::from_bytes_be(modulus)], 2048, PACK_WIDTH).unwrap(); - - poseidon_zk_login(vec![ - first, - second, - addr_seed, - max_epoch_f, - iss_base64_f, - index_mod_4_f, - header_f, - modulus_f, - ]) -}*/ From 2858e8575a1ce4cafd94c6a94b134b0055f20be8 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz Date: Mon, 21 Oct 2024 13:17:14 +0200 Subject: [PATCH 19/19] minor version up --- CHANGELOG.md | 2 +- Cargo.lock | 42 +++++++++++++++++++++--------------------- Cargo.toml | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd05d76a..4472414d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [2.2.13] – 2024-10-16 +## [2.3.0] – 2024-10-21 ### New - Add support of VERGRTH16 and POSEIDON instructions for zk-login. diff --git a/Cargo.lock b/Cargo.lock index cc36e760..2557c2d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,7 +199,7 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "api_derive" -version = "2.2.13" +version = "2.3.0" dependencies = [ "api_info", "proc-macro2", @@ -210,7 +210,7 @@ dependencies = [ [[package]] name = "api_info" -version = "2.2.13" +version = "2.3.0" dependencies = [ "serde", "serde_derive", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "api_test" -version = "2.2.13" +version = "2.3.0" dependencies = [ "api_derive", "api_info", @@ -5165,7 +5165,7 @@ dependencies = [ [[package]] name = "tvm_abi" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "chrono", @@ -5182,7 +5182,7 @@ dependencies = [ [[package]] name = "tvm_api" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "byteorder", @@ -5203,7 +5203,7 @@ dependencies = [ [[package]] name = "tvm_assembler" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "clap 4.5.19", @@ -5220,7 +5220,7 @@ dependencies = [ [[package]] name = "tvm_block" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "base64 0.21.7", @@ -5241,7 +5241,7 @@ dependencies = [ [[package]] name = "tvm_block_json" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "failure", @@ -5263,7 +5263,7 @@ dependencies = [ [[package]] name = "tvm_cli" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "assert_cmd", @@ -5305,7 +5305,7 @@ dependencies = [ [[package]] name = "tvm_client" -version = "2.2.13" +version = "2.3.0" dependencies = [ "aes", "anyhow", @@ -5374,7 +5374,7 @@ dependencies = [ [[package]] name = "tvm_client_processing" -version = "2.2.13" +version = "2.3.0" dependencies = [ "api_derive", "api_info", @@ -5394,7 +5394,7 @@ dependencies = [ [[package]] name = "tvm_common" -version = "2.2.13" +version = "2.3.0" dependencies = [ "external-ip", "failure", @@ -5407,7 +5407,7 @@ dependencies = [ [[package]] name = "tvm_debugger" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "base64 0.21.7", @@ -5424,7 +5424,7 @@ dependencies = [ [[package]] name = "tvm_executor" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "failure", @@ -5438,7 +5438,7 @@ dependencies = [ [[package]] name = "tvm_sdk" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "api_derive", @@ -5463,7 +5463,7 @@ dependencies = [ [[package]] name = "tvm_struct" -version = "2.2.13" +version = "2.3.0" dependencies = [ "failure", "hex-literal", @@ -5474,7 +5474,7 @@ dependencies = [ [[package]] name = "tvm_tests" -version = "2.2.11" +version = "2.3.0" dependencies = [ "anyhow", "ark-ff", @@ -5512,7 +5512,7 @@ dependencies = [ [[package]] name = "tvm_tl_codegen" -version = "2.2.13" +version = "2.3.0" dependencies = [ "crc 1.8.1", "failure", @@ -5526,7 +5526,7 @@ dependencies = [ [[package]] name = "tvm_types" -version = "2.2.13" +version = "2.3.0" dependencies = [ "aes-ctr", "anyhow", @@ -5557,7 +5557,7 @@ dependencies = [ [[package]] name = "tvm_vm" -version = "2.2.13" +version = "2.3.0" dependencies = [ "anyhow", "ark-bls12-381", @@ -5694,7 +5694,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "update_trusted_blocks" -version = "2.2.13" +version = "2.3.0" dependencies = [ "bincode", "serde", diff --git a/Cargo.toml b/Cargo.toml index c11c25a4..03a5bf50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ "tvm_tests" ] [workspace.package] -version = "2.2.13" +version = "2.3.0" rust-version = "1.76.0"