diff --git a/.dockerignore b/.dockerignore index 473661b..e75d33e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,6 @@ github.env Taskfile.yaml +# Rust +target +vdf/generated diff --git a/.gitignore b/.gitignore index 2768a9c..8b8f9ff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ ceremony-client .env.signers .task node-tmp-* +build + +# Rust +target diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c01756f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Local development + +The following software is required for local development (assuming MacOS ARM): + +- Go 1.20 +- Rust toolchain +- GMP 6.3: `brew install gmp` +- Install the Go plugin for uniffi-rs: `cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0` + +# Building release binaries + +The following is software is required to build release binaries (assuming MacOS +ARM) : + +- [Local development](#local-development) dependencies +- Docker +- [Taskfile](https://taskfile.dev/) + +Then from the repo root use the following commands to build the release binaries +that statically link the [native VDF](./crates/vdf) for the supported platforms: + +```shell +task build_node_arm64_macos +task build_node_arm64_linux +task build_node_arm64_macos +``` + +The output binaries will be in `node/build`. + +# Testing + +Testing the [`vdf`](./vdf) and [`node`](./node) packages requires linking the +[native VDF](./crates/vdf). The `test.sh` scripts in the respective directories +help with this. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..eee764f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1201 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-vec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "classgroup" +version = "0.1.0" +dependencies = [ + "criterion", + "libc", + "num-traits", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "goblin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oneshot-uniffi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uniffi" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" +dependencies = [ + "anyhow", + "camino", + "clap", + "uniffi_bindgen", + "uniffi_build", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "clap", + "fs-err", + "glob", + "goblin", + "heck 0.4.1", + "once_cell", + "paste", + "serde", + "toml", + "uniffi_meta", + "uniffi_testing", + "uniffi_udl", +] + +[[package]] +name = "uniffi_build" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" +dependencies = [ + "anyhow", + "camino", + "uniffi_bindgen", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "uniffi_core" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" +dependencies = [ + "anyhow", + "bytes", + "camino", + "log", + "once_cell", + "oneshot-uniffi", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", + "uniffi_build", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" +dependencies = [ + "anyhow", + "bytes", + "siphasher", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" +dependencies = [ + "anyhow", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "vdf" +version = "0.1.0" +dependencies = [ + "bit-vec", + "classgroup", + "criterion", + "hex", + "num-traits", + "sha2", + "uniffi", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weedle2" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" +dependencies = [ + "nom", +] + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..229c039 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,25 @@ +# Copyright 2018 Chia Network Inc and POA Networks Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# and limitations under the License. +[workspace] +members = [ + "crates/vdf", + "crates/classgroup", +] + +[profile.release] +# rpath = false is important to make Go bindings work +rpath = false +lto = true +debug = false +# panic = 'abort' diff --git a/Dockerfile b/Dockerfile index 42fa039..4475ea3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,20 @@ -FROM golang:1.20.14-alpine3.19 as build +FROM golang:1.20.14-bullseye as build-base + +ENV PATH="${PATH}:/root/.cargo/bin/" + +# Install GMP 6.2 (6.3 which MacOS is using only available on Debian unstable) +RUN apt-get update && apt-get install -y \ + libgmp-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY docker/rustup-init.sh /opt/rustup-init.sh + +RUN /opt/rustup-init.sh -y --profile minimal + +# Install uniffi-bindgen-go +RUN cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0 + +FROM build-base as build ENV GOEXPERIMENT=arenas @@ -6,16 +22,27 @@ WORKDIR /opt/ceremonyclient COPY . . +## Generate Rust bindings for VDF +WORKDIR /opt/ceremonyclient/vdf +RUN ./generate.sh + +# Build and install the node WORKDIR /opt/ceremonyclient/node -RUN go install ./... +RUN ./build.sh && cp node /go/bin RUN go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest +# Build and install qclient WORKDIR /opt/ceremonyclient/client RUN go build -o qclient ./main.go -FROM alpine:3.19 +# Allows exporting single binary +FROM scratch AS node +COPY --from=build /go/bin/node /node +ENTRYPOINT [ "/node" ] + +FROM debian:bullseye ARG NODE_VERSION ARG GIT_REPO diff --git a/Taskfile.yaml b/Taskfile.yaml index a2de09e..a4dd7da 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -25,6 +25,22 @@ tasks: - echo -n "Branch :" && echo " {{.GIT_BRANCH}}" - echo -n "Commit :" && echo " {{.GIT_COMMIT}}" silent: true + + build_node_arm64_macos: + desc: Build the Quilibrium node binary for MacOS ARM. Assumes it's ran from the same platform. Outputs to node/build. + cmds: + - vdf/generate.sh + - node/build.sh -o build/arm64_macos/node + + build_node_arm64_linux: + desc: Build the Quilibrium node binary for ARM64 Linux. Outputs to node/build. + cmds: + - docker build --platform linux/arm64 -f Dockerfile --output node/build/arm64_linux --target=node . + + build_node_amd64_linux: + desc: Build the Quilibrium node binary for AMD64 Linux. Outputs to node/build. + cmds: + - docker build --platform linux/amd64 -f Dockerfile --output node/build/amd64_linux --target=node . build: desc: Build the Quilibrium docker image, unless it is already built. diff --git a/client/go.mod b/client/go.mod index caad573..feeaf2c 100644 --- a/client/go.mod +++ b/client/go.mod @@ -24,8 +24,8 @@ require ( github.com/minio/sha256-simd v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/sys v0.21.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect diff --git a/client/go.sum b/client/go.sum index 03655ac..69e7b3f 100644 --- a/client/go.sum +++ b/client/go.sum @@ -89,8 +89,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -103,8 +103,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/crates/classgroup/Cargo.toml b/crates/classgroup/Cargo.toml new file mode 100644 index 0000000..7474010 --- /dev/null +++ b/crates/classgroup/Cargo.toml @@ -0,0 +1,34 @@ +# Copyright 2018 POA Networks Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# and limitations under the License. +[package] +name = "classgroup" +version = "0.1.0" +authors = ["Demi M. Obenour "] +description = """An implementation of class groups in Rust. Uses GMP for arithmetic.""" +keywords = ["classgroup", "vdf"] +repository = "https://github.com/poanetwork/vdf" +license = "Apache-2.0" +edition = "2018" + +[dependencies] +num-traits = "0.2" +libc = "0.2" + +[dev-dependencies] +criterion = ">=0.2" + +[[bench]] +name = "classgroup-bench" +harness = false +path = "bench/bench.rs" diff --git a/crates/classgroup/bench/bench.rs b/crates/classgroup/bench/bench.rs new file mode 100644 index 0000000..8dc7b22 --- /dev/null +++ b/crates/classgroup/bench/bench.rs @@ -0,0 +1,66 @@ +// Copyright 2018 POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate criterion; + +use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup}; +use criterion::Criterion; +use gmp::mpz::Mpz; +use std::str::FromStr; + +fn bench_square(c: &mut Criterion) { + for _ in 0..2 { + let m_2048 = -Mpz::from_str( + "201493927071865251625903550712920535753645598483515670853547009\ + 878440933309489362800393797428711071833308081461824159206915864\ + 150805748296170245037221957772328044276705571745811271212292422\ + 075849739248257870371300001313586036515879618764093772248760562\ + 386804073478433157526816295216137723803793411828867470089409596\ + 238958950007370719325959579892866588928887249912429688364409867\ + 895510817680171869190054122881274299350947669820596157115994418\ + 034091728887584373727555384075665624624856766441009974642693066\ + 751400054217209981490667208950669417773785631693879782993019167\ + 69407006303085854796535778826115224633447713584423", + ) + .unwrap(); + + let m_1024 = -Mpz::from_str( + "-11208471744389096429663063172516742066731683613191418514476174383781\ + 682509882427394963852743081347678693241523614532942268295868231081182\ + 819214054220080323345750407342623884342617809879459211722505867733607\ + 400509994975706778681543998242335468203860240586171413971485860382901\ + 6409314686266660248501773529803183", + ) + .unwrap(); + let group_1024 = GmpClassGroup::generator_for_discriminant(m_1024); + let group_2048 = GmpClassGroup::generator_for_discriminant(m_2048); + let (group_1024_clone, group_2048_clone) = (group_1024.clone(), group_2048.clone()); + c.bench_function("square 1024", move |b| { + b.iter(|| group_1024_clone.clone().square()) + }); + c.bench_function("multiply 1024", move |b| { + b.iter(|| &group_1024 * &group_1024) + }); + c.bench_function("square 2048", move |b| { + b.iter(|| group_2048_clone.clone().square()) + }); + c.bench_function("multiply 2048", move |b| { + b.iter(|| &group_2048 * &group_2048) + }); + } +} + +criterion_group!(benches, bench_square); +criterion_main!(benches); diff --git a/crates/classgroup/build.rs b/crates/classgroup/build.rs new file mode 100644 index 0000000..a4b0529 --- /dev/null +++ b/crates/classgroup/build.rs @@ -0,0 +1,16 @@ +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let target = env::var("TARGET").expect("cargo should have set this"); + if target == "aarch64-apple-darwin" { + println!("cargo:rustc-link-search=/opt/homebrew/Cellar/gmp/6.3.0/lib"); + } else if target == "aarch64-unknown-linux-gnu" { + println!("cargo:rustc-link-search=/usr/lib/aarch64-linux-gnu/"); + } else if target == "x86_64-unknown-linux-gnu" { + println!("cargo:rustc-link-search=/usr/lib/x86_64-linux-gnu/"); + } else { + panic!("unsupported target {target}"); + } +} diff --git a/crates/classgroup/src/gmp/ffi.rs b/crates/classgroup/src/gmp/ffi.rs new file mode 100644 index 0000000..d8cc2b1 --- /dev/null +++ b/crates/classgroup/src/gmp/ffi.rs @@ -0,0 +1,7 @@ +use super::mpz::*; + +#[link(name = "gmp", kind = "static")] +extern "C" { + pub fn __gmpz_fdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); + pub fn __gmpz_cdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); +} diff --git a/crates/classgroup/src/gmp/mod.rs b/crates/classgroup/src/gmp/mod.rs new file mode 100644 index 0000000..a03f391 --- /dev/null +++ b/crates/classgroup/src/gmp/mod.rs @@ -0,0 +1,12 @@ +#![warn(deprecated)] +#![allow(non_camel_case_types)] + +extern crate libc; +extern crate num_traits; + +mod ffi; +pub mod mpz; +pub mod sign; + +#[cfg(test)] +mod test; diff --git a/crates/classgroup/src/gmp/mpz.rs b/crates/classgroup/src/gmp/mpz.rs new file mode 100644 index 0000000..b8a1beb --- /dev/null +++ b/crates/classgroup/src/gmp/mpz.rs @@ -0,0 +1,1035 @@ +#![allow(unsafe_code)] +use libc::{c_char, c_int, c_long, c_ulong, c_void, c_double, size_t, strnlen}; +use super::sign::Sign; +use std::convert::From; +use std::mem::{uninitialized,size_of}; +use std::{fmt, hash}; +use std::cmp::Ordering::{self, Greater, Less, Equal}; +use std::str::FromStr; +use std::error::Error; +use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, BitXor, BitXorAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, Rem, RemAssign}; +use std::ffi::CString; +use std::{u32, i32, usize}; +use num_traits::{Zero, One}; + +use super::ffi::*; + +#[repr(C)] +pub struct mpz_struct { + _mp_alloc: c_int, + _mp_size: c_int, + _mp_d: *mut c_void +} + +pub type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead. +pub type mp_bitcnt_t = c_ulong; +pub type mpz_srcptr = *const mpz_struct; +pub type mpz_ptr = *mut mpz_struct; + +#[link(name = "gmp", kind = "static")] +extern "C" { + static __gmp_bits_per_limb: c_int; + fn __gmpz_init(x: mpz_ptr); + fn __gmpz_init2(x: mpz_ptr, n: mp_bitcnt_t); + fn __gmpz_init_set(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_init_set_ui(rop: mpz_ptr, op: c_ulong); + fn __gmpz_init_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; + fn __gmpz_clear(x: mpz_ptr); + fn __gmpz_realloc2(x: mpz_ptr, n: mp_bitcnt_t); + fn __gmpz_set(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; + fn __gmpz_get_str(s: *mut c_char, base: c_int, op: mpz_srcptr) -> *mut c_char; + fn __gmpz_get_ui(op: mpz_srcptr) -> c_ulong; + fn __gmpz_fits_ulong_p(op: mpz_srcptr) -> c_int; + fn __gmpz_get_si(op: mpz_srcptr) -> c_ulong; + fn __gmpz_get_d(op: mpz_srcptr) -> c_double; + fn __gmpz_fits_slong_p(op: mpz_srcptr) -> c_long; + fn __gmpz_sizeinbase(op: mpz_srcptr, base: c_int) -> size_t; + fn __gmpz_cmp(op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; + fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int; + fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_add_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); + fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_sub_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); + fn __gmpz_ui_sub(rop: mpz_ptr, op1: c_ulong, op2: mpz_srcptr); + fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_mul_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); + fn __gmpz_mul_si(rop: mpz_ptr, op1: mpz_srcptr, op2: c_long); + fn __gmpz_mul_2exp(rop: mpz_ptr, op1: mpz_srcptr, op2: mp_bitcnt_t); + fn __gmpz_neg(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_abs(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_tdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); + fn __gmpz_tdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); + fn __gmpz_tdiv_q_ui(q: mpz_ptr, n: mpz_srcptr, d: c_ulong); + fn __gmpz_tdiv_r_ui(r: mpz_ptr, n: mpz_srcptr, d: c_ulong); + fn __gmpz_fdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); + fn __gmpz_fdiv_q_2exp(q: mpz_ptr, n: mpz_srcptr, b: mp_bitcnt_t); + fn __gmpz_mod(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); + fn __gmpz_divisible_p(n: mpz_srcptr, d: mpz_srcptr) -> c_int; + fn __gmpz_and(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_ior(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_xor(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_com(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_popcount(op: mpz_srcptr) -> mp_bitcnt_t; + fn __gmpz_pow_ui(rop: mpz_ptr, base: mpz_srcptr, exp: c_ulong); + fn __gmpz_ui_pow_ui(rop: mpz_ptr, base: c_ulong, exp: c_ulong); + fn __gmpz_powm(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr); + fn __gmpz_powm_sec(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr); + fn __gmpz_hamdist(op1: mpz_srcptr, op2: mpz_srcptr) -> mp_bitcnt_t; + fn __gmpz_setbit(rop: mpz_ptr, bit_index: mp_bitcnt_t); + fn __gmpz_clrbit(rop: mpz_ptr, bit_index: mp_bitcnt_t); + fn __gmpz_combit(rop: mpz_ptr, bit_index: mp_bitcnt_t); + fn __gmpz_tstbit(rop: mpz_srcptr, bit_index: mp_bitcnt_t) -> c_int; + fn __gmpz_probab_prime_p(n: mpz_srcptr, reps: c_int) -> c_int; + fn __gmpz_nextprime(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_gcd(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_gcdext(g: mpz_ptr, s: mpz_ptr, t: mpz_ptr, a: mpz_srcptr, b: mpz_srcptr); + fn __gmpz_lcm(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_invert(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; + fn __gmpz_import(rop: mpz_ptr, count: size_t, order: c_int, size: size_t, + endian: c_int, nails: size_t, op: *const c_void); + fn __gmpz_export(rop: *mut c_void, countp: *mut size_t, order: c_int, size: size_t, + endian: c_int, nails: size_t, op: mpz_srcptr); + fn __gmpz_root(rop: mpz_ptr, op: mpz_srcptr, n: c_ulong) -> c_int; + fn __gmpz_sqrt(rop: mpz_ptr, op: mpz_srcptr); + fn __gmpz_millerrabin(n: mpz_srcptr, reps: c_int) -> c_int; +} + +#[repr(transparent)] +pub struct Mpz { + mpz: mpz_struct, +} + +unsafe impl Send for Mpz { } +unsafe impl Sync for Mpz { } + +impl Drop for Mpz { + fn drop(&mut self) { unsafe { __gmpz_clear(&mut self.mpz) } } +} + +/// The result of running probab_prime +#[derive(PartialEq)] +pub enum ProbabPrimeResult { + NotPrime, + ProbablyPrime, + Prime +} + +impl Mpz { + #[inline] + pub unsafe fn inner(&self) -> mpz_srcptr { + &self.mpz + } + + #[inline] + pub unsafe fn inner_mut(&mut self) -> mpz_ptr { + &mut self.mpz + } + + #[inline] + pub fn new() -> Mpz { + unsafe { + let mut mpz = uninitialized(); + __gmpz_init(&mut mpz); + Mpz { mpz: mpz } + } + } + + #[inline] + pub fn new_reserve(n: usize) -> Mpz { + unsafe { + let mut mpz = uninitialized(); + __gmpz_init2(&mut mpz, n as c_ulong); + Mpz { mpz: mpz } + } + } + + #[inline] + pub fn reserve(&mut self, n: usize) { + if self.bit_length() < n { + unsafe { __gmpz_realloc2(&mut self.mpz, n as c_ulong) } + } + } + + #[inline] + pub fn size_in_base(&self, base: u8) -> usize { + unsafe { + __gmpz_sizeinbase(&self.mpz, base as c_int) as usize + } + } + + // TODO: fail on an invalid base + // FIXME: Unfortunately it isn't currently possible to use the fmt::RadixFmt + // machinery for a custom type. + pub fn to_str_radix(&self, base: u8) -> String { + unsafe { + assert!(base >= 2 && base <= 36, "invalid base"); + // Extra two bytes are for possible minus sign and null terminator + let len = { + let len = __gmpz_sizeinbase(&self.mpz, base as c_int) as usize; + assert!(usize::MAX - len >= 2, "capacity overflow"); + len + 2 + }; + + // Allocate and write into a raw *c_char of the correct length + let mut vector: Vec = Vec::with_capacity(len); + __gmpz_get_str(vector.as_mut_ptr() as *mut _, base as c_int, &self.mpz); + let string_len = strnlen(vector.as_ptr() as *const _, len); + assert!(string_len < len); + vector.set_len(string_len); + // FIXME is this actually a problem? + String::from_utf8(vector).expect("GMP returned invalid UTF-8!") + } + } + + pub fn from_str_radix(s: &str, base: u8) -> Result { + let s = CString::new(s.to_string()).map_err(|_| ParseMpzError { _priv: () })?; + unsafe { + assert!(base == 0 || (base >= 2 && base <= 62)); + let mut mpz = uninitialized(); + let r = __gmpz_init_set_str(&mut mpz, s.as_ptr(), base as c_int); + if r == 0 { + Ok(Mpz { mpz: mpz }) + } else { + __gmpz_clear(&mut mpz); + Err(ParseMpzError { _priv: () }) + } + } + } + + #[inline] + pub fn set(&mut self, other: &Mpz) { + unsafe { __gmpz_set(&mut self.mpz, &other.mpz) } + } + + // TODO: too easy to forget to check this return value - rename? + pub fn set_from_str_radix(&mut self, s: &str, base: u8) -> bool { + assert!(base == 0 || (base >= 2 && base <= 62)); + let s = CString::new(s.to_string()).unwrap(); + unsafe { __gmpz_set_str(&mut self.mpz, s.as_ptr(), base as c_int) == 0 } + } + + #[inline] + pub fn bit_length(&self) -> usize { + unsafe { __gmpz_sizeinbase(&self.mpz, 2) as usize } + } + + #[inline] + pub fn compl(&self) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_com(&mut res.mpz, &self.mpz); + res + } + } + + #[inline] + pub fn abs(&self) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_abs(&mut res.mpz, &self.mpz); + res + } + } + + #[inline] + pub fn div_floor(&self, other: &Mpz) -> Mpz { + unsafe { + if other.is_zero() { + panic!("divide by zero") + } + + let mut res = Mpz::new(); + __gmpz_fdiv_q(&mut res.mpz, &self.mpz, &other.mpz); + res + } + } + + #[inline] + pub fn mod_floor(&self, other: &Mpz) -> Mpz { + unsafe { + if other.is_zero() { + panic!("divide by zero") + } + + let mut res = Mpz::new(); + __gmpz_fdiv_r(&mut res.mpz, &self.mpz, &other.mpz); + res + } + } + + /// Determine whether n is prime. + /// + /// This function performs some trial divisions, then reps Miller-Rabin probabilistic primality tests. A higher reps value will reduce the chances of a non-prime being identified as “probably prime”. A composite number will be identified as a prime with a probability of less than 4^(-reps). Reasonable values of reps are between 15 and 50. + pub fn probab_prime(&self, reps: i32) -> ProbabPrimeResult { + match unsafe { + __gmpz_probab_prime_p(&self.mpz, reps as c_int) as u8 + } { + 2 => ProbabPrimeResult::Prime, + 1 => ProbabPrimeResult::ProbablyPrime, + 0 => ProbabPrimeResult::NotPrime, + x => panic!("Undocumented return value {} from __gmpz_probab_prime_p", x), + } + } + + #[inline] + pub fn nextprime(&self) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_nextprime(&mut res.mpz, &self.mpz); + res + } + } + + #[inline] + pub fn gcd(&self, other: &Mpz) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_gcd(&mut res.mpz, &self.mpz, &other.mpz); + res + } + } + + /// Given (a, b), return (g, s, t) such that g = gcd(a, b) = s*a + t*b. + pub fn gcdext(&self, other: &Mpz) -> (Mpz, Mpz, Mpz) { + unsafe { + let mut g = Mpz::new(); + let mut s = Mpz::new(); + let mut t = Mpz::new(); + __gmpz_gcdext(&mut g.mpz, &mut s.mpz, &mut t.mpz, + &self.mpz, &other.mpz); + (g, s, t) + } + } + + #[inline] + pub fn lcm(&self, other: &Mpz) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_lcm(&mut res.mpz, &self.mpz, &other.mpz); + res + } + } + + #[inline] + pub fn is_multiple_of(&self, other: &Mpz) -> bool { + unsafe { + __gmpz_divisible_p(&self.mpz, &other.mpz) != 0 + } + } + + #[inline] + pub fn divides(&self, other: &Mpz) -> bool { + other.is_multiple_of(self) + } + + pub fn modulus(&self, modulo: &Mpz) -> Mpz { + unsafe { + if modulo.is_zero() { + panic!("divide by zero") + } + + let mut res = Mpz::new(); + __gmpz_mod(&mut res.mpz, &self.mpz, &modulo.mpz); + res + } + } + + // TODO: handle a zero modulo + pub fn invert(&self, modulo: &Mpz) -> Option { + unsafe { + let mut res = Mpz::new(); + if __gmpz_invert(&mut res.mpz, &self.mpz, &modulo.mpz) == 0 { + None + } else { + Some(res) + } + } + } + + #[inline] + pub fn popcount(&self) -> usize { + unsafe { __gmpz_popcount(&self.mpz) as usize } + } + + #[inline] + pub fn pow(&self, exp: u32) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_pow_ui(&mut res.mpz, &self.mpz, exp as c_ulong); + res + } + } + + #[inline] + pub fn powm(&self, exp: &Mpz, modulus: &Mpz) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_powm(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz); + res + } + } + + #[inline] + pub fn powm_sec(&self, exp: &Mpz, modulus: &Mpz) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_powm_sec(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz); + res + } + } + + #[inline] + pub fn ui_pow_ui(x: u32, y: u32) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_ui_pow_ui(&mut res.mpz, x as c_ulong, y as c_ulong); + res + } + } + + #[inline] + pub fn hamdist(&self, other: &Mpz) -> usize { + unsafe { __gmpz_hamdist(&self.mpz, &other.mpz) as usize } + } + + #[inline] + pub fn setbit(&mut self, bit_index: usize) { + unsafe { __gmpz_setbit(&mut self.mpz, bit_index as c_ulong) } + } + + #[inline] + pub fn clrbit(&mut self, bit_index: usize) { + unsafe { __gmpz_clrbit(&mut self.mpz, bit_index as c_ulong) } + } + + #[inline] + pub fn combit(&mut self, bit_index: usize) { + unsafe { __gmpz_combit(&mut self.mpz, bit_index as c_ulong) } + } + + #[inline] + pub fn tstbit(&self, bit_index: usize) -> bool { + unsafe { __gmpz_tstbit(&self.mpz, bit_index as c_ulong) == 1 } + } + + pub fn root(&self, n: u32) -> Mpz { + assert!(self.mpz._mp_size >= 0); + unsafe { + let mut res = Mpz::new(); + let _perfect_root + = match __gmpz_root(&mut res.mpz, &self.mpz, n as c_ulong) { + 0 => false, + _ => true, + }; + // TODO: consider returning `_perfect_root` + res + } + } + + pub fn sqrt(&self) -> Mpz { + assert!(self.mpz._mp_size >= 0); + unsafe { + let mut res = Mpz::new(); + __gmpz_sqrt(&mut res.mpz, &self.mpz); + res + } + } + + pub fn millerrabin(&self, reps: i32) -> i32 { + unsafe { + __gmpz_millerrabin(&self.mpz, reps as c_int) + } + } + + pub fn sign(&self) -> Sign { + let size = self.mpz._mp_size; + if size == 0 { + Sign::Zero + } else if size > 0 { + Sign::Positive + } else { + Sign::Negative + } + } + + pub fn one() -> Mpz { + unsafe { + let mut mpz = uninitialized(); + __gmpz_init_set_ui(&mut mpz, 1); + Mpz { mpz: mpz } + } + } + + pub fn zero() -> Mpz { Mpz::new() } + + pub fn is_zero(&self) -> bool { + self.mpz._mp_size == 0 + } +} + +#[derive(Debug)] +pub struct ParseMpzError { + _priv: () +} + +impl fmt::Display for ParseMpzError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ParseMpzError { + fn description(&self) -> &'static str { + "invalid integer" + } + + fn cause(&self) -> Option<&'static Error> { + None + } +} + +impl Clone for Mpz { + fn clone(&self) -> Mpz { + unsafe { + let mut mpz = uninitialized(); + __gmpz_init_set(&mut mpz, &self.mpz); + Mpz { mpz: mpz } + } + } +} + +impl Eq for Mpz { } + +impl PartialEq for Mpz { + fn eq(&self, other: &Mpz) -> bool { + unsafe { __gmpz_cmp(&self.mpz, &other.mpz) == 0 } + } +} + +impl Ord for Mpz { + fn cmp(&self, other: &Mpz) -> Ordering { + let cmp = unsafe { __gmpz_cmp(&self.mpz, &other.mpz) }; + if cmp == 0 { + Equal + } else if cmp < 0 { + Less + } else { + Greater + } + } +} + +impl PartialOrd for Mpz { + fn partial_cmp(&self, other: &Mpz) -> Option { + Some(self.cmp(other)) + } +} + +// Implementation of operators + +// This macro inserts a guard against division by 0 for Div and Rem implementations +macro_rules! div_guard { + (Div, $is_zero: expr) => { + if $is_zero { + panic!("divide by zero") + } + }; + (Rem, $is_zero: expr) => { + if $is_zero { + panic!("divide by zero") + } + }; + ($tr: ident, $is_zero: expr) => {} +} + +// On Windows c_long and c_ulong are only 32-bit - in order to implement operations for +// 64-bit types we need some workarounds +macro_rules! bit_guard { + (u64, $what: ident, $e1: expr, $e2: expr) => ( + if size_of::() == 8 || $what <= u32::MAX as u64 { + $e1 + } + else { + $e2 + } + ); + + (i64, $what: ident, $e1: expr, $e2: expr) => ( + if size_of::() == 8 || $what <= i32::MAX as i64 { + $e1 + } + else { + $e2 + } + ); + + (u32, $what: ident, $e1: expr, $e2: expr) => ($e1); + + (i32, $what: ident, $e1: expr, $e2: expr) => ($e1); +} + +macro_rules! impl_oper { + ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { + impl $tr for Mpz { + type Output = Mpz; + #[inline] + fn $meth(self, other: Mpz) -> Mpz { + self.$meth(&other) + } + } + + impl<'a> $tr<&'a Mpz> for Mpz { + type Output = Mpz; + #[inline] + fn $meth(mut self, other: &Mpz) -> Mpz { + self.$meth_assign(other); + self + } + } + + impl<'a> $tr for &'a Mpz { + type Output = Mpz; + #[inline] + fn $meth(self, mut other: Mpz) -> Mpz { + unsafe { + div_guard!($tr, other.is_zero()); + $fun(&mut other.mpz, &self.mpz, &other.mpz); + other + } + } + } + + impl<'a, 'b> $tr<&'b Mpz> for &'a Mpz { + type Output = Mpz; + fn $meth(self, other: &Mpz) -> Mpz { + unsafe { + div_guard!($tr, other.is_zero()); + let mut res = Mpz::new(); + $fun(&mut res.mpz, &self.mpz, &other.mpz); + res + } + } + } + + impl $tr_assign for Mpz { + #[inline] + fn $meth_assign(&mut self, other: Mpz) { + self.$meth_assign(&other) + } + } + + impl<'a> $tr_assign<&'a Mpz> for Mpz { + #[inline] + fn $meth_assign(&mut self, other: &Mpz) { + unsafe { + div_guard!($tr, other.is_zero()); + $fun(&mut self.mpz, &self.mpz, &other.mpz); + } + } + } + }; + + (both $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { + impl_oper!(normal $num, $cnum, $tr, $meth, $tr_assign, $meth_assign, $fun); + + impl $tr for $num { + type Output = Mpz; + #[inline] + fn $meth(self, mut other: Mpz) -> Mpz { + unsafe { + bit_guard!($num, self, { + $fun(&mut other.mpz, &other.mpz, self as $cnum); + other + }, other.$meth(Mpz::from(self))) + } + } + } + + impl<'a> $tr<&'a Mpz> for $num { + type Output = Mpz; + fn $meth(self, other: &'a Mpz) -> Mpz { + unsafe { + bit_guard!($num, self, { + let mut res = Mpz::new(); + $fun(&mut res.mpz, &other.mpz, self as $cnum); + res + }, other.$meth(Mpz::from(self))) + } + } + } + }; + + (normal $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { + impl $tr<$num> for Mpz { + type Output = Mpz; + #[inline] + fn $meth(mut self, other: $num) -> Mpz { + self.$meth_assign(other); + self + } + } + + impl<'a> $tr<$num> for &'a Mpz { + type Output = Mpz; + fn $meth(self, other: $num) -> Mpz { + unsafe { + div_guard!($tr, other == 0); + bit_guard!($num, other, { + let mut res = Mpz::new(); + $fun(&mut res.mpz, &self.mpz, other as $cnum); + res + }, self.$meth(Mpz::from(other))) + } + } + } + + impl $tr_assign<$num> for Mpz { + #[inline] + fn $meth_assign(&mut self, other: $num) { + unsafe { + div_guard!($tr, other == 0); + bit_guard!($num, other, + $fun(&mut self.mpz, &self.mpz, other as $cnum), + self.$meth_assign(Mpz::from(other))) + } + } + } + }; + + (reverse $num: ident, $cnum: ident, $tr: ident, $meth: ident, $fun: ident) => { + impl $tr for $num { + type Output = Mpz; + #[inline] + fn $meth(self, mut other: Mpz) -> Mpz { + unsafe { + bit_guard!($num, self, { + $fun(&mut other.mpz, self as $cnum, &other.mpz); + other + }, Mpz::from(self).$meth(other)) + } + } + } + + impl<'a> $tr<&'a Mpz> for $num { + type Output = Mpz; + fn $meth(self, other: &'a Mpz) -> Mpz { + unsafe { + bit_guard!($num, self, { + let mut res = Mpz::new(); + $fun(&mut res.mpz, self as $cnum, &other.mpz); + res + }, Mpz::from(self).$meth(other)) + } + } + } + }; + +} + +impl_oper!(Add, add, AddAssign, add_assign, __gmpz_add); +impl_oper!(both u64, c_ulong, Add, add, AddAssign, add_assign, __gmpz_add_ui); + +impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpz_sub); +impl_oper!(normal u64, c_ulong, Sub, sub, SubAssign, sub_assign, __gmpz_sub_ui); +impl_oper!(reverse u64, c_ulong, Sub, sub, __gmpz_ui_sub); + +impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpz_mul); +impl_oper!(both i64, c_long, Mul, mul, MulAssign, mul_assign, __gmpz_mul_si); +impl_oper!(both u64, c_ulong, Mul, mul, MulAssign, mul_assign, __gmpz_mul_ui); + +impl_oper!(Div, div, DivAssign, div_assign, __gmpz_tdiv_q); +impl_oper!(normal u64, c_ulong, Div, div, DivAssign, div_assign, __gmpz_tdiv_q_ui); + +impl_oper!(Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r); +impl_oper!(normal u64, c_ulong, Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r_ui); + +impl<'b> Neg for &'b Mpz { + type Output = Mpz; + fn neg(self) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_neg(&mut res.mpz, &self.mpz); + res + } + } +} + +impl Neg for Mpz { + type Output = Mpz; + #[inline] + fn neg(mut self) -> Mpz { + unsafe { + __gmpz_neg(&mut self.mpz, &self.mpz); + self + } + } +} + +impl<'b> Not for &'b Mpz { + type Output = Mpz; + fn not(self) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_com(&mut res.mpz, &self.mpz); + res + } + } +} + +impl Not for Mpz { + type Output = Mpz; + #[inline] + fn not(mut self) -> Mpz { + unsafe { + __gmpz_com(&mut self.mpz, &self.mpz); + self + } + } +} + +// Similarly to mpz_export, this does not preserve the sign of the input. +impl<'b> From<&'b Mpz> for Vec { + fn from(other: &Mpz) -> Vec { + unsafe { + let bit_size = size_of::() * 8; + let size = (__gmpz_sizeinbase(&other.mpz, 2) + bit_size - 1) / bit_size; + let mut result: Vec = vec!(0; size); + __gmpz_export(result.as_mut_ptr() as *mut c_void, 0 as *mut size_t, 1, size_of::() as size_t, 0, 0, &other.mpz); + result + } + } +} + +impl<'b> From<&'b Mpz> for Option { + fn from(other: &Mpz) -> Option { + unsafe { + let negative = other.mpz._mp_size < 0; + let mut to_export = Mpz::new(); + + if negative { + __gmpz_com(&mut to_export.mpz, &other.mpz); + } else { + __gmpz_set(&mut to_export.mpz, &other.mpz); + } + + if __gmpz_sizeinbase(&to_export.mpz, 2) <= 63 { + let mut result : i64 = 0; + __gmpz_export(&mut result as *mut i64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &to_export.mpz); + if negative { + Some(result ^ -1i64) + } else { + Some(result) + } + } else { + return None; + } + } + } +} + +impl<'b> From<&'b Mpz> for Option { + fn from(other: &Mpz) -> Option { + unsafe { + if __gmpz_sizeinbase(&other.mpz, 2) <= 64 && other.mpz._mp_size >= 0 { + let mut result : u64 = 0; + __gmpz_export(&mut result as *mut u64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &other.mpz); + Some(result) + } else { + None + } + } + } +} + +impl<'a> From<&'a Mpz> for f64 { + fn from(other: &Mpz) -> f64 { + unsafe { + __gmpz_get_d(&other.mpz) as f64 + } + } +} + +impl<'a> From<&'a [u8]> for Mpz { + fn from(other: &'a [u8]) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_import(&mut res.mpz, other.len(), 1, size_of::() as size_t, + 0, 0, other.as_ptr() as *const c_void); + res + } + } +} + +impl From for Mpz { + fn from(other: u64) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &other as *const u64 as *const c_void); + res + } + } +} + +impl From for Mpz { + fn from(other: u32) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &other as *const u32 as *const c_void); + res + } + } +} + +impl From for Mpz { + fn from(other: i64) -> Mpz { + unsafe { + let mut res = Mpz::new(); + + if other.is_negative() { + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &(other ^ -1i64) as *const i64 as *const c_void); + __gmpz_com(&mut res.mpz, &res.mpz); + } else { + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &other as *const i64 as *const c_void); + } + res + } + } +} + +impl From for Mpz { + fn from(other: i32) -> Mpz { + unsafe { + let mut res = Mpz::new(); + + if other.is_negative() { + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &(other ^ -1i32) as *const i32 as *const c_void); + __gmpz_com(&mut res.mpz, &res.mpz); + } else { + __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, + &other as *const i32 as *const c_void); + } + res + } + } +} + +impl_oper!(BitAnd, bitand, BitAndAssign, bitand_assign, __gmpz_and); +impl_oper!(BitOr, bitor, BitOrAssign, bitor_assign, __gmpz_ior); +impl_oper!(BitXor, bitxor, BitXorAssign, bitxor_assign, __gmpz_xor); + +impl<'b> Shl for &'b Mpz { + type Output = Mpz; + fn shl(self, other: usize) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong); + res + } + } +} + +impl<'b> Shr for &'b Mpz { + type Output = Mpz; + fn shr(self, other: usize) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong); + res + } + } +} + +impl Shl for Mpz { + type Output = Mpz; + fn shl(self, other: usize) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong); + res + } + } +} + +impl Shr for Mpz { + type Output = Mpz; + fn shr(self, other: usize) -> Mpz { + unsafe { + let mut res = Mpz::new(); + __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong); + res + } + } +} + +impl ShlAssign for Mpz { + fn shl_assign(&mut self, other: usize) { + unsafe { + __gmpz_mul_2exp(&mut self.mpz, &self.mpz, other as c_ulong); + } + } +} + +impl ShrAssign for Mpz { + fn shr_assign(&mut self, other: usize) { + unsafe { + __gmpz_fdiv_q_2exp(&mut self.mpz, &self.mpz, other as c_ulong); + } + } +} + +impl FromStr for Mpz { + type Err = ParseMpzError; + fn from_str(s: &str) -> Result { + Mpz::from_str_radix(s, 10) + } +} + +impl fmt::Display for Mpz { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_str_radix(10)) + } +} + +impl fmt::Debug for Mpz { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_str_radix(10)) + } +} + +impl hash::Hash for Mpz { + fn hash(&self, state: &mut S) { + unsafe { + for i in 0..self.mpz._mp_size.abs() { + let limb = self.mpz._mp_d as *const mp_limb_t; + let limb = *(limb.offset(i as isize)); + limb.hash(state); + } + } + } +} + +impl Zero for Mpz { + #[inline] + fn zero() -> Mpz { + Mpz::zero() + } + + #[inline] + fn is_zero(&self) -> bool { + self.is_zero() + } +} + +impl One for Mpz { + #[inline] + fn one() -> Mpz { + Mpz::one() + } +} + diff --git a/crates/classgroup/src/gmp/sign.rs b/crates/classgroup/src/gmp/sign.rs new file mode 100644 index 0000000..660b2b4 --- /dev/null +++ b/crates/classgroup/src/gmp/sign.rs @@ -0,0 +1,7 @@ +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)] +pub enum Sign { + Negative, + Zero, + Positive, +} + diff --git a/crates/classgroup/src/gmp/test.rs b/crates/classgroup/src/gmp/test.rs new file mode 100644 index 0000000..8036386 --- /dev/null +++ b/crates/classgroup/src/gmp/test.rs @@ -0,0 +1,582 @@ +use super::mpz::mp_limb_t; +use std; +use libc::c_int; + +#[link(name = "gmp", kind = "static")] +extern "C" { + static __gmp_bits_per_limb: c_int; +} + +#[test] +#[allow(unsafe_code)] +fn test_limb_size() { + // We are assuming that the limb size is the same as the pointer size. + assert_eq!(std::mem::size_of::() * 8, + unsafe { __gmp_bits_per_limb as usize }); +} + +mod mpz { + use super::super::mpz::Mpz; + use super::super::mpz::ProbabPrimeResult; + use super::super::sign::Sign; + use std::str::FromStr; + use std::convert::{From, Into}; + use std::{i64, u64}; + + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + #[test] + fn test_set() { + let mut x: Mpz = From::::from(1000); + let y: Mpz = From::::from(5000); + assert!(x != y); + x.set(&y); + assert!(x == y); + } + + #[test] + fn test_set_from_str_radix() { + let mut x: Mpz = From::::from(1000); + let y: Mpz = From::::from(5000); + assert!(x != y); + assert!(x.set_from_str_radix("5000", 10)); + assert!(x == y); + assert!(!x.set_from_str_radix("aaaa", 2)); + } + + #[test] + #[should_panic] + fn test_from_str_radix_lower_bound() { + let _ = Mpz::from_str_radix("", 1); + } + + #[test] + #[should_panic] + fn test_from_str_radix_upper_bound() { + let _ = Mpz::from_str_radix("", 63); + } + + #[test] + #[should_panic] + fn test_set_from_str_radix_lower_bound() { + let mut x = Mpz::new(); + x.set_from_str_radix("", 1); + } + + #[test] + #[should_panic] + fn test_set_from_str_radix_upper_bound() { + let mut x = Mpz::new(); + x.set_from_str_radix("", 63); + } + + #[test] + fn test_eq() { + let x: Mpz = From::::from(4242142195); + let y: Mpz = From::::from(4242142195); + let z: Mpz = From::::from(4242142196); + + assert!(x == y); + assert!(x != z); + assert!(y != z); + } + + #[test] + fn test_ord() { + let x: Mpz = FromStr::from_str("40000000000000000000000").unwrap(); + let y: Mpz = FromStr::from_str("45000000000000000000000").unwrap(); + let z: Mpz = FromStr::from_str("50000000000000000000000").unwrap(); + + assert!(x < y && x < z && y < z); + assert!(x <= x && x <= y && x <= z && y <= z); + assert!(z > y && z > x && y > x); + assert!(z >= z && z >= y && z >= x && y >= x); + } + + #[test] + #[should_panic] + fn test_div_zero() { + let x: Mpz = From::::from(1); + let y = Mpz::new(); + drop(x / y) + } + + #[test] + #[should_panic] + fn test_rem_zero() { + let x: Mpz = From::::from(1); + let y = Mpz::new(); + drop(x % y) + } + + #[test] + fn test_div_round() { + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + assert!((&x / &y).to_string() == (2i32 / 3).to_string()); + assert!((&x / -&y).to_string() == (2i32 / -3).to_string()); + } + + #[test] + fn test_rem() { + let x: Mpz = From::::from(20); + let y: Mpz = From::::from(3); + assert!((&x % &y).to_string() == (20i32 % 3).to_string()); + assert!((&x % 3).to_string() == (20i32 % 3).to_string()); + assert!((&x % -&y).to_string() == (20i32 % -3).to_string()); + assert!((-&x % &y).to_string() == (-20i32 % 3).to_string()); + } + + #[test] + fn test_add() { + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + let str5 = 5i32.to_string(); + assert!((&x + &y).to_string() == str5); + assert!((&x + 3).to_string() == str5); + assert!((&y + 2).to_string() == str5); + } + + #[test] + fn test_sub() { + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + assert!((&x - &y).to_string() == (-1i32).to_string()); + assert!((&y - &x).to_string() == 1i32.to_string()); + assert!((&y - 8).to_string() == (-5i32).to_string()); + } + + #[test] + fn test_mul() { + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + assert!((&x * &y).to_string() == 6i32.to_string()); + assert!((&x * 3i64).to_string() == 6i32.to_string()); + assert!((&y * -5i64).to_string() == (-15i32).to_string()); + // check with values not fitting in 32 bits + assert!((&x * 5000000000i64).to_string() == 10000000000i64.to_string()); + } + + #[test] + fn test_to_str_radix() { + let x: Mpz = From::::from(255); + assert!(x.to_str_radix(16) == "ff".to_string()); + } + + #[test] + fn test_to_string() { + let x: Mpz = FromStr::from_str("1234567890").unwrap(); + assert!(x.to_string() == "1234567890".to_string()); + } + + #[test] + fn test_invalid_str() { + let x: Result = FromStr::from_str("foobar"); + assert!(x.is_err()); + } + + #[test] + fn test_clone() { + let a: Mpz = From::::from(100); + let b = a.clone(); + let aplusb: Mpz = From::::from(200); + assert!(b == a); + assert!(a + b == aplusb); + } + + #[test] + fn test_from_int() { + let x: Mpz = From::::from(150); + assert!(x.to_string() == "150".to_string()); + assert!(x == FromStr::from_str("150").unwrap()); + } + + #[test] + fn test_from_slice_u8() { + let v: Vec = vec!(255, 255); + let x: Mpz = From::from(&v[..]); + assert!(x.to_string() == "65535".to_string()); + } + + #[test] + fn test_abs() { + let x: Mpz = From::::from(1000); + let y: Mpz = From::::from(-1000); + assert!(-&x == y); + assert!(x == -&y); + assert!(x == y.abs()); + assert!(x.abs() == y.abs()); + } + + #[test] + fn test_div_floor() { + let two: Mpz = From::::from(2); + let eight: Mpz = From::::from(8); + let minuseight: Mpz = From::::from(-8); + let three: Mpz = From::::from(3); + let minusthree: Mpz = From::::from(-3); + assert_eq!(eight.div_floor(&three), two); + assert_eq!(eight.div_floor(&minusthree), minusthree); + assert_eq!(minuseight.div_floor(&three), minusthree); + assert_eq!(minuseight.div_floor(&minusthree), two); + } + + #[test] + fn test_mod_floor() { + let one: Mpz = From::::from(1); + let minusone: Mpz = From::::from(-1); + let two: Mpz = From::::from(2); + let minustwo: Mpz = From::::from(-2); + let three: Mpz = From::::from(3); + let minusthree: Mpz = From::::from(-3); + let eight: Mpz = From::::from(8); + let minuseight: Mpz = From::::from(-8); + assert_eq!(eight.mod_floor(&three), two); + assert_eq!(eight.mod_floor(&minusthree), minusone); + assert_eq!(minuseight.mod_floor(&three), one); + assert_eq!(minuseight.mod_floor(&minusthree), minustwo); + } + + #[test] + fn test_bitand() { + let a = 0b1001_0111; + let b = 0b1100_0100; + let mpza: Mpz = From::::from(a); + let mpzb: Mpz = From::::from(b); + let mpzres: Mpz = From::::from(a & b); + assert!(mpza & mpzb == mpzres); + } + + #[test] + fn test_bitor() { + let a = 0b1001_0111; + let b = 0b1100_0100; + let mpza: Mpz = From::::from(a); + let mpzb: Mpz = From::::from(b); + let mpzres: Mpz = From::::from(a | b); + assert!(mpza | mpzb == mpzres); + } + + #[test] + fn test_bitxor() { + let a = 0b1001_0111; + let b = 0b1100_0100; + let mpza: Mpz = From::::from(a); + let mpzb: Mpz = From::::from(b); + let mpzres: Mpz = From::::from(a ^ b); + assert!(mpza ^ mpzb == mpzres); + } + + #[test] + fn test_shifts() { + let i = 227; + let j: Mpz = From::::from(i); + assert!((i << 4).to_string() == (&j << 4).to_string()); + assert!((-i << 4).to_string() == (-&j << 4).to_string()); + assert!((i >> 4).to_string() == (&j >> 4).to_string()); + assert!((-i >> 4).to_string() == (-&j >> 4).to_string()); + } + + #[test] + fn test_compl() { + let a: Mpz = From::::from(13); + let b: Mpz = From::::from(-442); + assert!(a.compl().to_string() == (!13i32).to_string()); + assert!(b.compl().to_string() == (!-442i32).to_string()); + } + + #[test] + fn test_pow() { + let a: Mpz = From::::from(2); + let b: Mpz = From::::from(8); + assert!(a.pow(3) == b); + assert!(Mpz::ui_pow_ui(2, 3) == b); + } + + #[test] + fn test_powm() { + let a: Mpz = From::::from(13); + let b: Mpz = From::::from(7); + let p: Mpz = From::::from(19); + let c: Mpz = From::::from(10); + assert!(a.powm(&b, &p) == c); + } + + #[test] + fn test_powm_sec() { + let a: Mpz = From::::from(13); + let b: Mpz = From::::from(7); + let p: Mpz = From::::from(19); + let c: Mpz = From::::from(10); + assert!(a.powm_sec(&b, &p) == c); + } + + #[test] + fn test_popcount() { + assert_eq!(Mpz::from_str_radix("1010010011", 2).unwrap().popcount(), 5); + } + + #[test] + fn test_hamdist() { + let a: Mpz = From::::from(0b1011_0001); + let b: Mpz = From::::from(0b0010_1011); + assert!(a.hamdist(&b) == 4); + } + + #[test] + fn test_bit_length() { + let a: Mpz = From::::from(0b1011_0000_0001_0000); + let b: Mpz = From::::from(0b101); + assert!(a.bit_length() == 16); + assert!(b.bit_length() == 3); + } + + #[test] + fn test_probab_prime() { + let prime: Mpz = From::::from(2); + assert!(prime.probab_prime(15) == ProbabPrimeResult::Prime); + + let not_prime: Mpz = From::::from(4); + assert!(not_prime.probab_prime(15) == ProbabPrimeResult::NotPrime); + } + + #[test] + fn test_nextprime() { + let a: Mpz = From::::from(123456); + let b: Mpz = From::::from(123457); + assert!(a.nextprime() == b); + } + + #[test] + fn test_gcd() { + let zero: Mpz = From::::from(0); + let three: Mpz = From::::from(3); + let six: Mpz = From::::from(6); + let eighteen: Mpz = From::::from(18); + let twentyfour: Mpz = From::::from(24); + assert!(zero.gcd(&zero) == zero); + assert!(three.gcd(&six) == three); + assert!(eighteen.gcd(&twentyfour) == six); + } + + #[test] + fn test_gcdext() { + let six: Mpz = From::::from(6); + let eighteen: Mpz = From::::from(18); + let twentyfour: Mpz = From::::from(24); + let (g, s, t) = eighteen.gcdext(&twentyfour); + assert!(g == six); + assert!(g == s*eighteen + t*twentyfour); + } + + #[test] + fn test_lcm() { + let zero: Mpz = From::::from(0); + let three: Mpz = From::::from(3); + let five: Mpz = From::::from(5); + let six: Mpz = From::::from(6); + let eighteen: Mpz = From::::from(18); + let twentyfour: Mpz = From::::from(24); + let seventytwo: Mpz = From::::from(72); + assert!(zero.lcm(&five) == zero); + assert!(five.lcm(&zero) == zero); + assert!(three.lcm(&six) == six); + assert!(eighteen.lcm(&twentyfour) == seventytwo); + } + + #[test] + fn test_is_multiple_of() { + let two: Mpz = From::::from(2); + let three: Mpz = From::::from(3); + let six: Mpz = From::::from(6); + assert!(six.is_multiple_of(&two)); + assert!(six.is_multiple_of(&three)); + assert!(!three.is_multiple_of(&two)); + } + + #[test] + fn test_modulus() { + let minusone: Mpz = From::::from(-1); + let two: Mpz = From::::from(2); + let three: Mpz = From::::from(3); + assert_eq!(two.modulus(&three), two); + assert_eq!(minusone.modulus(&three), two); + } + + #[test] + fn test_invert() { + let two: Mpz = From::::from(2); + let three: Mpz = From::::from(3); + let four: Mpz = From::::from(4); + let five: Mpz = From::::from(5); + let eleven: Mpz = From::::from(11); + assert!(three.invert(&eleven) == Some(four.clone())); + assert!(four.invert(&eleven) == Some(three.clone())); + assert!(two.invert(&five) == Some(three.clone())); + assert!(three.invert(&five) == Some(two.clone())); + assert!(two.invert(&four).is_none()); + } + + #[test] + fn test_one() { + let onea: Mpz = From::::from(1); + let oneb: Mpz = From::::from(1); + assert!(onea == oneb); + } + + #[test] + fn test_bit_fiddling() { + let mut xs: Mpz = From::::from(0b1010_1000_0010_0011); + assert!(xs.bit_length() == 16); + let mut ys = [true, false, true, false, + true, false, false, false, + false, false, true, false, + false, false, true, true]; + ys.reverse(); + for i in 0..xs.bit_length() { + assert!(xs.tstbit(i) == ys[i]); + } + xs.setbit(0); + ys[0] = true; + xs.setbit(3); + ys[3] = true; + xs.clrbit(1); + ys[1] = false; + xs.clrbit(5); + ys[5] = false; + xs.combit(14); + ys[14] = !ys[14]; + xs.combit(15); + ys[15] = !ys[15]; + for i in 0..xs.bit_length() { + assert!(xs.tstbit(i) == ys[i]); + } + } + + #[test] + fn test_root() { + let x: Mpz = From::::from(123456); + let y: Mpz = From::::from(49); + assert!(x.root(3) == y); + } + + #[test] + fn test_sqrt() { + let x: Mpz = From::::from(567); + let y: Mpz = From::::from(23); + assert!(x.sqrt() == y); + } + + #[test] + fn test_hash_short() { + let zero: Mpz = From::::from(0); + let one: Mpz = From::::from(1); + let two = &one + &one; + + let hash = |x : &Mpz| { + let mut hasher = DefaultHasher::new(); + x.hash(&mut hasher); + hasher.finish() + }; + + assert!(hash(&zero) != hash(&one)); + assert_eq!(hash(&one), hash(&(&two - &one))); + } + + #[test] + fn test_hash_long() { + let a = Mpz::from_str_radix("348917329847193287498312749187234192387", 10) + .unwrap(); + let b = Mpz::from_str_radix("348917329847193287498312749187234192386", 10) + .unwrap(); + let one: Mpz = From::::from(1); + + let hash = |x : &Mpz| { + let mut hasher = DefaultHasher::new(); + x.hash(&mut hasher); + hasher.finish() + }; + + assert!(hash(&a) != hash(&b)); + assert_eq!(hash(&a), hash(&(&b + &one))); + assert_eq!(hash(&(&a - &a)), hash(&(&one - &one))); + } + + #[test] + fn test_to_vec_u8() { + let minus_five: Mpz = From::::from(-5); + let minus_one: Mpz = From::::from(-1); + let zero: Mpz = From::::from(0); + let one: Mpz = From::::from(1); + let five: Mpz = From::::from(5); + let xffff: Mpz = From::::from(65535); + let max_u64: Mpz = From::::from(u64::MAX); + + assert_eq!(Into::>::into(&minus_five), vec!(5u8)); + assert_eq!(Into::>::into(&minus_one), vec!(1u8)); + assert_eq!(Into::>::into(&zero), vec!(0u8)); + assert_eq!(Into::>::into(&one), vec!(1u8)); + assert_eq!(Into::>::into(&five), vec!(5u8)); + assert_eq!(Into::>::into(&xffff), vec!(255u8, 255u8)); + assert_eq!(Into::>::into(&max_u64), vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8)); + } + + #[test] + fn test_to_u64() { + let minus_five: Mpz = From::::from(-5); + let minus_one: Mpz = From::::from(-1); + let zero: Mpz = From::::from(0); + let one: Mpz = From::::from(1); + let five: Mpz = From::::from(5); + let max_u64: Mpz = From::::from(u64::MAX); + + assert_eq!(Into::>::into(&minus_five), None); + assert_eq!(Into::>::into(&minus_one), None); + assert_eq!(Into::>::into(&zero), Some(0u64)); + assert_eq!(Into::>::into(&one), Some(1u64)); + assert_eq!(Into::>::into(&five), Some(5u64)); + assert_eq!(Into::>::into(&max_u64), Some(u64::MAX)); + assert_eq!(Into::>::into(&(&max_u64 + &one)), None); + } + + #[test] + fn test_to_i64() { + let min_i64: Mpz = From::::from(i64::MIN); + let minus_five: Mpz = From::::from(-5); + let minus_one: Mpz = From::::from(-1); + let zero: Mpz = From::::from(0); + let one: Mpz = From::::from(1); + let five: Mpz = From::::from(5); + let max_i64: Mpz = From::::from(i64::MAX); + + assert_eq!(Into::>::into(&(&min_i64 - &one)), None); + assert_eq!(Into::>::into(&min_i64), Some(i64::MIN)); + assert_eq!(Into::>::into(&minus_five), Some(-5i64)); + assert_eq!(Into::>::into(&minus_one), Some(-1i64)); + assert_eq!(Into::>::into(&zero), Some(0i64)); + assert_eq!(Into::>::into(&one), Some(1i64)); + assert_eq!(Into::>::into(&five), Some(5i64)); + assert_eq!(Into::>::into(&max_i64), Some(i64::MAX)); + assert_eq!(Into::>::into(&(&max_i64 + &one)), None); + } + + #[test] + fn test_sign() { + let zero: Mpz = From::::from(0); + let five: Mpz = From::::from(5); + let minus_five: Mpz = From::::from(-5); + + assert_eq!(zero.sign(), Sign::Zero); + assert_eq!(five.sign(), Sign::Positive); + assert_eq!(minus_five.sign(), Sign::Negative); + } + + #[test] + fn test_format() { + let zero = Mpz::zero(); + assert_eq!(format!("{}", zero), "0"); + let zero = Mpz::from(-51213); + assert_eq!(format!("{}", zero), "-51213"); + } +} diff --git a/crates/classgroup/src/gmp_classgroup/congruence.rs b/crates/classgroup/src/gmp_classgroup/congruence.rs new file mode 100644 index 0000000..7a30297 --- /dev/null +++ b/crates/classgroup/src/gmp_classgroup/congruence.rs @@ -0,0 +1,90 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![forbid(unsafe_code)] +use self::ffi::Mpz; +use super::ffi; + +/// Stores temporary values for congruence computations, to avoid +/// repeated allocations. +/// +/// It is allowed (but inefficient) to generate a fresh `CongruenceContest` +/// for each call to `solve_linear_congruence`. +/// +/// `self.solve_linear_congruence` can be called no matter what values +/// this struct’s public members hold, so long as they are valid `Mpz` values. +/// However, the values of these members after such a call must not be relied +/// on. +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct CongruenceContext { + pub g: Mpz, + pub d: Mpz, + pub q: Mpz, + pub r: Mpz, +} + +// #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +// struct NoCongruence; + +impl Default for CongruenceContext { + fn default() -> Self { + Self { + g: Mpz::new(), + d: Mpz::new(), + q: Mpz::new(), + r: Mpz::new(), + } + } +} + +impl CongruenceContext { + /// Solves `a*x = b (mod m)`, storing `x` in `mu` + /// + /// This function may clobber any or all of `self`’s member variables. + /// + /// # Panics + /// + /// Panics if the congruence could not be solved. + pub fn solve_linear_congruence( + &mut self, + mu: &mut Mpz, + v: Option<&mut Mpz>, + a: &Mpz, + b: &Mpz, + m: &Mpz, + ) { + ffi::mpz_gcdext(&mut self.g, &mut self.d, mu, a, m); + if cfg!(test) { + println!( + "g = {}, d = {}, e = {}, a = {}, m = {}", + self.g, self.d, mu, a, m + ); + } + if cfg!(debug_assertions) { + ffi::mpz_fdiv_qr(&mut self.q, &mut self.r, b, &self.g); + debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!"); + } else { + ffi::mpz_divexact(&mut self.q, b, &self.g) + } + ffi::mpz_mul(&mut self.r, &self.q, &self.d); + ffi::mpz_tdiv_r(mu, &self.r, m); + if let Some(v) = v { + if cfg!(debug_assertions) { + ffi::mpz_fdiv_qr(v, &mut self.r, &m, &self.g); + debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!"); + } else { + ffi::mpz_divexact(v, &m, &self.g) + } + } + } +} diff --git a/crates/classgroup/src/gmp_classgroup/ffi.rs b/crates/classgroup/src/gmp_classgroup/ffi.rs new file mode 100644 index 0000000..7e7b31f --- /dev/null +++ b/crates/classgroup/src/gmp_classgroup/ffi.rs @@ -0,0 +1,340 @@ +// Copyright 2018 POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! FFI bindings to GMP. This module exists because the `rust-gmp` crate +//! is too high-level. High-performance bignum computation requires that +//! bignums be modified in-place, so that their storage can be reused. +//! Furthermore, the `rust-gmp` crate doesn’t support many operations that +//! this library requires. +#![allow(unsafe_code)] +pub use super::super::gmp::mpz::Mpz; +use super::super::gmp::mpz::{mp_bitcnt_t, mp_limb_t}; +use libc::{c_int, c_long, c_ulong, c_void, size_t}; +// pub use c_ulong; +use std::{mem, usize}; +// We use the unsafe versions to avoid unecessary allocations. +#[link(name = "gmp", kind = "static")] +extern "C" { + fn __gmpz_gcdext(gcd: *mut Mpz, s: *mut Mpz, t: *mut Mpz, a: *const Mpz, b: *const Mpz); + fn __gmpz_gcd(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); + fn __gmpz_fdiv_qr(q: *mut Mpz, r: *mut Mpz, b: *const Mpz, g: *const Mpz); + fn __gmpz_fdiv_q(q: *mut Mpz, n: *const Mpz, d: *const Mpz); + fn __gmpz_divexact(q: *mut Mpz, n: *const Mpz, d: *const Mpz); + fn __gmpz_tdiv_q(q: *mut Mpz, n: *const Mpz, d: *const Mpz); + fn __gmpz_mul(p: *mut Mpz, a: *const Mpz, b: *const Mpz); + fn __gmpz_mul_2exp(rop: *mut Mpz, op1: *const Mpz, op2: mp_bitcnt_t); + fn __gmpz_sub(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); + fn __gmpz_import( + rop: *mut Mpz, + count: size_t, + order: c_int, + size: size_t, + endian: c_int, + nails: size_t, + op: *const c_void, + ); + fn __gmpz_tdiv_r(r: *mut Mpz, n: *const Mpz, d: *const Mpz); + fn __gmpz_sizeinbase(op: &Mpz, base: c_int) -> size_t; + fn __gmpz_fdiv_q_ui(rop: *mut Mpz, op1: *const Mpz, op2: c_ulong) -> c_ulong; + fn __gmpz_add(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); + fn __gmpz_add_ui(rop: *mut Mpz, op1: *const Mpz, op2: c_ulong); + fn __gmpz_set_ui(rop: &mut Mpz, op: c_ulong); + fn __gmpz_set_si(rop: &mut Mpz, op: c_long); + fn __gmpz_cdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong; + fn __gmpz_fdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong; + fn __gmpz_tdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong; + fn __gmpz_export( + rop: *mut c_void, + countp: *mut size_t, + order: c_int, + size: size_t, + endian: c_int, + nails: size_t, + op: &Mpz, + ) -> *mut c_void; + fn __gmpz_powm(rop: *mut Mpz, base: *const Mpz, exp: *const Mpz, modulus: *const Mpz); +} + +// MEGA HACK: rust-gmp doesn’t expose the fields of this struct, so we must define +// it ourselves and cast. +// +// Should be stable though, as only GMP can change it, and doing would break binary compatibility. +#[repr(C)] +struct MpzStruct { + mp_alloc: c_int, + mp_size: c_int, + mp_d: *mut mp_limb_t, +} + +macro_rules! impl_div_ui { + ($t:ident, $i:ident, $f:expr) => { + pub fn $i(n: &Mpz, d: $t) -> $t { + use std::$t; + let res = unsafe { $f(n, c_ulong::from(d)) }; + assert!(res <= $t::MAX.into()); + res as $t + } + }; +} + +impl_div_ui!(u16, mpz_crem_u16, __gmpz_cdiv_ui); +impl_div_ui!(u32, mpz_frem_u32, __gmpz_fdiv_ui); + +/// Returns `true` if `z` is negative and not zero. Otherwise, +/// returns `false`. +#[inline] +pub fn mpz_is_negative(z: &Mpz) -> bool { + unsafe { (*(z as *const _ as *const MpzStruct)).mp_size < 0 } +} + +#[inline] +pub fn mpz_powm(rop: &mut Mpz, base: &Mpz, exponent: &Mpz, modulus: &Mpz) { + unsafe { __gmpz_powm(rop, base, exponent, modulus) } +} + +#[inline] +pub fn mpz_tdiv_r(r: &mut Mpz, n: &Mpz, d: &Mpz) { + unsafe { __gmpz_tdiv_r(r, n, d) } +} + +/// Sets `g` to the GCD of `a` and `b`. +#[inline] +pub fn mpz_gcdext(gcd: &mut Mpz, s: &mut Mpz, t: &mut Mpz, a: &Mpz, b: &Mpz) { + unsafe { __gmpz_gcdext(gcd, s, t, a, b) } +} + +/// Doubles `rop` in-place +#[inline] +pub fn mpz_double(rop: &mut Mpz) { + if true { + // slightly faster + unsafe { __gmpz_mul_2exp(rop, rop, 1) } + } else { + unsafe { __gmpz_add(rop, rop, rop) } + } +} + +#[inline] +pub fn mpz_fdiv_qr(q: &mut Mpz, r: &mut Mpz, b: &Mpz, g: &Mpz) { + unsafe { __gmpz_fdiv_qr(q, r, b, g) } +} + +#[inline] +pub fn mpz_fdiv_q_ui_self(rop: &mut Mpz, op: c_ulong) -> c_ulong { + unsafe { __gmpz_fdiv_q_ui(rop, rop, op) } +} + +/// Unmarshals a buffer to an `Mpz`. `buf` is interpreted as a 2’s complement, +/// big-endian integer. If the buffer is empty, zero is returned. +pub fn import_obj(buf: &[u8]) -> Mpz { + fn raw_import(buf: &[u8]) -> Mpz { + let mut obj = Mpz::new(); + + unsafe { __gmpz_import(&mut obj, buf.len(), 1, 1, 1, 0, buf.as_ptr() as *const _) } + obj + } + let is_negative = match buf.first() { + None => return Mpz::zero(), + Some(x) => x & 0x80 != 0, + }; + if !is_negative { + raw_import(buf) + } else { + let mut new_buf: Vec<_> = buf.iter().cloned().skip_while(|&x| x == 0xFF).collect(); + if new_buf.is_empty() { + (-1).into() + } else { + for i in &mut new_buf { + *i ^= 0xFF + } + !raw_import(&new_buf) + } + } +} + +pub fn three_gcd(rop: &mut Mpz, a: &Mpz, b: &Mpz, c: &Mpz) { + unsafe { + __gmpz_gcd(rop, a, b); + __gmpz_gcd(rop, rop, c) + } +} + +#[inline] +pub fn size_in_bits(obj: &Mpz) -> usize { + unsafe { __gmpz_sizeinbase(obj, 2) } +} + +#[inline] +pub fn mpz_add(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) { + unsafe { __gmpz_add(rop, op1, op2) } +} + +#[inline] +pub fn mpz_mul(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) { + unsafe { __gmpz_mul(rop, op1, op2) } +} + +#[inline] +pub fn mpz_divexact(q: &mut Mpz, n: &Mpz, d: &Mpz) { + unsafe { __gmpz_divexact(q, n, d) } +} + +#[inline] +pub fn mpz_mul_2exp(rop: &mut Mpz, op1: &Mpz, op2: mp_bitcnt_t) { + unsafe { __gmpz_mul_2exp(rop as *mut _ as *mut Mpz, op1, op2) } +} + +/// Divide `n` by `d`. Round towards -∞ and place the result in `q`. +#[inline] +pub fn mpz_fdiv_q(q: &mut Mpz, n: &Mpz, d: &Mpz) { + if mpz_is_negative(n) == mpz_is_negative(d) { + unsafe { __gmpz_tdiv_q(q, n, d) } + } else { + unsafe { __gmpz_fdiv_q(q, n, d) } + } +} + +/// Sets `rop` to `(-1) * op` +#[inline] +#[cfg(none)] +pub fn mpz_neg(rop: &mut Mpz) { + assert!(mem::size_of::() == mem::size_of::()); + unsafe { + let ptr = rop as *mut _ as *mut MpzStruct; + let v = (*ptr).mp_size; + (*ptr).mp_size = -v; + } +} + +/// Subtracts `op2` from `op1` and stores the result in `rop`. +#[inline] +pub fn mpz_sub(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) { + unsafe { __gmpz_sub(rop as *mut _ as *mut Mpz, op1, op2) } +} + +/// Exports `obj` to `v` as an array of 2’s complement, big-endian +/// bytes. If `v` is too small to hold the result, returns `Err(s)`, +/// where `s` is the size needed to hold the exported version of `obj`. +pub fn export_obj(obj: &Mpz, v: &mut [u8]) -> Result<(), usize> { + // Requires: offset < v.len() and v[offset..] be able to hold all of `obj` + unsafe fn raw_export(v: &mut [u8], offset: usize, obj: &Mpz) -> usize { + // SAFE as `offset` will always be in-bounds, since byte_len always <= + // byte_len_needed and we check that v.len() >= byte_len_needed. + let ptr = v.as_mut_ptr().add(offset) as *mut c_void; + + // Necessary ― this byte may not be fully overwritten + *(ptr as *mut u8) = 0; + + // SAFE as __gmpz_export will *always* initialize this. + let mut s: usize = mem::uninitialized(); + let ptr2 = __gmpz_export(ptr, &mut s, 1, 1, 1, 0, obj); + assert_eq!(ptr, ptr2); + if 0 == s { + 1 + } else { + s + } + } + + let size = size_in_bits(obj); + assert!(size > 0); + + // Check to avoid integer overflow in later operations. + if size > usize::MAX - 8 || v.len() > usize::MAX >> 3 { + return Err(usize::MAX); + } + + // One additional bit is needed for the sign bit. + let byte_len_needed = (size + 8) >> 3; + if v.len() < byte_len_needed { + return if v.is_empty() && obj.is_zero() { + Ok(()) + } else { + Err(byte_len_needed) + }; + } + let is_negative = mpz_is_negative(obj); + + if is_negative { + // MEGA HACK: GMP does not have a function to perform 2's complement + let obj = !obj; + debug_assert!( + !mpz_is_negative(&obj), + "bitwise negation of a negative number produced a negative number" + ); + let new_byte_size = (size_in_bits(&obj) + 7) >> 3; + let offset = v.len() - new_byte_size; + + for i in &mut v[..offset] { + *i = 0xFF + } + unsafe { + assert_eq!(raw_export(v, offset, &obj), new_byte_size); + } + + // We had to do a one’s complement to get the data in a decent format, + // so now we need to flip all of the bits back. LLVM should be able to + // vectorize this loop easily. + for i in &mut v[offset..] { + *i ^= 0xFF + } + } else { + // ...but GMP will not include that in the number of bytes it writes + // (except for negative numbers) + let byte_len = (size + 7) >> 3; + assert!(byte_len > 0); + + let offset = v.len() - byte_len; + + // Zero out any leading bytes + for i in &mut v[..offset] { + *i = 0 + } + unsafe { + assert_eq!(raw_export(v, offset, &obj), byte_len); + } + } + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn check_expected_bit_width() { + let mut s: Mpz = (-2).into(); + assert_eq!(size_in_bits(&s), 2); + s = !s; + assert_eq!(s, 1.into()); + s.setbit(2); + assert_eq!(s, 5.into()); + } + + #[test] + fn check_export() { + let mut s: Mpz = 0x100.into(); + s = !s; + let mut buf = [0, 0, 0]; + export_obj(&s, &mut buf).expect("buffer should be large enough"); + assert_eq!(buf, [0xFF, 0xFE, 0xFF]); + export_obj(&Mpz::zero(), &mut []).unwrap(); + } + + #[test] + fn check_rem() { + assert_eq!(mpz_crem_u16(&(-100i64).into(), 3), 1); + assert_eq!(mpz_crem_u16(&(100i64).into(), 3), 2); + } +} diff --git a/crates/classgroup/src/gmp_classgroup/mod.rs b/crates/classgroup/src/gmp_classgroup/mod.rs new file mode 100644 index 0000000..f89d8b9 --- /dev/null +++ b/crates/classgroup/src/gmp_classgroup/mod.rs @@ -0,0 +1,590 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![deny(unsafe_code)] +use super::ClassGroup; +use super::gmp::mpz::Mpz; +use super::gmp::mpz::ProbabPrimeResult::NotPrime; +use num_traits::{One, Zero}; +use std::{ + borrow::Borrow, + cell::RefCell, + mem::swap, + ops::{Mul, MulAssign}, +}; +use std::convert::TryInto; + +mod congruence; +pub(super) mod ffi; + +#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Clone)] +pub struct GmpClassGroup { + a: Mpz, + b: Mpz, + c: Mpz, + discriminant: Mpz, +} + +#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Hash, Debug)] +pub struct Ctx { + negative_a: Mpz, + r: Mpz, + denom: Mpz, + old_a: Mpz, + old_b: Mpz, + ra: Mpz, + s: Mpz, + x: Mpz, + congruence_context: congruence::CongruenceContext, + h: Mpz, + w: Mpz, + m: Mpz, + u: Mpz, + a: Mpz, + l: Mpz, + j: Mpz, + b: Mpz, + k: Mpz, + t: Mpz, + mu: Mpz, + v: Mpz, + sigma: Mpz, + lambda: Mpz, +} + +thread_local! { + static CTX: RefCell = Default::default(); +} + +impl GmpClassGroup { + pub fn into_raw(self) -> (Mpz, Mpz) { + (self.a, self.b) + } + + fn inner_multiply(&mut self, rhs: &Self, ctx: &mut Ctx) { + self.assert_valid(); + rhs.assert_valid(); + + // g = (b1 + b2) / 2 + ffi::mpz_add(&mut ctx.congruence_context.g, &self.b, &rhs.b); + ffi::mpz_fdiv_q_ui_self(&mut ctx.congruence_context.g, 2); + + // h = (b2 - b1) / 2 + ffi::mpz_sub(&mut ctx.h, &rhs.b, &self.b); + ffi::mpz_fdiv_q_ui_self(&mut ctx.h, 2); + + debug_assert!(&ctx.h + &ctx.congruence_context.g == rhs.b); + debug_assert!(&ctx.congruence_context.g - &ctx.h == self.b); + + // w = gcd(a1, a2, g) + ffi::three_gcd(&mut ctx.w, &self.a, &rhs.a, &ctx.congruence_context.g); + + // j = w + ctx.j.set(&ctx.w); + + // s = a1/w + ffi::mpz_fdiv_q(&mut ctx.s, &self.a, &ctx.w); + + // t = a2/w + ffi::mpz_fdiv_q(&mut ctx.t, &rhs.a, &ctx.w); + + // u = g/w + ffi::mpz_fdiv_q(&mut ctx.u, &ctx.congruence_context.g, &ctx.w); + + // a = t*u + ffi::mpz_mul(&mut ctx.a, &ctx.t, &ctx.u); + + // b = h*u - s*c1 + ffi::mpz_mul(&mut ctx.b, &ctx.h, &ctx.u); + ffi::mpz_mul(&mut ctx.m, &ctx.s, &self.c); + ctx.b += &ctx.m; + + // m = s*t + ffi::mpz_mul(&mut ctx.m, &ctx.s, &ctx.t); + ctx.congruence_context.solve_linear_congruence( + &mut ctx.mu, + Some(&mut ctx.v), + &ctx.a, + &ctx.b, + &ctx.m, + ); + + // a = t*v + ffi::mpz_mul(&mut ctx.a, &ctx.t, &ctx.v); + + // b = h - t * mu + ffi::mpz_mul(&mut ctx.m, &ctx.t, &ctx.mu); + ffi::mpz_sub(&mut ctx.b, &ctx.h, &ctx.m); + + // m = s + ctx.m.set(&ctx.s); + + ctx.congruence_context.solve_linear_congruence( + &mut ctx.lambda, + Some(&mut ctx.sigma), + &ctx.a, + &ctx.b, + &ctx.m, + ); + + // k = mu + v*lambda + ffi::mpz_mul(&mut ctx.a, &ctx.v, &ctx.lambda); + ffi::mpz_add(&mut ctx.k, &ctx.mu, &ctx.a); + + // l = (k*t - h)/s + ffi::mpz_mul(&mut ctx.l, &ctx.k, &ctx.t); + ffi::mpz_sub(&mut ctx.v, &ctx.l, &ctx.h); + ffi::mpz_fdiv_q(&mut ctx.l, &ctx.v, &ctx.s); + + // m = (t*u*k - h*u - c*s) / s*t + ffi::mpz_mul(&mut ctx.m, &ctx.t, &ctx.u); + ctx.m *= &ctx.k; + ffi::mpz_mul(&mut ctx.a, &ctx.h, &ctx.u); + ctx.m -= &ctx.a; + ffi::mpz_mul(&mut ctx.a, &self.c, &ctx.s); + ctx.m -= &ctx.a; + ffi::mpz_mul(&mut ctx.a, &ctx.s, &ctx.t); + ffi::mpz_fdiv_q(&mut ctx.lambda, &ctx.m, &ctx.a); + + // A = s*t - r*u + ffi::mpz_mul(&mut self.a, &ctx.s, &ctx.t); + + // B = ju + mr - (kt + ls) + ffi::mpz_mul(&mut self.b, &ctx.j, &ctx.u); + ffi::mpz_mul(&mut ctx.a, &ctx.k, &ctx.t); + self.b -= &ctx.a; + ffi::mpz_mul(&mut ctx.a, &ctx.l, &ctx.s); + self.b -= &ctx.a; + + // C = kl - jm + ffi::mpz_mul(&mut self.c, &ctx.k, &ctx.l); + ffi::mpz_mul(&mut ctx.a, &ctx.j, &ctx.lambda); + self.c -= &ctx.a; + + self.inner_reduce(ctx); + } + + #[cfg_attr(not(debug_assertions), inline(always))] + fn new(a: Mpz, b: Mpz, c: Mpz, discriminant: Mpz) -> Self { + let s = GmpClassGroup { + a, + b, + c, + discriminant, + }; + s.assert_valid(); + s + } + + #[cfg_attr(not(debug_assertions), inline(always))] + fn assert_valid(&self) { + if cfg!(debug_assertions) { + let four: Mpz = 4u64.into(); + let four_ac: Mpz = four * &self.a * &self.c; + assert!(&self.discriminant + four_ac == &self.b * &self.b); + } + } + + fn inner_normalize(&mut self, ctx: &mut Ctx) { + self.assert_valid(); + ctx.negative_a = -&self.a; + if self.b > ctx.negative_a && self.b <= self.a { + return; + } + ffi::mpz_sub(&mut ctx.r, &self.a, &self.b); + ffi::mpz_mul_2exp(&mut ctx.denom, &self.a, 1); + ffi::mpz_fdiv_q(&mut ctx.negative_a, &ctx.r, &ctx.denom); + swap(&mut ctx.negative_a, &mut ctx.r); + swap(&mut ctx.old_b, &mut self.b); + ffi::mpz_mul(&mut ctx.ra, &ctx.r, &self.a); + ffi::mpz_mul_2exp(&mut ctx.negative_a, &ctx.ra, 1); + ffi::mpz_add(&mut self.b, &ctx.old_b, &ctx.negative_a); + + ffi::mpz_mul(&mut ctx.negative_a, &ctx.ra, &ctx.r); + ffi::mpz_add(&mut ctx.old_a, &self.c, &ctx.negative_a); + + ffi::mpz_mul(&mut ctx.ra, &ctx.r, &ctx.old_b); + ffi::mpz_add(&mut self.c, &ctx.old_a, &ctx.ra); + + self.assert_valid(); + } + + fn inner_reduce(&mut self, ctx: &mut Ctx) { + self.inner_normalize(ctx); + + while if ffi::mpz_is_negative(&self.b) { + self.a >= self.c + } else { + self.a > self.c + } { + debug_assert!(!self.c.is_zero()); + ffi::mpz_add(&mut ctx.s, &self.c, &self.b); + ffi::mpz_add(&mut ctx.x, &self.c, &self.c); + swap(&mut self.b, &mut ctx.old_b); + ffi::mpz_fdiv_q(&mut self.b, &ctx.s, &ctx.x); + swap(&mut self.b, &mut ctx.s); + swap(&mut self.a, &mut self.c); + + // x = 2sc + ffi::mpz_mul(&mut self.b, &ctx.s, &self.a); + ffi::mpz_mul_2exp(&mut ctx.x, &self.b, 1); + + // b = x - old_b + ffi::mpz_sub(&mut self.b, &ctx.x, &ctx.old_b); + + // x = b*s + ffi::mpz_mul(&mut ctx.x, &ctx.old_b, &ctx.s); + + // s = c*s^2 + ffi::mpz_mul(&mut ctx.old_b, &ctx.s, &ctx.s); + ffi::mpz_mul(&mut ctx.s, &self.a, &ctx.old_b); + + // c = s - x + ffi::mpz_sub(&mut ctx.old_a, &ctx.s, &ctx.x); + + // c += a + self.c += &ctx.old_a; + } + self.inner_normalize(ctx); + } + + fn inner_square_impl(&mut self, ctx: &mut Ctx) { + self.assert_valid(); + ctx.congruence_context.solve_linear_congruence( + &mut ctx.mu, + None, + &self.b, + &self.c, + &self.a, + ); + ffi::mpz_mul(&mut ctx.m, &self.b, &ctx.mu); + ctx.m -= &self.c; + ctx.m = ctx.m.div_floor(&self.a); + + // New a + ctx.old_a.set(&self.a); + ffi::mpz_mul(&mut self.a, &ctx.old_a, &ctx.old_a); + + // New b + ffi::mpz_mul(&mut ctx.a, &ctx.mu, &ctx.old_a); + ffi::mpz_double(&mut ctx.a); + self.b -= &ctx.a; + + // New c + ffi::mpz_mul(&mut self.c, &ctx.mu, &ctx.mu); + self.c -= &ctx.m; + self.inner_reduce(ctx); + } + + #[cfg_attr(not(debug_assertions), inline(always))] + fn inner_square(&mut self, ctx: &mut Ctx) { + if cfg!(debug_assertions) { + let mut q = self.clone(); + q.inner_multiply(self, ctx); + self.inner_square_impl(ctx); + assert_eq!(*self, q); + } else { + self.inner_square_impl(ctx); + } + } + + /// Call `cb` with a mutable reference to the context of type `Ctx`. + /// + /// The reference cannot escape the closure and cannot be sent across + /// threads. + /// + /// # Panics + /// + /// Panics if called recursively. This library guarantees that it will + /// never call this function from any function that takes a parameter of + /// type `&mut Ctx`. + pub fn with_context(cb: T) -> U + where + T: FnOnce(&mut Ctx) -> U, + { + let mut opt = None; + CTX.with(|x| opt = Some(cb(&mut x.borrow_mut()))); + opt.unwrap() + } +} + +impl Default for GmpClassGroup { + fn default() -> Self { + GmpClassGroup { + a: Mpz::new(), + b: Mpz::new(), + c: Mpz::new(), + discriminant: Mpz::new(), + } + } +} + +impl> MulAssign for GmpClassGroup { + #[cfg_attr(not(debug_assertions), inline(always))] + fn mul_assign(&mut self, rhs: B) { + let rhs = rhs.borrow(); + debug_assert!(self.discriminant == rhs.discriminant); + GmpClassGroup::with_context(|ctx| self.inner_multiply(rhs, ctx)); + } +} + +impl super::BigNum for Mpz { + fn probab_prime(&self, iterations: u32) -> bool { + let reps: i32 = iterations.try_into().expect("Iterations fits into i32"); + self.probab_prime(reps) != NotPrime + } + + fn setbit(&mut self, bit_index: usize) { + self.setbit(bit_index) + } + + fn mod_powm(&mut self, base: &Self, exponent: &Self, modulus: &Self) { + ffi::mpz_powm(self, base, exponent, modulus) + } +} + +impl super::BigNumExt for Mpz { + fn frem_u32(&self, modulus: u32) -> u32 { + ffi::mpz_frem_u32(self, modulus) + } + fn crem_u16(&mut self, modulus: u16) -> u16 { + ffi::mpz_crem_u16(self, modulus) + } +} + +impl> Mul for GmpClassGroup { + type Output = Self; + #[inline] + fn mul(mut self, rhs: B) -> Self { + self *= rhs.borrow(); + self + } +} + +impl<'a, B: Borrow> Mul for &'a GmpClassGroup { + type Output = GmpClassGroup; + + #[inline(always)] + fn mul(self, rhs: B) -> Self::Output { + let mut s = Clone::clone(self.borrow()); + s *= rhs; + s + } +} + +impl ClassGroup for GmpClassGroup { + type BigNum = Mpz; + + /// Normalize `self`. + /// + /// # Panics + /// + /// Panics if called within a call to `Self::with_context`. + fn normalize(&mut self) { + Self::with_context(|x| self.inner_normalize(x)) + } + + #[cfg_attr(not(debug_assertions), inline(always))] + fn inverse(&mut self) { + self.assert_valid(); + self.b = -self.b.clone(); + } + + fn serialize(&self, buf: &mut [u8]) -> Result<(), usize> { + self.assert_valid(); + if buf.len() & 1 == 1 { + // odd lengths do not make sense + Err(0) + } else { + let len = buf.len() >> 1; + ffi::export_obj(&self.a, &mut buf[..len])?; + ffi::export_obj(&self.b, &mut buf[len..]) + } + } + + fn from_bytes(bytearray: &[u8], discriminant: Self::BigNum) -> Self { + let len = (ffi::size_in_bits(&discriminant) + 16) >> 4; + let a = ffi::import_obj(&bytearray[..len]); + let b = ffi::import_obj(&bytearray[len..]); + Self::from_ab_discriminant(a, b, discriminant) + } + + fn from_ab_discriminant(a: Self::BigNum, b: Self::BigNum, discriminant: Self::BigNum) -> Self { + let mut four_a: Self::BigNum = 4u64.into(); + four_a *= &a; + let c = (&b * &b - &discriminant) / four_a; + Self { + a, + b, + c, + discriminant, + } + } + + /// Returns the discriminant of `self`. + #[inline(always)] + fn discriminant(&self) -> &Self::BigNum { + &self.discriminant + } + + fn size_in_bits(num: &Self::BigNum) -> usize { + ffi::size_in_bits(num) + } + + /// Reduce `self`. + /// + /// # Panics + /// + /// Panics if called within a call to `Self::with_context`. + fn reduce(&mut self) { + Self::with_context(|x| self.inner_reduce(x)) + } + + fn deserialize(buf: &[u8], discriminant: Self::BigNum) -> Self { + let len = buf.len(); + debug_assert!(len != 0, "Cannot deserialize an empty buffer!"); + debug_assert!(len & 1 == 0, "Buffer must be of even length"); + let half_len = len >> 1; + Self::from_ab_discriminant( + ffi::import_obj(&buf[..half_len]), + ffi::import_obj(&buf[half_len..]), + discriminant, + ) + } + + /// Square `self`.ClassGroupPartial + /// + /// # Panics + /// + /// Panics if called within the scope of a call to `with_context`. + fn square(&mut self) { + Self::with_context(|ctx| self.inner_square(ctx)) + } + + fn unsigned_deserialize_bignum(buf: &[u8]) -> Self::BigNum { + buf.into() + } + + /// Square `self` `iterations` times. + /// + /// # Panics + /// + /// Panics if called within the scope of a call to `with_context`. + fn repeated_square(&mut self, iterations: u64) { + Self::with_context(|ctx| { + for _ in 0..iterations { + self.inner_square(ctx) + } + }) + } + + fn generator_for_discriminant(discriminant: Self::BigNum) -> Self { + let one: Mpz = One::one(); + let x: Mpz = &one - &discriminant; + let mut form = Self::new(2.into(), one, x.div_floor(&8.into()), discriminant); + form.reduce(); + form + } + + fn pow(&mut self, mut exponent: Mpz) { + self.assert_valid(); + debug_assert!(exponent >= Mpz::zero()); + let mut state = self.identity(); + loop { + let is_odd = exponent.tstbit(0); + exponent >>= 1; + if is_odd { + state *= &*self + } + if exponent.is_zero() { + *self = state; + break; + } + self.square(); + } + } +} + +impl Default for Ctx { + fn default() -> Self { + Self { + negative_a: Mpz::new(), + r: Mpz::new(), + denom: Mpz::new(), + old_a: Mpz::new(), + old_b: Mpz::new(), + ra: Mpz::new(), + s: Mpz::new(), + x: Mpz::new(), + congruence_context: Default::default(), + w: Mpz::new(), + m: Mpz::new(), + u: Mpz::new(), + l: Mpz::new(), + j: Mpz::new(), + t: Mpz::new(), + a: Mpz::new(), + b: Mpz::new(), + k: Mpz::new(), + h: Mpz::new(), + mu: Mpz::new(), + v: Mpz::new(), + sigma: Mpz::new(), + lambda: Mpz::new(), + } + } +} + +pub fn do_compute(discriminant: Mpz, iterations: u64) -> GmpClassGroup { + debug_assert!(discriminant < Zero::zero()); + debug_assert!(discriminant.probab_prime(50) != NotPrime); + let mut f = GmpClassGroup::generator_for_discriminant(discriminant); + f.repeated_square(iterations); + f +} + +#[cfg(test)] +mod test { + #![allow(unused_imports)] + use super::*; + #[test] + fn normalize() { + let mut s = GmpClassGroup::new( + 16.into(), + (-23).into(), + 5837_3892.into(), + (-0xdead_beefi64).into(), + ); + let mut new = GmpClassGroup { + b: 9.into(), + c: 5837_3885.into(), + ..s.clone() + }; + s.normalize(); + assert_eq!(s, new); + + s = GmpClassGroup { + a: (1 << 16).into(), + b: (-76951).into(), + c: 36840.into(), + ..s + }; + new = GmpClassGroup { + b: 54121.into(), + c: 25425.into(), + ..s.clone() + }; + s.normalize(); + assert_eq!(s, new); + } +} diff --git a/crates/classgroup/src/lib.rs b/crates/classgroup/src/lib.rs new file mode 100644 index 0000000..8da546b --- /dev/null +++ b/crates/classgroup/src/lib.rs @@ -0,0 +1,251 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![deny(unsafe_code)] +use num_traits::{One, Zero}; +use std::ops::{Mul, MulAssign, Rem, ShlAssign}; + +pub mod gmp; + +pub mod gmp_classgroup; +pub use self::gmp_classgroup::{ + do_compute, + ffi::{export_obj, import_obj}, +}; +pub trait BigNum: + Zero + + One + + Clone + + PartialOrd + + std::fmt::Debug + + Rem + + ShlAssign + + for<'a> MulAssign<&'a Self> + + std::ops::Sub + + std::ops::Add + + std::convert::From + + for<'a> std::convert::From<&'a [u8]> + + std::ops::Shl + + std::ops::Shr + + std::ops::Neg + + std::str::FromStr + + for<'a> std::ops::Div<&'a Self, Output = Self> + + Eq + + std::hash::Hash +{ + fn probab_prime(&self, iterations: u32) -> bool; + fn setbit(&mut self, offset: usize); + fn mod_powm(&mut self, base: &Self, exponent: &Self, modulus: &Self); +} + +pub trait BigNumExt: BigNum { + fn frem_u32(&self, modulus: u32) -> u32; + fn crem_u16(&mut self, modulus: u16) -> u16; +} + +pub trait ClassGroup: + Sized + Clone + for<'a> MulAssign<&'a Self> + for<'a> Mul<&'a Self> + PartialEq + std::fmt::Debug +{ + type BigNum: BigNum; + + /// Produces a `Self` from `a`, `b`, and a discriminant. + fn from_ab_discriminant(a: Self::BigNum, b: Self::BigNum, discriminant: Self::BigNum) -> Self; + + /// Unmarshals a `Self` from a byte array and discriminant. + /// + /// The byte array will be in the format of two big-endian byte sequences + /// concatenated together. + fn from_bytes(bytearray: &[u8], discriminant: Self::BigNum) -> Self; + + /// Computes the identity element of `Self` for a given discriminant. + /// + /// If the discriminant is not valid, the result is unspecified. + /// + /// # Panics + /// + /// This may panic (but is not required to) if the discriminant is not + /// valid. If this function does not panic, the results of future + /// operations are unspecified: they will not invoke undefined behavior, + /// but may panic, loop forever, or just compute garbage. + /// + /// In debug builds, this will always panic if the discriminant is invalid. + fn identity_for_discriminant(discriminant: Self::BigNum) -> Self { + Self::from_ab_discriminant(Self::BigNum::one(), Self::BigNum::one(), discriminant) + } + + /// Serializes `self` to a byte array. Returns `Err(s)` if there + /// is not enough space in the buffer. + /// + /// The data must be serialized in twos-complement, big-endian format. + fn serialize(&self, buf: &mut [u8]) -> std::result::Result<(), usize>; + + /// Deserializes a bignum from raw bytes. The bytes **must** be interpreted + /// as a big-endian unsigned integer. + fn unsigned_deserialize_bignum(_: &[u8]) -> Self::BigNum; + + /// Reduce `self` in-place. + fn reduce(&mut self); + + /// Squares `self`, modifying it in-place. + /// + /// A default implementation is provided, but implementations are suggested + /// to override it for performance reasons. + fn square(&mut self) { + let s = self.clone(); + self.mul_assign(&s) + } + + /// Normalize `self`. + fn normalize(&mut self); + + /// The length of `num` in **bits** + fn size_in_bits(num: &Self::BigNum) -> usize; + + /// Gets the discriminant of `self`. + fn discriminant(&self) -> &Self::BigNum; + + /// Computes the identity element of a `ClassGroup`. + fn identity(&self) -> Self { + Self::identity_for_discriminant(self.discriminant().clone()) + } + + /// Generates a *generator* for the class group of `Self`, given a + /// discriminant. + /// + /// If the discriminant is not valid, the result is unspecified. + /// + /// # Relation to `Self::identity_for_discriminant` + /// + /// This is *not* the same as `Self::identity_for_discriminant`: the + /// identity element is *never* a generator for *any* group. This follows + /// from their definitions: the identity element, when multiplied by another + /// element, always gives that other element, whereas *every* element in the + /// group is some power of a generator. + /// + /// # Panics + /// + /// This may panic (but is not required to) if the discriminant is not + /// valid. If this function does not panic, the results of future + /// operations are unspecified: they will not invoke undefined behavior, + /// but may panic, loop forever, or just compute garbage. + /// + /// If the global allocator panics on running out of memory, then this + /// function may panic in the same situation, but it may also just abort the + /// program instead. + /// + /// In debug builds, this will always panic if the discriminant is invalid. + fn generator_for_discriminant(discriminant: Self::BigNum) -> Self { + Self::from_ab_discriminant(2.into(), One::one(), discriminant) + } + + /// Replaces `*self` with its inverse. + fn inverse(&mut self); + + /// Squares `self` repeatedly in-place. + /// + /// Implementors of this trait are encouraged to override this + /// with a more efficient implementation, if one exists. + fn repeated_square(&mut self, iterations: u64) { + for _ in 0..iterations { + self.square() + } + } + + /// Exponentiation + fn pow(&mut self, exponent: Self::BigNum); + + /// Deserialization + fn deserialize(buf: &[u8], discriminant: Self::BigNum) -> Self; +} + +#[cfg(test)] +mod test { + + use std::{ + fs::File, + io::{BufRead, BufReader}, + path::PathBuf, + }; + + use super::{gmp_classgroup::GmpClassGroup, ClassGroup}; + use super::gmp::mpz::Mpz; + + fn split_into_three_pieces(line: &str, c: char) -> [&str; 3] { + let mut iter = line.split(c); + let fst = iter.next().expect("bad test file"); + let snd = iter.next().expect("bad test file"); + let thd = iter.next().expect("bad test file"); + assert!(iter.next().is_none(), "bad test file"); + [fst, snd, thd] + } + + #[test] + fn multiplication_is_correct() { + let manifest_path = + std::env::var("CARGO_MANIFEST_DIR").expect("cargo should have set this"); + let mut path = PathBuf::from(&manifest_path); + path.push("tests/multiply.txt"); + let mut f = BufReader::new(File::open(path).expect("test file missing or unreadable")); + let mut buffer = String::new(); + loop { + let bytes_read = f + .read_line(&mut buffer) + .expect("could not read from test file"); + assert!(bytes_read == buffer.len()); + if bytes_read == 0 { + break; + } + if buffer.ends_with('\n') { + buffer.pop(); + } + if buffer.ends_with('\r') { + buffer.pop(); + } + let mut current_discriminant: Option = None; + let q: Vec<_> = split_into_three_pieces(&buffer, '|') + .iter() + .map(|i| { + let k = split_into_three_pieces(i, ','); + + let a = Mpz::from_str_radix(k[0], 10).expect("bad test file"); + let b = Mpz::from_str_radix(k[1], 10).expect("bad test file"); + let c = Mpz::from_str_radix(k[2], 10).expect("bad test file"); + let mut discriminant: Mpz = &b * &b; + let mut minuand: Mpz = (4u64).into(); + minuand *= &a * &c; + discriminant -= &minuand; + assert!(discriminant < Mpz::zero()); + // takes waaaay too long + // assert!(discriminant.probab_prime(20) != + // gmp::mpz::ProbabPrimeResult::NotPrime); + if let Some(ref q) = current_discriminant { + assert_eq!(q, &discriminant, "mismatching discriminant in test files"); + } else { + current_discriminant = Some(discriminant.clone()); + } + GmpClassGroup::from_ab_discriminant(a, b, discriminant) + }) + .collect(); + assert_eq!(q.len(), 3); + if q[0] == q[1] { + let mut i = q[0].clone(); + i.square(); + assert_eq!(i, q[2]); + } + assert_eq!(&q[1] * &q[0], q[2], "multiplication not valid"); + assert_eq!(&q[0] * &q[1], q[2], "multiplication not valid"); + buffer.clear(); + } + } + +} diff --git a/crates/classgroup/tests/multiply.txt b/crates/classgroup/tests/multiply.txt new file mode 100644 index 0000000..6249c9a --- /dev/null +++ b/crates/classgroup/tests/multiply.txt @@ -0,0 +1,100 @@ +10000018491751458060893889018190756675058808109876974330719629294415871248770716417843542202672894233523533522085426391611508488462673577289978500560291881560964103822003262872704649110111368415677918460552197008588860300461769848797788221536509692873112178498610293735717449110462487732034905273446995235572,6192881975696225786035966982664995064937044822044587534644251299449043731778362309709151420033302511678628887337754750911692576543520793791684926797453257880919340267222510512181015985728296989735175472866965866872698457694161211487470544291337368825900113948256559852781942460432108372735686602775132351861,447562623961213317971342646547297454284223350038133828902656285846421695114449573517005802064814603287280139301229441755696758326577197667784458131993559071961595818908854193681416803619972011522725445624820104005456169532111411278882533391024720916070194718519556110684723979632586634811370262763099820931946|10000018491751458060893889018190756675058808109876974330719629294415871248770716417843542202672894233523533522085426391611508488462673577289978500560291881560964103822003262872704649110111368415677918460552197008588860300461769848797788221536509692873112178498610293735717449110462487732034905273446995235572,6192881975696225786035966982664995064937044822044587534644251299449043731778362309709151420033302511678628887337754750911692576543520793791684926797453257880919340267222510512181015985728296989735175472866965866872698457694161211487470544291337368825900113948256559852781942460432108372735686602775132351861,447562623961213317971342646547297454284223350038133828902656285846421695114449573517005802064814603287280139301229441755696758326577197667784458131993559071961595818908854193681416803619972011522725445624820104005456169532111411278882533391024720916070194718519556110684723979632586634811370262763099820931946|19255554116382770161579383715714909264782708765539029964624834623077914838241374452996111823462588737699221151887520236764901217774034554643488538519529924118839366411749516259835028878669578401436677730193218203890014064720579917095034628468204338354122803225577022412929359504950608508400413031048217497926,15092837287167018117143864462870004173493326087323162483214185994683512256473920528820058682931229518373567536566141901399624393736734616696317492646832399845295961581562413238135817545423153806714585874605091134049460217739322207059368564835209958877374166810803213938557201936549078491894191793263450700347,234893006768044042788914260913118901546740453084924505628085298368208613193607118822477736613870586900826160773678687890939302953916150044522278344184471658898873737893277827322372416620559784208443693756270533224257971092005354126278524692768704444715469609790946460097751182675767317515935452615150233004184 +10000041052183522790242850644893154590720039288612095879016416132777489378534703527529316376767361213758229530778215090392226004364711343494340009516684351602465954563523094253968698993441741189497557646486818525059302740665570749018871945434231968929038967533223013692831944903924891259290137962329173675618,1902993169831098968408340994163042640289698812843652994188396853325597449053613940738900681358483309978075948057374939279288006967407927201371876070720282077185512088102089011109098339510946105167168603912904329219763993441428070797711607939058596983469167495985136256807429373538982995591135613664471290691,648679116947253221704188706776650677211463611636395838310356904951972039958552218839434071543988637793619482253205477878855250277635662749169650536657554110192985236141029049474956216985923614316507072329807839408341849104680142145376380471455107520480114830913820742685234228885993868983705228973767491332409|10000041052183522790242850644893154590720039288612095879016416132777489378534703527529316376767361213758229530778215090392226004364711343494340009516684351602465954563523094253968698993441741189497557646486818525059302740665570749018871945434231968929038967533223013692831944903924891259290137962329173675618,1902993169831098968408340994163042640289698812843652994188396853325597449053613940738900681358483309978075948057374939279288006967407927201371876070720282077185512088102089011109098339510946105167168603912904329219763993441428070797711607939058596983469167495985136256807429373538982995591135613664471290691,648679116947253221704188706776650677211463611636395838310356904951972039958552218839434071543988637793619482253205477878855250277635662749169650536657554110192985236141029049474956216985923614316507072329807839408341849104680142145376380471455107520480114830913820742685234228885993868983705228973767491332409|11014730391994022921548019318564443238610906141262076480168925966763126765751815894971319798676750825680596366806816953155468468927850506963854768575341863098700465049052526243803093026353195834059474734029876952052212354875982568724849333989940233032713622829273608000126280643959163722728068472850088622786,10741667368771260991465304819723549356187315169745538829427954074292104964386739024958802023185700235860418655331632400858711212007319896932342251013222776723172845936147563193613725240374195945000924112718166206035243862199173787901602224623957181722190890413718871860292878014198837725481829866947825981913,591458717193488352905603034790202837072660316706237076413003353962226001987681937225165602501036312777007571264636495875979803481147253392478958512772229202313701414596984055959140281478236518410326724468820458881999271606689529119264353275033892327553507658401114443924515886686374958949587811834733084613494 +10000381915681932465973261183425742883776417480816046593820159088331265076946313439425523314444345253320002870252043057595684488140407211015115892705028395378796407813776706176594457902083795049968208905578343034404017956993894296039160788337679442024505335413399442760803039586109332233036553257459967307992,4817573728667361865336022581228097408185105735439009440346088109945423944514625700845976724084897576632126538284617885680024575350161902075565426943435359103696435860065323384485576321976518692508202982451179520762630115309722600967720404130152140308793673263051352095721900258702511325402177650727880246935,669873650881721761367318894015191721808238052876596531632606045247446982615721443478227885999211090819818334947786875090863090531638122013530669226521626152920347047659485744946461307259365312735407042929006458450763753134816736952808194188478460912675596404179851630644942038849386883091149385220764843706257|10000381915681932465973261183425742883776417480816046593820159088331265076946313439425523314444345253320002870252043057595684488140407211015115892705028395378796407813776706176594457902083795049968208905578343034404017956993894296039160788337679442024505335413399442760803039586109332233036553257459967307992,4817573728667361865336022581228097408185105735439009440346088109945423944514625700845976724084897576632126538284617885680024575350161902075565426943435359103696435860065323384485576321976518692508202982451179520762630115309722600967720404130152140308793673263051352095721900258702511325402177650727880246935,669873650881721761367318894015191721808238052876596531632606045247446982615721443478227885999211090819818334947786875090863090531638122013530669226521626152920347047659485744946461307259365312735407042929006458450763753134816736952808194188478460912675596404179851630644942038849386883091149385220764843706257|15406883651839353468888340788129827256524366500559993343402492794080742895081542466902089892082975781941021139173750937371748781682695257732868858255213590996446142784059996942302405311028161097993332331718537383888482114789770414489490580461393020737016788325059322912336073066124099655242000162998144490191,4360823987526422964670528620808397080272081276432190896883401768539814490180903410645821165307382339042226562722529652661460320310396511517028476587614669988004410806997734064375576646534713644939599630073534432499720811712867334091133681123961660738588960398432344316577526812821260889068523826290764750305,434737123855318232136803285518736106774596594589476825779021338309188039202684276728719741767739900154018854551253981210446831263812934806367418646532886786527458187655685060926749423401952358398253824964655841491692769761412354811289837062586506164527515355144754089246394187279961001728737349715244065290684 +10000382084844819863091735393428537123796094124029988695624509543701671917373805547793586171907452267004536696714359178508237591675470611568215269390130161491021123479579310299191808477715227540644280867131359924216029489859205866802370878621090778893635118109144685744213704279596306855259529008805569484738,-444155911792016461297666514223280647275019670279235098115904524278820479908555182212414682305357120850467322036353999623022556562078881846242421627622835673248504490647482104203937046492778180626801172318868765508903156634858880238203680354870853572676123032093150013906751911065758499256507194503286999359,567054671672969689387757610046141412714538710354002952292665369546607156429867011238555624731427279061383543924144630291236714076290759079492403352598432624404020019598559946194717566760077730429172494635087510893397235439040191683342313758118884331110227782487142203190483880485876667351431228811762752414559|10000382084844819863091735393428537123796094124029988695624509543701671917373805547793586171907452267004536696714359178508237591675470611568215269390130161491021123479579310299191808477715227540644280867131359924216029489859205866802370878621090778893635118109144685744213704279596306855259529008805569484738,-444155911792016461297666514223280647275019670279235098115904524278820479908555182212414682305357120850467322036353999623022556562078881846242421627622835673248504490647482104203937046492778180626801172318868765508903156634858880238203680354870853572676123032093150013906751911065758499256507194503286999359,567054671672969689387757610046141412714538710354002952292665369546607156429867011238555624731427279061383543924144630291236714076290759079492403352598432624404020019598559946194717566760077730429172494635087510893397235439040191683342313758118884331110227782487142203190483880485876667351431228811762752414559|25233315598122077418065976820332071042466787077699487654424387918664961172156179342884760885536120785360009215201873305025819279551843543582105904004062292352688557410351568671077765651689593128194982886401323218888273326531345494420553999096902303332712335656165115841742118280506588108873800795844703864919,-21589572107561067243363628128888045942080137348693403707950771695641329996718935854060105037586070646944119604332897696206540905887323628203932721112852139156892903280775223036949323848394414919310082155940615053363132829628799672709557839434529964085755781777411447385312731490258576057970445296620960747711,229349228584333455202515805454481561086661761655883453088894599746824713549123206719584169689814830025633382253625181015273278307916408839487283320828823538420290774632766998050162873483736921565586622385485530453983863042070274251829142359266901387980967335820672065096008596106715431022577378179753339164658 +10000535283948766913969186677763146947350893764133523013624566402396075467775122389351423347627366996308717336970472190566686266526440447170486872996146388310569838407203380788397656952824650289706008150444069157387402604479170310815759950456001810768733293842505752683896727400110806658910272623240889276302,3517715128667026666780257130236186883393464552180724243651182669587910084592324227192755249223315343739548139286489599592680626480533511441942660471947189354661549994487257423179947475122454624754426244988595239282883275819687054584105503928955994194464535141072191228405010641132986293339925974908519502951,570034118010650587062470713310391834950695503036920240298132931861980289236162947574989015145270228575455513419386383991154247888350856213235253786311087987346865298158646949041224197372582390632868027286119802250763817862749191433673344918830453654023465432067298969962772419746088402608223812814936545467246|10000535283948766913969186677763146947350893764133523013624566402396075467775122389351423347627366996308717336970472190566686266526440447170486872996146388310569838407203380788397656952824650289706008150444069157387402604479170310815759950456001810768733293842505752683896727400110806658910272623240889276302,3517715128667026666780257130236186883393464552180724243651182669587910084592324227192755249223315343739548139286489599592680626480533511441942660471947189354661549994487257423179947475122454624754426244988595239282883275819687054584105503928955994194464535141072191228405010641132986293339925974908519502951,570034118010650587062470713310391834950695503036920240298132931861980289236162947574989015145270228575455513419386383991154247888350856213235253786311087987346865298158646949041224197372582390632868027286119802250763817862749191433673344918830453654023465432067298969962772419746088402608223812814936545467246|59075354970692991755903146214605554332637224507205941847466515241658938543685224447213353186403252887052183944064961699964728259961938411627544944845776708313892390437907961447141588832103578886894741951168483053303302416173045780507296127716028825436246283574600092245162214148065236680479535423660537547914,6142586061770095737227904853540455719428485301510321654081360726874454746843797212863006221294314976215484969948774214251692404250673117267549442037815482195083213974160653516820675375995512277154295678704255795063545010227709473438581077714090470093020228882800682332012139884210689872621538573295925265993,96605184581646361029373732724432135349175091555904351927012123488431445097722589746711095342410196584277564279992867684018993498546178659279293376777551513451631505380655431533215245951077120355215801949799249196142928522335615942042353764886891560316955633828555662725473411497902686741832487630568702990486 +10000992092359348487480681816729833858083850458212481718635084324812805161168823645716695515173763020806162121153711923870750015861003941980870964102569907660333270160386745314618020099129085566179786211585530303068327607946822258160299176181360948584855686949828385515610423848592364973361809055890165682387,1387707194943048769069000645578034755727575677682880147095892736572338185330919801102067876481652092034533316677281336622039276010947331496276488954193596489132454018768653574924396409513550904384989555254933742194365096022768325215822785577085941233088045260998209615597763890732713200353258054623633203363,717334904486111082107761816895355357018690502858423612748563938578649989943228419203563081094256539563484346776479991186971459579979441405718434993605445911043337999222596585935065011724285592737227690661183256354762587476450143021573235732571046140183664111033663616265739167081365443050278073128430130275044|10000992092359348487480681816729833858083850458212481718635084324812805161168823645716695515173763020806162121153711923870750015861003941980870964102569907660333270160386745314618020099129085566179786211585530303068327607946822258160299176181360948584855686949828385515610423848592364973361809055890165682387,1387707194943048769069000645578034755727575677682880147095892736572338185330919801102067876481652092034533316677281336622039276010947331496276488954193596489132454018768653574924396409513550904384989555254933742194365096022768325215822785577085941233088045260998209615597763890732713200353258054623633203363,717334904486111082107761816895355357018690502858423612748563938578649989943228419203563081094256539563484346776479991186971459579979441405718434993605445911043337999222596585935065011724285592737227690661183256354762587476450143021573235732571046140183664111033663616265739167081365443050278073128430130275044|46482666589787057164981427600152979028584675170625944424946407599960201881805307116957471661211638766618134840736062752900079748534826618093953946800313092285412874757225443617416186449293441503680335786478712016820930243711850679772176006938838607901709770799483635364697553013258865109416434882051210741449,3101717798468321538599785648396208464189816894621339325506629294456148802654755640066207376362353269286149982363784579708988481769754035006891067923386713257060529140906313751403507998251605485836475302614223762235407657418301209467207199741940328204824018102771458491705342260612142478146285653246057987987,154379792819937466421655387360779358004857339117994029103954006768201464432625988196022580370956875717212647779858597489967018623693936133011607398083022906238217469025231498041115162395196295497816525433748189786409656276394144968660209259259055129261299657708619246489632848864169630941858852164482792598772 +100016993550415829135262361263254459069906572411523652885898601946150332160005753209165983241360621518247046578246408973951913750019427396230791395391900464740479884371689964652672891087059763533492805056734857093926525888370387953270730195624561287530833550654825448807998575583518751690880145682614320134626,97867808093652711513661030354940855898834960524171083907471520733521588237588575528935854367900557849089129501606401645574828485643984844895342166280487749477320616345326562522776423978127616648618120061233592736634312164206210712776242358394865817287600812334839844119000151584498625451416447766525556737091,101546865178620340984298080630771114165409461904937118589108835750643335026750315119287055941177105859697880165662377691746530085636458948369814197349790717060438350144172923110723731589639766266300381349821152919234474715235659078426677984814293485454727036020005038295982154861599467045526190910921111647828|100016993550415829135262361263254459069906572411523652885898601946150332160005753209165983241360621518247046578246408973951913750019427396230791395391900464740479884371689964652672891087059763533492805056734857093926525888370387953270730195624561287530833550654825448807998575583518751690880145682614320134626,97867808093652711513661030354940855898834960524171083907471520733521588237588575528935854367900557849089129501606401645574828485643984844895342166280487749477320616345326562522776423978127616648618120061233592736634312164206210712776242358394865817287600812334839844119000151584498625451416447766525556737091,101546865178620340984298080630771114165409461904937118589108835750643335026750315119287055941177105859697880165662377691746530085636458948369814197349790717060438350144172923110723731589639766266300381349821152919234474715235659078426677984814293485454727036020005038295982154861599467045526190910921111647828|38112895924354771000755967523257705692975308805226188158888846989042277994318034233632572801944291367363544635160689172507870767350780603573652174702847837195353422410303076999489362677424810242035375507542324255582549804459073498689456734177829753341266635299826832746075600445484602669454902196797110414268,29514825972671498452469428270002667581396743351651746797469797047436108385118786112979101930068512381300796319538713657519350359618509818562580593402643136639943548729030802553674984090829042397520519175389582956780710082733565916489480248905811215441925467758974481931055406921284703112579763389522667256173,209369197456369085510398489829077224010383063845121124974155708663637684112727148688124840116395472316273115362880530986565561714461662746456509765896943657967931982155109566457128704664240543108345283001161566864139257311910823070822151712032036583892036613154176268529246135956533435036580269691993608092680 +10001857278272414635783742468687626112156223003835485801536389954295572560863634462501676022563000509436968020300398791815574826898175032553202096799719821296404518525211113962533485614199031043964942385615363652892938675160040173449995570062547675787656647030050979129677693759900885701969029983016110814344,4689276451232458601825639665209988136946233783317430787463374655024892705415877731372938558103104801918261384975590626995047805878141047994265820723310810966786623993284261416684874325742989563037963206467146622805115830511715873009621433988190289268680824928937364349844265466118648518849937971040073290847,417151168234058306514924962236880342366392470330250088900617117412557071558608977094869379187282436222898630224671275148160961737937513168266914431807498623302460140528881877180166348694674662748849360025138764269398178107070427436885941278328572218964052739099341639294288244256170434477924203033934350673327|10001857278272414635783742468687626112156223003835485801536389954295572560863634462501676022563000509436968020300398791815574826898175032553202096799719821296404518525211113962533485614199031043964942385615363652892938675160040173449995570062547675787656647030050979129677693759900885701969029983016110814344,4689276451232458601825639665209988136946233783317430787463374655024892705415877731372938558103104801918261384975590626995047805878141047994265820723310810966786623993284261416684874325742989563037963206467146622805115830511715873009621433988190289268680824928937364349844265466118648518849937971040073290847,417151168234058306514924962236880342366392470330250088900617117412557071558608977094869379187282436222898630224671275148160961737937513168266914431807498623302460140528881877180166348694674662748849360025138764269398178107070427436885941278328572218964052739099341639294288244256170434477924203033934350673327|39512406098482423779120312488933213318036506673065796538336022993655638182250527755522829589375917826833348984821059004871245970343092490834408525776732580142621174939994986501353324355190007207510458548320626445520306240377159533568686613898702507848891809938754441261902406274233712558160571614302439957131,33458680315871522230740954658476053975126560151398110919331173177225767029941330426356821906446363070251030468052516656211641983986229753635879608148342626307073260672093693099423083101538134818421873088154104042575469404107414196063491342206675483762419581621360672445423968155195195983917204254937268665705,112538323552595379512976869360963431325956968605739748467981199043411580278581204995308070112281536994589175551282469490999392089726267157369534414758432876571069898487221813246689682731800084089695271351717243345819033451481449481940560204129785884663224360555776373560572513249146398346919605386672664225732 +10001885848475688153826124264809818246080666151576830718882253306412201821167674972767046901596625026072385280166547579462646990262300818624039744400633121727773879619930855094164710044647150456604915949836019563376717637829785627004484641494826695600821088683607312916171680087163211415876920408834836303184,-6401849646396930994521658626667447090190354097997530993450466589091600058118189817231880440719330366452128426380645424906405833189843064340607355709362044588398581812540592198712107929843518387144633043143678667045861106413931254718474764939962100744640406024944116893338624373426827575556627557030324975185,729010733894420808263762284440227341447693348621882426869722779163540379242011358298248405166128119693780872987746515732812024832371695093716504877119416045933332381529307504733200317114594647306152268108402837078447121693601055930678151182644443827620435481034522157377127949376404692708089215142290715182147|10001885848475688153826124264809818246080666151576830718882253306412201821167674972767046901596625026072385280166547579462646990262300818624039744400633121727773879619930855094164710044647150456604915949836019563376717637829785627004484641494826695600821088683607312916171680087163211415876920408834836303184,-6401849646396930994521658626667447090190354097997530993450466589091600058118189817231880440719330366452128426380645424906405833189843064340607355709362044588398581812540592198712107929843518387144633043143678667045861106413931254718474764939962100744640406024944116893338624373426827575556627557030324975185,729010733894420808263762284440227341447693348621882426869722779163540379242011358298248405166128119693780872987746515732812024832371695093716504877119416045933332381529307504733200317114594647306152268108402837078447121693601055930678151182644443827620435481034522157377127949376404692708089215142290715182147|29744618895999892950369062264736486891947372089326189805787662049365991492371249728993520356943689392647109012744687302300685788536119433016012855224253957313263294648625309856809103016565484862180956099939466843259337398301571034092060768935310042949815131108676382925915723778520018870120465703148469427226,-10209285996871914054868241646783255177966316197845761911887894869148957597460422378515655227929008210712234487944652632986850515682880041083632277387837772452379138668071836676947710588769042538916436601704393264463866941375385749221300434945563044575029802713999893603873804815268692854499670177122342861333,245667750146427110150677187685482906099978771660913415239953145936955067540313763536644215438217145059701666728130321490946010447912027178133916738527033418368981585094936292739042791746985193177096407440545894318127458296684680664341938696795502212145624334822453802110708189609055956050992529688916696742439 +10002016107047298540914373810554280751018084476212026169532336244000095667290766720576480147453702781819098831501724861337484902920323127318735651635800283580581543246660775103367813382337363027395892342097619966629022106712471908155888170784651450900253429516651100879214540932985016853993115133868182018064,3932953570343042122021312972484149360925874859667466184891542534824273073163448674737029662190753442883970728845641115381889397609743429783435425637213409939798177187589001177019943245975437142488968879145205618985792078085357316999616817143927979980310665100836939307474346180730761675171280731347158671449,501820428787763072597412186811130523406055528535842317937667844140331895435375780110188856271616785538949009425271158566975765518229735762290911833082144356638560737127790858277137050097833066958564259261818227652665496782587799644931796940046040067871968056722480981736692953918030967693251282638067356406145|10002016107047298540914373810554280751018084476212026169532336244000095667290766720576480147453702781819098831501724861337484902920323127318735651635800283580581543246660775103367813382337363027395892342097619966629022106712471908155888170784651450900253429516651100879214540932985016853993115133868182018064,3932953570343042122021312972484149360925874859667466184891542534824273073163448674737029662190753442883970728845641115381889397609743429783435425637213409939798177187589001177019943245975437142488968879145205618985792078085357316999616817143927979980310665100836939307474346180730761675171280731347158671449,501820428787763072597412186811130523406055528535842317937667844140331895435375780110188856271616785538949009425271158566975765518229735762290911833082144356638560737127790858277137050097833066958564259261818227652665496782587799644931796940046040067871968056722480981736692953918030967693251282638067356406145|64735528603519488065780804878324224417188886620278284672701068126880574848630151784368770212266476848015707656767389613750457721321054695685260658278678665196373574627583845291930832489025699028328049591231345912341357077706665618380075933900907723135182099099317242925058024706513979297237254597076227095551,4676767511975502628189775967741301363073348373643615464321451471292999156583060169457486234222367809825517380380305131875518326506653500784620820595247817795436795668446618561421217197076229074005115884048096800861583629462266306937502121558685767398985500271610752282597009278306418521631471902811873963535,77558909729073708624985274700160896365175589183029958928607160881016530406365743721430360419631842295388705380922110512036514218268293799548453381932743351256518434510701744265175175287358735767897041689462764452869200380851139430193325516047764774954110200096814808839955087651569998366318539183831351467636 +10002034549022819403076408239222347017099550415714472028923655065363879242538082883332046406086443448767298655226522786685511031384602322251464988942315474592768020948704552969250388174426697733005815698500285576084348657180234667772665672224649309035191988841439951539719672753703757656633080728573515972292,2010796810968504378931299158317582090146742925585241000850486049458701149088072887117382202081460750175074877155829037914121263394655667323321997117300425990805089503958548860857023509792455388955490579562907955528791083522774450681564161379845706643578690350999966442870934289738064461129972772676090524913,558321669961648887847428632824052548431625768519625138834794746205714201508858412984925892097351057558062620149468106508584560558388430324467000609767675063271492932614039773497135546738436362846803805003389182782828963768739992366197919348230812882254139576244708687275965273358081737826555824405654768290694|6826578859626734597480939133878569229694460186644971629457853526114421649076835335603573751879988329839397104649987465835398566386002039755592773568446984903389961798459390528478761929712163120494037385730792909171532085167309911050308445263496353865937264941597436020907055251736048076644006844409202248304,5916703632910582851125880793132408903816292476260991242513549737921610794279828040608017189829216974970365350284663821730060215581487763067707193344265376739551991053238254698337087591646614840450823227220261123886424801128338724411047128491092060105475853943890821103779036774500319107460531685286202841441,819164879939066316247739921674596158995075399415076526828586576697986820808489862654252316603348700696267835592140978359698748448462852314742485570195189002909951418034161212683212111469166114805395316595157859568773382000204444562394625047968122644730117571140576687713835978983039148632840884180063353321919|24525593055568742416097249604269483346856874441455178370798633512644823613408551383898889724136436641596007886888916843304556505396562460452498580122367837296026711996552032327466172455184570034171840642876125912558571322892683749487069829210684821264854566376842632617791479252532263566234814371052354893484,-1533308789349159850456496166928278185899248924637820082743446320631452265558278807739507468009525157831824183682096795742851767532204899527778707496003773066153051313109361171305769881696175185189326727846932831915940721252274125841396183853650527186995865126146441484052102425089961043364891055445991541807,227677657081722376213157149142023336288707753333770972277638057778548802624067098792373455123375286502620159760351354502534495438446400227420867854824820469572948638801811562066346273782346907474917163347261714943740349452378338981756888788776146521650040273657711500699241321825395413707817445618060462480902 +10002074125017355975599743151046242846511112798798396053226619327592735057422378177948114365284430939135093491265336806767482478919758311098907293451660632908142687429542305038471993566061112091142254674235636984969318093242303552823770654042157452160266396125764144057012639465935378258561790879307671193782,-2677875592705731980082114894429792995071386706298929334230749772186164127600272370546755010431170895608048375369668020170159823760294147973474095537503850192302837032131733237064875342982073993793395058782971441692000690573793255526540716486233592692407763281116363187020386252791667246848349317822548915689,648635985571325401692595356147567233561468612108663071405974903212101924183730392746938934107001054497457734923399698902258386855829500228588241165821030031659482670628135844118612829510920403042586089191580683729603024542404607259365592152472123612035976391470864076397175842526847201114587386293478162448846|10002074125017355975599743151046242846511112798798396053226619327592735057422378177948114365284430939135093491265336806767482478919758311098907293451660632908142687429542305038471993566061112091142254674235636984969318093242303552823770654042157452160266396125764144057012639465935378258561790879307671193782,-2677875592705731980082114894429792995071386706298929334230749772186164127600272370546755010431170895608048375369668020170159823760294147973474095537503850192302837032131733237064875342982073993793395058782971441692000690573793255526540716486233592692407763281116363187020386252791667246848349317822548915689,648635985571325401692595356147567233561468612108663071405974903212101924183730392746938934107001054497457734923399698902258386855829500228588241165821030031659482670628135844118612829510920403042586089191580683729603024542404607259365592152472123612035976391470864076397175842526847201114587386293478162448846|67949938415113064293161178659030590691132496955041316494045733862875749417850747302562113500007310852668303846586641135508462313201852828769777121178050596003427926460422904475476244906898063142012649435038037100034350908875980928269206397866321214852019966694130786407505714074230941338096203488261864055662,53288668959102688425004591339691466327049075866255869214424335604117440952293373897678874847548640712084573721941183729796456325294146528429835461394439973255133211226526484818899123041166158632993340470979352834271983572524972059884357370847142645448863117621210245351327485761671145696210503054900410821273,105899036571802576293359771771735244647493044658191270723159384029727618422730315689072753328136534522456073200532359330590111785906447289835484981246848193838501538977975954024004079425925298710095769756420575788761877694146481988831153103750420171232975154220500803062063592047512891980560706613446433318602 +1000253663479701075381410901780503799818388911512704954335021374915858764824090995263167708417293347017273433263645587016366542848367626143993424043714190337762737334693150155289579305664876408056173092807453213218218789600598025704962632695206955492435575043105375877466941810990278101450609180156411393563,66294252873466406327783927757894402143872047742685585398248434686370376436933447604037129338463580005900665059990247763362159976852149607009612276330769317942643706356713296053874697713940805071384498697200382739281769000631492714220560824564622672983217861541737814215572898066821664279189734871952442485,7449081821920052343907585734636804107890073716887030220252146886374375473495388497829441955869708386804952455148603275078999958645575875758803250484635047415319443379977946970239132988474813562402674036138638943113227930164450433318295035974410121827732702738775533740738542926454278142700154894632584181276846|1000253663479701075381410901780503799818388911512704954335021374915858764824090995263167708417293347017273433263645587016366542848367626143993424043714190337762737334693150155289579305664876408056173092807453213218218789600598025704962632695206955492435575043105375877466941810990278101450609180156411393563,66294252873466406327783927757894402143872047742685585398248434686370376436933447604037129338463580005900665059990247763362159976852149607009612276330769317942643706356713296053874697713940805071384498697200382739281769000631492714220560824564622672983217861541737814215572898066821664279189734871952442485,7449081821920052343907585734636804107890073716887030220252146886374375473495388497829441955869708386804952455148603275078999958645575875758803250484635047415319443379977946970239132988474813562402674036138638943113227930164450433318295035974410121827732702738775533740738542926454278142700154894632584181276846|24568037830590216352984530012697330969024585773239190902318728852976076281369516446912320948078334220155283803919583544158932277992855289960471883436534381687899324079630011764816867889328310023423094633012275199876596315083044545869380586009580913007036860399795245680314963399389559624688311082823805090231,5319068676363461453927187061672827259672166236556729558696928212559807675749791870496620364221934584448485936117599756917409724038460841591469075162277678937851596763739958878425260723977292640004766308405052660448827954872311329092739598965306131405515429262746842239243566030717413542127898656259746125971,303566913138393892567904204367686915490068122814370585780506941778399006742359108535463859108136357801343091343038391472615790503246239776473238906631454625779972045236751565874336398670607783613554147722203607531035833062634596664836955674449545888313212125443460195013735390947268982347767364377764736422042 +10002641226772515081987795211537787929272477458505554463354638964352971364408874452069546961937801811210947177338408164991078687591091465516969203874900752888301636133298179753283838003443413422949614854305289101035884523695670918489325845677592608946818353360132477183288514801318828834214935649039394032252,-8793160452550363276528664072517898739234784407606709040941098303790678596260001324417462973553168029853952326856848991111004093395583096302100461452777142804629182141499607986715453131122448708636069213611853518781262192482364818383993101471525466753092118188242931192181704912063647353300605222746836800483,492078265126922274690434467399394077805701275647322071646319840779745006934618899651871133218190471317339124114044099413606811819906582945782428482112475530640807894231223382852644187084233002016394775416098135698147532762509163053201184493973160623592655199338520312133914851239167130412730662124292772722504|10002641226772515081987795211537787929272477458505554463354638964352971364408874452069546961937801811210947177338408164991078687591091465516969203874900752888301636133298179753283838003443413422949614854305289101035884523695670918489325845677592608946818353360132477183288514801318828834214935649039394032252,-8793160452550363276528664072517898739234784407606709040941098303790678596260001324417462973553168029853952326856848991111004093395583096302100461452777142804629182141499607986715453131122448708636069213611853518781262192482364818383993101471525466753092118188242931192181704912063647353300605222746836800483,492078265126922274690434467399394077805701275647322071646319840779745006934618899651871133218190471317339124114044099413606811819906582945782428482112475530640807894231223382852644187084233002016394775416098135698147532762509163053201184493973160623592655199338520312133914851239167130412730662124292772722504|33269093498653459355911056721677057317009942094586213583836482429509057025072754420372439736248690513834971332175814464148672813487558426999636798377556094849446738441259743858358991688742216573871382813744898911570710319471125784318155373816902285919608190930249032332855663246217414413642466621378338134637,-10949330241414165733888189262458140426986707558351886540903470879800574033213186052244846799127577601176842705714647638204280400911455131674484085082600626371557414203990940725212684526037217982855212341310843343357217588085473017983047320842712153347738590477893040712557903922232099275263522420010197087053,148267471797952946823163847078479485183284021963476657656706944246030488584019895488346778002211592139277760491813666056346782934726026456786554441575227882221237740554377749215785707126496176370984922985820419829339644729974154901755996939823200818910973576565060260711661905159023290114040762532541467088824 +100032603932113584190385248548088424648269645571686859576017823592423034520849963520508387815309023735382902503732005885189155388332561494704539042592634007656219743816845911733895132144423102052942452746877943975353248517709377531317937542644854604549820822373960740354167669496547979026679046866602436687763,-99537978095529356699713913260068351078290498972088228356731296595606062051578098868796341286417844471545193824704430742131836251590438154579238324251435089098889846479244366361006756968943661462663756515208457066560709300104052348033879750430334191090716067038009316021882909761152311655341491437691827562957,100461141672958569681488420113742834080404730978030677210672600173957843011309217083950874294428866093615815291020711039763544235459696431813304652678133959812856917140520431023445877504376180839416510225066460002908711498876105285713692498849763216560421523587971326926569083287005470828615251682690932454480|100032603932113584190385248548088424648269645571686859576017823592423034520849963520508387815309023735382902503732005885189155388332561494704539042592634007656219743816845911733895132144423102052942452746877943975353248517709377531317937542644854604549820822373960740354167669496547979026679046866602436687763,-99537978095529356699713913260068351078290498972088228356731296595606062051578098868796341286417844471545193824704430742131836251590438154579238324251435089098889846479244366361006756968943661462663756515208457066560709300104052348033879750430334191090716067038009316021882909761152311655341491437691827562957,100461141672958569681488420113742834080404730978030677210672600173957843011309217083950874294428866093615815291020711039763544235459696431813304652678133959812856917140520431023445877504376180839416510225066460002908711498876105285713692498849763216560421523587971326926569083287005470828615251682690932454480|83415806280351408759589239958761219329310176984650613508633653230456890652830525586600995644504636518476026029385588047137454270096528621205370620292951275504650266248010650846690600983384462303830915876850693795019055500604246841544238285169828416374845816289496545562107780789460316448092131365832361151375,-74625562140946530658296843057459607794092129677035083950600450768713067569753818651802415894941493999582236546770594323673470134033058099517659971836561944651594028658674853294680303580112276880640835753725828631472628486095723473976221487197988748307970291488083264976555432132424815586850501052682570560083,107469811246399151523671670639445335406080264077456915839785825558020206498489889359444002816596192076606675057819088885526103113392920720840544571898931473254561406865074149733521627542981016723238264871496686055481103379945620155327472162297506458535202575738651893005921523712726080367985636694514383291872 +10003476324006195750203056589672528920142608070881173628253070002202847822896965018507956629750620754180015153597378490052619698657641883238019501085375230761464051022240631149609917748136390010621917552270797301343624990317089853119601059038653584566960989367701622621948512038032835888249299441269693147481,8948477894687501835769347042476812359286265266925800130378128090450514350343716170849427570408163707014128103924229513747579348337292452228930399170228437675863524232253003114523522760158376999688617602181401251377230973508602086745348949552684443228687100653278976227886870750067529496753791759215379958009,452977737155070764205462061852384767406000511527628419268926246340664360293838298755195741559726771936393803381121945775594031166662560564547853061983512305458290529662211961236299108870033900884457317683226459798783650763565076645131166564022405125204306354508519035128680777341173496414054336245228904798396|10003476324006195750203056589672528920142608070881173628253070002202847822896965018507956629750620754180015153597378490052619698657641883238019501085375230761464051022240631149609917748136390010621917552270797301343624990317089853119601059038653584566960989367701622621948512038032835888249299441269693147481,8948477894687501835769347042476812359286265266925800130378128090450514350343716170849427570408163707014128103924229513747579348337292452228930399170228437675863524232253003114523522760158376999688617602181401251377230973508602086745348949552684443228687100653278976227886870750067529496753791759215379958009,452977737155070764205462061852384767406000511527628419268926246340664360293838298755195741559726771936393803381121945775594031166662560564547853061983512305458290529662211961236299108870033900884457317683226459798783650763565076645131166564022405125204306354508519035128680777341173496414054336245228904798396|5651402082864001341383043857276519034370923662130513841623791595519661596270558403629904832806805434101124739144545597592273345291679321664787896528184481483087832442891723960004144034071036416654549567647433046035924426144596821847342448417665300158067728473706875334422169591609969538712389716925515442159,1090636869023214934530000512317584955330428598448445756182897777909589608376391586933678383330159027516570062459675025398064909568706408769200853022274439337235651672149891920445243421589467522791785184925567074521782213195039081340473683210796200673383772228925769534634646704414996683315287011695982045215,798320586788500330131894474104550120349737015590338005277237799938184156294041064946603812109197024144698401875127120433554460509300984485272200798966972702950997831115495437993447800151856526214460125938349981191215783025651707239371732305323555609927700663473758594406982664526774948117622844814657936546368 +10003857993456427654260743531593175331844381828365670865226962439897092670436459982112189381696267158765639464830025128699564487196364496581401927783840749033897594251479939418637644343310965529659395490594160241233118920895398385679767173659034336248678548857485551806702464695049628038493630764757131936433,499412956562517742917849279756715433309262335746117865845799881793024584024558389384536935608560698495018673505480555335883339312289660314988198774876439555916228389426783735627572745304130362478355104078356335948823975431983850031098878540627311553089477219658101715631431867688289331308014437329410794367,428065574132217643458625663050023831718642242887566540643235772550790937328471994487142052675941441071975523602876098842203000859003355118835451924426231099194913042875268766884651796522017073832982218720474562973379560560341143898312656272368395693435837758889298389279644428917154166725285871991579086938078|10003857993456427654260743531593175331844381828365670865226962439897092670436459982112189381696267158765639464830025128699564487196364496581401927783840749033897594251479939418637644343310965529659395490594160241233118920895398385679767173659034336248678548857485551806702464695049628038493630764757131936433,499412956562517742917849279756715433309262335746117865845799881793024584024558389384536935608560698495018673505480555335883339312289660314988198774876439555916228389426783735627572745304130362478355104078356335948823975431983850031098878540627311553089477219658101715631431867688289331308014437329410794367,428065574132217643458625663050023831718642242887566540643235772550790937328471994487142052675941441071975523602876098842203000859003355118835451924426231099194913042875268766884651796522017073832982218720474562973379560560341143898312656272368395693435837758889298389279644428917154166725285871991579086938078|5985067419244985135241171028798929574240680468883302468191968098879216438700233164875805694297003438862738484975665356224507623680806342430269752869889205306990703427045634087633153837909332034829737848013329051690528535659192743560129505700514703339932109459152656849997168043791609090148125676966411164474,-3013789663785982033470828503772197819235935022596925513202295899674251698616743229507943605240952571134961898221616756365279257136756498538053825862952363683344784599061589171181375336294364884944425024815089748650913141333142482818080242503626668488451409454453378105252995530177887117956522924628476106577,715867557387629444794828253143137494171652360384349041477991757900406478237922421388389881678979412011018924778952400351577186261046593876844081918575484239857072969176632122684840733871691016063878843026835488228409619596420110671483199617250854032506474798364927317129700200264636864303167131823097056257391 +100039629164915279615632745626755403195135344051296300065703707540722103090866387847978086519807842461360227602981314815898651188162817881999812578911179147999641525372151514639575701701027057192828570924656410854140601616073626299097374452319600612002632648030238739679305929396591878384845108611708173073473,-99956757702796747144330474031362091634322580823618978945421296776762235722820502139320048823797118970112849105309821058917042066320137328941305079762427354700730983116887319872947138001541985096571674792479594585340751798952938060950882542376800246430517653157385999869147535721348848735105635711972964679549,102428094420528235210038473992722778047449595066683562474358311327561453376741151333873834215335094090938635116665776111534217214948922896682406927145735733279560659220902423840693623822669973775960053647983979336042821226775972118591820157680473747907152458057697531888053067296726895267408102940444171410942|100039629164915279615632745626755403195135344051296300065703707540722103090866387847978086519807842461360227602981314815898651188162817881999812578911179147999641525372151514639575701701027057192828570924656410854140601616073626299097374452319600612002632648030238739679305929396591878384845108611708173073473,-99956757702796747144330474031362091634322580823618978945421296776762235722820502139320048823797118970112849105309821058917042066320137328941305079762427354700730983116887319872947138001541985096571674792479594585340751798952938060950882542376800246430517653157385999869147535721348848735105635711972964679549,102428094420528235210038473992722778047449595066683562474358311327561453376741151333873834215335094090938635116665776111534217214948922896682406927145735733279560659220902423840693623822669973775960053647983979336042821226775972118591820157680473747907152458057697531888053067296726895267408102940444171410942|59758487461561694442379025688208789272805646117766841371919206129104643340187013959248829747415979662207515324483234883850993532329266696739297473585807619628400010464577117227971680163239657561855113693233183544551556435408658445465178524557249837569329921343630595316681776567395248915519114258200940556334,-22671153376331064045596883212849524458683137875144383539728632975135493675352244172470558064096651200683764074233134897430860850593927295220691708458835598930765635309529560060316074048705829611628256591181426206810132007799209323907835404383161225433151628885627129593154801395506335278453552670824539376361,131822706075099232761447085662042248387269214384273446870979850351593187356535380305031128889463232587293325792397508871970239127171842305342534211852386333093595103295196214505820601536505750244236747510387243858827641299979267104558491688743963318805624534666949772263803599250156326714304699457238299478944 +10004832714804908103723742535198592770160203517705805986990840545592954373052531534772757807185128680232142411531940850138353354052288042367716414491900227710660117192168358032143450533265736882961031789512953512836372805323721228539257249690634554067409180163736018674169229333523619015614939108311094404955,-4106122534013672070279170985250180991164806091813516237606357362858804809149171076685686783446662860787711693312632306442369721226548746949829113367814838200945066703674460902843843266912498986340273761329459609877828321975866552396500360382623866557971900410837449507727615090091955001901337773500512564083,735528321490864741305341471765335107420487103909921951579694743548116478766357351448185791472115882125120532716552174779001460694927011404974670401193452353207309236668713919095870342289746072100419468138261516298395168201040490324057099586440436334562163475983175689744239719212727501982130267247535538654526|10004832714804908103723742535198592770160203517705805986990840545592954373052531534772757807185128680232142411531940850138353354052288042367716414491900227710660117192168358032143450533265736882961031789512953512836372805323721228539257249690634554067409180163736018674169229333523619015614939108311094404955,-4106122534013672070279170985250180991164806091813516237606357362858804809149171076685686783446662860787711693312632306442369721226548746949829113367814838200945066703674460902843843266912498986340273761329459609877828321975866552396500360382623866557971900410837449507727615090091955001901337773500512564083,735528321490864741305341471765335107420487103909921951579694743548116478766357351448185791472115882125120532716552174779001460694927011404974670401193452353207309236668713919095870342289746072100419468138261516298395168201040490324057099586440436334562163475983175689744239719212727501982130267247535538654526|49571248488801947323762143907209086317313166403240424924024453432101823875387693931106394388064932448674243115016411805337571297304108452331736192767907165219921775519019524307831072755876229558621548399009624087618962075649066655387832586784423916396427426550173498305707525522262009377144776100617511504479,-29828959784506381554151288596212589266056524896738496309595862456247322273883550277461362725785642216517361460931008602989968457887994880159243708746757201494721079152033527869271494859280160324467867179845744346034683576782637256359631403582150391967236780147449482496203963125132702633751829108018063107905,152851999786112534607728017818026345885853920855328921975341927606898018268835818661916681924713268354620755264611816045133624308753790454966902035653944158070765154497702110731650604894939030177902410742021315843443639601716505769494787447868225921446367758854610060178076102048397807948745556177069401434816 +10005026798525081885012940723882427584501711356233986451433820326862561577003483273848888665415005023331324845917111198606297565890343057122006058437816088078150993643095110440273546307247953190370321453395387856022986496964659738868016549698302294761145902566546443562453064814285197415999088360521895892448,-2012773415393071452341702894100369945009950648974284842979647951404344133571843387257391629610481617222572984474542523680934261770552452770758419481294248980432288030428538457156536090278813518012614750771478130023297469887908317305397718948039728500945544029263259198696111632370324283021118376979818613221,535224191733498084376882360698126323023228440191548650672747703583096856785431353632400792141685069598130344590929419053715450660967162173014581599286976146407034427713180051638727241035734570695485508350936098840329272631647750135734419630658939038108543820389342159392044477918576834926838103968922627914592|10005026798525081885012940723882427584501711356233986451433820326862561577003483273848888665415005023331324845917111198606297565890343057122006058437816088078150993643095110440273546307247953190370321453395387856022986496964659738868016549698302294761145902566546443562453064814285197415999088360521895892448,-2012773415393071452341702894100369945009950648974284842979647951404344133571843387257391629610481617222572984474542523680934261770552452770758419481294248980432288030428538457156536090278813518012614750771478130023297469887908317305397718948039728500945544029263259198696111632370324283021118376979818613221,535224191733498084376882360698126323023228440191548650672747703583096856785431353632400792141685069598130344590929419053715450660967162173014581599286976146407034427713180051638727241035734570695485508350936098840329272631647750135734419630658939038108543820389342159392044477918576834926838103968922627914592|22336292342012135551012779505885821083546735296581603650297115029465681138287871430168423025904988089547671399414611655350486697669350669877738276496552244732628186316333718561702084292478964766694437983324796248956801158028485684181499933232337147261336601523192790302252474972512181980447183622505293176152,-11674427075188626733931744428592651339949229796533683950532721050654863919331228509781516498261584604218739331608896593403871873856541410150113580209210756699310754431102708096662231135908839829374052715278169746619957236796967122303020947804850902024480676480363166504231340429878256710974972888619078138229,241221441172507985920847839600569201674621990755660781190984844223834501365279182693592593623964679309297220103180052193705500388401906318363940879681334805954355205327811300356578283407461158222974345862172435329520610152326479352290565487656045066487426033103805627728579179611865031310778705197856088085583 +10006672794990347502279526000879267078734551177313370372283212271611928222796898904661389050998596001740140300896360857122349676163698172929644657861948036337955651058773337605834505825285215111994884147090626904932283811767278804138486301736275150746935294318794069137540121225700303083939876242601120625682,-9838237801085818249924597009069669407425270661770560087620729925196161025957715438545136585598174869667669532449305460474170293173380362768481774634876936899174710462784386243070041206971463923591073715195084153396862556329146939171493281676244388685209328525900813769124322086835985741784348578408662428059,491155226409710325351546145673359292444301383692142579605004960553566299358747456958419756937691174297624212871558627081110141997099054271399339089662075140351079784991312987158527194379830582795343003721494456884032748354538831215203553329779263289722351779436025499608302937937453427548391343898256662436681|10006672794990347502279526000879267078734551177313370372283212271611928222796898904661389050998596001740140300896360857122349676163698172929644657861948036337955651058773337605834505825285215111994884147090626904932283811767278804138486301736275150746935294318794069137540121225700303083939876242601120625682,-9838237801085818249924597009069669407425270661770560087620729925196161025957715438545136585598174869667669532449305460474170293173380362768481774634876936899174710462784386243070041206971463923591073715195084153396862556329146939171493281676244388685209328525900813769124322086835985741784348578408662428059,491155226409710325351546145673359292444301383692142579605004960553566299358747456958419756937691174297624212871558627081110141997099054271399339089662075140351079784991312987158527194379830582795343003721494456884032748354538831215203553329779263289722351779436025499608302937937453427548391343898256662436681|31407608254280798910068647236171832681250921019767339322092058225211898617080663268645257485291372241381998253211825069099135787304279471888561584499577479790815455728926265455210044341705458408895536936732959677488304976642419035897631658694309182269500334892813396007185893728237634667266625229835842258012,-22092195466303851660176460286320107196721548719910482849923927669374860570040607441847880914766942886335893807802817619964909625774361248243281497972957437956640995020582500875700785617741050040570062784832399237969854446892064368205401494750753136317996032567462911904310221537322445611817601703460856421217,159599806073129555202146898538117276396235868652725582464386632067108341746813360586970644466851546908557689300426749066266037355857824949308514825360431584985378792225819436535456535877098069496677684472533670862820828085751117871568305588734769334428789980131666205325600082215182496839515396421731764800737 +10007655975072154117483238977535537637081635031134550457387493208328357153313126763724056490057039627482071052486779071595119245261713445964779121986765033599055846695490518512461118572219672259974233020703702627262496120864385268977830794693731299984872419878272800221037178910859958719636556859814167846842,-8361996877393239419962455468169075798408150795370677399435249551651328619535668258497248839588331109071829636371568824578953377032648893445576430394495769342785817892484051892349027624952023346102193243274713308717688268734992258026540569970994360123565176304254781068869111211172521527332383420931814632155,527575030718114283859783398581144142162250986653324445494333022369741458612967189239531512810665999743981788039851897018720856433180698951454061341786291502239652788707044944021930279936172715091766668769968367606820938741461139670556714129528610125247077397188304136573449554427712758172626387820770141650206|10007655975072154117483238977535537637081635031134550457387493208328357153313126763724056490057039627482071052486779071595119245261713445964779121986765033599055846695490518512461118572219672259974233020703702627262496120864385268977830794693731299984872419878272800221037178910859958719636556859814167846842,-8361996877393239419962455468169075798408150795370677399435249551651328619535668258497248839588331109071829636371568824578953377032648893445576430394495769342785817892484051892349027624952023346102193243274713308717688268734992258026540569970994360123565176304254781068869111211172521527332383420931814632155,527575030718114283859783398581144142162250986653324445494333022369741458612967189239531512810665999743981788039851897018720856433180698951454061341786291502239652788707044944021930279936172715091766668769968367606820938741461139670556714129528610125247077397188304136573449554427712758172626387820770141650206|34241072322144183964883259292388971270387490908021459682602920713448556112203521610314068181522265567865990070656464669642401927077378188525809052299062988871029831250362663444310773841166814396928628138166361702759595641474414467093470838454994055079747035830130336863078894622890889652436509718402679470062,1655044484629008994406707658240182084237566731635262662670986570402287449045651466425429233810999012995111207637792772902737734854633738760139439026788661518884592067665179528199667479368791803292009159500093938626059289257062277449763464663360562677734593664715953368375153510854218241931074507165471380277,153704107279914282661047729774770107006301606465000116416112632832793659221845961744254897413922500063463878032418234980336383112232225712099359203910269544199247014938285831933417628129448739918915220344920675471322163945672122675565456045357008398369947791399948189771245653263744530465795945375711800221494 +10007966435478170058236863959453072022400241955644959598691575049123018331553853255192930054734316870465371869338898000445140839711278341717767617282979890871322011741629926128943966839416929813730135095452717804664810492420201325502018871240152164282158649420833075991948508448454814819879697083763652090752,7668231477440831839423530692551370703245159224024821557501520508935072774934016430350932340192015949812739085292897564854127442271354000519287430094037838940253057942410525639491576166138997981100229304259461266977184946214511723634011266273522059488169041964372462366036564169749432744133670979109152595493,447718029574060000854039425364603339241323607028045749886344661853336043472604487444001370995744392053933719052361283419535725001600963164946166051448582948801443754508763343722896658178932382756498803522119159379373755295799841416904795415386643502857959662236798809639975132008241096398997653679085633708897|10007966435478170058236863959453072022400241955644959598691575049123018331553853255192930054734316870465371869338898000445140839711278341717767617282979890871322011741629926128943966839416929813730135095452717804664810492420201325502018871240152164282158649420833075991948508448454814819879697083763652090752,7668231477440831839423530692551370703245159224024821557501520508935072774934016430350932340192015949812739085292897564854127442271354000519287430094037838940253057942410525639491576166138997981100229304259461266977184946214511723634011266273522059488169041964372462366036564169749432744133670979109152595493,447718029574060000854039425364603339241323607028045749886344661853336043472604487444001370995744392053933719052361283419535725001600963164946166051448582948801443754508763343722896658178932382756498803522119159379373755295799841416904795415386643502857959662236798809639975132008241096398997653679085633708897|40511141969971494931196941724119791194752303140317604712667802312789797258087471388916305711860938934695113621471555129205767772174234194577636062024449049659844773057153826765602668788474097413358584157199226050803019714953337366130977602640661927789662051175267419967969752702153115129111296636218703221612,-10457935161594282983478001185436442312204066321569717319909561123122508532580035425990850447859762708795499274494409851573173766858979090795797351580839052039648316518437023326040967891533445612383815607198257699325318317220032705269084861881246335591645639989108557010113256147197407668582018981690523309277,110917353905486580092614272588489684725195855203152146381960572034045032865176004516881779898341056044802327638909692940931520745099129277448149432184154526338845672459752333598562775198340962552587031950250223610238795938815226253408453715102541267901432200534831078606195360844918970056237910632079232669397 +10008244313737062814090386880777002042274406310106728621588663972235471114422710824990333652789716385198940169070112715764189602790244309290680116655115170883594213904067142922764109544956215574952085160301875958128721493047843010586892757750339772804652221926614373576181872540979939178502806140149454950631,-2481333037464667013966629436643252131544342493286852105020088420979287811035788180793459525355154058635281869829040750298007562342275673082167816644462962921681726865943832615136603374637684966019868013077849325437190351276393203980513956812271998916894664710817164796538864396449149557648172823426916063171,517388856778664723601259064328056938198839891258102587545663260307743028813773980886782766877880248247356976487931222165792012525513693034189039784629831615801247177080220119155265743113547860287043754078724492811312457109356002302194457816150319735657096232303313256118001093875043014711306978887626524797260|10008244313737062814090386880777002042274406310106728621588663972235471114422710824990333652789716385198940169070112715764189602790244309290680116655115170883594213904067142922764109544956215574952085160301875958128721493047843010586892757750339772804652221926614373576181872540979939178502806140149454950631,-2481333037464667013966629436643252131544342493286852105020088420979287811035788180793459525355154058635281869829040750298007562342275673082167816644462962921681726865943832615136603374637684966019868013077849325437190351276393203980513956812271998916894664710817164796538864396449149557648172823426916063171,517388856778664723601259064328056938198839891258102587545663260307743028813773980886782766877880248247356976487931222165792012525513693034189039784629831615801247177080220119155265743113547860287043754078724492811312457109356002302194457816150319735657096232303313256118001093875043014711306978887626524797260|64779254867032834011440641150787867084487920384040666681242863744168381419066139445297813847374258248415619741363374551837200937516385938256833819108665346550630274436247175069020139650724403378810927075885582938267576954742862532587966930483553143703545329576408261048628895456023143683431401990598479630366,24927519754546965921961831708915463327214053646451495956699845075284971443847002280078538714647321447563383780925628397892739377674787824980025060340980938596623558107083184245064110657008379362919768477366918649506291628246060968841505524504481964062641513562929769991452205428879332678008403472520391251145,82309686205222727769575596923556209136176331852352419263671129190093456370915941776219688571948801625823542691573133895930427074460493264530457559070546811793879069016319253690636501038391024472030629593224593147217100960263693987497514077967804017050957134551364124670419141176242216681820543629095623072541 +10008352850657920583191404584913972319002983012580386292746025042416454380781500166787911252581886951373899680476686789855174455691633284341038191233672952065406558892215211615248443825941676410729187290225060888418790745853338806784833379906941049072152726050837490871126796612653775780560679723194628349029,-9709060422739575026005372809573612137660920177893029425373199378974797630708961048789082569968621509437270608151157000245230087521990222886335775421061577025607819009612244487407314145511220306148818899675596604132364981950337516654200767452148218615182517964628917157152074917236803799933149738760713914115,671115082942262350108425488433280481526339397188879799636007596624691786030758042881307602706684291172315374822828497006497958099138318651797094407888149790626224845978208367284081376364107905539290535619502916118224586762249253502377439399087435554291997555942600131361589961111751560971988821471576625969886|10008352850657920583191404584913972319002983012580386292746025042416454380781500166787911252581886951373899680476686789855174455691633284341038191233672952065406558892215211615248443825941676410729187290225060888418790745853338806784833379906941049072152726050837490871126796612653775780560679723194628349029,-9709060422739575026005372809573612137660920177893029425373199378974797630708961048789082569968621509437270608151157000245230087521990222886335775421061577025607819009612244487407314145511220306148818899675596604132364981950337516654200767452148218615182517964628917157152074917236803799933149738760713914115,671115082942262350108425488433280481526339397188879799636007596624691786030758042881307602706684291172315374822828497006497958099138318651797094407888149790626224845978208367284081376364107905539290535619502916118224586762249253502377439399087435554291997555942600131361589961111751560971988821471576625969886|16114275461489124968204609015452254643913218363912153828520620336762113684215205643094736684144935580728436126433843432822838401301502605946365466722979644980151185661620762014580187078928560591048729719792010275975517300898462040047538702188845074821092289043342754604938854931775373800424648368644203310763,13547284929895770484441101131779787363607604008853234716726800689182086390631494419380414868563006093483607315075063367989733593307441496946636597309123175793027336201138908596859844194042146843338047555922226658114601025214153360367295508810902077991437858537936819515034120605401664389985997179289268252367,418205108772032981216907044691421436420223410030163644353520139623926934302604091399665635789664245218369914570143791026851295152484545480995319870729672449287479092631425718630481935403940901614139408947960419781742920397934070995211934874602805252466775364873888815295833211854864682623780313523183909895620 +10008513012069041332156344897527216827073553214887592180214088737934259014714007486627977262733380816543933881903835772165306652083392244023687978336905351870998572186485570559256669905157006164174099943880073052263685924132434457096891529676454801384608866315724043225840413063557160938985851639441472622874,4312440429846754396035977404383353442711216523950513352151701783462030788529545110163564186199448542666033789397218053312248834710387435083551347290942668449155398673665487605130911092851155993391138549740383991056332072450757325017931588809593307558375428030693435084458386227675282989067613496797817920303,522058710434436061847099419719287842052400501259816466826452187248685474462894015989166683733824910524432920930163132078895575756633553848962708405953874665062957204347147145554667232000278570561581943016274309565656027423053224928776350261510971295444303769013653510888595366416887399411638422346190508715452|10008513012069041332156344897527216827073553214887592180214088737934259014714007486627977262733380816543933881903835772165306652083392244023687978336905351870998572186485570559256669905157006164174099943880073052263685924132434457096891529676454801384608866315724043225840413063557160938985851639441472622874,4312440429846754396035977404383353442711216523950513352151701783462030788529545110163564186199448542666033789397218053312248834710387435083551347290942668449155398673665487605130911092851155993391138549740383991056332072450757325017931588809593307558375428030693435084458386227675282989067613496797817920303,522058710434436061847099419719287842052400501259816466826452187248685474462894015989166683733824910524432920930163132078895575756633553848962708405953874665062957204347147145554667232000278570561581943016274309565656027423053224928776350261510971295444303769013653510888595366416887399411638422346190508715452|56624718412625747746001342620243125157932460809156476585686153252078788391585133765039303843105555487145302765475232301210334902069549060211140618709834572969221737838704380629832808447436726398836532031324189279819743594568958857642880728907272717965484249241620624993448126533648876371412676969976240808091,11251560979241989333315174860442827950692807971893794693178074029555222489351465658673586544289854384482236484135520000810924047294537285452423708542539424019529971512734796753346419671011832872098038047241101770150064698634673955572614027093346044433647412285209492755021945840975963737352969268461227245507,92751569706316371333649854241258112606711033359078430605766627827390581284909646252513959841970681664755979852330064323247275252913920697545008377769665486889671185641317526987823359091775252097776601502427528886408060350050959249578998479135473207338710170069765535652326679605884886200884837141964865764438 +10008863920545293758159888428446364046156260276486716019468090049016703539043486840953638396736429084536043888977532647111473229479529562166982909202873868243789742163658153824593686536088450915373691535781953841623992587097366077922476705574496276542011226471851020760887612018025249445972903686455787297913,2645740853855108763896589086717998001934973089513790734148937968197932490008236360599464772889429848037464262397763532307275971891237738829761101393275168415676294997564886931379267812086428886706751772215615432393366054082725778686112559307784475932288658665407220266586240637350907136870607040913290590611,793400754874236243676721564968016542454513488899050997526586540816446069760957715423992612546686769171106427349384375943641326144133116588670645501231299064478777846694278704641598622565613076600211712243453441442617903127555189233115008530187155578099336294750097716133611190867259168037807083105588642566246|10008863920545293758159888428446364046156260276486716019468090049016703539043486840953638396736429084536043888977532647111473229479529562166982909202873868243789742163658153824593686536088450915373691535781953841623992587097366077922476705574496276542011226471851020760887612018025249445972903686455787297913,2645740853855108763896589086717998001934973089513790734148937968197932490008236360599464772889429848037464262397763532307275971891237738829761101393275168415676294997564886931379267812086428886706751772215615432393366054082725778686112559307784475932288658665407220266586240637350907136870607040913290590611,793400754874236243676721564968016542454513488899050997526586540816446069760957715423992612546686769171106427349384375943641326144133116588670645501231299064478777846694278704641598622565613076600211712243453441442617903127555189233115008530187155578099336294750097716133611190867259168037807083105588642566246|27460683971089209913632788439277008206698726108421557048449583612748157436343375175859322164187154644764726127789104341389062435393682455959407312665088265825287372841830854948020646918675509930411197475014852013755108095396665264198600695220092526372517655520066812589582003333706156211987354238157895214440,-18754257799889030610388359385148211437538401837086321292345976113516028840634213460141894145979065231860481969629551490782467029876512509259774443102990636739699402915097564612184570929798790707857065137355337741260683852677325380877763634549633686621832440525952151518844155190936539038380094790162128388423,292316854113502420768516012912807278549304319263771926401370626456917590670162968070277533769157336622178624301667258725748409713154982300194605653065586096039574795291737865145837966259393195694514901162748686464295686525957546330665390520676177065848461958642958875916650558856747431365214941153816669348325 +10009505680139870683354483014980979080857116598143181111545123603173294088551257446784978515102956309603131729036042239470868522730508351640411841336927180142285333130556003408088825172687266397290471685595705033772539426652454509785808561354205994913107889793645231496289597484325916247643676615653797810040,-3204245228048542338423395469208468824364162898707311656951717207097770099550386735738728259011638956652924858793824233816950950613612534337274326306432643930039092581092193180132506302083387198832944317276664858711681950020725043153356848379502277900787129851654969895020729278524823784274520152043485072291,452691911613679447746063326513639174263793060004909642518772775706171480163325072807358357220816303993075973139644460675947299910587502105955195991864534504547078402941938298035649970749378328953718405749778603278187778609058449113337901162098857859007739511955733974919843773983479386171581120876366473480535|10009505680139870683354483014980979080857116598143181111545123603173294088551257446784978515102956309603131729036042239470868522730508351640411841336927180142285333130556003408088825172687266397290471685595705033772539426652454509785808561354205994913107889793645231496289597484325916247643676615653797810040,-3204245228048542338423395469208468824364162898707311656951717207097770099550386735738728259011638956652924858793824233816950950613612534337274326306432643930039092581092193180132506302083387198832944317276664858711681950020725043153356848379502277900787129851654969895020729278524823784274520152043485072291,452691911613679447746063326513639174263793060004909642518772775706171480163325072807358357220816303993075973139644460675947299910587502105955195991864534504547078402941938298035649970749378328953718405749778603278187778609058449113337901162098857859007739511955733974919843773983479386171581120876366473480535|57325550832595720002282991260198520855619892385753125887287449562869890287547556782700649421653735594090065432438621527792246214244092693717739414731384442034231735428582082971424584764012096459469280873967739009228670210741931717901688698237272251048307176343047617528247235108742851430347676100126914108357,40951175564652222245195473979961933400303424050552593889813171845223826940735103640121837889061263540857785714549429721536079825338211400035410823730435714524768011703151474601155984454456549759808694516594213778747991012336774365782807914607474811422076337673527879293888167855766653181026300408358374972063,86312387529619002943462127766854108620725875072481894074267557421849877085810739137001331161310595596779531729111999016553742317053715695938778491822422663861385491102185170957066107188324354310777066756950531425606616940837381593339739089909995724195482868610730939023987110641593221757790669575104910938446 +1000951516029909402241580153254201911805533650981363847468064026947791885513152190496939080952901855372998038682278000380636609527998130327379270561313029246942896140134101369621908911346125374976926115893278132230058065500703131104226075681633220114919188893134454475954292791954736302126634675741318978601,-932129972046203740107893826647984861393190609401184260933369527488206703962436872059299754006964658145411135715285131543309666916261147162906324852866784469362588174806798886084835311322495644384917815753456114043848321591684728503353583125390553182460085266457044328481386164295062361453557198381234996483,7741880922056878066612714130026240867522108473639420974553105203701418374724364127305856418938534523230858044879263234730427059699274843010051016880192588782731180142670836033616687676672699018701220814586539096635490574816118709819174615703862984275251303192202153140463446907523629847791487096446425558516238|1000951516029909402241580153254201911805533650981363847468064026947791885513152190496939080952901855372998038682278000380636609527998130327379270561313029246942896140134101369621908911346125374976926115893278132230058065500703131104226075681633220114919188893134454475954292791954736302126634675741318978601,-932129972046203740107893826647984861393190609401184260933369527488206703962436872059299754006964658145411135715285131543309666916261147162906324852866784469362588174806798886084835311322495644384917815753456114043848321591684728503353583125390553182460085266457044328481386164295062361453557198381234996483,7741880922056878066612714130026240867522108473639420974553105203701418374724364127305856418938534523230858044879263234730427059699274843010051016880192588782731180142670836033616687676672699018701220814586539096635490574816118709819174615703862984275251303192202153140463446907523629847791487096446425558516238|15746368080076547639613112548931198412928034872598867786846558772081390410891968919792236071990423045407820022126215168896502300352310051471939494022340800892491023480415508952796942181491516127339639471207019480870149174572084740672853889392694282271865099892527052018243852819055812247442628083006705785149,-1817913436531155250968687681482056128774282329369952888473920830262042372654938097136436607889208234812116291336524382413655603485552821293038078939629653209114696856829043835764482596948782168253580822692634503701439593841617763234039276530741649509861202111285883608345674200240173376261557395276050534745,492167869580416546150864341469450817106189778801161330939305290046708175512988010176297694665433672849671984872726657705850871343875774836983621356338570200418265577466209423429850230482380970478840847989123705290014954835386530282830688430538273550828822069628430975922343455045834201595340872511606366704728 +10009614232615212022005150149343932420969657134336251266196874043830583063114875468409344410544755395263952674188421355541706476649104687178621105860662213481607819203924674901060643908339267017280510002551378392012520463262809409257654601850085574494274200629627329653203473234690149811173235149360768384838,836267856629353024976937718074908246524235283001080657657057590803147642759710349203535369107634985057019274642907780561827986871269168282562729482602832882014993174240061797035451659603107102838592209619951864142851506020290496133563766536500833473922797379921857659870104796371847757654270012370698502999,784213921791375719854653276558811892255578032965532623567863494564671611248783758720878204565462346000781224582747048981949572160149632172258392213554094289354008679022701865566865099047150582908470578815534139684037571258726801746576984534581957278215217261339431677162978264928931155436559875241964125506266|91259641317840920388592572245493602418223311736654347455817117920969722081887399519379251381184940824844626111264019221904601665534920622151118371387906395484279959508114917794568416938471005687918332893135141888811509257566326226278046422522746020345472499138217410394253037717517813153026786742476211897426,65560628471815349730768404773504307627679453655870244754876894481952096786914419991524915369113837577161059316635270325176467655387763062001209403412378388608286732350937986269983898741335821089925199082458466627097168531389395465235586971316043725352106687336132311388859476958068300601993983492409770068953,97787509018580500559531280765247530593654008165836933101614934455794219747727474184974783904602569289723706867556213004773348953706945069163461128745310430174496134494281188144065521418637123474052338785100571778752720085930925320282428718659058820028049740359320116709840549247824331580105759766861379891210|75062088452630474843888448210053283462706588708992115575383926339301467347310815006622009334498696501710113137263962332974627478074375539845396462501277814094889463218705190380441269364077952749970929670210201903809188825244244127139203763727765293010747505303529125943832432756718681546490336041697468666190,5541281329506174033291380410034395388042944047800558435987093009948507724655465795692214345462752044394730637949505190953507095375192582819240934021514991426264136507386865262105651669874195906257084096658225527132816732104755767839079135854552727988309212343735183861434005237105894184406202983254934534757,104675750550793205502943520352684154101269712315945996783868759572927470248283594480842218327785617106312969404704918354113342765451442832450177716298160659447475598063377646514258038986139271814855804490712610499304684910754302950004231911223315677097295880861233808821150324765848314271787214250899197923793 +10009735080309013514440203870605983374104835055250399704317172848646825795572764221124512471397022599041102696110601760496809311877056400885225531243115647095694305859001567326435058426543669680082356076887117616533496794600222886637873441727978976019755009690240085029104982970925792121991104293242809524644,6716504442878527910519807778046246423810093302344836517925018933141102172400301207571530237654753113978791017298256211048865142019514745459130820608857728114059755451415522450033212605102272496818594519931368393561070233092047087381778868100623694505448318327728934167707696920045126563192647607794472189195,721610628334648695598193480418084731432879897882901829331594044580759141755040057210356863808123513214754128306537665937117531576524824114459745892010308401743734165555223754018460218362992047097741240949227118743681363740856040612578898979577195958019157067541288613303223475902295909138865214617457058483843|10009735080309013514440203870605983374104835055250399704317172848646825795572764221124512471397022599041102696110601760496809311877056400885225531243115647095694305859001567326435058426543669680082356076887117616533496794600222886637873441727978976019755009690240085029104982970925792121991104293242809524644,6716504442878527910519807778046246423810093302344836517925018933141102172400301207571530237654753113978791017298256211048865142019514745459130820608857728114059755451415522450033212605102272496818594519931368393561070233092047087381778868100623694505448318327728934167707696920045126563192647607794472189195,721610628334648695598193480418084731432879897882901829331594044580759141755040057210356863808123513214754128306537665937117531576524824114459745892010308401743734165555223754018460218362992047097741240949227118743681363740856040612578898979577195958019157067541288613303223475902295909138865214617457058483843|27431399959730041618757181598450126761864467783308250953166653158864868050165660437728250584906458406104160649372946064796764756251284036703521851065427172085011598154374858106257477054034049690307574700876194576753048475242472071051384544187235302865991596395901667453599382886279428660852987448092730327814,-12178152192814077151051956033210165813331619111090720689608458837738277955478946125067643676733373652534546194632007566276305197498317660468910084573634326652156582085984031315753626693903214933704476608819110626280721237157346811918265527840918335083118991187163668918374733603234110068582400025069332861471,264256662843741154538126874284653325441730644362235064492791411891511464369737085603945845443869261733906715033378896197504349395743395072323232105722154314007209047495860245950090828739984743068229024820070744102308175917924790982043751500738655732108120833669083027766207125418432774798887679934336031211189 +100097767925729329322181122349613179670027446504792908817095637890752573498574361347439148152051968207056866825997618536117991814714859714673883034645066867063812091504212589938420469209673745687587262010655197327448038749016704401923718318821311108473542621283106029369259039074767836862058509435455755610726,-100049042457569505632055807384899059068938967940837318894350268996535213352709148936435708901083176589583550587767198440304487034715449239754368855557475044885723026390661018171437823688972174609609018769743817618355306963644565862125983532960059011062792908538954329635940471395263688377520252608542030523093,101825233069512741038457795802309532831632092007485080725676678162290037786417230184436300741781748657320031840082727976574819880666874823641143033563613526015930298529985774382970686476257558271965201142223855170907771875249088691707619925926120372987467772228909661019762594761741996613700919454999805975044|100097767925729329322181122349613179670027446504792908817095637890752573498574361347439148152051968207056866825997618536117991814714859714673883034645066867063812091504212589938420469209673745687587262010655197327448038749016704401923718318821311108473542621283106029369259039074767836862058509435455755610726,-100049042457569505632055807384899059068938967940837318894350268996535213352709148936435708901083176589583550587767198440304487034715449239754368855557475044885723026390661018171437823688972174609609018769743817618355306963644565862125983532960059011062792908538954329635940471395263688377520252608542030523093,101825233069512741038457795802309532831632092007485080725676678162290037786417230184436300741781748657320031840082727976574819880666874823641143033563613526015930298529985774382970686476257558271965201142223855170907771875249088691707619925926120372987467772228909661019762594761741996613700919454999805975044|84308318710770953640248175476462028139373764391035194691231680218526343685551415536853656437464155941615590227223191821309564306137129412203074445224501367988293836354108333795252385654176431244360276218862523025987282479232565449230085787098609814824691928891608841637881937218976744434331438048491668714172,78229471895771291032128733343240907956513700512674961776679342047382405281968278678548353708794851883965121941126776164617402656831058062037098035411278996202926380143407188337949264849125051865072631849969234447888440699755954052452126159543200468837557873802507174337535425627611660644229281086936050355075,109360363649395746265656497473367613906192696966623732296103764282264963662145240362278977792876351026988778202744708027814748063715992412060773465595050876884872367497101878287000352814221891140816680001766329736587915177644869655423120132329944663172310205372239088325795595410385678741576083941746461375629 +1000990088197024747059083499592558231720263720277516776155079181049136503434198702340667607714363713879340855424897665647049377714485771691188931707633550660945052279457196551479047254741496420585602556120439906566870228385196796680534214981451257503126475671546702014976009092407415021171352670275245814728,725466386677782932169006961452587026457506864587404408874444216403861787891316322821563900402539391905854377725716394516795127638578550566829765062852138101610829715414344025748861390095121907615243675775588453320217679236986850051456109259336757301010447881360582473998540771452509411313781955577190588933,5517508390471385461294072894661016222336566054567430728481305159339660984012399389945095200514405410813099792232460346983221900276173777626934161693012967410321899909279792957271372152068664807744591895618427921351514391226515490690862669088614356482368865242803422288159831017511240290921861425877221350767081|1000990088197024747059083499592558231720263720277516776155079181049136503434198702340667607714363713879340855424897665647049377714485771691188931707633550660945052279457196551479047254741496420585602556120439906566870228385196796680534214981451257503126475671546702014976009092407415021171352670275245814728,725466386677782932169006961452587026457506864587404408874444216403861787891316322821563900402539391905854377725716394516795127638578550566829765062852138101610829715414344025748861390095121907615243675775588453320217679236986850051456109259336757301010447881360582473998540771452509411313781955577190588933,5517508390471385461294072894661016222336566054567430728481305159339660984012399389945095200514405410813099792232460346983221900276173777626934161693012967410321899909279792957271372152068664807744591895618427921351514391226515490690862669088614356482368865242803422288159831017511240290921861425877221350767081|46386382398471210654004936862977280764038033260370855702299152174715903684807635787033726061221737095817373565974565953991423132816014499962739297327315390959305555345973541148973281098200177613839273688191655843120140926599099288046020383471244522466342336148402764983519506510433171993666037668400990623062,30909786208868059159308250284546387617592958673051467586322533557805038169619650467442753505158926723729781335720702109207080121759415266351938588413071223894526233303271669156163543157906212613065654926067039001367294657463422342698879421926602847752406836893005886958919719183994605725308548242138957881171,124210879529497457542798731661855988692615123385567383434289407838970666113795793650595394981286850762118704131523110658152541154934468138859842609878663166338576053338898592108554591614195107201143517584467526852469899754023757894264352510613574752993978429183938806214485060920755151052534935466538850750938 +10010004064090651409010594639848304417245586560948860214310742766846249258119176243618948796060231286565945627267454791543296430719743208401586187196864109595450365240377376347430379493062158659135705093920261708675191488141331016387425285934969492844933812420736541635790559026628543841128935951718908539896,-1498575286639922441240963650822632036400568058110825911189335188996116649771598943688044499782411654295552472829397529434461014441578505662359180553723401992140786537396607735356416120600823531080136067285152784381639454281243980298334520221160338176676576774798710776186339169032737324810281860916038070823,768468744922072210410085870438045813460934852024069843981629956982064663744441536899640311347039303574749086761908444837858696612124820590763553776868490058405671131188766507451909827840059264627966884129949211264617246300058675643121776631374263858887287691658300066890342985411108805960696775940061827501049|10010004064090651409010594639848304417245586560948860214310742766846249258119176243618948796060231286565945627267454791543296430719743208401586187196864109595450365240377376347430379493062158659135705093920261708675191488141331016387425285934969492844933812420736541635790559026628543841128935951718908539896,-1498575286639922441240963650822632036400568058110825911189335188996116649771598943688044499782411654295552472829397529434461014441578505662359180553723401992140786537396607735356416120600823531080136067285152784381639454281243980298334520221160338176676576774798710776186339169032737324810281860916038070823,768468744922072210410085870438045813460934852024069843981629956982064663744441536899640311347039303574749086761908444837858696612124820590763553776868490058405671131188766507451909827840059264627966884129949211264617246300058675643121776631374263858887287691658300066890342985411108805960696775940061827501049|28314042997988233306636589016992476577770908296597830278146083272521268550372497996517202454826620755010065709821222609305573779332296860088326682557505516615132304908709189030516196077907461669993069872444768482204126654812645619744037494119483770734571472757955818228427379193994724836630122637837874512512,-3910830326710790111629753186982470489266159472894461132493344186147852161393575078274643639038642275689976708947162470525418556533103511874282953768387384089989557162835543128542264012421515524615699954054931189762734554550136613958599656445264920707571157499612722532218838749658906057952745224391208374423,271795782638036641105135359411824479015439355083041167763715963674151201738370794758665358014925962658456682314365819593590637317922383444961883165716906142863933218099402568928834160919844733051508148071302780085990761872080854429570287769745420760134784589649743625063761926379339662449726354233483569572692 +10010469709639397131321593392335940518221591944212653476848636010049901173327189141010003266402662587851391795365145565853592244249890218572600240492819519129624586319882991468883851157495158734614747790710618700576914513912845835699748008363226744953360119054075282875557290214809856164142199477757165509164,7505657900398833324827399204281082596119737445028635348485466721806081208043020690125518041418692182505619967598743043368451311836537618411006688337064144530591029793349206581566058245087905481171249541532084530428115422022022771262499445387394812364092046818720427959757560293344117843608115308687123143421,553113242511887630245562923692119334560619363555162251614925548023827683747558857060226873484593892808999168052131745589052836855443167606888604202950573221560622773360660465500305832700518144444548624823481416168401044677399877530532448619602616847965589554700283201541685397541240490155576228110029131773379|63201743899616470908035016615759783248572310773988939570648682086965508954735585744990615463863202134213890574490859916770336808958389758836363215334497075053557112818568576204445815232807749791417195377923291221271056534552496867547808556556792554364734430966783089440150789750091730879530896624414277659061,-55856955103087382729788364385235549210397677016869607285896429414455503436682728351867754944498329815149524455764192011560832811681933262606199210273482312024649522293283703849873542800068494104680666316436079341962770915103078184937312059708038123793720277348890693601123206211567358221715195838805665244815,99725721230004762208212433032530958477513183167215245049998941633413237167002350956483975841846292547322289722635488222088283425749457741260773683563042470151127137265045721725293085765918300826804733069413639039496778512157339321750973991239393851776816288547058721349853339439566413417882881431596395398482|10058483900212848371336105395105034597443877759659095074874545915088017898536154919284167493951088960283199509655255215299440632845548287448716500241460028925186589031890037337660582657444623147488470508614291087038125788600526809670994940639159256871538287711131658514500837340353796975836990505301624273881,-157799394991431658935500911446539445587307591494655221580870826914115793039596841571933100144135016253304167518063315606333327146563644719359095984750603598277704663545389186967829006269785943764149594510946914419779083189746476236548753466257639182993421200334901817261951648692278188884421732061466347929,549073390680838282030926276806663190640362547475399531148862958328951733805907419890212210186161292258493318221366553074237370828617692229205217240695895636477792753409007387702564155250318872755670718485591591748806803837858464359711143468897253705933551825195496604931204015549587680036788025676123194339726 +10010496751485016737255498721953568674323163915462879922384146496780957659766649785727318078913117215770623612059774196084160730194502430474210832948012098222392905483059314666266093994762308130821733627116456649448335020123456572070799012785074345756980230844151670979497392292798505519219012749959532875338,799688122820510610823764584829566759424107985411345815493636913295490164723810636027858758547620320075665083037412723404618585417481351642215686069179403481765070501469154817238059870792625025657772680475594951623612932084444307492923899340395814785386177783715246947669812896758158101579611206283404125383,756465676775987727565397432418408198121332665761199779426305954315978948084770158074763521327096161584122642931162604561074895576932338265005852611804594502809713943064130145585384616864112057298562543101439879468994210857521510834193578678095039312141817959445372442666042645305218271194929494814070515333525|10010496751485016737255498721953568674323163915462879922384146496780957659766649785727318078913117215770623612059774196084160730194502430474210832948012098222392905483059314666266093994762308130821733627116456649448335020123456572070799012785074345756980230844151670979497392292798505519219012749959532875338,799688122820510610823764584829566759424107985411345815493636913295490164723810636027858758547620320075665083037412723404618585417481351642215686069179403481765070501469154817238059870792625025657772680475594951623612932084444307492923899340395814785386177783715246947669812896758158101579611206283404125383,756465676775987727565397432418408198121332665761199779426305954315978948084770158074763521327096161584122642931162604561074895576932338265005852611804594502809713943064130145585384616864112057298562543101439879468994210857521510834193578678095039312141817959445372442666042645305218271194929494814070515333525|88526457805417802579401128655636200680578875592064917653502726799402631022732331707242469404309708934422669188417199074013672835521067841289769648786519913947468121765630841991231363845393790849492596901524640146832343923907202043034825750225542103503647484110551329413090031876302117118017242617457435270440,-55270872554503717308092985383981103433537850547649491053003970562528650386510337748001788465211336165026556518877922750831164872435215600571701093825986357449663403092607944719717658773706993903771608486872517959780200593880280040497747294339054563275578214457748886755324708980839180036767067720944832209613,94165686390158171873356770999242344439144784888928297429784348143756989501060133555039087406934644294830253094462126060631940792293289142829036758298101067851753964448066092115935075783351846337421975097419550731994478824011482838934049698582968608287926659413694080435137971696387627102349753238458722293238 +10010579112627452164700751672418124874438960016155391309411143579238371993812216949415371161492459719515415809121706298625750585115724165801767312632070537335293199529430577590690991572481217905708780746070115008642386973910356482808275744430781549387996153714070117005169542728240082244119738613459581149403,2350957735421970008675187616979703886327431020247822920032684793437439591770682963150195069182216167082120247951141628182676139493494439884424368912802413855370850694844333281369444099710260137140856858089878674493931790511953123605380418199403899915269505474711266010465371671818915910810005642457030207323,611423654589890839284741885001129722618409625326976389817674733477626186444470464645132913394627656053210319902647997769502456733804852681598112059600692683589494771437615834703370743285630660946188840487388799145726650756609808617614030574039934664771328233896579676781994740365464050319193605788676121096976|10010579112627452164700751672418124874438960016155391309411143579238371993812216949415371161492459719515415809121706298625750585115724165801767312632070537335293199529430577590690991572481217905708780746070115008642386973910356482808275744430781549387996153714070117005169542728240082244119738613459581149403,2350957735421970008675187616979703886327431020247822920032684793437439591770682963150195069182216167082120247951141628182676139493494439884424368912802413855370850694844333281369444099710260137140856858089878674493931790511953123605380418199403899915269505474711266010465371671818915910810005642457030207323,611423654589890839284741885001129722618409625326976389817674733477626186444470464645132913394627656053210319902647997769502456733804852681598112059600692683589494771437615834703370743285630660946188840487388799145726650756609808617614030574039934664771328233896579676781994740365464050319193605788676121096976|8039922802491265414309990967793279613501148402448480465019122506003939256870540144853780285033203931808455458595860030453208550342558408097242925918803433428637982781245121194507511100106884732787332881816376538778408183713312626895063525916116529477067428617194552870724443468826009500481151973572267660629,7782542056885878734681190877592906346631460224605439140627247356888850052165135682978538906914658013311431434956582299659243906965976772069489496351182726287233109256230929112390639759813836413367620416284403736856845659506160807594525033721234682734219240024280033734701579761670420320393555156688458386939,763000498381829086301710784279931419423976764939217073711509076091719761279556145759370750276614372372724227557071534934449510558501017918011817000937860419860520748646784487080323157808376840620794576624474012291138723116851111311356377966880000941424814810860193927148425226557672422373368027666445875216544 +10011186832308679529580531778689417394449477080570215256255872899524060756354513251052234139190381882237674326102549194541918465150411281044342531791718191209528218579215954684479017629118919205540336463087633388203942961094184672710469514635568862008937176486425382826532999400454876885123467677882356280867,-9760739041412831860016040329300538464595968662597654195818825742388623357499061055114241473465244979572894681398742727120008689894660036669893911021076723092236596538937507422477033501397620347314916527511417876669224922540378674704881346598392965888769411037021701309263621236037226524490335501235413158317,618797456627391285757491837806082074086781183030320963821992656495001963414332567515207750538267219197978733813073360730643354769504354220428586481088489050423524166052003546758616279336334294024003134192912678054276268653141558092399335706944717740861723542047714673114465932057975066598256237991004833528194|10011186832308679529580531778689417394449477080570215256255872899524060756354513251052234139190381882237674326102549194541918465150411281044342531791718191209528218579215954684479017629118919205540336463087633388203942961094184672710469514635568862008937176486425382826532999400454876885123467677882356280867,-9760739041412831860016040329300538464595968662597654195818825742388623357499061055114241473465244979572894681398742727120008689894660036669893911021076723092236596538937507422477033501397620347314916527511417876669224922540378674704881346598392965888769411037021701309263621236037226524490335501235413158317,618797456627391285757491837806082074086781183030320963821992656495001963414332567515207750538267219197978733813073360730643354769504354220428586481088489050423524166052003546758616279336334294024003134192912678054276268653141558092399335706944717740861723542047714673114465932057975066598256237991004833528194|16023810805641333724336357094511552886496985977223317205804900540875359074549841799895438359675279197334185032768159914670757201278192258514539721858337894442748764924011517017369466984819970583389409069776399176053947560735257602992978470081403520015409641979689232868403667818818613535419071872687266278871,-7532673756475565262302348084703438182578166716950696747316478761861175843795966574151023129542515752521204794815061142348575304950316771972303577053107419061405627955596801577300288807854600908796497666677601605740930719732644371749303298593761133443055158847238113190613766743442416892398264321417028494683,386004572289283022539377207289773679498488550299986782511093221618938108821853499898482934516175608928422720022347987369229961237741779367136076661442684969604660313702194515039707016073494920297591526290529740277402244949703587380758181579357976708139982649833967127198595634906215849970601175752843362414638 +10011352260197967961196723001882777157351136553686255118590538903088960848511094106778638364952379274889738636611531352467905470187088001978395724543759615578178012440339389212117360666565610883522821465968556183822388268042856072812425704980952391373927012924156734141733616109526841203308615171993851798580,-7221676671346271775547094631755878098073875121922187404285664906337078018452572717764275630077273635227060270555255283560769931807823554231983067592327106941484374528295871153247243771907559825959222732921231505238074239141672724791953035282099263068621712554135551648164407808630494744659356436708196075003,491103641942430897255353076452858177434280940975186423223949785500010643311551520732003340225232164561507795653594281473147298622615199173589020255105363616020518202959139902358320338695214760426102498591057589117988289772846024859991303086757574971564242450863802854515962057480781826855732055129393601722620|10011352260197967961196723001882777157351136553686255118590538903088960848511094106778638364952379274889738636611531352467905470187088001978395724543759615578178012440339389212117360666565610883522821465968556183822388268042856072812425704980952391373927012924156734141733616109526841203308615171993851798580,-7221676671346271775547094631755878098073875121922187404285664906337078018452572717764275630077273635227060270555255283560769931807823554231983067592327106941484374528295871153247243771907559825959222732921231505238074239141672724791953035282099263068621712554135551648164407808630494744659356436708196075003,491103641942430897255353076452858177434280940975186423223949785500010643311551520732003340225232164561507795653594281473147298622615199173589020255105363616020518202959139902358320338695214760426102498591057589117988289772846024859991303086757574971564242450863802854515962057480781826855732055129393601722620|47792242549528045573835222090102709180753366247917233792162207697772127315858077638348932444421521322861739464396186442116808539325522348191328660258855448870212049194866543072912231226457359914737534217070905308248553545640574239424386722275092722710319161088562287826715987711727881278079923845948791676890,8254269885969125051120540706292376386106399376632912551223385556280906209369492834220174830708813086153383708455555132979546664334186800724505969898808175578003259356450761612161617233904190263463404177018953974392386560633539661122851396041321655235390273818809845177966554527106703090511634271703426366333,102958270685953367083211535309354861429334576908033521565612066728144639011805671376037609804664223083707360606267980895711740633481159521495849279040716328723662579233841335201356070651023351445332747117601073346257424542725915546556026838056238556081287286460939074972020327613774707117438966240554700925838 +10011859648773232442448733215609838143695842496672408041181163963731715385957428830906426802116840506850796500226397482148532808790741216756533590408501689411024510944680051255986998627975919616236379312627952364824369227089618523233361113970064976301643797723660966748317498805671195280559795030489377669812,1389268097793948084201915587623858469968349389719030883277892933626050552994624565080658001697742466760286196070343106937791393185285082388402785127475337008454634105961822228566730985518119778298380464943436464040236734762976514693785454254940058632017513195975469702286256915116671279121716893380760195997,798259439380551890168577021365722645610234093426080631569938818141778075039283575889046619146360005141391892307832892070793699590106322160142086889812498495186005607708401945977916695847229243650515563078729723204186390753029064543583093290363210178756937751032079469629502953157831010865389293997646642560816|10011859648773232442448733215609838143695842496672408041181163963731715385957428830906426802116840506850796500226397482148532808790741216756533590408501689411024510944680051255986998627975919616236379312627952364824369227089618523233361113970064976301643797723660966748317498805671195280559795030489377669812,1389268097793948084201915587623858469968349389719030883277892933626050552994624565080658001697742466760286196070343106937791393185285082388402785127475337008454634105961822228566730985518119778298380464943436464040236734762976514693785454254940058632017513195975469702286256915116671279121716893380760195997,798259439380551890168577021365722645610234093426080631569938818141778075039283575889046619146360005141391892307832892070793699590106322160142086889812498495186005607708401945977916695847229243650515563078729723204186390753029064543583093290363210178756937751032079469629502953157831010865389293997646642560816|42206894030530619844844137895190664968269730414499521872109243265156383878372533066719066634351278056931106119952256575854241753055519807843572490047146976978089248439736200704784039417511594978273239033477711961360762067155137236184651290217781497985287933853456015958183471535758824703982061917287661765041,40970642478148233733033585114396071242748464687693709425944631778683899124773146938566992970029345645063087493796799166205427214444613129772321140093187953348169602638764727669726146858903079780374349625954437240902856681427277267635228715453381995681831199770224812459964590952867744306421769761996026104513,199285626990423651406783664663645910990492228214328517061400776387771491511391310851645339521126305819574623301901411324234792418046438608476979083398394165188934652648732128312553721596148859379616564443828216278968549632096439205379175627317399435861673444161870109940456991316291287290279435962880377080302 +10011942112859072995258791154733863477789940396938883213028206575320538554823437297402241742896497695874369416027516907850508925314968512498072222974096801648178807861791486753853486254133021354211722209138812867027895370716192265840613761606054294753819681190630045043947858812851889188252918713433862450937,-5571668968866828804921046721301654575883923332633233994134906673281267773210784380932788963105885600448276206900049033963090555880641132208787100277713410661373854250945949489885604664165828601242508315193830303811886340805084372525080806602568264342555171074951419758002241352180046540480238252242954050299,447717522759824444351173111605711384841786993787566688069178368722388364402515540644758414533643421974927299526439953604872416797996604293432960735663438930460329264500528581210531189312463600150764233828882749159851806734992346380036786298515789780808132282396713107095426662454069422796780131140784450873310|10011942112859072995258791154733863477789940396938883213028206575320538554823437297402241742896497695874369416027516907850508925314968512498072222974096801648178807861791486753853486254133021354211722209138812867027895370716192265840613761606054294753819681190630045043947858812851889188252918713433862450937,-5571668968866828804921046721301654575883923332633233994134906673281267773210784380932788963105885600448276206900049033963090555880641132208787100277713410661373854250945949489885604664165828601242508315193830303811886340805084372525080806602568264342555171074951419758002241352180046540480238252242954050299,447717522759824444351173111605711384841786993787566688069178368722388364402515540644758414533643421974927299526439953604872416797996604293432960735663438930460329264500528581210531189312463600150764233828882749159851806734992346380036786298515789780808132282396713107095426662454069422796780131140784450873310|27084975518223203685159476564968667757147005650320881882446538924664746760650597697153771281773275150298344920435750377585362202361041033907635631944580948271756519774659017735803323446011519248098440794538345241902148398434473456015090213973679829939390143526742895252747749904765235510343943624603085395760,-12790519385524034711380512698893130061457017090294213212099271214034680483663421242204264773620969593678221374876014811278470247764306480672296083402927981473695204988274213121345880281894543363725179804965957322222445321774678314607579703404237389600553993220560492758375020231080071561518133534954466259951,166721966963161057002408800656254458745347212698279982813080522419206471402712564010508086006697422863841361930966373632778322663543126671570353059325275245779405843551444614505569300692917404907917428765459530333591345110277642064762234238705296425159456946404870175457906061825086330206230526422507612458697 +10011955414042796957539613462833567748978021174979466353940011258968857683495843510716962870026112990120612239420094468274757074371715099897797764809018818677244411173050607051965491060861928470702220861911485527125770697960299381766502895029523905888655809759985815187019718331529320273577105879315557816044,-2903598288233181369386909069725761325455718972241715705067575929894098338713960225913955377920698582104810776546675110854231130224088963639880575858411672466883767586627134811452446768341259728766799505769981364639560814489840847334997666650046443822662727211952763808116443820225341403833059567092278686013,716711840847237503666263684416016435149389642949031161572660687058464860752744538837256522716160171257335781518708196625364621151126528577774399883526209845714231475374012476325785739496418344991482641972669482173664514234171584896006659617692101904655946713038460582513645370686741753929246439907983936752037|10011955414042796957539613462833567748978021174979466353940011258968857683495843510716962870026112990120612239420094468274757074371715099897797764809018818677244411173050607051965491060861928470702220861911485527125770697960299381766502895029523905888655809759985815187019718331529320273577105879315557816044,-2903598288233181369386909069725761325455718972241715705067575929894098338713960225913955377920698582104810776546675110854231130224088963639880575858411672466883767586627134811452446768341259728766799505769981364639560814489840847334997666650046443822662727211952763808116443820225341403833059567092278686013,716711840847237503666263684416016435149389642949031161572660687058464860752744538837256522716160171257335781518708196625364621151126528577774399883526209845714231475374012476325785739496418344991482641972669482173664514234171584896006659617692101904655946713038460582513645370686741753929246439907983936752037|83377818300427508414411209474182765418541299931790991979162498055814470115047955070666996621536705209820738216257135146862349180486198221400982101436215575798938096836021071281557720129695222554778979084677391347787960453403954349664348198928269790759939576077051077722913333980873848885097124565249932890109,-30688215255611971606034471669429848439589330363616017559694024730487742561639314516549592500671986661135255749032859202031979689977991786343363266117721953715761747898795102634113940122259396542403236218273245556434610755838474462460273735366438965428724794482250645649141152999575795556913839603294733616297,88860815315671630897460232604076507207530961201107386907073059232104245557771716637121266612833291311086440284416177092484049670682110328081485080434205469417936503447466464463362446293805166057694349242947508206617775986775538756539497474332372390720218420029346868304694279430904189373022716924576015411382 +10012228673376152026567450992902390970336864997567041834794435762949115261281228493411090141625349816927161690458296667158108080969724709444972658280448694411038715631967371509920701285876643071095813601274276803568595952200658716678278724478871970783503276566469041579910541903097002012017970816393023705126,-1525621196152714906745704861653134857598506051934926836340086172347518826544771422485438019089512861580045344082067612865732790885320087313117232977161635917848068594652072218066650842997301426696286712170439049522381084448274527064469835335059461198790200539335886996343589558210546809155519571241608841115,566490489998797306378193876913958339109032806676495000099448643263727848667893470101258216128095777975779077696408017781065855401798377205019264716443061687881268372472869438487229092017706767156974596159933038800310353717032995999433855144018018195220506116678554717313645342356609548972497509792111447080303|10012228673376152026567450992902390970336864997567041834794435762949115261281228493411090141625349816927161690458296667158108080969724709444972658280448694411038715631967371509920701285876643071095813601274276803568595952200658716678278724478871970783503276566469041579910541903097002012017970816393023705126,-1525621196152714906745704861653134857598506051934926836340086172347518826544771422485438019089512861580045344082067612865732790885320087313117232977161635917848068594652072218066650842997301426696286712170439049522381084448274527064469835335059461198790200539335886996343589558210546809155519571241608841115,566490489998797306378193876913958339109032806676495000099448643263727848667893470101258216128095777975779077696408017781065855401798377205019264716443061687881268372472869438487229092017706767156974596159933038800310353717032995999433855144018018195220506116678554717313645342356609548972497509792111447080303|43590031232680232081751882157307176889837208488946678228473969287186808910765585247541543237267000539198165783309913805801898560564494504170518670105700488271939383325260531063287350050801106407955825720824399992214830540252117419097263989404727460007269455161541372200543947623309137659512638261713267690824,-14075226919726761245118463757100097494169008867441262054574698130139530299753414803053777844415814847468435199262862690860015506966052100586678181635131495519430715844772863497248903106204345001653326109572317033217334530762155783910231739525445183612742122146838723561339801552140211476495875670393868085081,131240521940112916676543723913094551994900810880147949771730918304609983182487804507629012504949522364314455047343021279573082629269863237002108329413796491307563278912051552679953053070493799302202693873331428377723854674840449409246578209307981263784655485960382622975619701504230119584672038533695429676088 +1001288292714450803721216442216625955625371798611921786124245018047248562264647981975960215285171753909781321204807230585425114478278803844011930274438946371170816602064333453376960652483578633927890649034364140705267107257789492504807548712851379509812488664968862197781823935761608178854275129769647589581,118977223991225808492576983063622698908224268079465629025347336989392083161221074952362214752172730464574518166801398443928377167452950936101606770394549907364810511870992758058622270316795961219734709916323416843582267371642230512848102350867740488489154654911017481701711273952134350507762249130961129603,4253782247854217005640367062054391551273020323289717198551116404593406680781947315659948108589518702797872582317228254446273819182123102223859859093093126618316964313793208051942159218633324159151062222504543999694994085787779078206117679218461273671966899590739444942724001001618068559652898782396232628519674|1001288292714450803721216442216625955625371798611921786124245018047248562264647981975960215285171753909781321204807230585425114478278803844011930274438946371170816602064333453376960652483578633927890649034364140705267107257789492504807548712851379509812488664968862197781823935761608178854275129769647589581,118977223991225808492576983063622698908224268079465629025347336989392083161221074952362214752172730464574518166801398443928377167452950936101606770394549907364810511870992758058622270316795961219734709916323416843582267371642230512848102350867740488489154654911017481701711273952134350507762249130961129603,4253782247854217005640367062054391551273020323289717198551116404593406680781947315659948108589518702797872582317228254446273819182123102223859859093093126618316964313793208051942159218633324159151062222504543999694994085787779078206117679218461273671966899590739444942724001001618068559652898782396232628519674|28938807607695569686193558386017186559599585089880944105080644798657187851944851177349121001670507484268388813019981112914318210410185959709469975835597908447130200721022330232315439534240435891776843814205222365393996713243986623555128903274366840091822641672516816965782305494688964249039137567600077936606,24347068586442893587653361936682544233359974224524919385561963293036974216353969467745312829316424149479715944098504674533950906586338239024243122404600846692591968993298391467756407074710363297328032595080001517924404972784909440292445668484007116372818768610926770836254572445727057593300358575616247842763,152302535148483948223815371530668367432578267200771233287129083802472440010529096619024512937585549897229409792244544585546299937914900082139679373959823145377421946865824314455823557999559223736926801877211472988708620154393053288483777738533792797643686229459318486035573754517579909390578108894692032268889 +10012892006475941528884203206760641995368133321794055404979199342382084602756352644705532078779012887564604213637869579074484075768567055417796954674356138026767547529561933792018043105730958440781327057508393480700527196787164950646236383499370902496883935791129999602941562207002549251300455418372635519273,1454009605238489140114391427335527519147008275556174452371701295849315335234637169205945347453687617440824028465168238395128115858746597274081455839498538752590048744221995446875637484166488769782049750872805524958169087781809205120801537577068712904423342748390795604976651954642488089689583155223913397665,647808943230731060739626381975524675037163647891128462337945233305926315404323308376753006196333731632781667393569616294591379982170007646969372304454389485880137478967587874806562743050788204733473153064889810620961745850926397404102543921057382519028198560438333275110757811110797391594327323261044640054976|10012892006475941528884203206760641995368133321794055404979199342382084602756352644705532078779012887564604213637869579074484075768567055417796954674356138026767547529561933792018043105730958440781327057508393480700527196787164950646236383499370902496883935791129999602941562207002549251300455418372635519273,1454009605238489140114391427335527519147008275556174452371701295849315335234637169205945347453687617440824028465168238395128115858746597274081455839498538752590048744221995446875637484166488769782049750872805524958169087781809205120801537577068712904423342748390795604976651954642488089689583155223913397665,647808943230731060739626381975524675037163647891128462337945233305926315404323308376753006196333731632781667393569616294591379982170007646969372304454389485880137478967587874806562743050788204733473153064889810620961745850926397404102543921057382519028198560438333275110757811110797391594327323261044640054976|62940556237396653206223780718542562667295386352158429493270469961690767724114029222148067827069562399174914339449248246366326268552997433890745884344199015208364859348865726612586847277646257664344896903583225600388420348724002194132332892190932637136851080726053181726410409254132012307744554948406613929323,-48701511676436282890206508014619418354003032902027055232648782348677470406094053907961181547187251236573045647699655583258566497581891423764342023041779904338115306722370857935574573523817812044494597510209680776289279513137149479122384803569185846747971729826779306714510975413862168549755168167117700353327,112469164343071489234368373987004423456191302343816707379444012274611228263948855290569720261858996544051020707105809245289927202553907369725233852283792575569835413308417689095793467463934173594106404637573580430116767215310604286894257928685108943559541701617509990028119392117707508006024253191362515564488 +10012909351086759965456044227627057711408098785482672328633074337493434448564318338609803059310568728348413958910299881715937715018572879175542723270961874435550327968633029584188957768139340259030454592302362749027465867807734115139476094923287105973980458884201581736181829195017361330152871853820144480008,4004735351364710265644908449319598352103612215188460925760295665563484237162745827742855116753659687319941982652183152982522805963387540988424745778802028813186258777373064074552858455437921359277118582292259532327491507456668283228943221341315392967683928177537547570473748486481294902027111753951887811107,625070500924631773027293646808528931297961990338169633089637061010766445639876245993583660254312851352153995204943188734825803541904480394551165674837469282411059121521375161737576421883549419892239480294917943542161102975888315623576549465990742662361177906359742645436834392762941048730926726541953775339985|10012909351086759965456044227627057711408098785482672328633074337493434448564318338609803059310568728348413958910299881715937715018572879175542723270961874435550327968633029584188957768139340259030454592302362749027465867807734115139476094923287105973980458884201581736181829195017361330152871853820144480008,4004735351364710265644908449319598352103612215188460925760295665563484237162745827742855116753659687319941982652183152982522805963387540988424745778802028813186258777373064074552858455437921359277118582292259532327491507456668283228943221341315392967683928177537547570473748486481294902027111753951887811107,625070500924631773027293646808528931297961990338169633089637061010766445639876245993583660254312851352153995204943188734825803541904480394551165674837469282411059121521375161737576421883549419892239480294917943542161102975888315623576549465990742662361177906359742645436834392762941048730926726541953775339985|50884288706475165946257509654999208555658693396648687044835752784386552584102384977309647778026166442592405819250800637374065583324042092667913200394806282864115429746583280943890188029227669788614986056318825797041482189685920834253378958370006347565609320222176974991924753600658153514244660657255122224708,38124750578737274821917753227232162791003089617481557231259566762030985520934492451354616032457170217275564281951330766101660738724598191687885679545346283525262542724874642642872748420737930473130307644519437933305026842012536784886496944579276550709211116316390318564020889816097235068462785319614865578597,130062522389522343683740057432381314776477134408262105090740417520527750971142246152091337403925616258740469387086918783120971977871460574454924803144389152275224257452330149332865693355986252454785361887191345579925263888502541640915087986171712168495464223258466766753612088491549102305993177855419426172515 +10012949731508230844521554364973074187572984168621445800774150709798807735949381704091845966274845524513566631062798752350499554699759712145607818652191568463373664709797900265336143905874117568859521742454341137224521191983729963831041097053387797083787709902762145306866562987693831491238763225325353128845,-7151999616242866495807184767334673387014110620932054515899434747323053830494035687486485101495361247552977403879925385683437335608704813457204456533123612810231681288244199329093278043176840326889166441056953674708680650112341950599518566211501622893081961748190383051196092405691509055911825933224776999729,728959856841002416924230811929428724002543698647639902715200337469187398607311841753203087774058534727465005007422722827247541795373827101651083024979629054119806748202357685733330535940416577507509240075110229140018035405816024445205831928017961602089222683008780078758377712656395593651285944681456109357272|78605684766061357400507779695495682929810684632437884872357120089392494231881706222602069457907886449103098011256954019318391632581377073457287658351584831830230683661446071913790640516272177525020187886119102997352695696049059080937602038841787771510139456284931095360062636771451048097974369276252684666749,12001075534855282519055781006726767731199194746822836204491410167536180166431388377323739159072959927587441133024108242424202303987846968293631866746295774320809136575432861690259530718674237632206265488487198601880322884976030897140623633254152458705315742157972429278484090634288310049511931491105240527901,93151749819352486101012886560489221249552002889236789406862251708880381277922290057447780576080950571200028266859881169907512608303652032886801146810143008245384785580165444902988038417617761865310968792125862316413739796643982228185896004498606219961899388723793207292461251691711779811000343374670531988570|95620961524949716684140097524982794699249535271050516669544121744125934159117898820120095869213277316814159636331359612088008309956314498753337898007810553303289522178449103493384329227781778413500531168007453332099452587335790687068580171335323542117871903087433014777736086345342400718427907876478857651725,93982690612240904950679627999951286744516720026289165825378439518867065181987722717690665329424786689958612327347934970490613914683496125042910877240489318265091859294188434182919729530207613831730142844292090902152344156800509267822168626995816691703927249712872762026654985358484494213663737589506902782009,99292425117587212531473852181491241954331600716435740239461638370783102438068248269577051049726048567729703659744591520045688390816935889052570162756642088994924462717034854539966002991020871080627249804440896263676225604896518999268622239261793212314602300584784534836058487675621509713476733501463323785340 +10013285697697981291514875192049827757071760177573323421009966878146856227693938310986650067592898605619488251263628358029535725840627847357496217367653253065239804661689467675594407401100934372130923704422822224913415836705341468552018728686468194407664564227575182128302559705354560745061529474614082985076,6561642167054255252332139226189226301150630422474494620863616714017817447379372804603010573956570809208555270847201719676149529315047658055027624866235618098171962008631941847341271231615706090718182990766223922159167490454724094386151343698580819149354278973243680974477529170554988807127882542455236037061,528470097447394031501467541165507900676972213983504375431777006857690508074506764381712795328953309294516807977445847891975262681647237636757123951794958241571326610288116591734368211279530252114133992576937361883752806300690109922381969083425358175983601420535008716582685323406262131690670391327047692590496|10013285697697981291514875192049827757071760177573323421009966878146856227693938310986650067592898605619488251263628358029535725840627847357496217367653253065239804661689467675594407401100934372130923704422822224913415836705341468552018728686468194407664564227575182128302559705354560745061529474614082985076,6561642167054255252332139226189226301150630422474494620863616714017817447379372804603010573956570809208555270847201719676149529315047658055027624866235618098171962008631941847341271231615706090718182990766223922159167490454724094386151343698580819149354278973243680974477529170554988807127882542455236037061,528470097447394031501467541165507900676972213983504375431777006857690508074506764381712795328953309294516807977445847891975262681647237636757123951794958241571326610288116591734368211279530252114133992576937361883752806300690109922381969083425358175983601420535008716582685323406262131690670391327047692590496|34436981724331071994857876336695803178232447897168183469251879445354282383737983320261577504714614276116113259188008664067129808039959751651485877586471601565784430914037035998508212337945584341667506911125463475285113792006322617814372685212577273915390962094210529917778766692621996665878783549527139893242,32421657027122874777191628085590775058881834171831914535958291812982208823927027425208685420460283486647223529499620732980942837410329269106357656112224843439688604221190662744374320594231296457180058248568608247918397639378809724702503728912863511608290047988244839274296444657984762607288102260430546556327,160982437047557923662754621724904101004108273738876884592163845288132647289990060919034667221490978793506721749816537966400403944327808168366534024580437483775879522831741601830069730429889808208871000895202628107312664119771131677027106136972021612902580949354880064038858290748071858588504931122717671875719 +10013409568078797146570807857755720961248912529367151061974511181033586582464029378963193763825696350496154303179345126636835517120186897096948192379786846194127995559270109497428813513500508574813803534331316886434340387606885978254975074973425350503976585044856706375756665039166645930515210729176181994797,6863076338634175024934436723026392698236823689304369693969685928390616820215350991816780229964708018996782742906430454861638727991380590099557403163016242141034822837520016392592164770889783961757225608245037212056737255646000577024303400659319142788815209178052443133447533618473993771130005829940742472843,518144219445747450843112374880923475954988909716176430338161904285754222207619744119028881545602958596524518340559183715691125114950676034953086100367357569860971147170398898521979791627387469550508096062409978585338647803044577182942437027156401628087522267601972713267759073787404132654921721043098478369296|10013409568078797146570807857755720961248912529367151061974511181033586582464029378963193763825696350496154303179345126636835517120186897096948192379786846194127995559270109497428813513500508574813803534331316886434340387606885978254975074973425350503976585044856706375756665039166645930515210729176181994797,6863076338634175024934436723026392698236823689304369693969685928390616820215350991816780229964708018996782742906430454861638727991380590099557403163016242141034822837520016392592164770889783961757225608245037212056737255646000577024303400659319142788815209178052443133447533618473993771130005829940742472843,518144219445747450843112374880923475954988909716176430338161904285754222207619744119028881545602958596524518340559183715691125114950676034953086100367357569860971147170398898521979791627387469550508096062409978585338647803044577182942437027156401628087522267601972713267759073787404132654921721043098478369296|29934292569471815703363755226997845073545738667501237803957680847283080542129475423696483417806010171923751057450372494361758724728289501602492090448848706266885172109480272010048281849170055027096272553904872380723830007840644079815126735090510221286243662888112310922242506575820245103502418648518037684112,-21627427564859692871607980544502391995135725746472152647532172629071699503752589147589008201502208786678594136605740253912219755939688067145589663222363251747851181456245722891111913772396992196602024806546104102083185098682262204868868794139167512528524369543939531083241005579818092881356982615423576691605,176839029147532789455522785442738478049409371224700882039503756023790320876676330359714505430586793397649436855899139335082011213013721973064579158662211626800445041202290699798718862085318933995294002499387627536860514923891246937832235709964008507131234282169012371627871115559920941075179401745449676837538 +10013439159433989368964725373563382887574891949489700677050044742848904863973460805304293375442411192907083507310299969395983146408589524560833202656559624127327840001867965274370013167539210363322627273718141213894086509619780941576547772641539573210833142422223317097724915074066448586076045470572140906640,8310509330265721057433243761087295977033094222529694041792873186617167079529403730551603568975196878825930300295178836012162497002423788954615523897720318575793014458944774857654309162161287534450951840479782552544416928129945375223479302487034431413802055998746646446418560576461091628250104710978988283711,729371463016273963110544177662324936807730201765611306002068268068668637824971025044896789932884019488152669624502699796991126775679816762002628560217169359562928488795097209366461843162752726085374841269043547767926070040941464791696126630730708190840765048657149163857767697743125679328771823496672841634424|53070231924347082568804835060631378289496498123832644772276016787246416299549861270518581840230464146779761127524498364504195386387182521904349896158340177993161553682765729098600652803891496382298875979768509788803608935382898072295003870146958848103249920622300892108001270267505518700281027764636096833740,-10417045904363157434661773205739749791733323923523249180794936274249482583161962687848890485454386657190132561052636607343240275768181642068289523597327390757351630390400726183726689859598985450769013120294233573698641240921187000189001584616004996169093549349734180954432033587699679729849675222478884233311,137805678896928752296520072917407826444192224958002583188528402832110905130383122933446618731410797305667977506853537200263986333845054038041545138300862253525372279908216585177453144947870717454801757363277754721032068341587435554423804921498405475740879440309992782986462772299747827377706986933475774033684|56482649708459145913698445611252485312060512622120077359133908474066254680736347932747096146010188731146496181655662751016088725094095969432429720148408144169456178462601187248728823790080612841522193324466093276526908124707660336237710411213793152471895601301243018110500181075901054216803639852864737028850,49500528206529841911957152384541310290857923328806104231198472543790151686945922117895513040239668591093558926952515368216015961042415506812499837082111798870583213244606704215667322437109994138978691823955863634369767001231824513186587618556524171225612093890634215231765102523588484540352521700864775908391,139845177982276960575270039101197150993163035851524438788484301872591911839811648314287998492505051870128263318114638169162126726205946284015475459749582002542133038527256092765477445685371965587948783428628744556595668607565825917211361759008178572918967281201176709071648799305995083323084664578756735938622 +100137176306265990029733961444031383061223366889811053704411233166327830634077756142922727010656909223245031237249254709133350667800868491437148280477941194204587700926281351055456250199609042270725753605165960788792303060065875576152280599302149022622498012279559937562935558359151996671916418735428920407874,97779166460841276445850871197751897473918068054418745266060401791237288238653436085640513289818870139139618919771865928628062692360137571273452019987828179736062700190532592747648476510214800565987627353502647292543809222510700867942163153624606570877663088964161374448935565221244874684751958995844140920147,102256681515788126438883260779614224655986266663397201843001234522477597459794964756711032437403434184534404583233460968937962164574558546102488980641209149336930446800149993628815025349402768080588150480797996340762754608056907877670259116917971852689279794852877026737551375891068290636218096081379871615065|100137176306265990029733961444031383061223366889811053704411233166327830634077756142922727010656909223245031237249254709133350667800868491437148280477941194204587700926281351055456250199609042270725753605165960788792303060065875576152280599302149022622498012279559937562935558359151996671916418735428920407874,97779166460841276445850871197751897473918068054418745266060401791237288238653436085640513289818870139139618919771865928628062692360137571273452019987828179736062700190532592747648476510214800565987627353502647292543809222510700867942163153624606570877663088964161374448935565221244874684751958995844140920147,102256681515788126438883260779614224655986266663397201843001234522477597459794964756711032437403434184534404583233460968937962164574558546102488980641209149336930446800149993628815025349402768080588150480797996340762754608056907877670259116917971852689279794852877026737551375891068290636218096081379871615065|90230316563580194408667213300439360765549943827123723976699582813489678898952655680387614045807099591452452020884059027873359796950334151880947386773848115789736943898016681027189561282963394481712553688761042044178529870890932063063291912576811880180339151930033798900788177324802354824840693823677567948727,-51250096968515553727207440971544562384114008768089106206247467547899665759345213630706768471270630937078525436219387041016063211534659780348494492859921683763678230787094584046438254568966852960609578580031708027705688875405694260795850267621602038107210044773776590144869507841095128986805399917716889737097,94271497992835932562874103278757400032116756041765039747726332995183554964390204442288393334665236335700063020174534799860251424117225874828741908247259400897208844068836969114844343301370484015148786737029807531127609578040269356203181806490127049090765570457173053771731322678344641402857532580837050951380 +1001395889265586485395767421092943095772484906688205160639025138850588355434167443569518670890639224060287615982046173119211466447418875356487968111638376610456681184419174307282534045999642719677458693603373061246804412063778941537663208494251233702824916937867260454282227810431834716831538058300952240529,60445540632407873888807630431208524230030823670563578058253542014522089940657440267941912297376844686920437735513309169811551129412183931683096248710036617268265519243947751270645191479229689326385715524956466565650374324873653293511970021452999675894489762841364719216977754928108945414058693987652866277,5401452543992462314517473547060846830682300053665170002473827326781788915141651047957910827411217522592705590143110487190395657380723574363184777022159851917393607961064987992588915644654812213550360705959643031621136573608890274219923270810168453305278905475435769643968988593393956330128341342800859836282482|1001395889265586485395767421092943095772484906688205160639025138850588355434167443569518670890639224060287615982046173119211466447418875356487968111638376610456681184419174307282534045999642719677458693603373061246804412063778941537663208494251233702824916937867260454282227810431834716831538058300952240529,60445540632407873888807630431208524230030823670563578058253542014522089940657440267941912297376844686920437735513309169811551129412183931683096248710036617268265519243947751270645191479229689326385715524956466565650374324873653293511970021452999675894489762841364719216977754928108945414058693987652866277,5401452543992462314517473547060846830682300053665170002473827326781788915141651047957910827411217522592705590143110487190395657380723574363184777022159851917393607961064987992588915644654812213550360705959643031621136573608890274219923270810168453305278905475435769643968988593393956330128341342800859836282482|43569972642791160005757596858255828258440677425601503825448806514649923603624018287716685991744061240705340542732331922577472226472918231509238166036331218027449035406029770845535194662631393899654058445399116462950394778843477054303490660149914576382156352231393154632904722395547296167018467287872528029256,-25416175075838450919641769013264410597729745958193362136948110865397498509541978552163608664910111097484344111265508414674502206468095426484449495661952091027512836383946952942259134571474962916748153155124469369237399224386694894533985438381306408742628779331072259662078374717232763484127547679303302310423,127851513581210146707222534812462714415549658228702116548129323569875687997527570139914376876955894345964691178029394628745573178902316765592327648023513178993717765546280790932769863585265709550819660882599525799584893587529991012504312937097442098858522399473806578431530443021404617174701716319817659510588 +10014457466865501413264699180995213607651643403581155351850240885586127254516466035686557278805989563280873217997386135507560429328380625332058111008767730524810617486297285562994007263758369576890950982876431843971907525378186076190945281470031905336296565482376151661355756246367703162199805483942789509516,-9493045169000225624825724585241654877107258957466554573322941788423005986836702078635071088783742277452705183557515581054220105186163500969879785143181676844657120253295906990349839818041129525896218008774011956975336293108128480236859770511279248182237458109627660116415432972887068943678814730002774447323,568058498128347562017983106577404112679290790118077765226872096344304166614495246835964393367142362074124393647429278191341969083397190437238809441291521483431836555168421336650034272837791888742028164348356631901893675815620388348481938896223555723594783353067563133868242273893775394833482067029611721906579|10014457466865501413264699180995213607651643403581155351850240885586127254516466035686557278805989563280873217997386135507560429328380625332058111008767730524810617486297285562994007263758369576890950982876431843971907525378186076190945281470031905336296565482376151661355756246367703162199805483942789509516,-9493045169000225624825724585241654877107258957466554573322941788423005986836702078635071088783742277452705183557515581054220105186163500969879785143181676844657120253295906990349839818041129525896218008774011956975336293108128480236859770511279248182237458109627660116415432972887068943678814730002774447323,568058498128347562017983106577404112679290790118077765226872096344304166614495246835964393367142362074124393647429278191341969083397190437238809441291521483431836555168421336650034272837791888742028164348356631901893675815620388348481938896223555723594783353067563133868242273893775394833482067029611721906579|53924208564494923109968517258991384333718615783597634502228353963509962336751805354923463494565719411128406689879296751392427452179492575502279868846589843663305526485431433798862642111241114809566645178986499564696116126963309686958809916838000470566457881788520159467305886335238376585070031885019107861839,-39165088112891919485404645022206551911392044983195122526582505244941571614658605614311191813725723193620640489676510478992438060577861340792571425647895723271516089195795031639152263494946222662918005100610385322895768473350699779206361702599565733658715228168714169147264299885332019593127372341848528310877,112189763824528641217468278574322392988954546777239131658850758660466358827365295080995339889134329849615042048060538504294364321483596732194229239161149447040110980960983657967678809117682823152517826486688609621632734218254085881353576474560418869461310902870862203604502294697766172436420730459846253285376 +10014524612435081655051402581388141399758826121078479680077428037590919760198044078469208114625992172565561472610137633731570114446039320551421576820201144498480274752068507237188168464666743295560743051180514619150806895664325776982239371917265280309982409950396003685063877356037007592827997650696359708648,-1151946584820929060448198375444913319887694243637725495546164532401952339142382368891700429417009398962503441132652463153588614606824550308747271936296460648801898782148675402610858915130433609314541230955826121143276189468724039832396682232064702428868374548095200287491142543410829209121388657552507539861,755148183880958266120452185655234110618667867205538459331580575221728013160051641776310146717168795492323023035012567121444609095123943446710618919745199683082156201032014589922592096239933647413759449971964484414757026090967529868635390069577397530636511831668757182454799405458183267048363982001659170207347|10014524612435081655051402581388141399758826121078479680077428037590919760198044078469208114625992172565561472610137633731570114446039320551421576820201144498480274752068507237188168464666743295560743051180514619150806895664325776982239371917265280309982409950396003685063877356037007592827997650696359708648,-1151946584820929060448198375444913319887694243637725495546164532401952339142382368891700429417009398962503441132652463153588614606824550308747271936296460648801898782148675402610858915130433609314541230955826121143276189468724039832396682232064702428868374548095200287491142543410829209121388657552507539861,755148183880958266120452185655234110618667867205538459331580575221728013160051641776310146717168795492323023035012567121444609095123943446710618919745199683082156201032014589922592096239933647413759449971964484414757026090967529868635390069577397530636511831668757182454799405458183267048363982001659170207347|46183360432532901454553912811649590320395866004347241196844991991079215314437275037790647677890495653136878666779844887628869070006778207117633836660092513861015319661569732287838772799418674107359979430356246346034550280154482402202513605341927486676571446547869725605869822695502032982833841088921112910317,-14839171560103132001614843311520281027921489422034665235320812512225719145369465447283012912841921017696170329655940078247191555778130550993274994429848671209676820244675419866031667103832358269654123112505016252317575238332509399397558348115029597533711563469431946692326093523953990323828622920869190596305,164933181779897671999712222932130083401866004577771560343160060853528269308468525452931360567865498324819919495168385048274257865546801611749112060417208336526645794766502287072279593583106527746581118239327199774476900334621937982627978739872164479446504941326886004356233761306601172587310954186017120057146 +10015153163121593836478079113660124757348318592530821165639828390191159358973882062973457665510869038410016978521906069415643885467466803613263638452835291035274253082105374798431579187029855868716866951698965254377198199868261126247017409456764474165861037253182443325274363795830109568972878953062238823520,2382294090568001333199894323474279123934374114667847405540440750564854209907703388935432920732110218963078674073256448624811505546395497000378710736855311825351193195350046490926404354706980500837042629648272073851723169837427468358824989832884534921916167168920876623159906890551519514875606250679556403973,773658465692173962483130527303229646901934499596511207834787839028928145069426505005504820136922810366817841934360207193839133022641619097494932108724559232945611195348726835877676174729010759098808115181632361389730445448407363060843805088069390583778242530477288002693827656348092952397617162960252636436602|10015153163121593836478079113660124757348318592530821165639828390191159358973882062973457665510869038410016978521906069415643885467466803613263638452835291035274253082105374798431579187029855868716866951698965254377198199868261126247017409456764474165861037253182443325274363795830109568972878953062238823520,2382294090568001333199894323474279123934374114667847405540440750564854209907703388935432920732110218963078674073256448624811505546395497000378710736855311825351193195350046490926404354706980500837042629648272073851723169837427468358824989832884534921916167168920876623159906890551519514875606250679556403973,773658465692173962483130527303229646901934499596511207834787839028928145069426505005504820136922810366817841934360207193839133022641619097494932108724559232945611195348726835877676174729010759098808115181632361389730445448407363060843805088069390583778242530477288002693827656348092952397617162960252636436602|2334289880943001376407857326996263570161383789108737840675851906077977981768540714248105544895055900962482225672861273136265466132609608331964249615854131927898907957201650301595252550620756829520427054784019840985991520693282395588941752214974743008251596421642708049368885083348322205731564243670420111453,1451720076983591598762998723081545117923198868478265830640664361188690301293679623937617406037087334975387230852094993435248087727723628228521184122895045650428549727009619829664472593953602490826316016345941727517760259061554173070969494032097919619747777129170826368624036489935713881661043471800066640125,3318960568956834644312274599956969298741234864897695465866703354170475923995521916039531437101483638236150279927673715871252637092748519401149230098061946550109095773979423194478592673363716301124276065026975130628863523060647342416992862735921072287765667600233548851774826575592417995450427441845506696081388 +10015239581157875832393535763226085031936027674008799231064578015529654192320817181717861924169857992310709531421935508097069554814977182072669044193680614850544453265357095259368437732015348877933787885875170804438256215681419620514332393733243248548151757671725579685427667920968624432291421418590675885300,5094068907677575740286879080674249533942090145311835759008798415694966420126408035500684853222542571817165748053609110326610732625612063208376418866488998532875479258993000620044826461966140228426897339103003926919606128736757098245146058573375685873266553963971816210554103991392539430164989850926128708273,793368698167290739626939845245925598679004619304386735598558585912760256279890735283141314660505981777266664338091862952502183635644778863932176282239208069911448671090051312086285039683208751050938084831532228722294544316547609430035555984901118374565436615559075980852757981922632778527357570396074193505873|10015239581157875832393535763226085031936027674008799231064578015529654192320817181717861924169857992310709531421935508097069554814977182072669044193680614850544453265357095259368437732015348877933787885875170804438256215681419620514332393733243248548151757671725579685427667920968624432291421418590675885300,5094068907677575740286879080674249533942090145311835759008798415694966420126408035500684853222542571817165748053609110326610732625612063208376418866488998532875479258993000620044826461966140228426897339103003926919606128736757098245146058573375685873266553963971816210554103991392539430164989850926128708273,793368698167290739626939845245925598679004619304386735598558585912760256279890735283141314660505981777266664338091862952502183635644778863932176282239208069911448671090051312086285039683208751050938084831532228722294544316547609430035555984901118374565436615559075980852757981922632778527357570396074193505873|54841829397576178848410586601034860596951681568779361478370108261032921497569280442168530570346157404440784855573637229833444102498053726559151577392605738325853410653119896676062193149054976747541732412004218217068288550127184839213667255982218678702854737220904918059908451831872125006158411607941690397052,-13987639594862577439517093919564754940146287009709146462369986810150221519296281298521622497304190878362220137401179604871651085725669668566995040192751337189374220954170616856835063054456944563624013156491483611079953326833211481288513306777121436082074004700443915242579221138749893848640705537321387708809,145658957896464652977038505022308448361415349923894631554394890309500215673949920864830014124570888235622920757378372327525946059952077895236293799705256119864823158645268515234330467061529263252614881624406296566043408419602845128600163566622927193489899129202143975708704672075445501568437520798105023647844 +10016254093062341091793169016069728267098466973354611327776341296362926980734885768145505535610323176943330336454162903286601650062616238131379152236760546371204482195908361542328829078490793642835057146484428739306586521325328236448343779367153378279828280298660045704810418678221790320328995853516877961219,5290291792844776128036538578818355234036731339837804827682257620535756451822532868533550409363458436730292692155637706486234356872153487706954079157252741244973963860424508734267445638531496348565715559236158994920739250737957339663944820624379832490664101888239401802029497939684558696213321821587965089165,649562196414599732260624464563141423074514382020176141033151990702926870363780837252385965871530682720560442789827097838322398249975199460284454895932864056555126156062190575895999061116214790474483579500239339070750293285631666586984632253828693474154470829221739655058926181416125562534958534381263761974132|10016254093062341091793169016069728267098466973354611327776341296362926980734885768145505535610323176943330336454162903286601650062616238131379152236760546371204482195908361542328829078490793642835057146484428739306586521325328236448343779367153378279828280298660045704810418678221790320328995853516877961219,5290291792844776128036538578818355234036731339837804827682257620535756451822532868533550409363458436730292692155637706486234356872153487706954079157252741244973963860424508734267445638531496348565715559236158994920739250737957339663944820624379832490664101888239401802029497939684558696213321821587965089165,649562196414599732260624464563141423074514382020176141033151990702926870363780837252385965871530682720560442789827097838322398249975199460284454895932864056555126156062190575895999061116214790474483579500239339070750293285631666586984632253828693474154470829221739655058926181416125562534958534381263761974132|4371923964825216081284965901486251829658920327478160330494959761785570498729926171763697403539994609514035386549444286899305836316283570402957212167175599769519526858160920653621106184279087086218630872059466833612874880235324503114394586087353649281136173057014948419793113247251617601913225740371158264594,-1777711233855585326424402788112018092969733488690398670027508570423282261674718543600694888501454195345939794788269076453964223553057248156896791027286117126036185606587718958830247368692129308590218482424190086311842595428742140075700660885589198113766412954745249944832418277914084817045523687626938171785,1486753504481531714235052666066139608869409848938074431937349188798515713076253106271449862728854109674272536360912828894345019832890057397353770574425655506024994198304163182702822689738838001321557096641997078734385067590564038418788081682782254559978113888414124552326849527747130706995014118004294289090507 +100168933817004159727571823870862212374515071383247163682233493029515956409883385367746187285740348786673303354766599662884032925310153869913659930858915269690815416234679514078167380783771768659750083394948158950008326340270387586985723448583932705818464704601214600293828130344813737095058092807371622380596,94832715670637342331954204053963565603302480280224254821703778448479787031215111088413069986664424694762700821340882966261664606716747356784210807087846121536668261049472463334524682357378613143974178468771819549191894308095591279746614292380149290609465170348542192697415722868093623009037253233869856957249,102860441967964242444445722269341757702905607863364253263839843561869841563005656247302036622183568251273499262767768690361280263007610763737074443848261770701568579600837276156244861738658629562432640564576786387713071777708265072467592751700403901387393831303255944800743982818455033707731784929932463764787|100168933817004159727571823870862212374515071383247163682233493029515956409883385367746187285740348786673303354766599662884032925310153869913659930858915269690815416234679514078167380783771768659750083394948158950008326340270387586985723448583932705818464704601214600293828130344813737095058092807371622380596,94832715670637342331954204053963565603302480280224254821703778448479787031215111088413069986664424694762700821340882966261664606716747356784210807087846121536668261049472463334524682357378613143974178468771819549191894308095591279746614292380149290609465170348542192697415722868093623009037253233869856957249,102860441967964242444445722269341757702905607863364253263839843561869841563005656247302036622183568251273499262767768690361280263007610763737074443848261770701568579600837276156244861738658629562432640564576786387713071777708265072467592751700403901387393831303255944800743982818455033707731784929932463764787|77074101972769923370658023573461029047908280864501436531886214070884695444419790476920141159581106162534554398040667029684395317753749995140975694643351101153246406361333865778019332847126758508398386399309944270422140994351224794089223904030644354844471144608782627152160492615030406249102513998568586126653,41985809674026851301068939458342266766093613320697544468890621111459064094913132603897896518617407840492037076180430740254366932298578105226006922522339189157081422030305375009727018508446301230399756872145212262654632874007091596766171377732560260349745066521408866260391195589212337788533541057115385883425,110229138576369926974358954548772667512560757802376313780826844717365768043167923353943051327604684088175403151021231033281660580097059744410859188703138886987578267563448651782227630417696079180690392826925010189611494463744920925421564075513181916017454497019126236913116432477001913262238126225201422341436 +10016905787587129103970068378589209223718079791180726370802218768976971488497998963132244508629494308529380628538141221743580243393344335649567002150936320257090927900467530902572471077942584896593451110546304416815718151825873142786318484895510554032583903064792109176935301749381314577344473149515437073560,-4606191417439560848418163571752652850846391635765859587403508494460979835111500495993727812816590518091323150783186546267331220869638878833615969103418728210432746474134652280483753966001415196686238333974286033749286862708642243562674370580850529480084335445537434013760930078201975018692661527689582576651,605629172398620500162437997408160351967898827176789386195142449064206069917749164747262079121234714184955198496120255981525746584380916729025666697652941726995464456228081635615903549843932017595245592861355354651584306759089064045480854767640497444940703279199283744488071666641763271403206424800946819221209|10016905787587129103970068378589209223718079791180726370802218768976971488497998963132244508629494308529380628538141221743580243393344335649567002150936320257090927900467530902572471077942584896593451110546304416815718151825873142786318484895510554032583903064792109176935301749381314577344473149515437073560,-4606191417439560848418163571752652850846391635765859587403508494460979835111500495993727812816590518091323150783186546267331220869638878833615969103418728210432746474134652280483753966001415196686238333974286033749286862708642243562674370580850529480084335445537434013760930078201975018692661527689582576651,605629172398620500162437997408160351967898827176789386195142449064206069917749164747262079121234714184955198496120255981525746584380916729025666697652941726995464456228081635615903549843932017595245592861355354651584306759089064045480854767640497444940703279199283744488071666641763271403206424800946819221209|46304687373394436931218438666336335256163483212484332920442711829320278593351077938042811198542492407186729960199059393629663370119443451307712349370714705707036441431251782566272288509732854919564985572759872505231639307883389746522852343879592729064407291688011480357040596643477509242715875322162180945750,-27559962602683142671407402152656684625711978340483108455301920226275039655520624691717381412007576185077377268485337641259513780832297300630514833099989822452624240349981167585374487019267119021970798715861631920467292530317231419988216997273247875678528676583110608263771292353047679830100015076536212572871,134999594026951253395775325545499481323026670784912424362786946325493588697203309584859459643146426717172468824814166286260797091069281816967149658244654968987888219904891951992996909324931101736714925044299968419433398393443198400917682271553527341988170608553689440600718627726318712053029382276372293927321 +10018204832407485307717168433283551951171211565712475881182623460525924044598415564148247583748572210844295784844361310074903318189804960966908772513031346031383059069976302114174587533940128565286800673190990221782901119861314311455679210523773394109738879256410739142961640761546729001001316019848803176862,5319904375533742100925641023534751951391638893478820023967035481652261436239987131193126434052892185984232529181792190920674907331089418651303709226767934571557921846173913244300134187483219524696758678859856206200663423378880336983240402046185791279466371047694436246549133924131892629303395892591776395187,649443554629399472805877307531888884997294549224205118199170867300682218925831813905978113513120968194233947187441042861450829488125193696091497608405966874500722600331516590109468259720034716473854550338705028445661682847162605116427138852824514186119049574433700978648124399292078009263486664308050317605762|10018204832407485307717168433283551951171211565712475881182623460525924044598415564148247583748572210844295784844361310074903318189804960966908772513031346031383059069976302114174587533940128565286800673190990221782901119861314311455679210523773394109738879256410739142961640761546729001001316019848803176862,5319904375533742100925641023534751951391638893478820023967035481652261436239987131193126434052892185984232529181792190920674907331089418651303709226767934571557921846173913244300134187483219524696758678859856206200663423378880336983240402046185791279466371047694436246549133924131892629303395892591776395187,649443554629399472805877307531888884997294549224205118199170867300682218925831813905978113513120968194233947187441042861450829488125193696091497608405966874500722600331516590109468259720034716473854550338705028445661682847162605116427138852824514186119049574433700978648124399292078009263486664308050317605762|2096824613311195474736703091933491927179118439681576075463684305365113996801091784928235546455105051723066941197368294736517297176841884535935805063900042702255946184765201041823632273617760317603104813509978347996857764943233871467178918416729927262302333533232369242879390413535385046393166248041635195052,106494743809548339750384465880660679449902990323530191499768868050880389213560457433755933556230921885636912867886887645004590062925256300108980851523487384554584007694663026566980186001150284697993766392145530903618307059918756399086400576557720952521322359177695970013138988731324890614696675530003172189,3099537274480186341907264372921810635861168363663532429504499040028118656288725100184032700559268063816635775634703345843577214400172811320277070043994325333354476328328682954931303645039746659585813529747367061450073478508564524387846459195219414272058883943010351216728564728313947382708438971484753032540491 +10018324718324265352080889354041349230495045650756363847859249064826167700621077306379636998633382620068424485758426219639651755498284131150741688356919555549109464768469845299901089390604198312107185124929799165529332689261450442020302769382765032211061987664530506790585428478002180255625233322864976647458,-1506556466689461719964363510118987647616549995746954868616471745983245113792074110437071688516535364802439931589935160320446594866789971924891832800418288544496229576060497571654938278590804451001178571222736016531030712235951293438712713277945256316492298818368402112911658258565046390998975710669014707937,708633648140842422465025989226402132551754445128385378651747216241166649232185357696677838986015643979480257385865744447602978939236447538983280973796461564754777224324765925807967303202117722154439166886733422154436177593473337680099402130518111476687602398807958385973240844776043934886139211712396905414373|10018324718324265352080889354041349230495045650756363847859249064826167700621077306379636998633382620068424485758426219639651755498284131150741688356919555549109464768469845299901089390604198312107185124929799165529332689261450442020302769382765032211061987664530506790585428478002180255625233322864976647458,-1506556466689461719964363510118987647616549995746954868616471745983245113792074110437071688516535364802439931589935160320446594866789971924891832800418288544496229576060497571654938278590804451001178571222736016531030712235951293438712713277945256316492298818368402112911658258565046390998975710669014707937,708633648140842422465025989226402132551754445128385378651747216241166649232185357696677838986015643979480257385865744447602978939236447538983280973796461564754777224324765925807967303202117722154439166886733422154436177593473337680099402130518111476687602398807958385973240844776043934886139211712396905414373|27695493339474189059880649994786373673681195258723034498967136263221174895242876882887946040754182923842018399590448977999734476968405279409965275664350294423197625592498762797252651752487096596479518881899735472134497736489815871889587384160668070191112126826489102305651218385469424433736996571142100268141,4244952032054732923978416579691917713463067102733490131769022354718180777349838220573662792933493750823939044158056520471214587505994364897599832929831064732609354344151098280452640031958247121275726298011899146169585223669027857229201360814944532694404419990370729211245101258947186079227140704211123597077,256477087542010205875387979681474864287758986482727894664413009819175948644274490742191718780565989800083756066810584023109412061717270312386676508030363737098913494555400729954736934622756650518307368707185355806725304278546342578972238562139946071381611959969612417306120634997866733933066171286156441897864 +100183725937805337440102832154923451468884088040067509735031176134138272029603097931029532527171620687937178427853408917605171373483732022096443082050272616813579999826937201905718430121138104894761796713162794983612090638008542903172271321979734531328047767185223183894705715872373581190063338544430105324944,97967360545064065581782092795782542381718050317435898718948431525445051912029574864522929506831468927036372238440312318277489221772379035158891587900186742286147138092170859279721424649522055176445825889170777870731814816272149484567390197282747308726861433765864290861778135213069453090668850681241158130141,102026058802637364547431940124628332383045736950389197653455431566764985503089749509318465184383586821649550424369391712983254618997917250229615538329822378126555642981029789087346297188093481472570239624171949132198549570384613605722016512646835562730355439782372504448945801732597394795504733391497603335093|100183725937805337440102832154923451468884088040067509735031176134138272029603097931029532527171620687937178427853408917605171373483732022096443082050272616813579999826937201905718430121138104894761796713162794983612090638008542903172271321979734531328047767185223183894705715872373581190063338544430105324944,97967360545064065581782092795782542381718050317435898718948431525445051912029574864522929506831468927036372238440312318277489221772379035158891587900186742286147138092170859279721424649522055176445825889170777870731814816272149484567390197282747308726861433765864290861778135213069453090668850681241158130141,102026058802637364547431940124628332383045736950389197653455431566764985503089749509318465184383586821649550424369391712983254618997917250229615538329822378126555642981029789087346297188093481472570239624171949132198549570384613605722016512646835562730355439782372504448945801732597394795504733391497603335093|88007552516538570862938195555687347843271125145294862509637863339852312849461683699513427251868777755449793173646890377883712394792262777503483942996934326765981582162423696391672000556247247431253370862284402004050248548817767631668543644528300726312835546938100615886799945875203418182610947796762957426066,46229538931090505519067196461411597385016117678710797853895441617844339335997518932818211184588127766146461427860967017470462043930326616555616035492326025837765159149630918451827844844437116744925433303753825438769925710637787423788344940219740545569047456022116580673560308925831201666938083175493702647671,94949150488319392606413346466333119512866765599276437121309157049458742789511630485348500087618567561361017601972082423173906361345987933875129792711583865107081204947273992176380167405635064486260061816002217859656028475745573246943400761862339441042416462774614661346152692808807449954694367626488600259377 +10018622993047838712433185410421446815061984959152870777572656734193435222251946970691795794836467121595552277401220487788714277091933394850502637162917792769686767139849624312881217655116086523917779102305498425044983500792458780789534783880422443059521517950075233845690825129430658238084704480639376209109,-5642888291743578132708587871691433542854601085995709323535797030150736747981212204721414421313379808144339701595994626772514328521365374368168430420450149143091140909885716813202658261033852230689379211692039890782701731228409652608328076923100699005939261407374626950263084881921749869854247192520776393467,584355741641273221932263410866659097943618996328052690659780811632775391934038170008705223727517700749237903184431819452649538607172642783739379843963426355234430525043677403033326216332450474494227299404505243469315575849027861412999876408965870212198057391050926245137105584182883631254668161360450853213630|10018622993047838712433185410421446815061984959152870777572656734193435222251946970691795794836467121595552277401220487788714277091933394850502637162917792769686767139849624312881217655116086523917779102305498425044983500792458780789534783880422443059521517950075233845690825129430658238084704480639376209109,-5642888291743578132708587871691433542854601085995709323535797030150736747981212204721414421313379808144339701595994626772514328521365374368168430420450149143091140909885716813202658261033852230689379211692039890782701731228409652608328076923100699005939261407374626950263084881921749869854247192520776393467,584355741641273221932263410866659097943618996328052690659780811632775391934038170008705223727517700749237903184431819452649538607172642783739379843963426355234430525043677403033326216332450474494227299404505243469315575849027861412999876408965870212198057391050926245137105584182883631254668161360450853213630|24492216963212266409994030118552483730975075727585752220177989563872338705971497453471962798275543072636175655672560120906290569324009187038649563218726182874757477950170840864973817320145411108769238293767323154108926503045123037222803844779103784397763216133236290396907058542243428101056150879809315089176,-17735224044627622852810014209171696937481849587925646605967048837801771413294839162751742330787917315172217980725109761639973896911760524548506285715284414033504356013230406678376141516049028049732948719065205234900025147050216480775931691209693009856949654955944471263615211623003442072374457069595919699233,241918233622395884761827246850514897219165802162342296635123580790888932192977763833922926853355444881644755349323889380463316458550630788255600843973415342916444918642659362862569058232566277775534472941540495721557558697754452057639207696448965752690070221361062821443638513586031328286832012283835743514220 +10018933732727277902205269315771289076593947560040587959114941078087116999373425488340685401505876624281584630582917353725134238041079746342415896279966203184863826892445916822683268888700587092452305745538315423010290563725863170080340035065039975298577793326244665530455537053974727163555479979119191279926,-2305656050929911594001774361902538333750937712118410383814661797948886130836022054225957304174319742645328482100663492843669952358370802861270894168816436326458990297136526459920949376942432261379981780315229778535749028029896216855337892147060100885167806805043764484945583720350824386167496969085180728505,426903073734578001112620417146509321508736309565051582451873814142074420259405364041324675206078055851221135785335125834745297538613608978468731354815366776968439807098716134814276564770795992539739869501301828055278204465499226602180360134210119244471648153940999928351968352054963731820177407885865927236658|10018933732727277902205269315771289076593947560040587959114941078087116999373425488340685401505876624281584630582917353725134238041079746342415896279966203184863826892445916822683268888700587092452305745538315423010290563725863170080340035065039975298577793326244665530455537053974727163555479979119191279926,-2305656050929911594001774361902538333750937712118410383814661797948886130836022054225957304174319742645328482100663492843669952358370802861270894168816436326458990297136526459920949376942432261379981780315229778535749028029896216855337892147060100885167806805043764484945583720350824386167496969085180728505,426903073734578001112620417146509321508736309565051582451873814142074420259405364041324675206078055851221135785335125834745297538613608978468731354815366776968439807098716134814276564770795992539739869501301828055278204465499226602180360134210119244471648153940999928351968352054963731820177407885865927236658|26579833924289520389972900117950394438805828628221899849785251193277262506904016180015838661767033925903809658684422106275456221210787145479887893793178117616282806012189342470201902133434844784106437109753666637085736679857929223320267986046560553880930252162405414807068330327382869655263308507921578124762,-12071122961357042682227388807856025622183781701383406123339407125622773263556987057807120839167314088703384163940961495607053608272112660158109007999608142815575559883680071225874610842202742230050716632165554413346974345932440553672309803223445371844345386485359912292135145947019769810450457220546043659979,162236250544606905260439724773080091403174351417582646687611423124289071438608418146998192800378143503443566522030518800544598083530735564341780541276153264296511032654040655556029284610154943880012602862804365596003928006715967740792065055405085248350810462900711904458160412653922105321414238780026013533451 +10018948288270418016780081341685235002997245256040164792426543952818991311558791493453519174957285944783722833865026222848031081817691340856453828555107871396513690880005707344898646359417008593189440903277104626759357903337151059344508962185668959714673026792114793015152022487676173726198202553281736763192,-6995555163054430382942870868581755160069395592106884274460542261252343393118569480209218511916560630596078206970035597385154389463448089846021818488631352733935369530889081823095829009383638648970953617256944401187962256866752201837099775227177656065063350644379695273754386677388279021465213328634933930909,721042528909917874686430575245079781825221838112029624394686069315349560814178350680306853206143047638999149938695007663434153092166743090545673695580676514178586788701941454964134693721185647384090760708127649587795147765724504088383646300322664057264796405575462352962768416720670014119545119956267157763268|33152009177899700335521286237987596749114678289874326434440918518081126413178191723162867529955418655435996482622593235632019894996887430996202492483564865515014035645906573982414795827153656592748272697286574461771116159112804016039989028059075628750439940373451196506327787093378094310321443683918398305578,19078728942670828368834699251746230066071047051172922041653025393624623551743744386999716370764191631344442619983012078124921474009852416209669177199713374821106687471027572426997637428928400364743864020836844501941937756570061589022465875716319591910681201998018650317776190333584438330413688185262916051155,220283868712478416207788658621383280997894846941561822444891957123908778028879195278346553006033805168466857198910274082404942136780954015736899511278911633428569844883635491399257549871333616419819287122510218677255768780334985075712076521491595155945026941146633288297234150638278140903654693829381901681364|86660112777924566325641144753803400410997086305075442702977432289312131972915955256795072094482313726948480079751898750790544713440908592818334342498838917381523558133222779818572943010979268307136948067185583734409642160207725489813897991564467762533071090190022128208402492072833343072675416905847421692846,-52778887618554305290105838041380262564458801465646670949464065301477666757134518520029567230285725793439487930254994645696418125229532386083964770290005616954332222417663293453485136710527439679565903814537080125880293745499032607178356596254426977323351345945596998496291222195474053846483056964155485024969,91256009874012914314189895519654249139544913048606429213352879670217368386794747037392624823085153501261342847050224541672528576684432409807110715865396865727844957353872518329845940826549252426734698443465027159176074936925639415490497467627459134074448093109088470713684894800193345119623601342741289991431 +10019019997781066559943515640881506642517558843222778169026234770851975313720579259773361086779089551884331113250530982852069738010518159622349375335824689350970737457654843734623714224913981064444982445158390435699719229301999181267314607899665318687660691355693147862987025822541914292231182646321427861873,-3157363997717363888291408594979293600171398541934051160356171159608233287859036491344319963143369936444410446129850053542356863751408144208404845266526711359417425663346085658910109244458752728340593138106611282955961606114280076234921423984338932045399865574815874428373668830300085650219459974701588901291,427660300107522994538791232761616142662131142234945666620460681757069587002421636449099874675218488912225359428713775902235016576565531397345002001166527254555699729200052739867740788272516457497859568251192144704431298212101856469342734690447583085607097591547685515622397916186942279884556709767139560196364|10019019997781066559943515640881506642517558843222778169026234770851975313720579259773361086779089551884331113250530982852069738010518159622349375335824689350970737457654843734623714224913981064444982445158390435699719229301999181267314607899665318687660691355693147862987025822541914292231182646321427861873,-3157363997717363888291408594979293600171398541934051160356171159608233287859036491344319963143369936444410446129850053542356863751408144208404845266526711359417425663346085658910109244458752728340593138106611282955961606114280076234921423984338932045399865574815874428373668830300085650219459974701588901291,427660300107522994538791232761616142662131142234945666620460681757069587002421636449099874675218488912225359428713775902235016576565531397345002001166527254555699729200052739867740788272516457497859568251192144704431298212101856469342734690447583085607097591547685515622397916186942279884556709767139560196364|21550716916645018398165650019236850766796511258117069952017796540701386085912310717417651598467640925140901250417026118119274327376121328459299004640348530767025071918784935281870705231282717494840395458987826494640924389129904911635742804398745940919397702998940021391844339448198369222701583556010313045812,17308540888407999086403450710891722292596558140904996642436794702554735336548386086410226733754785281982433279805336861038046891710619959255360830608311138886000204010857210058502793117398659272632248311839231357476736302883731390652600445524351263663967663494261178750828036606884450644013387538641171794195,202180803355870010447215408817189049345827932931561109501494466474799106708426285256026437292412097802628616665602361337631758401467452446995726703770591794057694222974232570992815439680545736890553211079290478720762205284250715176457370298196341449115424087895906723941555883338741498383975320110297668277534 +10019269520234431826137367355034420920528860342846780753959912064827599010243316724633755419135436935645907443407020572618899291215095816080730065338555965834485853320180090560809076866724238012634325051855947616588404872824038021038592555404461140712393653058441964129349148722979422040489509372096847725674,4522869991076735362499160116541059903683984737748984347542239263701333187108105456062644949444149453629982469461841568384073346981390834850295332934943879978241839313265925834724485912067878288054867100877621399054735204930899125650232136163964080568519169554901660276496750207252542508193487574803619459009,749663683253588383775532442379228650764046549728574777396900821733935114135159669567652069917832665405176945410288020981482404785970875873582684426212358839598234585501899432885966938532819200647768194074040482435441119436072379143147234400064595949108182133121869311200924895068707591158185629325001898213097|10019269520234431826137367355034420920528860342846780753959912064827599010243316724633755419135436935645907443407020572618899291215095816080730065338555965834485853320180090560809076866724238012634325051855947616588404872824038021038592555404461140712393653058441964129349148722979422040489509372096847725674,4522869991076735362499160116541059903683984737748984347542239263701333187108105456062644949444149453629982469461841568384073346981390834850295332934943879978241839313265925834724485912067878288054867100877621399054735204930899125650232136163964080568519169554901660276496750207252542508193487574803619459009,749663683253588383775532442379228650764046549728574777396900821733935114135159669567652069917832665405176945410288020981482404785970875873582684426212358839598234585501899432885966938532819200647768194074040482435441119436072379143147234400064595949108182133121869311200924895068707591158185629325001898213097|16642018863761441710765797012067927359722077189969631448415362616699814913503672898852374525215334055299068298216385689523710707393718883505223743676435071846547044089283998146628167129062401919282532587286538467437993909697773987546172287165832896898434018866746267084068433592983100742343012553891013967598,4279618085412193426188644638927864595084294097891450444438077735383453062127268915528450003127312343513730070105859170701493137563013978799842440344152818674511355384686181809257130294212609318791976849425989687196701708107582124757707100916931554678238461537620568164241235565012338998887375426548345583339,451300244762011954040540232948856842185637826616664360199909803894796107535366932948228367749161671550552967885565839529658452718412544695138612399812114901538129955756634712380719016039028157710981132001101643596366369267735875381875175432502771795477425963992931644164806539340880034536557519705047322385756 +10019417926514296392019946929112818021632198703101505458649653394849455829204203329294836960034957633501294764450648155864378373289178486051989714219614702737597295310475376780688730971937576079121199314793519307265245938553456529418922522984552293638273911817508398110317305685502955048568809327523071451646,7901274255200127696618788587659559342110188499337362982289909048078505324309251529636836412429419509644512565320215289593933580545899621400755280134055539493035902983697255734323738954580031486643652880504218537900293807494750583881428021909372888539470375818772560108989429450107579283565673329101511361623,623699550931583586227312516211712634135558043787600676758608115259112248746313728815655527067581286781548781459656217474418345498402764321216306327583412055637930534007526887412883845579485648951016708462255973917762702757210736584322682381497339273737323760137458761222143566171226992185720766268284746949539|33994172292722720621983078916917152805135157553786453695681859425113486805780487896660717595372501233092400041645960826591356846046682770081212496668808601116475820169782887756136359474132767453083956483565660497074117273547864843066209384954581834231890370515327604527171929343867967182910635357940103381259,31993846672125961531384598386820046988679306439927918439126442104342750287165534338581303476671621941233213276321267207968356271919850887377330275696357098758109012385572207725576199219446164534402970313646005215676387512077572153065651471880735849343888575800500099273015977254516159942552263434250458169021,190897440537416564844354648094133803032782149306929915760090455032909782181885170078703110757010607891226613247221902350507051587112666985339761578838390574506735798985627221778883031220656445342689661417080864579978266745285225101384742969161503945655665695989381533846227380883303389726073267640913232240808|46223752318790909370837447383363380695209474743451082994109239582734730617406604327737568722130199854939421799114849872972877989567189718205858628003551407137904188277330292052370440786619825504842930785565096667031645779355485895793277208105594179243179236367866554346063343397949912203277267219196168228342,-11006265064354212636439188801633654461277681721343546696389358983928696946083632218719947786058303199938972841132237674419697191902116627029793522898887023505508883048022803011324802659223889838681052775013756116093960676539648227562055647315361638076266948642978861465645013053193461759019970585499519918551,135510058813836316466595636693848570774859961098724584660465530747418644245153590246150906297996570248784693174475582519076799984652691145697384165112598092893383581702308752699625740019767305915611482144859189733431647333812818245189583002227073705672065057825892795634209388635037930002295896526893410999911 +10019602901864092738325953873535047812547299524695025320532290515768840900630595544396879008556083370139972255849271116199083634435552540915196064651229780380925328336224573551564497154428220750159228126503023660786371036661986963326869101885946108118123565859605937169197265825780593487194236118858010532600,385562394428775749047853575173957314087625602564743010180946094529317438985024787344743900106472493168796231871305499111699051361035813309229378162588371556942740300961721890004066420192802443990741112403096930009444198021764517249355582327168404565052575639878289683556483174213973783173191751884045426337,783418388779217407199495491198572563161785093246466615634830075323053502538909242522004194931674520522772536562755280126097220160459899598091584353065112800205031495803329979380114748688327366649214078234380064643848371559165846159884696566323937944146599304471519733682046929885711023157291005000370881207583|10019602901864092738325953873535047812547299524695025320532290515768840900630595544396879008556083370139972255849271116199083634435552540915196064651229780380925328336224573551564497154428220750159228126503023660786371036661986963326869101885946108118123565859605937169197265825780593487194236118858010532600,385562394428775749047853575173957314087625602564743010180946094529317438985024787344743900106472493168796231871305499111699051361035813309229378162588371556942740300961721890004066420192802443990741112403096930009444198021764517249355582327168404565052575639878289683556483174213973783173191751884045426337,783418388779217407199495491198572563161785093246466615634830075323053502538909242522004194931674520522772536562755280126097220160459899598091584353065112800205031495803329979380114748688327366649214078234380064643848371559165846159884696566323937944146599304471519733682046929885711023157291005000370881207583|19818230550133203045823734101898906263121512206428289485014719092970295967340599816897147977749512129070950063889339566610951920388554330328298156066258170373411927366975503222525343688945315211747565841144619516815319867733346621311891854079913905473945585105165350274151561111090081792706060108559348689465,3535705381589141871228391312322719660822687473426523492896512078425893509048104602680687792493669387659393458499063851065894084002514574997947346565631807028562721897282782831306960899838643543821499923380013426924166037069379808013932912663720597103553887305082262913905822119893857258661880909162082386383,396232614221934638032209379440961132627800399045535096109310461742382984824006540071415151913091585171033970335144034008200593280126662125846778006926029922409396791751216059456912978293211117174561768028351334637727875808828406496707486419218523437819900629926847694284488804630237181598046520852448325184912 +10019618759445604574695938593576587154046024907827143734869384751181580594765954554297229655147503034078881467428687208204647162639839815171638500727552711523715462319701731893862102462479728615304020826611064530542284194703939928285119162487825469366941939907341692107287635698074740058272417655173119766470,-1495231899271916161022455577964100860902948284811380648472435397705462086200159484323324090415310461943736883556854457678257712744145878200402349694425772714427495950140611274533744925805188738644517051127445631541048041016411029423836592778690668280454275321001430386581000830461603779827661500573849313313,783469223238034771138196543049546952638608016561545783572815717469547125551690528706587314602219345674223915943792376346892343135362218779360461138111067908088830730205053230437782849794424701715846764766896886615248793041482000930114725702333293352788421520623938402925312326001614873502389289399996101695820|10019618759445604574695938593576587154046024907827143734869384751181580594765954554297229655147503034078881467428687208204647162639839815171638500727552711523715462319701731893862102462479728615304020826611064530542284194703939928285119162487825469366941939907341692107287635698074740058272417655173119766470,-1495231899271916161022455577964100860902948284811380648472435397705462086200159484323324090415310461943736883556854457678257712744145878200402349694425772714427495950140611274533744925805188738644517051127445631541048041016411029423836592778690668280454275321001430386581000830461603779827661500573849313313,783469223238034771138196543049546952638608016561545783572815717469547125551690528706587314602219345674223915943792376346892343135362218779360461138111067908088830730205053230437782849794424701715846764766896886615248793041482000930114725702333293352788421520623938402925312326001614873502389289399996101695820|42753617832955580018896456376048021312038672906196490293353833260191208069121641097415768067383199309083970209480148720670849061245193936234205337011636997701073642429299438906449136644520319530218401933372485811940869805081506160718825508067884253210821932270118450554609943933258707984251287707298966456434,17230882403850817862353558174953648187864024855604030801497255731670352761964080837026196910757872387822284474688098560486179344653906733048259368377140267627812727873134204479739477928295254560644024291521347574950750033700697110313592478883239065168888362080121017118321399563553912315660492325767550439625,185334720796235401233770375301583579692277465177160979515315309579304038663377302594175210667527463523713902806451243556694869849316694559583762178930255061453115298736511664428765337617081386042405590606496094216885684005811351670599975552269701611841562351169528636440894665534868320186990351387365005093446 +10019692946699738437088786776088494849594837049086417807717694310404351446172508582779767667693745900344488207593378322991177040183985344860702086830308533532509706853397521152883298228273128452797173239342923997882671035778655648164732292144430552486960912845252279998708953177942214236682313539500552760871,2604527605619485478722364121534608303298155156200794123073555280322873845863667712157493176540131822726294136122515227024701303496679207443255980148330176850776277321446427192954383305967741429509598325549628410919591073607402118557146971439755257250099080900555940132394424289156437827280461319685081840835,500718425039020767061203454192505123268716467124573838196978962956303476515938135055207132642966201859533626566887497521633145487747565092871485790754737106452537951081291971352805654412531250563576927867442028177911508524615458471957056998884949042800057393476930961808638050281181278355398049850987480026266|10019692946699738437088786776088494849594837049086417807717694310404351446172508582779767667693745900344488207593378322991177040183985344860702086830308533532509706853397521152883298228273128452797173239342923997882671035778655648164732292144430552486960912845252279998708953177942214236682313539500552760871,2604527605619485478722364121534608303298155156200794123073555280322873845863667712157493176540131822726294136122515227024701303496679207443255980148330176850776277321446427192954383305967741429509598325549628410919591073607402118557146971439755257250099080900555940132394424289156437827280461319685081840835,500718425039020767061203454192505123268716467124573838196978962956303476515938135055207132642966201859533626566887497521633145487747565092871485790754737106452537951081291971352805654412531250563576927867442028177911508524615458471957056998884949042800057393476930961808638050281181278355398049850987480026266|15699856336284744968275216258343503146645953756650748657692246165468174044843605062520381697859516745152728271221936503804746010309726370554190521588468426695997279591480421106636754720909204606127286384900034321176510676319624471022876412905986167145718126102692531020933251202001854123564019876070185880355,-14062166839366990397106911248374270143217677864591057546982352524148999437729801685798965579843060529335708158623771293637111706433187114619631528674568287241750380206758693785598159577574034470606603276333153981703961125634290277406642003061722480822932526131741380714977106447263763374124622526844984498859,322600729981396869806359195462894217882445977495880795669692121484810837171658548584546952485525802042033579797467228310295552846960328437752401071423653349872764602844139832402563063433112043761099494603274082871711473366936549010464198833941650861319850342621348528624209403813616631484437129382551268946870 +10019878828465334585310006306241539349820320632176313877609501227637096062920082798688866463474161563221707726590576927421178038553651876427988000587231398238649949818114022781306536860520405792494648694702226319794624629000713829609168795402418848754413215058377284034953425744232395623600320736707606263601,1457969396702138085449463993396644727452880810876852537963663018612951369129008613129868381569339225995112076334917995066335564006261425730889703965704362733694154907573251182502287488642500690958462811412545500622611307129116327910472660655763332350656262023349742750811995788737019311563028749123005882623,450291340913970001914821927902049497930656487941189505155449421740207064831253795807819514379798428822187833726946052293837627776646264129023306160855543475421211570474321370516290659041655321190880413623652464931091503946846331738732993987858421621514193715128900207229532916132573315382608752305324170212688|10019878828465334585310006306241539349820320632176313877609501227637096062920082798688866463474161563221707726590576927421178038553651876427988000587231398238649949818114022781306536860520405792494648694702226319794624629000713829609168795402418848754413215058377284034953425744232395623600320736707606263601,1457969396702138085449463993396644727452880810876852537963663018612951369129008613129868381569339225995112076334917995066335564006261425730889703965704362733694154907573251182502287488642500690958462811412545500622611307129116327910472660655763332350656262023349742750811995788737019311563028749123005882623,450291340913970001914821927902049497930656487941189505155449421740207064831253795807819514379798428822187833726946052293837627776646264129023306160855543475421211570474321370516290659041655321190880413623652464931091503946846331738732993987858421621514193715128900207229532916132573315382608752305324170212688|42833037907205783423276083695584027308854900022881436412191284154327219859963073830726581978719142468079055995456299937273491938799745755641832339881754413481117724798837471944396287268574687471412696368395253559323362777618554120629431245413190434891698142985970974309630607227057049486649455303551234276454,39533289765204979838239940217464189791925681811448897199438008522556423440885704979337332145873978223602711609006720684578384015360399795422483770905500296209984111909778890881255526888804755991926913525266473446809003766056812782710240729514579954010888129016691348159521572577875112811888010834450317724241,114445618247053384708154338158850812121782306445016732813783780022720172489813267526238634887903604880900808775058943405768328545540868455633901730958967680579278364092793074061036266572372464072327099841482886966487871555516444733955521438600902217517451457471166242011115873608622049499975622745683155293044 +10020286611438471830628019358455663881253310586699113562825236385112929540691864656311239753327727457544039348532845219250052901384983806849838772233628634015372101882756673893804993295286755978494686187836862364142553996432815511321224683238615875757382081170105089085250727802357622063598298344850144933258,-3518711690583590719591097309663537838033234040270517781284035777894691716513958367977437977244707408588621580445912322309023058291956527967904833369032334021917801602130557563969030363343390282689269679494383594614447232630864097161162053988664606910387710340058810601198928739842230703566256279504206597349,624519074467883157241759882142650482668439956786299222741478860768930417779553600133573019763129305374619657419598952403430928431333332942138935285782814167747294995855160857963617057240775629113016734743963566849367848417555290458534979590030936513460373735155075741191499370817771701007396549636851814063246|8984140046463484249883815882793946664284637844291004682379330614023973939307670161213321888699915249072065095665013984357459013131040423611078930602512682262356539184355252741789076484547599307370908468303880417320438645852556648240043112769759543510509999231273948875843246292758661134579579434257790056943,1015829211229239775971450394627474475125445320143707214965330038892897841144751214160653701706601947354240523693277132829250608515076685164228306669891554248890083979225036216154539270241518786129131737028646904986272214000689553330402618431223976598945398343370629254397826639390022921851207744783430299181,696229436805911789845333715373446839368886781044433762113742356470360747294068486152977041956647781976745992022313448046591023280602965461797453603661925762491060402477228052040796508933029960965488494546655270327536485285614615574903948243360057525231142937895796209410153481097105649076038536726330776071856|54848884991217637960566999744777250759299676195564728508167267655054271555707478739692179275489551583228746099712696785024768087317010330909987410610335755940330039266190842809649304513680352828151859917245186776225281746820196246056188053726348717015680880973426980177317094806038726097322528009147634772745,-6297694570572926762876118238570574530971092334512760425031884066392157325338148271545111848669911902764684562706179269339278979620083804367858431071965438609706945865206821584390347519912299967269039438763099113180095159546022212222371772149775642184659607016581991317838734844206339663600961049231899483767,114217089877346912860627247021964232304547591103532855496244374445579581677534108677722729277710412822218846458954885849274521645333106817369257230151814552428619784818123898009869914417388072106361002314975966932911313776975771180600386738223895005689517440276702703392932181245821359844597699717902940161882 +10020350829980446730171851653876883566847163081423697114380946239282341122006641305758856122547334357120649922140862854047676100901410759420113771337592330434048703781028710403003719890979006119445870636592350392949743016116360518402562929646175152381835283065319457849053035555929737557936105886116269575510,5109280702416633154295665717802160083976280911440360164357040723966034505263983198614731009455276771449649216657900445462253241694441028125347117381803166387820276260518904247537793302370100297043111469835733504997940289628818493126591029673530532890213508380205622484398576652164337711722991311438354895077,783009249844890893386725492620727464553802137797080547324163831661264002221403011235072342035014102836039015675936188668078646910670188403603171656900915122608838040537846311585633442130109085368959065613240580402159306705278726186443869273434480098383561830991110484097132938532579731404550435571781667457120|10020350829980446730171851653876883566847163081423697114380946239282341122006641305758856122547334357120649922140862854047676100901410759420113771337592330434048703781028710403003719890979006119445870636592350392949743016116360518402562929646175152381835283065319457849053035555929737557936105886116269575510,5109280702416633154295665717802160083976280911440360164357040723966034505263983198614731009455276771449649216657900445462253241694441028125347117381803166387820276260518904247537793302370100297043111469835733504997940289628818493126591029673530532890213508380205622484398576652164337711722991311438354895077,783009249844890893386725492620727464553802137797080547324163831661264002221403011235072342035014102836039015675936188668078646910670188403603171656900915122608838040537846311585633442130109085368959065613240580402159306705278726186443869273434480098383561830991110484097132938532579731404550435571781667457120|15925442580907323476159397125803944340654208405155024852617286343514956884706735535756801413937274485810029110697926230088903038708172843921662902925858010133310107241826173293821650453674715296467364194160263065021258375363251922427504055324499581378214158250201451314577475359578763255572268099357250433862,-7555018813268449946347299883155637510823174468910058845458344328340586029132905296413170968626375161086356436888766911933184468019856845539645923943455062521960029199818385839225962202237763532700191551972267033706448220551883282613693004882011515763441495954827960366711246754821589418038272565907011571371,493158713590448502858812148491777446425856175908645102112390069549258575786631074217529579034304661646702428496672314797453719364387931287920597953147023776521758543809562386644010437874871311725548645377471116791426470171042917330992088151061235643311858502168972419940204783448967903363982044887911681560644 +10020520888850607221318889209733010855356370939979030352174416847268871176606842611908448929226351061331244222832181615393476121893202716429497688626737367070357875341852767661277331348237224754401428337725087948250057680576003972340744936007808116625981445480427395587481367415686693519322831225744083857506,-3510865184553106032575534381192821350315875177100225193260562098432442799313338094676188269972656054940854032321449718355451351690660219631429988981801589127116014570347706272895437608443770068021130141264825492984427313262655182236186480543751195475768423487011396127341338009641051881511727659162848161119,631736658355910953992723930048397079196586052511742763210137641692860240361410089621711682505909275894759266095700988382555714505394268624248297891868203056209475282038131157087467910727013960998888913755441699771876897234334835639550616100989309716008969633105517000398222168491114030388197708472040972683126|10020520888850607221318889209733010855356370939979030352174416847268871176606842611908448929226351061331244222832181615393476121893202716429497688626737367070357875341852767661277331348237224754401428337725087948250057680576003972340744936007808116625981445480427395587481367415686693519322831225744083857506,-3510865184553106032575534381192821350315875177100225193260562098432442799313338094676188269972656054940854032321449718355451351690660219631429988981801589127116014570347706272895437608443770068021130141264825492984427313262655182236186480543751195475768423487011396127341338009641051881511727659162848161119,631736658355910953992723930048397079196586052511742763210137641692860240361410089621711682505909275894759266095700988382555714505394268624248297891868203056209475282038131157087467910727013960998888913755441699771876897234334835639550616100989309716008969633105517000398222168491114030388197708472040972683126|7743624975856046040306859618381122855435839505066655963077953345318192394961725484815279361678840380508650449544352702656790861663924047145774380332205220566837995316217250717822771650639012193352578327705393209628172084550305955102732361657948117240351750958876943333563882332223706621973470079325216233558,-1302101084353535785220069078550654080595332453473298993211431176604229397211571627224468015823760998656644913758576425096529602829962318111227560243799515644278666734720045652589883053894188670485823003998604116205699634345292108055002592831517880997584910995083278522924829895139882422136963697022188627761,817146068444645002282702401442161961453363715531517354922416373299365609662611633811411725714915989553805697260975442785287852917015804775140015044436435034561860932937633743951090004573111260937285724402644730836466114286731010063169028245934842509507242843981736397798548000353928823827450308171577842094862 +10020928293252284825691361744328291985679526412406671670547266480511907045983316758483586023724996977667177961315263269397743828323222195866600241379821175298238115703011379072606569390759148045042025527825985903353933863183965714600189445609817913064133950477152949408914363876047922634974111379776851043444,8142743010559227647391965354039043610167208616578224783916189122845589179285287981476385252457789283574398377141778580365522603626148442954692842646237080732477747098895946414915542936790529750280288364463486949414374698119959104763454330750738981793594749326992763123032351693132354526673391669903228534689,592964939014299189950759948556152413778070028508201513223477782517837089792535061751235218815245724595945353108562584681842937744985593454797280372456160144528618905336752579099036263281502692258180148097231362749391384857475259373320991218168838336648271137666762974150421876463236269917491554488254970217679|1349884692028663713443418855258970852876197688505766806916101525225125648882224033090914393786384981404185367136201476426040087000294669320520442557740324611111940178669433599306350594555401574017007121415045406126185440950248044705540071793090107212207268142684391021538262661004297297377597036659211434174,875208077680684118200876261868445011629698306468238985964846580756586701312125036248886125282325554453814339944800057599270619114144498434513170361313175501368378946075602194132049645256086611958223310749365652107262190169934699379958455541016773996539749758645125590779000274985163557422936755735709025447,4389763511378485954501282191747251660999265924712682485695638493214865378547677386856476228802410653501422368180730844272453992845175409659922990510986478738442978379229425566565975718386747664393902959866984083918397026705604419570614664652992630348606149487368881973666571039701786237266865588917768672714852|5132295574467316848841777686734617679960174295612803556136691640948831222631657128041983413228627956037030789543068853182770008751639881188344733284990628383483491534738190385257771536358960825091917844011611151709882253457446948086421180899165481250089224998180312937340245384853080966454437114981749282088,4739229759958591334649295599424854432655955954287517912213597569502250150023192426249576133181257597090869245470242256174272934097508617180274802785425851556700817333154643929185825330049486269453049410315760063060060300773867433992976428473895933388104059320286367359084036012644394853593574323294698599047,1155642354763640840161317866632512711606463189115904666846240158382151567767869875575965412366883980252176109447698054839109820546539837615968386168917753356894372414795267678454138557008897676758489406076799290056896394919016510966326013771652656266881913835619564662608220574395369543699406086980500479286021 +1002117978472811787753331928095730917976095264113100009019616793747721435107135088389509812754479746771762680547024275550906766428627777497396364614972130274470274918515966945652987824482224985008334448385591915791378703701911471719689908547324909949135740705163689874051360252727792128439306172396510982072,-605384264858430906616142488992272359132356724983679496986875094989266808748892270936577381465129550495430948251840196888998891525556778784313001078991820767039598015715393254809115469379426480017252950332375890914475777381882010670869152139638115965300974540658001803028482400664131564914546111105190254697,5913050976191825085156815974405378266929897129377882420061135471366299940142986781640170880340909029950997987433372868814199338484242838439841578708925504283923079897355159590243914836924282498902916652661483948536914918309139164893684671128828548900808846820323860573206533041501286493089345814823705125482184|1002117978472811787753331928095730917976095264113100009019616793747721435107135088389509812754479746771762680547024275550906766428627777497396364614972130274470274918515966945652987824482224985008334448385591915791378703701911471719689908547324909949135740705163689874051360252727792128439306172396510982072,-605384264858430906616142488992272359132356724983679496986875094989266808748892270936577381465129550495430948251840196888998891525556778784313001078991820767039598015715393254809115469379426480017252950332375890914475777381882010670869152139638115965300974540658001803028482400664131564914546111105190254697,5913050976191825085156815974405378266929897129377882420061135471366299940142986781640170880340909029950997987433372868814199338484242838439841578708925504283923079897355159590243914836924282498902916652661483948536914918309139164893684671128828548900808846820323860573206533041501286493089345814823705125482184|40380288636863554747802272146363479186663329648459490067115808757434033306882038739884681373117979723495792330864501446629245889731229516933727403492773771957483850679041758865017396807842498482944854723605982182982516939476048881995525535805104281408686338183559590430185038164235953706463250800021094604474,-39534865948835591455192703514729394748021266253728249692602243000799548352268225360374954844443730084878434721021241498114475458481167089270721522242274850596448738616202710373135498775106936938952151771547223007405550740805387552512761050820125134092471485389585963771433812018574391368483598373549383847189,156418754990595886837540510636676538980249340054775526675231187766083040611703861850669234853631535367187296945071108522620946681763860321505477715553908841995650918300850635601347255855518666703848642329714582982193362014895765955759528160104377932684150225067984397783920984799879483126817672124425872829049 +10021358599463053436428121851639014288861925656265693598359693460594603335959883569550641125363212428397536880700859686977743945025535807563785786052244914761332363029072620567677261483868230251440566526595521949067385197316983806258145013751454322468391099167319094251906044804264200412596430324237392628100,709083183297048652772820333122772466256400885278203522245823989743215866042577745109340161132152908476855845193022669210873284198994493560336775521366659865852432460708969754436068709338598181470025481044065851120985245468046464349075382208377683917405549429133970439515821299430661611942330536123845644949,516570730285299534762323653103362077033679349887441156383985263227144702832028548168588332437855509742797208817471793880841971810641558363411834198813856099949994799818753787070184420373328485385171466383296907894871575302325766835865200237080249407408770698788688709844525521993129914019403957225364497263784|10021358599463053436428121851639014288861925656265693598359693460594603335959883569550641125363212428397536880700859686977743945025535807563785786052244914761332363029072620567677261483868230251440566526595521949067385197316983806258145013751454322468391099167319094251906044804264200412596430324237392628100,709083183297048652772820333122772466256400885278203522245823989743215866042577745109340161132152908476855845193022669210873284198994493560336775521366659865852432460708969754436068709338598181470025481044065851120985245468046464349075382208377683917405549429133970439515821299430661611942330536123845644949,516570730285299534762323653103362077033679349887441156383985263227144702832028548168588332437855509742797208817471793880841971810641558363411834198813856099949994799818753787070184420373328485385171466383296907894871575302325766835865200237080249407408770698788688709844525521993129914019403957225364497263784|45614503146354773723748422556503247371485318543120586857419562717702458851951901017328552145694380945314803604713256441070275022414069445773768101699000362770774983002903055045789385932735047082208988353464300453066243128392263161058473354625441431303590972274514200470903553097396578608004283743393727480965,-18121746874119905746733087661833019801123133290011543785996868679743860577167772600952885673213204134707814090152450287251108460725457761668330446170883400606809709199165941064933022535458655256850936026007055165113021346772772048647561510274730081303287537167422875133875982474754404203878182518086566378039,115286014209231820841785285504789236723202458419099047051127275140595097884705397561562945865060894329450657461353202401141562369532605474636151114816630008035888537731586842019104642780200033707263419710825605300157241899226642312799356394901240315456385563221341513078098381767868711376025198760539717198382 +10021467180917602737976485607440169246689782775819592060097133723376896163041617997117690261968456452635527584517534178504548298348503697184587408892932776130526709512085862666360259215825375712520283335147827351975626062358619071671249870717811464295853663335144999169566479738875598518880232950110692415860,5837741371138928752178739797917364838658798118140089345232324713852930065920933839519905580179654383108038638880741427980662680469791777270068068248248823295528533080598248956003543247574941878960563240116001302598572351690506654603050328390643642345907246472180377442808566360199364409627306574545050404961,447367712945794368035040617182455309390859836657260473211881159345841479208328013611245196832742331205848397804369783648021077720443154207595416670723327933025826385393654289188255079761853719682847837385185400997339750661153486494578411301935184740783631461198583032914565210707960404049019611688784713553950|10021467180917602737976485607440169246689782775819592060097133723376896163041617997117690261968456452635527584517534178504548298348503697184587408892932776130526709512085862666360259215825375712520283335147827351975626062358619071671249870717811464295853663335144999169566479738875598518880232950110692415860,5837741371138928752178739797917364838658798118140089345232324713852930065920933839519905580179654383108038638880741427980662680469791777270068068248248823295528533080598248956003543247574941878960563240116001302598572351690506654603050328390643642345907246472180377442808566360199364409627306574545050404961,447367712945794368035040617182455309390859836657260473211881159345841479208328013611245196832742331205848397804369783648021077720443154207595416670723327933025826385393654289188255079761853719682847837385185400997339750661153486494578411301935184740783631461198583032914565210707960404049019611688784713553950|37349917633767587717677900017226055640277491797128368066909216648299856708848885314856667952257677125356703617528489552040640666031343260644627231518748509259039268948250724796991429094425535890736981916444739110193691988414365116633947866879178749608358114634543684726462828729304210028284694641568628398966,28432301470760114127472799211494908630719349909135890789013779669649467182102043473145513283547284407986093529470668063517370252190889483927419539271833812410008532555047333957640590516339384293520187649830718680466604203963675273404448810489933228206090139475240540056839557201036234130668781355507913201183,125217411042216743409615853418748212447815557938720716586287232669270939052168073429461670911284540249994159813915524580152040717865022372477773851596046555005754956888615646701914356508633194785367798807957000924761874706728044310360895862676117058335122487191434401996751617050877596333038588838996255145412 +10021498468260956088123000232540981309673362233093607160766199611849988598018670545801586655713528191099718167654049219862424879654097800612715754405882205966256512537388088543329708772570689386840584832681600027519346949153293344313097460804932850840053785736778266237521116511372386612740914586110495537184,3731424607272136278046418371062826309603938690430502989163037797814883875895107208656392082954628965555189423854897982564780098075475012739517997385664143357277834178448678167762594236943371764347482562787414335427396456552673654489280935057856453787409277651050808844230948476551514072021069206021678774679,804130312590685641878596579775606667166276173286759021130255643061750446804433775305738231667374247846782607238734204509216228540137516790899866440807044660490591982953819190288555363659024778526537985822773652575997791262130221988665167762257066646395773224522658242462757313827560884465576118125526400301268|34167053368438934062493883132954265990697806318308586148616977663701145830016368570117108522767165162437388551633476818714638781998737588453423052906955047313659481428825017492981415212399429876112133486106544289854247118707826610748061980313138870978861241099932331052851628733408772936072321439631381625681,-3231990625187035132148669134941674343311291560670575472626948487039873506375201953961203524971750773872175368844083313789606744945666601496978495543448223413432959722175027775640416642119534579082078058359377011061266769493053544073177090778768228650034186796092538667273516567672252447273843436045477135595,235833074847574898390813679013790646015645150909185733872405459206523708909325302363230937825102097363178252008781874033668789787718772243559737247157023625992313606650868510119173526138833975525463395139358451436580786324137262685697090102400693677208248369147898653293586089386800659102730021728025849255818|64608837982278224108987963939830921137767130655870201859314566649037112194604993755919994541029928783963356571015929786284493006279718103094473109088356869444636451105877134516067500703977445578997872357043341015093673550983708510265625469154579844276561631683451922580837098594165662625287526508058436293986,15854906341458894966500422391448052536768193946037447623218750633953720338742777805649471066920966160101792990529839212517155533383911249825767111242302747793376405376781322851763232537121183798411448041082168628199040455135693063512226758138709898399548068871039436946823094929235771529576088321067557016361,125647737690478667744295859750549841902875194170056775019306475803353424716724181236654109541003077830795994847519888612974479612555855274394676374638319448048091194349835875247946393849792063872096400150096455332718354245732182310596592154379165437563189009506346555534189191250868232374253149843604451203312 +100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|97265337163108204413956364816446311461172514617683583383746668715450840222180976393430496104553022674333721978573099848181220662887846947468935453182046364733749916475895309307017567642434296055225121834950440706059303257140878621147190170027097598386070490643511792242136161870345758898813890460055238965518,87547457109798873839305649757452333043926932497015596041815056726077989206997009131840148396020804211298638181409067017194388111483773222118240882283209994405160200490126585806391098433830826470475358556954973925001096433563812177048160467037091694157852152308504545492956027258260588167152638099756708452923,102515957029857878751803789736896993327202543313952394340885451428025600212535749454672085478483321275958139112689603772374702592116757008616636478536965453679964666255956305064090090239129654015924433954512354305722977754010864408774189090428174122344384620043576093595618564991259055360564491303523423085863 +100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|97265337163108204413956364816446311461172514617683583383746668715450840222180976393430496104553022674333721978573099848181220662887846947468935453182046364733749916475895309307017567642434296055225121834950440706059303257140878621147190170027097598386070490643511792242136161870345758898813890460055238965518,87547457109798873839305649757452333043926932497015596041815056726077989206997009131840148396020804211298638181409067017194388111483773222118240882283209994405160200490126585806391098433830826470475358556954973925001096433563812177048160467037091694157852152308504545492956027258260588167152638099756708452923,102515957029857878751803789736896993327202543313952394340885451428025600212535749454672085478483321275958139112689603772374702592116757008616636478536965453679964666255956305064090090239129654015924433954512354305722977754010864408774189090428174122344384620043576093595618564991259055360564491303523423085863|36966589133632021596451231446360613869218644305972974964188922476722370035917724082641341991636532809500406571267262673636673259154835535079572834230006192461227395506315158937114124659074990425552664025796331234355303904150803244972310400202941266552149385712614489884410598364289566113507512621328083820598,-21149549205459986335385704446469107610959268704221609170214996514478740430167085550085863459876947711137447213809502018277525104101042350103376631096271919925064995296178696672186362840988476041323653097243744018198278462448741240768165379772727430920245528842325914682295445854217287403981994755438946746143,220927487842748418739085114242513506611909793723984315299233121420377274197319470229298268289856409101985756388437199198962449705412131211265923072982106236351953282676471404053070507026981693842676184502073850443982862759823135849927410711140706664324113248738142786497634534093355523248932828221913746822818 +1002171279912987474674729832690970557140429555644292059472271841324924331291685060249454596336585889404705002700240738701699260928512934819245660001207610075089195766056310376194900771895925996113770666776022108500330653518924376342638824072832759321658474598385675431858595122771183526939999696158578609708,826219028959713490046361889088584439498783654783530925153550597879152616132729000468702177706363955325292708928091882754198698376648310966516057873159349764829040425546512821864182430231493467696041840597321743210951783900165181749863389211006249005916285731575237461143803624956905795631847651371075603271,8037828098286918052259824988376802356784599160404526733485731117320394626772712632224126968007402853349764765913068975115077635719542022449549397610278043584259551667143554443745235133704301422592616247052815801996895563245349515275951060813799742580455732670079073038616591480535324416008144264918698168050014|1002171279912987474674729832690970557140429555644292059472271841324924331291685060249454596336585889404705002700240738701699260928512934819245660001207610075089195766056310376194900771895925996113770666776022108500330653518924376342638824072832759321658474598385675431858595122771183526939999696158578609708,826219028959713490046361889088584439498783654783530925153550597879152616132729000468702177706363955325292708928091882754198698376648310966516057873159349764829040425546512821864182430231493467696041840597321743210951783900165181749863389211006249005916285731575237461143803624956905795631847651371075603271,8037828098286918052259824988376802356784599160404526733485731117320394626772712632224126968007402853349764765913068975115077635719542022449549397610278043584259551667143554443745235133704301422592616247052815801996895563245349515275951060813799742580455732670079073038616591480535324416008144264918698168050014|56177784089692916832266345214421120674340798487038570515623153805048107174705903801913422904686022519185882309714950449353350144136176082122642988743155385846519789014579069658520240091050781441562176069717906258293112423657764692478227614483398005555460543943687308770699629754468588531994448652035243537193,-1367086938896255072793415069058299472671169571526909227192393757206171174220534221238412428332819898373711167739278653738196147736460040492805449727552702294473184951105379473908985544436596593693459127262500591594358945429165046595165680187593280155590732587752336804926254680443537232304173256876819864345,143394353759539327949427865403227850259090677769631111628953936665415814894670562885615312902238352976078395198035416430261300974094600135242231268642783230986499797624830094698405716034919055851528418996945744623233014619026973652777892429824489371625486460871462705495597542593148226840678864076948049036056 +10022430537581100668502883292824778933607339338765926026805737984600928768394291101969168677779321137283218236917508266473465030665219284863536608447940487677072083129795072785840083494425556238492937940196822995238448372796541954279303435932510765640503040286741618037016213243353519162818665268721728774804,1745450390765598318476765814191109791291817192933930838487529317598912090407141417101048723630667618601898718290746648849351810269839537783425961583377520701947088669609241693035013571476458016904170389418378228794668337339954300480921565354479003099904568784841604791321827362751710640603340143528678878307,505461416773210200375665916297012066614237052797213136609066313311545733018491487357728242574093909073856795981653867763762281713211234379922321747443616377604676750509494828442443340820844933440417718090216464110039019539088373064239526712549777394214168807828906636896179669124200810156121848745927583143473|10022430537581100668502883292824778933607339338765926026805737984600928768394291101969168677779321137283218236917508266473465030665219284863536608447940487677072083129795072785840083494425556238492937940196822995238448372796541954279303435932510765640503040286741618037016213243353519162818665268721728774804,1745450390765598318476765814191109791291817192933930838487529317598912090407141417101048723630667618601898718290746648849351810269839537783425961583377520701947088669609241693035013571476458016904170389418378228794668337339954300480921565354479003099904568784841604791321827362751710640603340143528678878307,505461416773210200375665916297012066614237052797213136609066313311545733018491487357728242574093909073856795981653867763762281713211234379922321747443616377604676750509494828442443340820844933440417718090216464110039019539088373064239526712549777394214168807828906636896179669124200810156121848745927583143473|62092481921639574438226283198332200678734028657724766941730022043809545444204108322446905830622252301375431538847493859046365695561521947886739278282380330944740137778796806258440017010320211759144908638103476555150573303911926239710190937911611647166321874200336757808613044926465128049757211183544247137033,-45250053315775064910191280612561362661486537888549446589078696876018947013616669550765115160411532144837380748629686624052593601626644191366587957076497250945144687082001936959339633808733565487985938465191480629685961056777143827741613522372695750936020580143021192692134512265227690413020620317312128938767,89818959533274049458857462069020739338602011671046728330943513188118466840658369260446327848180189713317967953477747595755322234416809755612045527023070344299134617743385420998285144607795275808302453674682604268889767229654448620219461284821255145925444306004911131336470833940664306256327917520781637949994 +10022447467429108159774355787589122715485396978224199367300758397771363796346073591552810427326339622121413685155961164725589610901918895551781900417862806225664599680621980718988526130452221161919053852672286805155084312599146807342205269705230729665300558186233143844168304167857171548003707472393702474384,1188885044590400163258159304120537014931301063692806659646722818307638465604090862597898645794165661603569562151904733849823451481071963642820939826997500655539582070601901658042242359967350311563512079177663668335375683704849269904109356286951724174166294895547399547486092075854607019467491563004574181747,451886511793730238078310968270671960837012936994555807769579552350299617939295621484477388940254813126337697555682035175155312684470552706006082326229489214590934446980684912399661406451818153885180492656373585024394872163807899894979861799817481760468528780471201306793514412189815424515752868704991093442748|10022447467429108159774355787589122715485396978224199367300758397771363796346073591552810427326339622121413685155961164725589610901918895551781900417862806225664599680621980718988526130452221161919053852672286805155084312599146807342205269705230729665300558186233143844168304167857171548003707472393702474384,1188885044590400163258159304120537014931301063692806659646722818307638465604090862597898645794165661603569562151904733849823451481071963642820939826997500655539582070601901658042242359967350311563512079177663668335375683704849269904109356286951724174166294895547399547486092075854607019467491563004574181747,451886511793730238078310968270671960837012936994555807769579552350299617939295621484477388940254813126337697555682035175155312684470552706006082326229489214590934446980684912399661406451818153885180492656373585024394872163807899894979861799817481760468528780471201306793514412189815424515752868704991093442748|40311793122681847438147936825674014314470693373123318161207015676732082581716792137317735331938108693356512243120485847992937858572985495883514340613966135614307974866016309204238807033530669264492564117724246353883749827195305324197399377631361609176376894124562777952015115546002574992839306368859847102214,-33025539083635098527284543501358773726385310602673068647569756256609245347645406103541323476799319282115094670558563042038040727572072629107289743928712116480609261863925810781181839890265471330792670893248452312920468922228853995606392415425665874155050360471274554137526685669823510791388257867791420447345,119104774305358145853754696022566395542085319811674406549968528384273306539129655277119394569116384064134522924495522726505126314830673393570305912602792523829301472113875383292982915986048501532006750975293601050038174705411480721485112499986909208662941192321772927410908019836648310546774872889908741289549 +10022730206246523605885847628248331589129959745152946800589982371582759735440896033124734292653525513269378463322751069994968860121969888496580966465696069881018097413525001416210515174455496944629883370533539582159385347137053307519490537337422600372155743988569466107652391801498216166822344049274248006914,729727310531644666459577636524370584122920562232400100508958613100574209791027073647329563436154072167135037277674792721862334569450792556614550488339055151138688316081220432057278684502305768700617734898572463248131416139418546546921772768563777642345566507958981323489827996692750181630164696164350792239,743420530670049129014551314283001582671251574132606225656558769248051872668919945335156046109684599461479010072698042194265131432439432111708952985059170648240550914992169145894926437588173425753889988734024781047390921725232442091277340971091116650569099484901188657501225210251920789312381353410873675482898|10022730206246523605885847628248331589129959745152946800589982371582759735440896033124734292653525513269378463322751069994968860121969888496580966465696069881018097413525001416210515174455496944629883370533539582159385347137053307519490537337422600372155743988569466107652391801498216166822344049274248006914,729727310531644666459577636524370584122920562232400100508958613100574209791027073647329563436154072167135037277674792721862334569450792556614550488339055151138688316081220432057278684502305768700617734898572463248131416139418546546921772768563777642345566507958981323489827996692750181630164696164350792239,743420530670049129014551314283001582671251574132606225656558769248051872668919945335156046109684599461479010072698042194265131432439432111708952985059170648240550914992169145894926437588173425753889988734024781047390921725232442091277340971091116650569099484901188657501225210251920789312381353410873675482898|72678153493282504157416115644391264652311137140691071678059939078869970502440343742868078709786102781757123551689967637475890683084227768997487411568948523707471659432320585674519265605598599734502760770267332905322559905487379207111063130039684891358469047921852095373415568614214678421199229135813148340086,-33947255666808860516772098102208086001134373039996489095024233296987004975315716216270171442041054094605710390151835995913332617034994068103936254773578912095997116516855870766220741602335129322709546766837859664219492792132163257557798382623121354098297535938342782377977312458602436715508338777893530715947,106484190269718620144286637065233814518223762302071472353291401620347574484719889974719727699170546479802692571973907348709106400438154108695479596777257546039047068390011589281587022778512291574952016353907379824791098458869045617748541670371657706126860369909581308416699070396340994092087729258233572584479 +10022801037884735919398225401015346770690037220981230548926941756106963920408338416095733094536206053772963879852109190901255264805008288279841331919785607478274212775267264447609163695284184368267756738466008982331882800742073245734831347575593957813641726104668466028052775256385701674654962758632735214325,-1581758127940839328365881014818315360646059541554455415456767586268677829342640676667660057584626141079060910685268398574862315277919005616512245424342499450499940252940175197812452339693288044870174334000429767858420712066019926176503980859313840839446940401868444636117019979796283038985302067912785275287,496761537019467923365643288264945659788228256979170730808696057920098575449994591930452099194380843846370073248896650848520976197841222484748214967557803091427696552713317560221122191533744679546984546053333189737767090004462878944114371161170193473185997313558677097782867340116873490763865370370260817678938|10022801037884735919398225401015346770690037220981230548926941756106963920408338416095733094536206053772963879852109190901255264805008288279841331919785607478274212775267264447609163695284184368267756738466008982331882800742073245734831347575593957813641726104668466028052775256385701674654962758632735214325,-1581758127940839328365881014818315360646059541554455415456767586268677829342640676667660057584626141079060910685268398574862315277919005616512245424342499450499940252940175197812452339693288044870174334000429767858420712066019926176503980859313840839446940401868444636117019979796283038985302067912785275287,496761537019467923365643288264945659788228256979170730808696057920098575449994591930452099194380843846370073248896650848520976197841222484748214967557803091427696552713317560221122191533744679546984546053333189737767090004462878944114371161170193473185997313558677097782867340116873490763865370370260817678938|11794018787280482940784484560654447929703367834543013693618622456325444683498014462584498990809979794991029406828035162064888206099231897450516338131683344468341641773247077777974904033180523619849644665052604243871182886239709602918372696154159689574416694382901020412810986466933364313296340223658056711860,1521303582082972784094072429213245037004474422912041747980341661334088522130166480999863587718878595218681652383126000473728595142115360315778132844751721718890137106680913339185860894697918722593994440198312742439897553470706013918108591714015302153342792691194124679477731145179750991721088470556891980683,422154249545788907790313192562529747503206514258177376656051975747255059759645179919603489351691318624495599133821906453410850735326793444201922900151270842818708202863054380424556183873836633029531584190623724167592312286966999660766414372084390763660497972689763908414494950088490657933080790950343854684683 +100229993686309443431652234853242745584964039848901396902154758000675611952948762456754223980100376888310959032918053199573371179952836402943594446966248713771392255748269391671122973567354604611827710836480143363448852247469233467634585666281897503837387248046923275198978369387627574778973203963568459570613,99141614774063628352404317381455383177814780210220526925227232275804977777537108958838490639289349073928621828114260050626184229387757267144939794360548040966543453766396248232212371430223357646841577045712198699745634479223254936354615654319866477688010773948549511551046967361375809493630740150224195152939,104882524400956127942658813062851389442407913609672222789148495255743494809906874598039501219688723468166574648371069153919928988258063568059818823680918241728433303999086584504182405446032391227196284068159574388579981415818096136448105143139694516800086480906674126689437313489030594417564677758780953521314|100229993686309443431652234853242745584964039848901396902154758000675611952948762456754223980100376888310959032918053199573371179952836402943594446966248713771392255748269391671122973567354604611827710836480143363448852247469233467634585666281897503837387248046923275198978369387627574778973203963568459570613,99141614774063628352404317381455383177814780210220526925227232275804977777537108958838490639289349073928621828114260050626184229387757267144939794360548040966543453766396248232212371430223357646841577045712198699745634479223254936354615654319866477688010773948549511551046967361375809493630740150224195152939,104882524400956127942658813062851389442407913609672222789148495255743494809906874598039501219688723468166574648371069153919928988258063568059818823680918241728433303999086584504182405446032391227196284068159574388579981415818096136448105143139694516800086480906674126689437313489030594417564677758780953521314|74350434749389969050012184990337127551177662105941520713519479144559556197790064845857130327167806787623076521428876751871163669518580183330141936425233250661556229643890019866856080560251792692090494599862764037832371889499003253542457382200017573287275373464647146587627430764219256453016377003846953421792,63957711791573361964387609614017192151897432836032720396105880275969302058600840013396804158201720534370023895822842857827830012733763196699928990175961939998886321856401382898475734879783268690655497427397663979021512999064707392335539401656442120559970485354029428771216688798043679886727502284879667604695,122094202522303244187343830185980046602374556531568820744954812272038371153739943186637285289631950376927966459293327247925407412742819149064968500238603572438294529950547276948751033111097715894035925769404645235126181286620345914299937264438033627270225587240098530161700877220337370607067995020225846162049 +100236185197041329075554833621063049933091933804804579181020863476728313391686305869039610612323226747485959655907451027539483829746780221656275287251359920572256326848112354466643258852396004468792417619989592999892771161118188446161121453052287245392349650298061886772129843629230859327769032485896380376,-23246228755139486121091450291914215536752934295258164744923084651696211557139982911633633936256958755233390860799953871691506689375274550434281909010783595844874773750530708001462730196953616598369162178869242223651107363158755851755977149870788847101056032248840046983417481075963548958473469668684959891,56573523673680298471644280373809509686143659597565817726545502453421314503494549466829923326874504507298291631695935926527600390521472116074127195438583945763976558015737054829572336871056542824657451863625497940311479875421301704568832621760721804490304525701867696665290350769186367013604263730372702025776917|100236185197041329075554833621063049933091933804804579181020863476728313391686305869039610612323226747485959655907451027539483829746780221656275287251359920572256326848112354466643258852396004468792417619989592999892771161118188446161121453052287245392349650298061886772129843629230859327769032485896380376,-23246228755139486121091450291914215536752934295258164744923084651696211557139982911633633936256958755233390860799953871691506689375274550434281909010783595844874773750530708001462730196953616598369162178869242223651107363158755851755977149870788847101056032248840046983417481075963548958473469668684959891,56573523673680298471644280373809509686143659597565817726545502453421314503494549466829923326874504507298291631695935926527600390521472116074127195438583945763976558015737054829572336871056542824657451863625497940311479875421301704568832621760721804490304525701867696665290350769186367013604263730372702025776917|15573203821391096660668742152065727671791482748659900060639926963022005424305428598384096201045285103243110012385503647750757013115954608677386233978142224494513680866630913236076316930192686744226921983870965664346251492074685634583531334565997695428546882772894918870424603926033309071559111059501203642333,6451721584690521069581901111974092204654122587875579916279551744658661205413364185368986076832511568929170794843492990781144450828332965740817648161987976580582338126230945095334678085775013660661642032765404588316501300352495628863315640949745573214882043885532409624351786399389352651138436910377540588715,364800994330757396882653090957020494991186585063682233319677342832051344502776958834410035811370111943816463424448302716551318762170472662165419035921367121365358358160571142517808605560056227966869017916492144933000445349984077920674346135535102210585266868874844995392794923436866721883251932973852604825116 +10023667082494025533694458923906062911614808800770741660171152481026059347510371753561616097379084784341713671154750835715019868680624888814365226032644794597463378220681171484265152741451558871527205613714299617780955377578029153710181790009777505367079339560569389236075705577562497976407198835496123421815,8237178824212969139758302266371465433903111044341794615829413365403141507594223080352356455683475273814082845524013102162873125179530876016035628585832833134556337909718743386830931466874558092486241907311137385119488677802975754525714977343935483066353264879509528297193753064624793968877384112576484389591,423224971588853021692214116546653537988666116441804013450094782696541031203993989512468938158606185066216192664407632356213925851579704646681338385590758369803509256824915492724160624602987883926813515751341908451718832678074898298694978135986894313441355375932022035725661361883088309484290780962315557040384|10023667082494025533694458923906062911614808800770741660171152481026059347510371753561616097379084784341713671154750835715019868680624888814365226032644794597463378220681171484265152741451558871527205613714299617780955377578029153710181790009777505367079339560569389236075705577562497976407198835496123421815,8237178824212969139758302266371465433903111044341794615829413365403141507594223080352356455683475273814082845524013102162873125179530876016035628585832833134556337909718743386830931466874558092486241907311137385119488677802975754525714977343935483066353264879509528297193753064624793968877384112576484389591,423224971588853021692214116546653537988666116441804013450094782696541031203993989512468938158606185066216192664407632356213925851579704646681338385590758369803509256824915492724160624602987883926813515751341908451718832678074898298694978135986894313441355375932022035725661361883088309484290780962315557040384|26149581659024134542252839056088737943459101230098434304929833472689045273647101980834416767117184344850968739815058973073425320764635194473778310753733774870500611744687135320440722493629102059325894273417025541554717397282491317870553755571826770905575804901409545560793682652830798005534542887045797606186,-1697969983698485305905454448895722929114256960413081228420951351866600414430800217182268923658152076765210118720420817273440690524435493363475828642615467592516719174944772197605654745416391960101282581330420264887754748587983051609045080004443224578293135292425351561632174977350140009380537152490928076887,161609629862554141142708472275797044218689904367615056614920333643328937851927686237891781051003871507296405842898237370248243352582987628460341700892139196626441792037632328670727659225186548971653052724874684965299456515833967561157293186033533538079205556741150926459475886439855496878616457828726831550112 +10023862893594232582190646068648463209940952006884955056666263414474264317722655546318247009455771884983355234222787422801894657323776793269825967901010897328305149754199815134059038386803327107954623997783328925014573712361190412041544730846393144970158584993932522919092961533807689663994273510181230611975,-2760322820547873699921094239708262618123220686640344280427532457964735913231839541155448488755106353058077772483391926518490758309421884945189004380274532339303673658136307214150768559915038249044318636340829040623019533080008795877188365713108541851533478868182315253939354465782006188226272150540248455533,539774532098344028178575637715654362402942864818067869426574212334581836029933543954242820122684669884416483020859433711413498388105161261765872011520166122694643001745601237406507189268543940858796801993814111596277340371144355358041455940732653675597524992815557778776692308187755956982584432604519599405036|10023862893594232582190646068648463209940952006884955056666263414474264317722655546318247009455771884983355234222787422801894657323776793269825967901010897328305149754199815134059038386803327107954623997783328925014573712361190412041544730846393144970158584993932522919092961533807689663994273510181230611975,-2760322820547873699921094239708262618123220686640344280427532457964735913231839541155448488755106353058077772483391926518490758309421884945189004380274532339303673658136307214150768559915038249044318636340829040623019533080008795877188365713108541851533478868182315253939354465782006188226272150540248455533,539774532098344028178575637715654362402942864818067869426574212334581836029933543954242820122684669884416483020859433711413498388105161261765872011520166122694643001745601237406507189268543940858796801993814111596277340371144355358041455940732653675597524992815557778776692308187755956982584432604519599405036|48715243603698629821940426961114291788526831094737919680655564244368028434506892148169445801801507062147482077938401141271200004998443292904217897448972538551776558146708202066192286102689914350481841990540885514221263570815029978710961611989482704700171591369852446182654047272669614885074291437285365544460,15461979039278362276597154663342472093520340953601325231902305531667625678747495978358134272949704300055117324152966543774546452680787464009096008897144630532639259858616922948118805845884304673520502690819270668894425836172912196918903901652212033563796089034742441883378992888990103186375633458530164516317,112254170401540486949707124025758283679636240637378289192656933481574624585762302045534446659987957789349537165930984237831795400327841686426067814232036082567083362372524941094990583657803451112651533845361102072607539347050570081691100018981326399925221570110823787216043908322347678600920061436414622205345 +10024289314253109068181408824584907548682813194738591861732979563130066037537322274697443177137048505246344585833979570630525401656305713560413859208020518275537432959569499157916033857588787751319126726484190263493857704290501320067515311770609186057345956871152108834406551727855172143151298819670712846606,250504711193651543885319560950205973661493792695329060474635142907355144915197487552594082031949875905008463463563678142215091936373578313885813322111597330162926418717728507984924427400756505737871837782137693463723537653383553918621336520844369928180694979696895523967764933497235970432812594037072497051,715621301200572432492975207084152505969843326949635795107806123209445143151718517449817068713936125495042559248838811939558778417894618132276860461288711015473626724568542195567695133648202437411311798035098899324593482673311597084169133485553033610858821471717692594066324611630669968328053616507731719142856|10024289314253109068181408824584907548682813194738591861732979563130066037537322274697443177137048505246344585833979570630525401656305713560413859208020518275537432959569499157916033857588787751319126726484190263493857704290501320067515311770609186057345956871152108834406551727855172143151298819670712846606,250504711193651543885319560950205973661493792695329060474635142907355144915197487552594082031949875905008463463563678142215091936373578313885813322111597330162926418717728507984924427400756505737871837782137693463723537653383553918621336520844369928180694979696895523967764933497235970432812594037072497051,715621301200572432492975207084152505969843326949635795107806123209445143151718517449817068713936125495042559248838811939558778417894618132276860461288711015473626724568542195567695133648202437411311798035098899324593482673311597084169133485553033610858821471717692594066324611630669968328053616507731719142856|69691918841176288984823797473901681196094628879675315489755259444998436434953893357490252440851727841764856894926617359858762775119043951866997363697297297444653923770370354552225052699848341814307273549886449783549055935119439453155817735871573060612568620074695549908654214345458834165261842993120064731877,29396998803244259208706324369693841135210373137766178345587378836957006029896347992580130862460199303906902776177861781944189386331882004200746161097147483839158568813322086972498062377955537624817737605600339132204987534032119897113967273038860438816060235575010015500174845850861550917579850703027368690837,106032740697299793989572674990101926746114173477172287236417937947154096127701068054351010022541808717403069236123423199088480578855329299917113038220143550055260783011691574203288951873393089140671443554631887510834797278656898859315134431047639142121497581377857339388563046962362704012299890107532747273864 +10025428900225290685290151690469854982214932916715816521705584076773008242243937008766386881454192668460673460928145859037221457715710934570710912601758825277917537132977601878466722300639421318388444709119075347515835153260761313907776418189378977092187686581753209864749194659254262457796167519362282389944,8035407417908027120985682166291560102987169154314800046344974577695327891178900017914738842677039490694291401465931876496716613929624358740551659992744919248664062419629947961043318471204322567520912143542047278378993142962380418872588429956261466474640589358106914252999077869082097127384356318300378316515,526506212965607285294504652802203087863317784238837123201810456971631654056439372780456787465506517550858742170829690899565417756124817089047569475165769047941621936008499130409010932902058625548248971355379292220521819976269615165269965092960486278068237861168382524126578791019346639264332649030378056985183|10025428900225290685290151690469854982214932916715816521705584076773008242243937008766386881454192668460673460928145859037221457715710934570710912601758825277917537132977601878466722300639421318388444709119075347515835153260761313907776418189378977092187686581753209864749194659254262457796167519362282389944,8035407417908027120985682166291560102987169154314800046344974577695327891178900017914738842677039490694291401465931876496716613929624358740551659992744919248664062419629947961043318471204322567520912143542047278378993142962380418872588429956261466474640589358106914252999077869082097127384356318300378316515,526506212965607285294504652802203087863317784238837123201810456971631654056439372780456787465506517550858742170829690899565417756124817089047569475165769047941621936008499130409010932902058625548248971355379292220521819976269615165269965092960486278068237861168382524126578791019346639264332649030378056985183|22138319840700167895312881508181272807615611642960031764554010440709354488166777949391350577243475719290294812551529754345491786841502661934416467056115565617682227037416000132315258676326832664293472268496755124942179527934459542753167413348749025306046598965185451619481594689484505194124705909904529437016,-11131863740438194145696527360624732907005872365618169777307266620259512556501908857842536958655885195096195748687569086057992329814846073549253878495916056982261048696264863065937434987201822416655310303356962123778695372607503843603636308900759414300401601767853289915741229529512784406304245742359645877437,239100722014735247362237833086276623512072741916888955896402203382427372194255695065669877432592987292352301916479402236621014870053157629159394772682571609781590319296070407875820019520943129073048256367075297134176669670916790346961022995994025660850270895833918044332478002360056773821184240475743476227793 +10025696373056081323076067608649787757301021243808185859274808349280293058956119916709251366791092102112010300737183625444037192198725817688527600134257833611989912831501342672141015848343142445555687647450237725473967806277927764282835935236016323094913726640542283793306041765928288192544236949963888652742,-7551573577419239436071851881922105087510160439185121186338107875456959549550841973546977393389532111591614312842887678906809652876632858754122403767673808362967953534249136664179536748454994677273595591516700421480181975305574013927943181245218443636797391029556909610245497977668952560989113626530355626403,488551202347944315504020596344859283372184958565644254623325222360870646703286196267475027122265755221917465236349901297478448862017138325309245093096937651510172757567584161967211867376922683411877153052678659984267061266457787269417246896692832538104568250487618601354692837088103049130077128213591142309282|10025696373056081323076067608649787757301021243808185859274808349280293058956119916709251366791092102112010300737183625444037192198725817688527600134257833611989912831501342672141015848343142445555687647450237725473967806277927764282835935236016323094913726640542283793306041765928288192544236949963888652742,-7551573577419239436071851881922105087510160439185121186338107875456959549550841973546977393389532111591614312842887678906809652876632858754122403767673808362967953534249136664179536748454994677273595591516700421480181975305574013927943181245218443636797391029556909610245497977668952560989113626530355626403,488551202347944315504020596344859283372184958565644254623325222360870646703286196267475027122265755221917465236349901297478448862017138325309245093096937651510172757567584161967211867376922683411877153052678659984267061266457787269417246896692832538104568250487618601354692837088103049130077128213591142309282|60393031392510595353689024388979736338459176869905458858711562614756995826747740419365757994707737913997543366818386810567166008495382740947599739430340534765458717365457600414802742877973222192406990314478073640352910084093417199594859293029865969059185936671473103965892459853411850141569702842003428649274,38329753573953857590669151489102652306888210200689056278625104334993443543324622863340848043537460677248162565965074671978338401303611611484783137870568580776992301362308417714890643838644524909137849140837295996399799637901901974938629017550061052634048860038885099946489697555545683915123490961748882032563,86948805727102164020528697795654924433436758890959241635759391106001442581272485956111792521204085749386969011988358799013634480122996757146530322550896381169828204152724081141046858586814946327125019525970600049950459272456428386457599502469581747116784271717706447744628609754739530433937342398267975398266 +10025795277027889904587708106143218928217212795791943900096455901045016119560329143219194735847213817310006544292588010221295347093799623990992065640705758739633420740707391553060038825197435786302291280814741597987499076013530747593280825513696921556065232738339683658383829389180388637941998690144811369597,5684979695119467447669475199616030835217750876317308626399899267476547529035287916782085067945907170746605510283861183133612038067129245932165458949837306805149633974813244043762392619755476811530088171886491397765159164208502011381649757076514242464099478526057069033992519207091422655970324739132300656901,562007444349085595243678168150362315344210015071199683818344834829191775432825810670825147187078104135705553739701002486305372357596398874560795249464367016590567012959728033251032467564115881230202627660086530992291649152268041406000599974523312325932278194132351429623587227242904398909856612628818780435778|10025795277027889904587708106143218928217212795791943900096455901045016119560329143219194735847213817310006544292588010221295347093799623990992065640705758739633420740707391553060038825197435786302291280814741597987499076013530747593280825513696921556065232738339683658383829389180388637941998690144811369597,5684979695119467447669475199616030835217750876317308626399899267476547529035287916782085067945907170746605510283861183133612038067129245932165458949837306805149633974813244043762392619755476811530088171886491397765159164208502011381649757076514242464099478526057069033992519207091422655970324739132300656901,562007444349085595243678168150362315344210015071199683818344834829191775432825810670825147187078104135705553739701002486305372357596398874560795249464367016590567012959728033251032467564115881230202627660086530992291649152268041406000599974523312325932278194132351429623587227242904398909856612628818780435778|21268893649707309919570226960346372728495718162766890279898665692070832053021527941744710318344298178920800948932846738089018664772788493927580517099544523821251022066659574678369202749060209753445042621950578890219002532761197990179516522502045501310564866950615799259252489912339574839719060814022687315833,-16974163508967143175633640446755920949410222455507178592573412674696095005693865169009177473634493301741992193686041205183814819978515841920175784743689108590732720018205453159865088935842801461210617037675036778351747079803439546961298001090840400908639940207556458714733757110771041917290102952953525885901,267927541659497862467954399158595317217757334505550228883969422271210761133505257969057962914766286654857630940214532971487737583736851759345565614399969808206018020458924660929875641469250964043761370010683938550578868703713683401770700995854517531350144574746588257756156838858326386968013405064043171677102 +10027231464587935675639730747678568553908782143975994882531107664457436183429164280181747996889942331170488347016005448660418260392761004178712470722876674735769717730721096608074660784751458654872470573207263246635112395824536847938300087322544843942058256547417838850894365569811278659238183569174057618461,-4440267082761131414853294025879558077404333378765096794740543986499915534978609296838455472705453725784503668845242671918380807204902116758601260037461056825902249629220350908043324356588944839161111532952326818438147003761862650635018374512533491039199092599100710336766544058009407418500582600655649176731,648644865497954786776779349508457974872894617589720812073415733603605246322174185807123848556285887617844905639166726609275182111944451202589938026255239735903760010573449137429043799240258539000988138770732321918291392488327546867698375214486961050410251228096630089455328472100573545758827677160537099320072|10027231464587935675639730747678568553908782143975994882531107664457436183429164280181747996889942331170488347016005448660418260392761004178712470722876674735769717730721096608074660784751458654872470573207263246635112395824536847938300087322544843942058256547417838850894365569811278659238183569174057618461,-4440267082761131414853294025879558077404333378765096794740543986499915534978609296838455472705453725784503668845242671918380807204902116758601260037461056825902249629220350908043324356588944839161111532952326818438147003761862650635018374512533491039199092599100710336766544058009407418500582600655649176731,648644865497954786776779349508457974872894617589720812073415733603605246322174185807123848556285887617844905639166726609275182111944451202589938026255239735903760010573449137429043799240258539000988138770732321918291392488327546867698375214486961050410251228096630089455328472100573545758827677160537099320072|46009921711915221172675762660378602913284935911769009327398886576025556944392570855250807675821524214292205195685897041743100957229886916848065466280285331142834500895832407569582736664860239313946858454701727263963934792933919730548918244937925570913918752904708052633399310307728141781833372082621654521012,23113475896105025107394605331889841460333790037514477610982037645403180016015663190091781841332002225731097821541822074963875072814544317858697958764287783670995655541483455486482934375887626558700537105583870368524253911345190227270218382103667348149461739557925536602713765457923023851021682724701425292285,144158936962616263074854848511540730235089365933518189341717329619972562457005307870230026030935456404849352326770086269924745439466300887545713518178631945541398236558781981355199214433550895067837895099984050382102279411033270720567051341019780619857285120976043103941344405749600962507460384488305160927409 +10028350739307738239553437040783010537831658077620987335136512740169676263676747904072610524038617826531776850363823183733316438383606013506243196250082245650509414494066287488240898643357609392647649696817421880362011995934355791054933802156008906495889209763185641418699747996844644309107005112769042124318,-8707724909729199988066303291337645249173793540898282778024990496827621579508639942367666079187451324678862416133361451354021503910330702173658524643590899178624105480074443491370735876152164927759833250717689047284841393067105491783984924710355073809596596309834373465404107419929383484013294580151001556205,709758849546988349416271112886481225556022674837057904210411294800853958134290458192748393663317224087035819308413648727887254453418237510262143014913358121419251454923066768843049946946235581252429358021933518874438830803109875124372809973223871915099838973789742920465584130081571378073407884375094121268086|75318449301263415467735932548665333631833209464496019863964846786179367552717568503501179580307848690931127517090493242442668414948431300766436151276701082711193885234526326365772794857402011587084042826807831628195071551088506032974178171732912459672450935320336391563419572190330442739927553072512433668492,-37666884930926310053453757600840503983118095033807980727340808659295811653448510252245931091899049389573453471548035871058367468721695376360491358764096189091201995027259909431928638716214539254513869701208949761595174662474754859884399931318260163661631099379190898913272807941135716989109599181870658955411,98959195118263740892956000993748226884659367220332828268929254332674345256309662055166848715197441404549693155497652798902798133883715701424760429622411156195661335500009744018343869593442437677434882815576040667549098187431048868332096738149061496080175268157896224795266747997461998351291015430290846127991|78879828918733154172761232408717349879484411577276118445906917725867063887736403698268620449039366903222875325557071665537210036919488537356651491469585633888702020869953229589162929365722510146484615161939420331780149558523973332122378453822513488024388432239153051455307708434618917487055946350509115159954,76022832032228931560745697540761625684085285731069434889900171934534714627230254695020398894919788417337545845925550378316932977023401785630385785258013781974664129868656557307645950862628223235191878262315897562597443878541677560567949780990105397727409041603839660905756066382442879369790583798789010488305,108311876812780092185464248430819211209817518273155531596997245418001592611818208219323720419932959536655772814492616252593108875759365327114882816039706034356112007450695439375062874008822159624139628714241658551452565287963490475631456873365249553095821106476912177956653681222238113836907581862856535718737 +10028851844651833483859929571953137249991455639548429827963027247884276614126582614765754168788406967864569784762670102265610798647378386836840906226432130520069813697908016956233348000504802826879321612396642793367212498698674853695626535119160503473498038239103440516242421347929877540717111105756485685416,2125595786027029524418010744012416366895751257304333344547068089057782417304598028459234751630103098379533864111162338454453990302791615035666668646880454521909199231924063610130346480860493194786475025500179927152042631414216166076205706865335089506746163544867373884186074330874303125032398057106297186863,800913161978634698742609378449357774955505407483415355913501780948951093468088505693408572348493350961801168010893237963412292289122055848739177106855852125098292236006510856110523212361731635197072591774393685461794786770421350652687522647241859653967881884006552182286419954577117744245767788677817306762852|50429916262905224121199165505326103712322633321578675412441680250060233972857110270845245669993781820897616267433177701631160063889458653764653687193369398981186203131244488744056545097485284912257268749768458331368107477031080466529105477483573960360042156349879055924595032652993263006931935621163071940669,-27065457947223595691396496360583757525811978893552969421355220262690251856919447274985744020030753772138102799000695707517100290349316439468276434701083568894717249805760937039437729313480400330251378090593495078991541936054800615447964857892934462412215184000258243195317080477356913381022045983896051265339,162884360410278142867611075754290453359699000687335791914852080089316910769333692647979960993562595617317591055325367385753910502341805589561432506963888415490402296553372275035046411345233183682360113909981999769321373626395576042577426393704313732652524189312065702142816306042456646293512481995292218184630|53997723292458827021420578276444072896002053124414909531202213558828743141566632795132611868503445251027453958158504792518315802051451653007369750551307662332396699632827748059470875485288011830316694909885816703989889585271656952405885761371722676008299809654786389827849524552375005490619782071967768476620,-3921961296864439599504210025762424797468664702267290731411285739993844771294339132594454147684650522033462891630908841344585194018116919380259122700777039543903609394837238783496880317096351827072103366260798880944073390853134441762823497871536553346031444078137460262118850735234076150428857645894786599751,148801743068668131617014767083337764289837422117725728166091414005082627848729316116752646484455568027336119364510594603975358934000097718262611755893849397982664596027513725455266261222215386005085253076887565120162601272630243587251846986242350641739720550891898677287459766121608903079025422071040317411427 +10029389724354647916501896404393742667486460299990236556418317010668116357688170330436730152626311842309710400719826928488284825527027730454134618086311842571929328216480439284941404499751921093227604323134474990591797348436817566328316099817073417778247297081309102907064789976846493401165211794614652077581,-5748548483444797737722189452249937786310843486604864328602367281135708748614533947090219774019556230317272055169227525539578087511031078860820692360107715435130140444616499305586047090927584090418666083007681585523416727535418733837425822999564006750813702161869964846496575730545650729911357481033875975819,719895727819428792994563756994341424767785889195228293344753744212732679301708252203825226413012156273021174986595157595824763180256881701588113889797640827369987995936500880423386237711358833858185065722206691788564039408747808726964665919487597212670306097386648373066512338291830265434985728533154609458396|10029389724354647916501896404393742667486460299990236556418317010668116357688170330436730152626311842309710400719826928488284825527027730454134618086311842571929328216480439284941404499751921093227604323134474990591797348436817566328316099817073417778247297081309102907064789976846493401165211794614652077581,-5748548483444797737722189452249937786310843486604864328602367281135708748614533947090219774019556230317272055169227525539578087511031078860820692360107715435130140444616499305586047090927584090418666083007681585523416727535418733837425822999564006750813702161869964846496575730545650729911357481033875975819,719895727819428792994563756994341424767785889195228293344753744212732679301708252203825226413012156273021174986595157595824763180256881701588113889797640827369987995936500880423386237711358833858185065722206691788564039408747808726964665919487597212670306097386648373066512338291830265434985728533154609458396|8560998041202342563145796199673331908087223591151890019844277290088279806853407215903188817680041281745686724901293662893322531582604865370359246593736212994518909947445852055733198112706083016676348016714291995623917124402224705247934604030962953619706293397331305385867121828720733169551586472433525366937,-537975643989974344334263003423538768209474800355518283566587248897859525466409192148505701554962331296631250873445941844817525452815362174465113061273994639614043454341045805645253425898526417994404807933232055819444976823823121190979410608683098711316112363065614462414343124780847750195760827288806749811,842416466225224033183393216850362224780744722633748075411867357471068659147784175969996596348967969848559647034288532517371764252498077837862667546193299637156461175039504339023851201930547252305821527420041035325847162633397442876512610187216200063222815713605031344575281997919080197584636819283493689893368 +10029462828108406279939177067115161395010840703955688660855251935920272008672857135011101256731718086932191566776707625465927083826902687987460773347952918706606341231446896979494902183159052228641287627294356517943283997224691515527031637969828335115038316970291491432668820800917926368076854280638205187309,-6629646230072911423556297764360629625589965368903862583111147478898388162363395818084398589541887766856708633717083099875720612184669212924373539095145308857941719336023981955297255371765324592355503775749174475673743444341624220885937903545914339945102711106579165895756968511409705213351719512183267438507,782742743661597372172423816386424221021017552503284524697466177183281891845425353410464186233869636520966594583971179297268228166989165546064661406781232750204176842910595282543729669785450570724055031796400642778914378223882150571438409693254554219540729724954243581265311980228274664427499269984624348473720|10029462828108406279939177067115161395010840703955688660855251935920272008672857135011101256731718086932191566776707625465927083826902687987460773347952918706606341231446896979494902183159052228641287627294356517943283997224691515527031637969828335115038316970291491432668820800917926368076854280638205187309,-6629646230072911423556297764360629625589965368903862583111147478898388162363395818084398589541887766856708633717083099875720612184669212924373539095145308857941719336023981955297255371765324592355503775749174475673743444341624220885937903545914339945102711106579165895756968511409705213351719512183267438507,782742743661597372172423816386424221021017552503284524697466177183281891845425353410464186233869636520966594583971179297268228166989165546064661406781232750204176842910595282543729669785450570724055031796400642778914378223882150571438409693254554219540729724954243581265311980228274664427499269984624348473720|78667156036256111077611624900655903416490936286908879028793529978954307476546731244382117972535629204391216663640753691624585098486838208251820032478479477157140644001833697695041181016581251701307504852404041540782811897181398727717806959310986773271700555774873273014053192416692372242335858566589217791557,-11681938670990905592355073596188490162953864508666802257304897456361955348551384361326321552281799532866414312577544184561189074950098884814900830627703536569755802878449922371901033061871486784064588452214883192668082672979794267084922475962025561930112420060063420934779749780994794637529679089941387143427,100087743332058471063169855843669770171915090829420561680411008586982501053400685795132793033729482971332564612241450018617179058547543051543609602249472699027915450803902552375241387388609502154707845080333148480015751381946173697011349301767118798190494650916047348538729674905622316757245591467381527471900 diff --git a/crates/vdf/Cargo.toml b/crates/vdf/Cargo.toml new file mode 100644 index 0000000..acc815d --- /dev/null +++ b/crates/vdf/Cargo.toml @@ -0,0 +1,46 @@ +# Copyright 2018 POA Networks Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# and limitations under the License. +[package] +name = "vdf" +version = "0.1.0" +authors = ["Demi M. Obenour "] +readme = "README.md" +keywords = ["vdf", "classgroup", "crypto", "cryptography"] +repository = "https://github.com/poanetwork/vdf" +license = "Apache-2.0" +edition = "2018" +description = "An implementation of Verifiable Delay Functions (VDFs) in Rust" + +[lib] +crate-type = ["lib", "staticlib"] +name = "vdf" + +[dependencies] +classgroup = { path = "../classgroup", version = "^0.1.0" } +num-traits = "0.2" +sha2 = "0.8" +bit-vec = "0.5" +uniffi = { version= "0.25", features = ["cli"]} + +[build-dependencies] +uniffi = { version = "0.25", features = [ "build" ] } + +[dev-dependencies] +criterion = ">=0.2" +hex = "0.3" + +[[bench]] +name = "classgroup-bench" +harness = false +path = "bench/bench.rs" diff --git a/crates/vdf/README.md b/crates/vdf/README.md new file mode 100644 index 0000000..63276c7 --- /dev/null +++ b/crates/vdf/README.md @@ -0,0 +1,223 @@ +# Verifiable Delay Function (VDF) Implementation in Rust + +## What is a VDF? + +A Verifiable Delay Function (VDF) is a function that requires substantial time +to evaluate (even with a polynomial number of parallel processors) but can be +very quickly verified as correct. VDFs can be used to construct randomness +beacons with multiple applications in a distributed network environment. By +introducing a time delay during evaluation, VDFs prevent malicious actors from +influencing output. The output cannot be differentiated from a random number +until the final result is computed. See +for more details. + +## Description + +This VDF implementation is written in Rust. The GMP library is used for +arithmetic and greatest common divisor (GCD) calculations. We use class groups +to implement the approaches described in the following papers: + +1. [Simple Verifiable Delay Functions](https://eprint.iacr.org/2018/627.pdf). Pietrzak, 2018 +2. [Efficient Verifiable Delay Functions](https://eprint.iacr.org/2018/623.pdf). Wesolowski, 2018 + +The chosen generator is (2, 1, c), where c is calculated from the provided +discriminant. A form is represented internally (a, b, c), with the +discriminant not being used in most omputations. This implementation performs +reduction is performed after every multiplication and squaring, as not doing so +did not give any gains in our benchmarks. + + +This repo includes three crates: + +* `classgroup`: a class group implementation, as well as a trait for class + groups. +* `vdf`: a Verifyable Delay Function (VDF) trait, as well as an + implementation of that trait. +* `vdf-cli`: a command-line interface to the vdf crate. It also includes + additional commands, which are deprecated and will be replaced by a CLI to + the classgroup crate. + +## Usage + +- Install [Rust]. We (POA Networks) have tested the code with the latest + stable, beta, and nightly versions of Rust. It may work with older + versions, but this is not guaranteed. +- Install the [GNU Multiple Precision Library](https://gmplib.org/) + * On Debian and derivatives (including Ubuntu): + ```sh + $ sudo apt-get install -y libgmp-dev + ``` + * On Red Hat and derivatives (Fedora, CentOS) + ```sh + $ sudo dnf -y install gmp-devel + ``` +- Download and prepare the repository + + ```sh + $ git clone https://github.com/poanetwork/vdf.git + $ cargo install --path=vdf-cli + $ # or for the competition binary + $ cargo install --path=vdf-competition + ``` + +### Command Line Interface + +To initiate, use the `vdf-cli` command followed by 2 arguments: + +- _challenge_: byte string of arbitrary length +- _difficulty_: number of iterations, each iteration requires more time to evaluate + +This generates the Weslowski proof of time. To generate the Pietrzak proof of +time, pass `-tpietrzak`. For detailed usage information, run `vdf-cli --help`. + +Once complete you will see the output, returned as a `Vec`. The CLI tool +hex-encodes its output. + +**Example** + +```sh +$ vdf-cli aa 100 +005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b +``` + +To verify, use the `vdi-cli` command with the same arguments and include the +output. + +**Example** + +```sh +$ vdf-cli aa 100 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b +Proof is valid +``` +### VDF Library + + + +```rust +extern crate vdf; +use vdf::{InvalidProof, PietrzakVDFParams, VDFParams, WesolowskiVDFParams, VDF}; + +/// The correct solution. +const CORRECT_SOLUTION: &[u8] = + b"\x00\x52\x71\xe8\xf9\xab\x2e\xb8\xa2\x90\x6e\x85\x1d\xfc\xb5\x54\x2e\x41\x73\xf0\x16\ + \xb8\x5e\x29\xd4\x81\xa1\x08\xdc\x82\xed\x3b\x3f\x97\x93\x7b\x7a\xa8\x24\x80\x11\x38\ + \xd1\x77\x1d\xea\x8d\xae\x2f\x63\x97\xe7\x6a\x80\x61\x3a\xfd\xa3\x0f\x2c\x30\xa3\x4b\ + \x04\x0b\xaa\xaf\xe7\x6d\x57\x07\xd6\x86\x89\x19\x3e\x5d\x21\x18\x33\xb3\x72\xa6\xa4\ + \x59\x1a\xbb\x88\xe2\xe7\xf2\xf5\xa5\xec\x81\x8b\x57\x07\xb8\x6b\x8b\x2c\x49\x5c\xa1\ + \x58\x1c\x17\x91\x68\x50\x9e\x35\x93\xf9\xa1\x68\x79\x62\x0a\x4d\xc4\xe9\x07\xdf\x45\ + \x2e\x8d\xd0\xff\xc4\xf1\x99\x82\x5f\x54\xec\x70\x47\x2c\xc0\x61\xf2\x2e\xb5\x4c\x48\ + \xd6\xaa\x5a\xf3\xea\x37\x5a\x39\x2a\xc7\x72\x94\xe2\xd9\x55\xdd\xe1\xd1\x02\xae\x2a\ + \xce\x49\x42\x93\x49\x2d\x31\xcf\xf2\x19\x44\xa8\xbc\xb4\x60\x89\x93\x06\x5c\x9a\x00\ + \x29\x2e\x8d\x3f\x46\x04\xe7\x46\x5b\x4e\xee\xfb\x49\x4f\x5b\xea\x10\x2d\xb3\x43\xbb\ + \x61\xc5\xa1\x5c\x7b\xdf\x28\x82\x06\x88\x5c\x13\x0f\xa1\xf2\xd8\x6b\xf5\xe4\x63\x4f\ + \xdc\x42\x16\xbc\x16\xef\x7d\xac\x97\x0b\x0e\xe4\x6d\x69\x41\x6f\x9a\x9a\xce\xe6\x51\ + \xd1\x58\xac\x64\x91\x5b"; +fn main() { + // The length of the prime numbers generated, in bits. + let num_bits: u16 = 2048; + + // An instance of the VDF. Instances can be used arbitrarily many times. + let pietrzak_vdf = PietrzakVDFParams(num_bits).new(); + + // Solve for the correct answer. This will take a minute or two. + assert_eq!( + &pietrzak_vdf.solve(b"\xaa", 10000).unwrap()[..], + CORRECT_SOLUTION + ); + + // Verify the answer. This should be far faster (less than a second). + assert!(pietrzak_vdf.verify(b"\xaa", 10000, CORRECT_SOLUTION).is_ok()); +} +``` + +## Benchmarks + +Benchmarks are provided for the classgroup operations. To run benchmarks: + +```sh +$ ./bench.sh +``` + +Additional benchmarks are under development. + +### Current Benchmarks + +These were generated by `./bench.sh aadf`. Outliers could be due to preemption +by the OS and/or hypervisor. Changes are relative to the previous test run +done on the same machine. Since the previous run was done with different +settings and/or code than reported here, these changes are not meaningful. + +```text +Benchmarking square with seed aadf: 512: Collecting 100 samples in estimated 5.0439 s (374k iteratio square with seed aadf: 512 + time: [13.301 us 13.333 us 13.372 us] + change: [-22.286% -21.745% -21.225%] (p = 0.00 < 0.05) + Performance has improved. +Found 22 outliers among 100 measurements (22.00%) + 5 (5.00%) high mild + 17 (17.00%) high severe + +Benchmarking multiply with seed aadf: 512: Collecting 100 samples in estimated 5.0452 s (293k iterat multiply with seed aadf: 512 + time: [17.219 us 17.251 us 17.287 us] + change: [-24.323% -23.739% -23.149%] (p = 0.00 < 0.05) + Performance has improved. +Found 10 outliers among 100 measurements (10.00%) + 4 (4.00%) high mild + 6 (6.00%) high severe + +Benchmarking square with seed aadf: 1024: Collecting 100 samples in estimated 5.0822 s (177k iterati square with seed aadf: 1024 + time: [28.672 us 28.716 us 28.767 us] + change: [-29.947% -29.339% -28.708%] (p = 0.00 < 0.05) + Performance has improved. +Found 8 outliers among 100 measurements (8.00%) + 1 (1.00%) low mild + 1 (1.00%) high mild + 6 (6.00%) high severe + +Benchmarking multiply with seed aadf: 1024: Collecting 100 samples in estimated 5.0886 s (136k itera multiply with seed aadf: 1024 + time: [37.163 us 37.207 us 37.254 us] + change: [-21.403% -20.750% -20.170%] (p = 0.00 < 0.05) + Performance has improved. +Found 8 outliers among 100 measurements (8.00%) + 1 (1.00%) low mild + 1 (1.00%) high mild + 6 (6.00%) high severe + +Benchmarking square with seed aadf: 2048: Collecting 100 samples in estimated 5.2519 s (76k iteratio square with seed aadf: 2048 + time: [69.115 us 69.254 us 69.430 us] + change: [-28.091% -27.738% -27.341%] (p = 0.00 < 0.05) + Performance has improved. +Found 8 outliers among 100 measurements (8.00%) + 1 (1.00%) low mild + 1 (1.00%) high mild + 6 (6.00%) high severe + +Benchmarking multiply with seed aadf: 2048: Collecting 100 samples in estimated 5.0554 s (56k iterat multiply with seed aadf: 2048 + time: [90.922 us 91.057 us 91.201 us] + change: [-25.236% -24.794% -24.336%] (p = 0.00 < 0.05) + Performance has improved. +Found 13 outliers among 100 measurements (13.00%) + 2 (2.00%) low mild + 5 (5.00%) high mild + 6 (6.00%) high severe +``` + +[Rust]: + + +## License + +Copyright 2018 Chia Network Inc and POA Networks Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/crates/vdf/bench/bench.rs b/crates/vdf/bench/bench.rs new file mode 100644 index 0000000..4757276 --- /dev/null +++ b/crates/vdf/bench/bench.rs @@ -0,0 +1,54 @@ +// Copyright 2018 POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate criterion; + +use hex; + +use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup}; +use criterion::Criterion; +use std::{cell::RefCell, env, rc::Rc}; +use vdf::create_discriminant; +fn bench_square(c: &mut Criterion) { + let bench_params = |c: &mut Criterion, len: u16, seed: &[u8]| { + let i = Rc::new(RefCell::new(GmpClassGroup::generator_for_discriminant( + create_discriminant(seed, len), + ))); + { + let i = i.clone(); + c.bench_function( + &format!("square with seed {}: {}", hex::encode(seed), len), + move |b| b.iter(|| i.borrow_mut().square()), + ); + } + { + let multiplier = i.borrow().clone(); + c.bench_function( + &format!("multiply with seed {}: {}", hex::encode(seed), len), + move |b| b.iter(|| *i.borrow_mut() *= &multiplier), + ); + } + }; + let seed = env::var("VDF_BENCHMARK_SEED") + .ok() + .and_then(|x| hex::decode(x).ok()) + .expect("bug in calling script"); + for &i in &[512, 1024, 2048] { + bench_params(c, i, &seed) + } +} + +criterion_group!(benches, bench_square); +criterion_main!(benches); diff --git a/crates/vdf/build.rs b/crates/vdf/build.rs new file mode 100644 index 0000000..a8de622 --- /dev/null +++ b/crates/vdf/build.rs @@ -0,0 +1,115 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use std::{env, fs::File, io::Write, path::PathBuf, u16}; + +/// The number of odd primes less than 65536. +const PRIMES_LEN: usize = 6541; + +/// The number of integers that are: +/// +/// * equal to 7 mod 8 +/// * not divisible by any prime number less than or equal to 13. +/// * less than 8 * 3 * 5 * 7 * 11 * 13 +const RESIDUES_LEN: usize = 5760; + +/// The number of odd prime numbers between 13 and 65536 exclusive. +const SIEVE_INFO_LEN: usize = PRIMES_LEN - 5; + +fn odd_primes_below_65536() -> Vec { + const N: usize = 1 << 16; + let mut sieve = vec![true; N >> 1]; + let mut q = (N as f64).powf(0.5) as usize; + assert!(q * q <= N); + q += 1; + assert!(q * q > N); + for i in (3..q).step_by(2) { + if sieve[i >> 1] { + for i in ((i * i >> 1)..sieve.len()).step_by(i) { + sieve[i] = false; + } + } + } + // mega cheat ― we know the exact size of this vector + let res: Vec<_> = (1..N / 2) + .filter(|&i| sieve[i]) + .map(|i| 2 * i + 1) + .collect(); + assert_eq!(res.len(), PRIMES_LEN); + res +} + +fn mod_exponentiation(base: usize, exponent: usize, modulus: usize) -> usize { + assert!(base < u16::MAX.into()); + assert!(exponent < u16::MAX.into()); + assert!(modulus < u16::MAX.into()); + let (mut base, mut exponent, modulus) = (base as u32, exponent as u32, modulus as u32); + let mut state = 1; + loop { + if exponent & 1 != 0 { + state *= base; + state %= modulus; + } + exponent >>= 1; + if exponent == 0 { + return state as _; + } + base *= base; + base %= modulus; + } +} + +macro_rules! const_fmt { + () => { + "#[allow(warnings)]\nconst {}: [{}; {}] = {:#?};\n\n"; + }; +} + +/// A product of many small prime numbers. We precompute the numbers between +/// `1` and `M` that are coprime to `M`. Any number whose residue modulo `M` is +/// one of these is not divisible by any of the prime factors of `M`. This +/// speeds up the generation of random prime numbers. +const M: usize = 8 * 3 * 5 * 7 * 11 * 13; +fn emit(f: &mut dyn Write, name: &str, t: &str, obj: &[T]) { + write!(f, const_fmt!(), name, t, obj.len(), obj).expect("i/o error in build script"); +} + +/// Write the generated code to `f`. +fn generate(f: &mut dyn Write) { + write!(f, "const M: u32 = 8 * 3 * 5 * 7 * 11 * 13;\n\n").expect("i/o error"); + let residues: Vec = { + let primes = [3, 5, 7, 11, 13]; + let not_divisible = |&x: &usize| primes.iter().all(|p| x % p != 0); + (7..M).step_by(8).filter(not_divisible).collect() + }; + assert_eq!(residues.len(), RESIDUES_LEN); + emit(f, "RESIDUES", "u32", &residues[..]); + let sieve_info: Vec<(usize, usize)> = odd_primes_below_65536()[5..] + .iter() + .map(|&i| (i, mod_exponentiation(M % i, i - 2, i))) + .collect(); + assert_eq!(sieve_info.len(), SIEVE_INFO_LEN); + emit(f, "SIEVE_INFO", "(u16, u16)", &sieve_info[..]); +} + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + uniffi::generate_scaffolding("src/lib.udl").expect("uniffi generation failed"); + + let manifest_path = env::var("OUT_DIR").expect("cargo should have set this"); + let mut path = PathBuf::from(&manifest_path); + path.push("constants.rs"); + let mut f = File::create(path).expect("cannot create constants.rs"); + generate(&mut f); +} diff --git a/crates/vdf/src/create_discriminant.rs b/crates/vdf/src/create_discriminant.rs new file mode 100644 index 0000000..4b10225 --- /dev/null +++ b/crates/vdf/src/create_discriminant.rs @@ -0,0 +1,199 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Creation of discriminants. +//! +//! The [`pot`] tool does not accept a discriminant as a command-line argument. +//! Instead, we generate the discriminant from a (much smaller) seed. +//! +//! For performance, we follow the Chia network's [`inkfish`] implementation +//! of ["Close to Uniform Prime Number Generation With Fewer Random Bits"][1] +//! by Pierre-Alain Fouque and Mehdi Tibouchi. +//! We employ a table of precomputed constants generated by `build.rs`. +//! +//! [1]: https://eprint.iacr.org/2011/481.pdf +//! [`inkfish`]: +//! [`pot`]: + +include!(concat!(env!("OUT_DIR"), "/constants.rs")); + +use classgroup::BigNumExt; +use num_traits::Zero; +use sha2::{digest::FixedOutput, Digest, Sha256}; +use std::u16; + +fn random_bytes_from_seed(seed: &[u8], byte_count: usize) -> Vec { + assert!(byte_count <= 32 * ((1 << 16) - 1)); + let mut blob = Vec::with_capacity(byte_count); + let mut extra: u16 = 0; + while blob.len() < byte_count { + let mut hasher = Sha256::new(); + hasher.input(seed); + let extra_bits: [u8; 2] = [((extra & 0xFF00) >> 8) as _, (extra & 0xFF) as _]; + hasher.input(&extra_bits); + blob.extend_from_slice(&hasher.fixed_result()[..]); + extra += 1; + } + blob.resize(byte_count, 0); + blob +} + +/// Create a discriminant from a seed (a byte string) and a bit length (a +/// `u16`). The discriminant is guaranteed to be a negative prime number that +/// fits in `length` bits, except with negligible probability (less than +/// 2^(-100)). It is also guaranteed to equal 7 modulo 8. +/// +/// This function uses sha256 to expand the seed. Therefore, different seeds +/// will result in completely different discriminants with overwhelming +/// probability, unless `length` is very small. However, this function is +/// deterministic: if it is called twice with identical seeds and lengths, it +/// will always return the same discriminant. +/// +/// This function is guaranteed not to panic for any inputs whatsoever, unless +/// memory allocation fails and the allocator in use panics in that case. +pub fn create_discriminant(seed: &[u8], length: u16) -> T { + let (mut n, residue) = { + // The number of “extra” bits (that don’t evenly fit in a byte) + let extra: u8 = (length as u8) & 7; + + // The number of random bytes needed (the number of bytes that hold `length` + // bits, plus 2). + let random_bytes_len = ((usize::from(length) + 7) >> 3) + 2; + let random_bytes = random_bytes_from_seed(seed, random_bytes_len); + let (n, last_2) = random_bytes.split_at(random_bytes_len - 2); + let numerator = (usize::from(last_2[0]) << 8) + usize::from(last_2[1]); + + // If there are any extra bits, right shift `n` so that it fits + // in `length` bits, discarding the least significant bits. + let n = T::from(n) >> usize::from((8 - extra) & 7); + (n, RESIDUES[numerator % RESIDUES.len()]) + }; + n.setbit(usize::from(length - 1)); + debug_assert!(n >= Zero::zero()); + let rem = n.frem_u32(M); + + // HACK HACK `rust-gmp` doesn’t expose += and -= with i32 or i64 + if residue > rem { + n = n + u64::from(residue - rem); + } else { + n = n - u64::from(rem - residue); + } + debug_assert!(n >= Zero::zero()); + + // This generates the smallest prime ≥ n that is of the form n + m*x. + loop { + // Speed up prime-finding by quickly ruling out numbers + // that are known to be composite. + let mut sieve = ::bit_vec::BitVec::from_elem(1 << 16, false); + for &(p, q) in SIEVE_INFO.iter() { + // The reference implementation changes the sign of `n` before taking its + // remainder. Instead, we leave `n` as positive, but use ceiling + // division instead of floor division. This is mathematically + // equivalent and potentially faster. + let mut i: usize = (n.crem_u16(p) as usize * q as usize) % p as usize; + while i < sieve.len() { + sieve.set(i, true); + i += p as usize; + } + } + + for (i, x) in sieve.iter().enumerate() { + if !x { + let q = u64::from(M) * u64::from(i as u32); + n = n + q; + if n.probab_prime(1) { + return -n; + } + n = n - q; + } + } + // M is set to a number with many prime factors so the results are + // more uniform https://eprint.iacr.org/2011/481.pdf + // TODO: Explain previous reference to https://eprint.iacr.org/2011/401.pdf + n = n + (u64::from(M) * (1 << 16)) as u64 + } +} + +#[cfg(test)] +mod test { + use super::*; + use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup}; + type Mpz = ::BigNum; + use std::str::FromStr; + + #[test] + fn check_discriminant_1() { + assert_eq!( + create_discriminant::(b"\xaa", 40), + (-685_537_176_559i64).into() + ); + } + + #[test] + fn check_discriminant_3() { + assert_eq!( + create_discriminant::(b"\xaa", 1024), + Mpz::from_str( + "-112084717443890964296630631725167420667316836131914185144761\ + 7438378168250988242739496385274308134767869324152361453294226\ + 8295868231081182819214054220080323345750407342623884342617809\ + 8794592117225058677336074005099949757067786815439982423354682\ + 0386024058617141397148586038290164093146862666602485017735298\ + 03183" + ) + .unwrap() + ) + } + + #[test] + fn check_discriminant_2() { + assert_eq!( + create_discriminant::(b"\xaa", 2048), + -Mpz::from_str( + "201493927071865251625903550712920535753645598483515670853547009\ + 878440933309489362800393797428711071833308081461824159206915864\ + 150805748296170245037221957772328044276705571745811271212292422\ + 075849739248257870371300001313586036515879618764093772248760562\ + 386804073478433157526816295216137723803793411828867470089409596\ + 238958950007370719325959579892866588928887249912429688364409867\ + 895510817680171869190054122881274299350947669820596157115994418\ + 034091728887584373727555384075665624624856766441009974642693066\ + 751400054217209981490667208950669417773785631693879782993019167\ + 69407006303085854796535778826115224633447713584423" + ) + .unwrap() + ); + } + #[test] + fn check_random_bytes() { + assert_eq!( + &random_bytes_from_seed(b"\xaa", 7), + b"\x9f\x9d*\xe5\xe7<\xcb" + ); + assert_eq!( + &random_bytes_from_seed(b"\xaa", 258)[..], + &b"\x9f\x9d*\xe5\xe7<\xcbq\xa4q\x8e\ + \xbc\xf0\xe3:\xa2\x98\xf8\xbd\xdc\xaa\xcbi\xcb\x10\xff\x0e\xafv\xdb\xec!\xc4K\ + \xc6Jf\xf3\xa5\xda.7\xb7\xef\x87I\x85\xb8YX\xfc\xf2\x03\xa1\x8f4\xaf`\xab\xae]n\ + \xcc,g1\x12EI\xc7\xd5\xe2\xfc\x8b\x9a\xde\xd5\xf3\x8f'\xcd\x08\x0fU\xc7\xee\xa85\ + [>\x87]\x07\x82\x00\x13\xce\xf7\xc3/@\xef\x08v\x8f\x85\x87dm(1\x8b\xd9w\xffA]xzY\ + \xa0,\xebz\xff\x03$`\x91\xb66\x88-_\xa9\xf1\xc5\x8e,\x15\xae\x8f\x04\rvhnU3f\x84\ + [{$\xa6l\x95w\xa9\x1f\xba\xa8)\x05\xe6\x8f\x167o\x11/X\x9cl\xab\x9c\xcb}\xec\x88\ + \xf8\xa5\xabXpY\xb0\x88\xed@r\x05\xba\\\x03\xf6\x91\xf8\x03\xca\x18\x1c\xcdH\x1c\ + \x91\xe1V\xed;\x94oJ\xa8 \xa4\x97\xb7K\xce\xc4e\xea\xa2\xbf\x8b\x1f\x90\x87\xc8\ + \x15\xee\x0e\x0fPC:\xb5\xe1g\x97\xea/_\x86c\xaf\x12Wp\xfd\x11\xdb\x17\xe6\x9f\ + \xa5\x8a"[..] + ); + } +} diff --git a/crates/vdf/src/lib.rs b/crates/vdf/src/lib.rs new file mode 100644 index 0000000..4156829 --- /dev/null +++ b/crates/vdf/src/lib.rs @@ -0,0 +1,261 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![deny(warnings)] +//! # Rust implementations of class groups and verifyable delay functions +//! +//! This repo includes three crates +//! +//! * `classgroup`, which includes a class group implementation, as well as a +//! trait for class groups. +//! * `vdf`, which includes a Verifyable Delay Function (VDF) trait, as well as +//! an implementation of that trait. +//! * `vdf-cli`, which includes a command-line interface to the `vdf` crate. It +//! also includes additional commands, which are deprecated and will later be +//! replaced by a CLI to the `classgroup` crate. +//! +//! ## Usage +//! +//! First, install Rust, Cargo, and the GNU Multiprecision Library (GMP). Then, +//! follow one of the below steps. +//! +//! ### To use the command line interface +//! +//! ```sh +//! $ git clone https://github.com/poanetwork/vdf +//! $ cd vdf +//! $ cargo install +//! $ vdf-cli aa 100 +//! 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b +//! $ vdf-cli aa 100 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b +//! Proof is valid +//! ``` +//! +//! ### To use the VDF library +//! +//! ```rust +//! extern crate vdf; +//! use vdf::{InvalidProof, PietrzakVDFParams, VDFParams, WesolowskiVDFParams, VDF}; +//! const CORRECT_SOLUTION: &[u8] = +//! b"\x00\x52\x71\xe8\xf9\xab\x2e\xb8\xa2\x90\x6e\x85\x1d\xfc\xb5\x54\x2e\x41\x73\xf0\x16\ +//! \xb8\x5e\x29\xd4\x81\xa1\x08\xdc\x82\xed\x3b\x3f\x97\x93\x7b\x7a\xa8\x24\x80\x11\x38\ +//! \xd1\x77\x1d\xea\x8d\xae\x2f\x63\x97\xe7\x6a\x80\x61\x3a\xfd\xa3\x0f\x2c\x30\xa3\x4b\ +//! \x04\x0b\xaa\xaf\xe7\x6d\x57\x07\xd6\x86\x89\x19\x3e\x5d\x21\x18\x33\xb3\x72\xa6\xa4\ +//! \x59\x1a\xbb\x88\xe2\xe7\xf2\xf5\xa5\xec\x81\x8b\x57\x07\xb8\x6b\x8b\x2c\x49\x5c\xa1\ +//! \x58\x1c\x17\x91\x68\x50\x9e\x35\x93\xf9\xa1\x68\x79\x62\x0a\x4d\xc4\xe9\x07\xdf\x45\ +//! \x2e\x8d\xd0\xff\xc4\xf1\x99\x82\x5f\x54\xec\x70\x47\x2c\xc0\x61\xf2\x2e\xb5\x4c\x48\ +//! \xd6\xaa\x5a\xf3\xea\x37\x5a\x39\x2a\xc7\x72\x94\xe2\xd9\x55\xdd\xe1\xd1\x02\xae\x2a\ +//! \xce\x49\x42\x93\x49\x2d\x31\xcf\xf2\x19\x44\xa8\xbc\xb4\x60\x89\x93\x06\x5c\x9a\x00\ +//! \x29\x2e\x8d\x3f\x46\x04\xe7\x46\x5b\x4e\xee\xfb\x49\x4f\x5b\xea\x10\x2d\xb3\x43\xbb\ +//! \x61\xc5\xa1\x5c\x7b\xdf\x28\x82\x06\x88\x5c\x13\x0f\xa1\xf2\xd8\x6b\xf5\xe4\x63\x4f\ +//! \xdc\x42\x16\xbc\x16\xef\x7d\xac\x97\x0b\x0e\xe4\x6d\x69\x41\x6f\x9a\x9a\xce\xe6\x51\ +//! \xd1\x58\xac\x64\x91\x5b"; +//! +//! fn main() { +//! let pietrzak_vdf = PietrzakVDFParams(2048).new(); +//! assert_eq!( +//! &pietrzak_vdf.solve(b"\xaa", 100).unwrap()[..], +//! CORRECT_SOLUTION +//! ); +//! assert!(pietrzak_vdf.verify(b"\xaa", 100, CORRECT_SOLUTION).is_ok()); +//! } +//! ``` +//! +//! ### To run the benchmarks +//! +//! Benchmarks are provided for the classgroup operations. Run `cargo bench` +//! to run them. Additional benchmarks are under development. +use classgroup; + +mod create_discriminant; +use std::fmt::Debug; + +pub use self::{ + create_discriminant::create_discriminant, + proof_pietrzak::{PietrzakVDF, PietrzakVDFParams}, + proof_wesolowski::{WesolowskiVDF, WesolowskiVDFParams}, +}; + +/// Message used to report an internal miscalculation of serialization buffer +/// sizes. +const INCORRECT_BUFFER_SIZE: &str = + "internal error: incorrect buffer size calculation (this is a bug)"; + +mod proof_of_time; +mod proof_pietrzak; +mod proof_wesolowski; + +uniffi::include_scaffolding!("lib"); + +/// An empty struct indicating verification failure. +/// +/// For security reasons, the functions that perform verification *do not* +/// return any information on failure. Use `VDF::validate_params` to check if +/// the parameters are correct. +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)] +pub struct InvalidProof; + +/// An error return indicating an invalid number of iterations. The string is a +/// human-readable message describing the valid iterations. It should not be +/// interpreted by programs. +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)] +pub struct InvalidIterations(String); + +/// The type of VDF parameters. +/// +/// Parameters represent public information that can be shared by all users +/// of the protocol. As such, they must implement `Clone`, so that they can +/// be duplicated. They also must implement `Send`, so that a parallel +/// application can send them safely across threads. +/// +/// The parameters *do not* include the difficulty level (usually an +/// iteration count), since that can be separate for each invocation. +/// +/// This must implement `Clone` and `Eq`. +pub trait VDFParams: Clone + Eq { + type VDF: VDF + Sized; + + /// Creates an instance of this VDF from the given parameters. + /// + /// # Performance + /// + /// This method is expected to be fairly cheap. For example, it is okay if + /// it allocates memory, but it should not perform expensive computations or + /// I/O. + /// + /// # Panics + /// + /// This method **MUST NOT** fail due to invalid values for `params`. Such + /// errors should be checked by the factory functions for `Self::Params`. + /// + /// This function **MAY** panic for other reasons. For example, it is + /// allowed to panic if an allocation fails, or if a needed external library + /// could not be dynamically loaded. + fn new(self) -> Self::VDF; +} + +/// A Verifiable Delay Function (VDF). +/// +/// VDFs are problems that require a certain amount of time to solve, even on a +/// parallel machine, but can be validated much more easily. +/// +/// While VDFs are considered to be cryptographic primitives, they generally do +/// *not* operate on highly sensitive data. As such, implementers of this trait +/// **do not** guarantee that they will be immune to side-channel attacks, and +/// consumers of this trait **MUST NOT** expect this. +/// +/// Instances of this trait are *not* expected to be `Sync`. This allows them +/// to reuse allocations (such as scratch memory) accross invocations without +/// the need for locking. However, they **MUST** be `Send` and `Clone`, so that +/// consumers can duplicate them and send them across threads. +pub trait VDF: Send + Debug { + /// Solve an instance of this VDF, with challenge `challenge` and difficulty + /// `difficulty`. + /// + /// The output is to be returned in a `Vec`, so it can be stored to disk + /// or sent over the network. + /// + /// # Challenge format + /// + /// The challenge is an opaque byte string of arbitrary length. + /// Implementors **MUST NOT** make any assumptions about its contents, + /// and **MUST** produce distinct outputs for distinct challenges + /// (except with negiligible probability). + /// + /// This can be most easily implemented by using the challenge as part of + /// the input of a cryptographic hash function. The VDFs provided in this + /// crate use this strategy. + /// + /// The difficulty must be checked before performing any expensive + /// computations. + /// + /// Most applications will generate the challenge using a + /// cryptographically-secure pseudorandom number generator, but implementors + /// **MUST NOT** rely on this. In particular, this function must be secure + /// even if `challenge` is chosen by an adversary. Excessive values for + /// `difficulty` may cause excessive resource consumption, but must not + /// create any other vulnerabilities. + /// + /// # Complexity + /// + /// The VDFs in this crate consume memory that does not depend on + /// `difficulty`, and time linearly proportional to `difficulty`. + /// Implementors of this trait should document the resource use. + /// + /// # Purity + /// + /// This method must have no side effects. In particular, it must be + /// **deterministic**: it must always return the same output for the same + /// inputs, except with negligible probability. Furthermore, while it may + /// change `self` via interior mutability, such changes must not affect + /// future calls to this method, `Self::check_difficulty`, or + /// `Self::verify`. They *may* affect the `Debug` output. + fn solve(&self, challenge: &[u8], difficulty: u64) -> Result, InvalidIterations>; + + /// Check that the difficulty is valid. + /// + /// This must return `Ok` if and only if `difficulty` is valid. Otherwise, + /// it must return `Err`. + /// + /// # Rationale + /// + /// It would be more ideomatic Rust to use the type system to enforce that a + /// difficulty has been validated before use. However, I (Demi) have not + /// yet figured out an object-safe way to do so. + fn check_difficulty(&self, difficulty: u64) -> Result<(), InvalidIterations>; + + /// Verifies an alleged solution of this VDF, with challenge `challenge` and + /// difficulty `difficulty`. Return `Ok(())` on success, or + /// `Err(InvalidProof)` on failure. + /// + /// This function *does not* return any extended error information for + /// security reasons. To check that the difficulty is correct, call + /// `Self::check_difficulty`. + /// + /// # Uniqueness of valid solutions + /// + /// For any `(challenge, difficulty)` tuple, there must be at most one + /// `alleged_solution` (as measured by `Eq`) that causes this function to + /// return `Ok(())`. If the difficulty is valid (as determined by + /// `check_difficulty`), there must be exactly one such solution; otherwise, + /// there must be none. + /// + /// # Purity + /// + /// This method must have no side effects. In particular, it must be + /// **deterministic**: it must always return the same output for the same + /// inputs. Furthermore, while it may change `self` via interior + /// mutability, such changes must not affect future calls to this method, + /// `Self::prove`, or `Self::check_difficulty`. Such changes **MAY** affect + /// debugging output. + fn verify( + &self, + challenge: &[u8], + difficulty: u64, + alleged_solution: &[u8], + ) -> Result<(), InvalidProof>; +} + +/// Solve and prove with the Wesolowski VDF using the given parameters. +/// Outputs the concatenated solution and proof (in this order). +pub fn wesolowski_solve(int_size_bits: u16, challenge: &[u8], difficulty: u32) -> Vec { + let vdf = WesolowskiVDFParams(int_size_bits).new(); + vdf.solve(challenge, difficulty.into()).expect("invalid difficulty") +} + +/// Verify with the Wesolowski VDF using the given parameters. +/// `alleged_solution` is the output of `wesolowski_solve`. +pub fn wesolowski_verify(int_size_bits: u16, challenge: &[u8], difficulty: u32, alleged_solution: &[u8]) -> bool { + let vdf = WesolowskiVDFParams(int_size_bits).new(); + vdf.verify(challenge, difficulty.into(), alleged_solution).is_ok() +} diff --git a/crates/vdf/src/lib.udl b/crates/vdf/src/lib.udl new file mode 100644 index 0000000..66c0d18 --- /dev/null +++ b/crates/vdf/src/lib.udl @@ -0,0 +1,4 @@ +namespace vdf { + sequence wesolowski_solve(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty); + boolean wesolowski_verify(u16 int_size_bits, [ByRef] sequence challenge, u32 difficulty, [ByRef] sequence alleged_solution); +}; diff --git a/crates/vdf/src/proof_of_time.rs b/crates/vdf/src/proof_of_time.rs new file mode 100644 index 0000000..4b6afb6 --- /dev/null +++ b/crates/vdf/src/proof_of_time.rs @@ -0,0 +1,88 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use super::classgroup::ClassGroup; +use std::{collections::HashMap, usize}; + +pub fn serialize(proof: &[V], y: &V, int_size_bits: usize) -> Vec { + let proof_len = proof.len(); + let element_length = 2 * ((int_size_bits + 16) >> 4); + let proof_len_in_bytes = (proof_len + 1) * element_length; + let mut v = vec![0; proof_len_in_bytes]; + y.serialize(&mut v[0..element_length]) + .expect(super::INCORRECT_BUFFER_SIZE); + for (index, group) in proof.iter().enumerate() { + let offset = (index + 1) * element_length; + group + .serialize(&mut v[offset..offset + element_length]) + .expect(super::INCORRECT_BUFFER_SIZE) + } + v +} +pub fn deserialize_proof( + proof_blob: &[u8], + discriminant: &T::BigNum, + orig_length: usize, +) -> Result, ()> +where + T: ClassGroup, + for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>, + for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>, +{ + let length = T::size_in_bits(discriminant); + if length > usize::MAX - 16 { + return Err(()); + } + let length = (length + 16) >> 4; + if length == 0 { + return Err(()); + } + if orig_length != length { + return Err(()); + } + let length = length * 2; + let proof_blob_length = proof_blob.len(); + let rem = proof_blob_length % length; + if rem != 0 { + return Err(()); + } + let proof_len = proof_blob_length / length; + let mut v = Vec::with_capacity(proof_len); + for i in 0..proof_len { + let offset = i * length; + v.push(T::from_bytes( + &proof_blob[offset..offset + length], + discriminant.clone(), + )) + } + Ok(v) +} + +pub fn iterate_squarings(mut x: V, powers_to_calculate: U) -> HashMap +where + V: ClassGroup, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, + U: Iterator, +{ + let mut powers_calculated = HashMap::new(); + let mut powers_to_calculate: Vec = powers_to_calculate.collect(); + powers_to_calculate.sort_unstable(); + let mut previous_power: u64 = 0; + for ¤t_power in &powers_to_calculate { + x.repeated_square(current_power - previous_power); + powers_calculated.insert(current_power, x.clone()); + previous_power = current_power + } + powers_calculated +} diff --git a/crates/vdf/src/proof_pietrzak.rs b/crates/vdf/src/proof_pietrzak.rs new file mode 100644 index 0000000..786cecb --- /dev/null +++ b/crates/vdf/src/proof_pietrzak.rs @@ -0,0 +1,466 @@ +// Copyright 2018 Chia Network Inc and POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use super::proof_of_time::{deserialize_proof, iterate_squarings, serialize}; +use classgroup::{gmp_classgroup::GmpClassGroup, BigNumExt, ClassGroup}; +use num_traits::{One, Zero}; +use std::{fmt, num::ParseIntError, ops::Index, str::FromStr, u64, usize}; + +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone, Debug)] +pub struct Iterations(u64); + +#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Copy, Clone, Debug)] +pub enum InvalidIterations { + OddNumber(u64), + LessThan66(u64), +} + +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct ParseIterationsError { + kind: Result, +} + +impl From for ParseIterationsError { + fn from(t: InvalidIterations) -> Self { + Self { kind: Ok(t) } + } +} + +impl From for ParseIterationsError { + fn from(t: ParseIntError) -> Self { + Self { kind: Err(t) } + } +} + +impl fmt::Display for InvalidIterations { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + InvalidIterations::OddNumber(s) => { + write!(f, "Pietrzak iterations must be an even number, not {}", s) + } + InvalidIterations::LessThan66(s) => write!( + f, + "Pietrzak proof-of-time must run for at least 66 iterations, not {}", + s + ), + } + } +} + +impl From for u64 { + fn from(t: Iterations) -> u64 { + t.0 + } +} + +impl fmt::Display for ParseIterationsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + Ok(ref q) => ::fmt(q, f), + Err(ref q) => ::fmt(q, f), + } + } +} + +impl FromStr for Iterations { + type Err = ParseIterationsError; + fn from_str(s: &str) -> Result { + Self::new(s.parse::().map_err(ParseIterationsError::from)?) + .map_err(ParseIterationsError::from) + } +} + +impl Iterations { + pub fn new>(iterations: T) -> Result { + let iterations = iterations.into(); + if iterations & 1 != 0 { + Err(InvalidIterations::OddNumber(iterations)) + } else if iterations < 66 { + Err(InvalidIterations::LessThan66(iterations)) + } else { + Ok(Iterations(iterations)) + } + } +} + +/// Selects a reasonable choice of cache size. +fn approximate_i(t: Iterations) -> u64 { + let x: f64 = (((t.0 >> 1) as f64) / 8.) * 2.0f64.ln(); + let w = x.ln() - x.ln().ln() + 0.25; + (w / (2. * 2.0f64.ln())).round() as _ +} + +fn sum_combinations<'a, T: IntoIterator>(numbers: T) -> Vec { + let mut combinations = vec![0]; + for i in numbers { + let mut new_combinations = combinations.clone(); + for j in combinations { + new_combinations.push(i + j) + } + combinations = new_combinations + } + combinations.remove(0); + combinations +} + +fn cache_indices_for_count(t: Iterations) -> Vec { + let i: u64 = approximate_i(t); + let mut curr_t = t.0; + let mut intermediate_ts = vec![]; + for _ in 0..i { + curr_t >>= 1; + intermediate_ts.push(curr_t); + if curr_t & 1 != 0 { + curr_t += 1 + } + } + let mut cache_indices = sum_combinations(&intermediate_ts); + cache_indices.sort(); + cache_indices.push(t.0); + cache_indices +} + +fn generate_r_value(x: &T, y: &T, sqrt_mu: &T, int_size_bits: usize) -> T::BigNum +where + T: ClassGroup, + for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>, + for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>, +{ + use sha2::{digest::FixedOutput, Digest, Sha256}; + + let size = (int_size_bits + 16) >> 4; + let mut v = Vec::with_capacity(size * 2); + for _ in 0..size * 2 { + v.push(0) + } + let mut hasher = Sha256::new(); + for i in &[&x, &y, &sqrt_mu] { + i.serialize(&mut v).expect(super::INCORRECT_BUFFER_SIZE); + hasher.input(&v); + } + let res = hasher.fixed_result(); + T::unsigned_deserialize_bignum(&res[..16]) +} + +fn create_proof_of_time_pietrzak( + challenge: &[u8], + iterations: Iterations, + int_size_bits: u16, +) -> Vec +where + T: ClassGroup, + ::BigNum: BigNumExt, + for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>, + for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>, +{ + let discriminant = super::create_discriminant::create_discriminant(&challenge, int_size_bits); + let x = T::from_ab_discriminant(2.into(), 1.into(), discriminant); + + let delta = 8; + let powers_to_calculate = cache_indices_for_count(iterations); + let powers = iterate_squarings(x.clone(), powers_to_calculate.iter().cloned()); + let proof: Vec = generate_proof( + x, + iterations, + delta, + &powers, + &generate_r_value, + usize::from(int_size_bits), + ); + serialize( + &proof, + &powers[&iterations.into()], + usize::from(int_size_bits), + ) +} + +pub fn check_proof_of_time_pietrzak( + challenge: &[u8], + proof_blob: &[u8], + iterations: u64, + length_in_bits: u16, +) -> Result<(), super::InvalidProof> +where + T: ClassGroup, + T::BigNum: BigNumExt, + for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>, + for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>, +{ + let discriminant = super::create_discriminant::create_discriminant(&challenge, length_in_bits); + let x = T::from_ab_discriminant(2.into(), 1.into(), discriminant); + let iterations = Iterations::new(iterations).map_err(|_| super::InvalidProof)?; + if usize::MAX - 16 < length_in_bits.into() { + // Proof way too long. + return Err(super::InvalidProof); + } + let length: usize = (usize::from(length_in_bits) + 16usize) >> 4; + if proof_blob.len() < 2 * length { + // Invalid length of proof + return Err(super::InvalidProof); + } + let result_bytes = &proof_blob[..length * 2]; + let proof_bytes = &proof_blob[length * 2..]; + let discriminant = x.discriminant().clone(); + let proof = + deserialize_proof(proof_bytes, &discriminant, length).map_err(|()| super::InvalidProof)?; + let y = T::from_bytes(result_bytes, discriminant); + verify_proof( + &x, + &y, + proof, + iterations, + 8, + &generate_r_value, + length_in_bits.into(), + ) + .map_err(|()| super::InvalidProof) +} + +fn calculate_final_t(t: Iterations, delta: usize) -> u64 { + let mut curr_t = t.0; + let mut ts = vec![]; + while curr_t != 2 { + ts.push(curr_t); + curr_t >>= 1; + if curr_t & 1 == 1 { + curr_t += 1 + } + } + ts.push(2); + ts.push(1); + assert!(ts.len() >= delta); + ts[ts.len() - delta] +} + +pub fn generate_proof( + x: V, + iterations: Iterations, + delta: usize, + powers: &T, + generate_r_value: &U, + int_size_bits: usize, +) -> Vec +where + T: for<'a> Index<&'a u64, Output = V>, + U: Fn(&V, &V, &V, usize) -> V::BigNum, + V: ClassGroup, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, +{ + let identity = x.identity(); + let i = approximate_i(iterations); + let mut mus = vec![]; + let mut rs: Vec = vec![]; + let mut x_p = vec![x]; + let mut curr_t = iterations.0; + + let mut y_p = vec![powers[&curr_t].clone()]; + + let mut ts = vec![]; + + let final_t = calculate_final_t(iterations, delta); + + let mut round_index = 0; + while curr_t != final_t { + assert_eq!(curr_t & 1, 0); + let half_t = curr_t >> 1; + ts.push(half_t); + assert!(round_index < 63); + let denominator: u64 = 1 << (round_index + 1); + + mus.push(if round_index < i { + let mut mu = identity.clone(); + for numerator in (1..denominator).step_by(2) { + let num_bits = 62 - denominator.leading_zeros() as usize; + let mut r_prod: V::BigNum = One::one(); + for b in (0..num_bits).rev() { + if 0 == (numerator & (1 << (b + 1))) { + r_prod *= &rs[num_bits - b - 1] + } + } + let mut t_sum = half_t; + for b in 0..num_bits { + if 0 != (numerator & (1 << (b + 1))) { + t_sum += ts[num_bits - b - 1] + } + } + let mut power = powers[&t_sum].clone(); + power.pow(r_prod); + mu *= &power; + } + mu + } else { + let mut mu = x_p.last().unwrap().clone(); + for _ in 0..half_t { + mu *= &mu.clone() + } + mu + }); + let mut mu: V = mus.last().unwrap().clone(); + let last_r: V::BigNum = generate_r_value(&x_p[0], &y_p[0], &mu, int_size_bits); + assert!(last_r >= Zero::zero()); + rs.push(last_r.clone()); + { + let mut last_x: V = x_p.last().unwrap().clone(); + last_x.pow(last_r.clone()); + last_x *= μ + x_p.push(last_x); + } + mu.pow(last_r); + mu *= y_p.last().unwrap(); + y_p.push(mu); + curr_t >>= 1; + if curr_t & 1 != 0 { + curr_t += 1; + y_p.last_mut().unwrap().square(); + } + round_index += 1 + } + if cfg!(debug_assertions) { + let mut last_y = y_p.last().unwrap().clone(); + let mut last_x = x_p.last().unwrap().clone(); + let one: V::BigNum = 1u64.into(); + last_y.pow(one.clone()); + assert_eq!(last_y, y_p.last().unwrap().clone()); + last_x.pow(one << final_t as usize); + } + mus +} + +pub fn verify_proof( + x_initial: &V, + y_initial: &V, + proof: T, + t: Iterations, + delta: usize, + generate_r_value: &U, + int_size_bits: usize, +) -> Result<(), ()> +where + T: IntoIterator, + U: Fn(&V, &V, &V, usize) -> V::BigNum, + V: ClassGroup, + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, +{ + let mut one: V::BigNum = One::one(); + let (mut x, mut y): (V, V) = (x_initial.clone(), y_initial.clone()); + let final_t = calculate_final_t(t, delta); + let mut curr_t = t.0; + for mut mu in proof { + assert!( + curr_t & 1 == 0, + "Cannot have an odd number of iterations remaining" + ); + let r = generate_r_value(x_initial, y_initial, &mu, int_size_bits); + x.pow(r.clone()); + x *= μ + mu.pow(r); + y *= μ + + curr_t >>= 1; + if curr_t & 1 != 0 { + curr_t += 1; + y.square(); + } + } + one <<= final_t as _; + x.pow(one); + if x == y { + Ok(()) + } else { + Err(()) + } +} + +#[derive(Debug, Clone)] +pub struct PietrzakVDF { + int_size_bits: u16, +} +use super::InvalidIterations as Bad; + +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)] +pub struct PietrzakVDFParams(pub u16); +impl super::VDFParams for PietrzakVDFParams { + type VDF = PietrzakVDF; + fn new(self) -> Self::VDF { + PietrzakVDF { + int_size_bits: self.0, + } + } +} + +impl super::VDF for PietrzakVDF { + fn check_difficulty(&self, difficulty: u64) -> Result<(), Bad> { + Iterations::new(difficulty) + .map_err(|x| Bad(format!("{}", x))) + .map(drop) + } + fn solve(&self, challenge: &[u8], difficulty: u64) -> Result, Bad> { + Ok(create_proof_of_time_pietrzak::( + challenge, + Iterations::new(difficulty).map_err(|x| Bad(format!("{}", x)))?, + self.int_size_bits, + )) + } + + fn verify( + &self, + challenge: &[u8], + difficulty: u64, + alleged_solution: &[u8], + ) -> Result<(), super::InvalidProof> { + check_proof_of_time_pietrzak::( + challenge, + alleged_solution, + difficulty, + self.int_size_bits, + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn check_approximate_i() { + assert_eq!(approximate_i(Iterations(534)), 2); + assert_eq!(approximate_i(Iterations(134)), 1); + assert_eq!(approximate_i(Iterations(1024)), 2); + } + #[test] + fn check_cache_indices() { + assert_eq!(cache_indices_for_count(Iterations(66))[..], [33, 66]); + assert_eq!( + cache_indices_for_count(Iterations(534))[..], + [134, 267, 401, 534] + ); + } + + #[test] + fn check_calculate_final_t() { + assert_eq!(calculate_final_t(Iterations(1024), 8), 128); + assert_eq!(calculate_final_t(Iterations(1000), 8), 126); + assert_eq!(calculate_final_t(Iterations(100), 8), 100); + } + #[test] + fn check_assuptions_about_stdlib() { + assert_eq!(62 - u64::leading_zeros(1024u64), 9); + let mut q: Vec<_> = (1..4).step_by(2).collect(); + assert_eq!(q[..], [1, 3]); + q = (1..3).step_by(2).collect(); + assert_eq!(q[..], [1]); + q = (1..2).step_by(2).collect(); + assert_eq!(q[..], [1]); + } +} diff --git a/crates/vdf/src/proof_wesolowski.rs b/crates/vdf/src/proof_wesolowski.rs new file mode 100644 index 0000000..bbc72b5 --- /dev/null +++ b/crates/vdf/src/proof_wesolowski.rs @@ -0,0 +1,316 @@ +// Copyright 2018 POA Networks Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::proof_of_time::{iterate_squarings, serialize}; +use classgroup::{gmp_classgroup::GmpClassGroup, BigNum, BigNumExt, ClassGroup}; +use sha2::{digest::FixedOutput, Digest, Sha256}; +use std::{cmp::Eq, collections::HashMap, hash::Hash, mem, u64, usize}; +use std::convert::TryInto; + +#[derive(Debug, Clone)] +pub struct WesolowskiVDF { + int_size_bits: u16, +} +use super::InvalidIterations as Bad; + +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)] +pub struct WesolowskiVDFParams(pub u16); +impl super::VDFParams for WesolowskiVDFParams { + type VDF = WesolowskiVDF; + fn new(self) -> Self::VDF { + WesolowskiVDF { + int_size_bits: self.0, + } + } +} + +impl super::VDF for WesolowskiVDF { + fn check_difficulty(&self, _difficulty: u64) -> Result<(), Bad> { + Ok(()) + } + fn solve(&self, challenge: &[u8], difficulty: u64) -> Result, Bad> { + if difficulty > usize::MAX as u64 { + Err(Bad("Cannot have more that usize::MAX iterations".to_owned())) + } else { + Ok(create_proof_of_time_wesolowski::< + ::BigNum, + GmpClassGroup, + >( + challenge, difficulty as usize, self.int_size_bits + )) + } + } + + fn verify( + &self, + challenge: &[u8], + difficulty: u64, + alleged_solution: &[u8], + ) -> Result<(), super::InvalidProof> { + check_proof_of_time_wesolowski::<::BigNum, GmpClassGroup>( + challenge, + alleged_solution, + difficulty, + self.int_size_bits, + ) + .map_err(|()| super::InvalidProof) + } +} +/// To quote the original Python code: +/// +/// > Create `L` and `k` parameters from papers, based on how many iterations +/// > need to be performed, and how much memory should be used. +pub fn approximate_parameters(t: f64) -> (usize, u8, u64) { + let log_memory = (10_000_000.0f64).log2(); + let log_t = (t as f64).log2(); + let l = if log_t - log_memory > 0. { + 2.0f64.powf(log_memory - 20.).ceil() + } else { + 1. + }; + + let intermediate = t * (2.0f64).ln() / (2.0 * l); + let k = (intermediate.ln() - intermediate.ln().ln() + 0.25) + .round() + .max(1.); + + let w = (t / (t / k + l * (2.0f64).powf(k + 1.0)) - 2.0).floor(); + (l as _, k as _, w as _) +} + +fn u64_to_bytes(q: u64) -> [u8; 8] { + if false { + // This use of `std::mem::transumte` is correct, but still not justified. + unsafe { std::mem::transmute(q.to_be()) } + } else { + [ + (q >> 56) as u8, + (q >> 48) as u8, + (q >> 40) as u8, + (q >> 32) as u8, + (q >> 24) as u8, + (q >> 16) as u8, + (q >> 8) as u8, + q as u8, + ] + } +} + +/// Quote: +/// +/// > Creates a random prime based on input s. +fn hash_prime(seed: &[&[u8]], t: u32) -> T { + let mut j = 0u64; + loop { + let mut hasher = Sha256::new(); + hasher.input(b"prime"); + hasher.input(u64_to_bytes(j)); + for i in seed { + hasher.input(i); + } + hasher.input(t.to_be_bytes()); + let n = T::from(&hasher.fixed_result()[..16]); + if n.probab_prime(1) { + break n; + } + j += 1; + } +} + +/// Quote: +/// +/// > Get“s the ith block of `2^T // B`, such that `sum(get_block(i) * 2^(k*i)) +/// > = t^T // B` +fn get_block(i: u64, k: u8, t: u64, b: &T) -> T { + let mut res = T::from(0); + let two = T::from(2); + res.mod_powm(&two, &T::from(t - u64::from(k) * (i + 1)), b); + res *= &((two >> 1) << (k as usize)); + res / b +} + +fn eval_optimized + Eq + Hash>( + h: &L, + b: &U, + t: usize, + k: u8, + l: usize, + powers: &T, +) -> L +where + T: for<'a> std::ops::Index<&'a u64, Output = L>, +{ + assert!(k > 0, "k cannot be zero"); + assert!(l > 0, "l cannot be zero"); + let kl = (k as usize) + .checked_mul(l) + .expect("computing k*l overflowed a u64"); + assert!(kl <= u64::MAX as _); + assert!((kl as u64) < (1u64 << 53), "k*l overflowed an f64"); + assert!((t as u64) < (1u64 << 53), "t overflows an f64"); + assert!( + k < (mem::size_of::() << 3) as u8, + "k must be less than the number of bits in a usize" + ); + let k1 = k >> 1; + let k0 = k - k1; + let mut x = h.identity(); + let identity = h.identity(); + let k_exp = 1usize << k; + let k0_exp = 1usize << k0; + let k1_exp = 1usize << k1; + for j in (0..l).rev() { + x.pow(U::from(k_exp as u64)); + let mut ys: HashMap = HashMap::new(); + for b in 0..1usize << k { + ys.entry(U::from(b as u64)) + .or_insert_with(|| identity.clone()); + } + let end_of_loop = ((t as f64) / kl as f64).ceil() as usize; + assert!(end_of_loop == 0 || (end_of_loop as u64 - 1).checked_mul(l as u64).is_some()); + for i in 0..end_of_loop { + if t < k as usize * (i * l + j + 1) { + continue; + } + let b = get_block((i as u64) * (l as u64), k, t as _, b); + *ys.get_mut(&b).unwrap() *= &powers[&((i * kl) as _)]; + } + + for b1 in 0..k1_exp { + let mut z = identity.clone(); + for b0 in 0..k0_exp { + z *= &ys[&U::from((b1 * k0_exp + b0) as u64)] + } + z.pow(U::from((b1 as u64) * (k0_exp as u64))); + x *= &z; + } + + for b0 in 0..k0_exp { + let mut z = identity.clone(); + for b1 in 0..k1_exp { + z *= &ys[&U::from((b1 * k0_exp + b0) as u64)]; + } + z.pow(U::from(b0 as u64)); + x *= &z; + } + } + x +} + +pub fn generate_proof + Eq + Hash>( + x: &V, + iterations: u64, + k: u8, + l: usize, + powers: &U, + int_size_bits: usize, +) -> V +where + U: for<'a> std::ops::Index<&'a u64, Output = V>, +{ + let element_len = 2 * ((int_size_bits + 16) >> 4); + let mut x_buf = vec![0; element_len]; + x.serialize(&mut x_buf[..]) + .expect(super::INCORRECT_BUFFER_SIZE); + let mut y_buf = vec![0; element_len]; + powers[&iterations] + .serialize(&mut y_buf[..]) + .expect(super::INCORRECT_BUFFER_SIZE); + let b = hash_prime( + &[&x_buf[..], &y_buf[..]], + iterations.try_into().expect("iterations fit into u32") + ); + eval_optimized(&x, &b, iterations as _, k, l, powers) +} + +/// Verify a proof, according to the Wesolowski paper. +pub fn verify_proof>( + mut x: V, + y: &V, + mut proof: V, + t: u64, + int_size_bits: usize, +) -> Result<(), ()> { + let element_len = 2 * ((int_size_bits + 16) >> 4); + let mut x_buf = vec![0; element_len]; + x.serialize(&mut x_buf[..]) + .expect(super::INCORRECT_BUFFER_SIZE); + let mut y_buf = vec![0; element_len]; + y.serialize(&mut y_buf[..]) + .expect(super::INCORRECT_BUFFER_SIZE); + let b = hash_prime( + &[&x_buf[..], &y_buf[..]], + t.try_into().expect("iterations fit into u32") + ); + let mut r = T::from(0); + r.mod_powm(&T::from(2u64), &T::from(t), &b); + proof.pow(b); + x.pow(r); + proof *= &x; + if &proof == y { + Ok(()) + } else { + Err(()) + } +} + +pub fn create_proof_of_time_wesolowski + Eq + Hash>( + challenge: &[u8], + iterations: usize, + int_size_bits: u16, +) -> Vec +where + for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>, + for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>, +{ + let discriminant = super::create_discriminant::create_discriminant(&challenge, int_size_bits); + let x = V::from_ab_discriminant(2.into(), 1.into(), discriminant); + assert!((iterations as u128) < (1u128 << 53)); + let (l, k, _) = approximate_parameters(iterations as f64); + let q = l.checked_mul(k as _).expect("bug"); + let powers = iterate_squarings( + x.clone(), + (0..=iterations / q + 1) + .map(|i| i * q) + .chain(Some(iterations)) + .map(|x| x as _), + ); + let proof = generate_proof(&x, iterations as _, k, l, &powers, int_size_bits.into()); + serialize(&[proof], &powers[&(iterations as _)], int_size_bits.into()) +} + +pub fn check_proof_of_time_wesolowski>( + challenge: &[u8], + proof_blob: &[u8], + iterations: u64, + int_size_bits: u16, +) -> Result<(), ()> +where + T: BigNumExt, +{ + let discriminant: T = super::create_discriminant::create_discriminant(challenge, int_size_bits); + let x = V::from_ab_discriminant(2.into(), 1.into(), discriminant.clone()); + if (usize::MAX - 16) < int_size_bits.into() { + return Err(()); + } + let int_size = (usize::from(int_size_bits) + 16) >> 4; + if int_size * 4 != proof_blob.len() { + return Err(()); + } + let (result_bytes, proof_bytes) = proof_blob.split_at(2 * int_size); + let proof = ClassGroup::from_bytes(proof_bytes, discriminant.clone()); + let y = ClassGroup::from_bytes(result_bytes, discriminant); + + verify_proof(x, &y, proof, iterations, int_size_bits.into()) +} diff --git a/docker/rustup-init.sh b/docker/rustup-init.sh new file mode 100755 index 0000000..c49b6ab --- /dev/null +++ b/docker/rustup-init.sh @@ -0,0 +1,811 @@ +#!/bin/sh +# shellcheck shell=dash +# shellcheck disable=SC2039 # local is non-POSIX + +# This is just a little script that can be downloaded from the internet to +# install rustup. It just does platform detection, downloads the installer +# and runs it. + +# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local` +# extension. Note: Most shells limit `local` to 1 var per line, contra bash. + +# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but +# beware this makes variables global with f()-style function syntax in ksh93. +# mksh has this alias by default. +has_local() { + # shellcheck disable=SC2034 # deliberately unused + local _has_local +} + +has_local 2>/dev/null || alias local=typeset + +is_zsh() { + [ -n "${ZSH_VERSION-}" ] +} + +set -u + +# If RUSTUP_UPDATE_ROOT is unset or empty, default it. +RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}" + +# NOTICE: If you change anything here, please make the same changes in setup_mode.rs +usage() { + cat < + Choose a default host triple + --default-toolchain + Choose a default toolchain to install. Use 'none' to not install any toolchains at all + --profile + [default: default] [possible values: minimal, default, complete] + -c, --component ... + Component name to also install + -t, --target ... + Target name to also install + --no-update-default-toolchain + Don't update any existing default toolchain after install + --no-modify-path + Don't configure the PATH environment variable + -h, --help + Print help + -V, --version + Print version +EOF +} + +main() { + downloader --check + need_cmd uname + need_cmd mktemp + need_cmd chmod + need_cmd mkdir + need_cmd rm + need_cmd rmdir + + get_architecture || return 1 + local _arch="$RETVAL" + assert_nz "$_arch" "arch" + + local _ext="" + case "$_arch" in + *windows*) + _ext=".exe" + ;; + esac + + local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}" + + local _dir + if ! _dir="$(ensure mktemp -d)"; then + # Because the previous command ran in a subshell, we must manually + # propagate exit status. + exit 1 + fi + local _file="${_dir}/rustup-init${_ext}" + + local _ansi_escapes_are_valid=false + if [ -t 2 ]; then + if [ "${TERM+set}" = 'set' ]; then + case "$TERM" in + xterm*|rxvt*|urxvt*|linux*|vt*) + _ansi_escapes_are_valid=true + ;; + esac + fi + fi + + # check if we have to use /dev/tty to prompt the user + local need_tty=yes + for arg in "$@"; do + case "$arg" in + --help) + usage + exit 0 + ;; + *) + OPTIND=1 + if [ "${arg%%--*}" = "" ]; then + # Long option (other than --help); + # don't attempt to interpret it. + continue + fi + while getopts :hy sub_arg "$arg"; do + case "$sub_arg" in + h) + usage + exit 0 + ;; + y) + # user wants to skip the prompt -- + # we don't need /dev/tty + need_tty=no + ;; + *) + ;; + esac + done + ;; + esac + done + + if $_ansi_escapes_are_valid; then + printf "\33[1minfo:\33[0m downloading installer\n" 1>&2 + else + printf '%s\n' 'info: downloading installer' 1>&2 + fi + + ensure mkdir -p "$_dir" + ensure downloader "$_url" "$_file" "$_arch" + ensure chmod u+x "$_file" + if [ ! -x "$_file" ]; then + printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2 + printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2 + exit 1 + fi + + if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then + # The installer is going to want to ask for confirmation by + # reading stdin. This script was piped into `sh` though and + # doesn't have stdin to pass to its children. Instead we're going + # to explicitly connect /dev/tty to the installer's stdin. + if [ ! -t 1 ]; then + err "Unable to run interactively. Run with -y to accept defaults, --help for additional options" + fi + + ignore "$_file" "$@" < /dev/tty + else + ignore "$_file" "$@" + fi + + local _retval=$? + + ignore rm "$_file" + ignore rmdir "$_dir" + + return "$_retval" +} + +check_proc() { + # Check for /proc by looking for the /proc/self/exe link + # This is only run on Linux + if ! test -L /proc/self/exe ; then + err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc." + fi +} + +get_bitness() { + need_cmd head + # Architecture detection without dependencies beyond coreutils. + # ELF files start out "\x7fELF", and the following byte is + # 0x01 for 32-bit and + # 0x02 for 64-bit. + # The printf builtin on some shells like dash only supports octal + # escape sequences, so we use those. + local _current_exe_head + _current_exe_head=$(head -c 5 /proc/self/exe ) + if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then + echo 32 + elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then + echo 64 + else + err "unknown platform bitness" + fi +} + +is_host_amd64_elf() { + need_cmd head + need_cmd tail + # ELF e_machine detection without dependencies beyond coreutils. + # Two-byte field at offset 0x12 indicates the CPU, + # but we're interested in it being 0x3E to indicate amd64, or not that. + local _current_exe_machine + _current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1) + [ "$_current_exe_machine" = "$(printf '\076')" ] +} + +get_endianness() { + local cputype=$1 + local suffix_eb=$2 + local suffix_el=$3 + + # detect endianness without od/hexdump, like get_bitness() does. + need_cmd head + need_cmd tail + + local _current_exe_endianness + _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)" + if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then + echo "${cputype}${suffix_el}" + elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then + echo "${cputype}${suffix_eb}" + else + err "unknown platform endianness" + fi +} + +# Detect the Linux/LoongArch UAPI flavor, with all errors being non-fatal. +# Returns 0 or 234 in case of successful detection, 1 otherwise (/tmp being +# noexec, or other causes). +check_loongarch_uapi() { + need_cmd base64 + + local _tmp + if ! _tmp="$(ensure mktemp)"; then + return 1 + fi + + # Minimal Linux/LoongArch UAPI detection, exiting with 0 in case of + # upstream ("new world") UAPI, and 234 (-EINVAL truncated) in case of + # old-world (as deployed on several early commercial Linux distributions + # for LoongArch). + # + # See https://gist.github.com/xen0n/5ee04aaa6cecc5c7794b9a0c3b65fc7f for + # source to this helper binary. + ignore base64 -d > "$_tmp" <&2 + echo 'Your Linux kernel does not provide the ABI required by this Rust' >&2 + echo 'distribution. Please check with your OS provider for how to obtain a' >&2 + echo 'compatible Rust package for your system.' >&2 + echo >&2 + exit 1 + ;; + *) + echo "Warning: Cannot determine current system's ABI flavor, continuing anyway." >&2 + echo >&2 + echo 'Note that the official Rust distribution only works with the upstream' >&2 + echo 'kernel ABI. Installation will fail if your running kernel happens to be' >&2 + echo 'incompatible.' >&2 + ;; + esac +} + +get_architecture() { + local _ostype _cputype _bitness _arch _clibtype + _ostype="$(uname -s)" + _cputype="$(uname -m)" + _clibtype="gnu" + + if [ "$_ostype" = Linux ]; then + if [ "$(uname -o)" = Android ]; then + _ostype=Android + fi + if ldd --version 2>&1 | grep -q 'musl'; then + _clibtype="musl" + fi + fi + + if [ "$_ostype" = Darwin ]; then + # Darwin `uname -m` can lie due to Rosetta shenanigans. If you manage to + # invoke a native shell binary and then a native uname binary, you can + # get the real answer, but that's hard to ensure, so instead we use + # `sysctl` (which doesn't lie) to check for the actual architecture. + if [ "$_cputype" = i386 ]; then + # Handling i386 compatibility mode in older macOS versions (<10.15) + # running on x86_64-based Macs. + # Starting from 10.15, macOS explicitly bans all i386 binaries from running. + # See: + + # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. + if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then + _cputype=x86_64 + fi + elif [ "$_cputype" = x86_64 ]; then + # Handling x86-64 compatibility mode (a.k.a. Rosetta 2) + # in newer macOS versions (>=11) running on arm64-based Macs. + # Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries. + + # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. + if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then + _cputype=arm64 + fi + fi + fi + + if [ "$_ostype" = SunOS ]; then + # Both Solaris and illumos presently announce as "SunOS" in "uname -s" + # so use "uname -o" to disambiguate. We use the full path to the + # system uname in case the user has coreutils uname first in PATH, + # which has historically sometimes printed the wrong value here. + if [ "$(/usr/bin/uname -o)" = illumos ]; then + _ostype=illumos + fi + + # illumos systems have multi-arch userlands, and "uname -m" reports the + # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86 + # systems. Check for the native (widest) instruction set on the + # running kernel: + if [ "$_cputype" = i86pc ]; then + _cputype="$(isainfo -n)" + fi + fi + + case "$_ostype" in + + Android) + _ostype=linux-android + ;; + + Linux) + check_proc + _ostype=unknown-linux-$_clibtype + _bitness=$(get_bitness) + ;; + + FreeBSD) + _ostype=unknown-freebsd + ;; + + NetBSD) + _ostype=unknown-netbsd + ;; + + DragonFly) + _ostype=unknown-dragonfly + ;; + + Darwin) + _ostype=apple-darwin + ;; + + illumos) + _ostype=unknown-illumos + ;; + + MINGW* | MSYS* | CYGWIN* | Windows_NT) + _ostype=pc-windows-gnu + ;; + + *) + err "unrecognized OS type: $_ostype" + ;; + + esac + + case "$_cputype" in + + i386 | i486 | i686 | i786 | x86) + _cputype=i686 + ;; + + xscale | arm) + _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + fi + ;; + + armv6l) + _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + + armv7l | armv8l) + _cputype=armv7 + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + + aarch64 | arm64) + _cputype=aarch64 + ;; + + x86_64 | x86-64 | x64 | amd64) + _cputype=x86_64 + ;; + + mips) + _cputype=$(get_endianness mips '' el) + ;; + + mips64) + if [ "$_bitness" -eq 64 ]; then + # only n64 ABI is supported for now + _ostype="${_ostype}abi64" + _cputype=$(get_endianness mips64 '' el) + fi + ;; + + ppc) + _cputype=powerpc + ;; + + ppc64) + _cputype=powerpc64 + ;; + + ppc64le) + _cputype=powerpc64le + ;; + + s390x) + _cputype=s390x + ;; + riscv64) + _cputype=riscv64gc + ;; + loongarch64) + _cputype=loongarch64 + ensure_loongarch_uapi + ;; + *) + err "unknown CPU type: $_cputype" + + esac + + # Detect 64-bit linux with 32-bit userland + if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then + case $_cputype in + x86_64) + if [ -n "${RUSTUP_CPUTYPE:-}" ]; then + _cputype="$RUSTUP_CPUTYPE" + else { + # 32-bit executable for amd64 = x32 + if is_host_amd64_elf; then { + echo "This host is running an x32 userland; as it stands, x32 support is poor," 1>&2 + echo "and there isn't a native toolchain -- you will have to install" 1>&2 + echo "multiarch compatibility with i686 and/or amd64, then select one" 1>&2 + echo "by re-running this script with the RUSTUP_CPUTYPE environment variable" 1>&2 + echo "set to i686 or x86_64, respectively." 1>&2 + echo 1>&2 + echo "You will be able to add an x32 target after installation by running" 1>&2 + echo " rustup target add x86_64-unknown-linux-gnux32" 1>&2 + exit 1 + }; else + _cputype=i686 + fi + }; fi + ;; + mips64) + _cputype=$(get_endianness mips '' el) + ;; + powerpc64) + _cputype=powerpc + ;; + aarch64) + _cputype=armv7 + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + riscv64gc) + err "riscv64 with 32-bit userland unsupported" + ;; + esac + fi + + # Detect armv7 but without the CPU features Rust needs in that build, + # and fall back to arm. + # See https://github.com/rust-lang/rustup.rs/issues/587. + if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then + if ensure grep '^Features' /proc/cpuinfo | grep -E -q -v 'neon|simd'; then + # At least one processor does not have NEON (which is asimd on armv8+). + _cputype=arm + fi + fi + + _arch="${_cputype}-${_ostype}" + + RETVAL="$_arch" +} + +say() { + printf 'rustup: %s\n' "$1" +} + +err() { + say "$1" >&2 + exit 1 +} + +need_cmd() { + if ! check_cmd "$1"; then + err "need '$1' (command not found)" + fi +} + +check_cmd() { + command -v "$1" > /dev/null 2>&1 +} + +assert_nz() { + if [ -z "$1" ]; then err "assert_nz $2"; fi +} + +# Run a command that should never fail. If the command fails execution +# will immediately terminate with an error showing the failing +# command. +ensure() { + if ! "$@"; then err "command failed: $*"; fi +} + +# This is just for indicating that commands' results are being +# intentionally ignored. Usually, because it's being executed +# as part of error handling. +ignore() { + "$@" +} + +# This wraps curl or wget. Try curl first, if not installed, +# use wget instead. +downloader() { + # zsh does not split words by default, Required for curl retry arguments below. + is_zsh && setopt local_options shwordsplit + + local _dld + local _ciphersuites + local _err + local _status + local _retry + if check_cmd curl; then + _dld=curl + elif check_cmd wget; then + _dld=wget + else + _dld='curl or wget' # to be used in error message of need_cmd + fi + + if [ "$1" = --check ]; then + need_cmd "$_dld" + elif [ "$_dld" = curl ]; then + check_curl_for_retry_support + _retry="$RETVAL" + get_ciphersuites_for_curl + _ciphersuites="$RETVAL" + if [ -n "$_ciphersuites" ]; then + _err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1) + _status=$? + else + echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" + if ! check_help_for "$3" curl --proto --tlsv1.2; then + echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" + _err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1) + _status=$? + else + _err=$(curl $_retry --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1) + _status=$? + fi + fi + if [ -n "$_err" ]; then + echo "$_err" >&2 + if echo "$_err" | grep -q 404$; then + err "installer for platform '$3' not found, this may be unsupported" + fi + fi + return $_status + elif [ "$_dld" = wget ]; then + if [ "$(wget -V 2>&1|head -2|tail -1|cut -f1 -d" ")" = "BusyBox" ]; then + echo "Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure" + _err=$(wget "$1" -O "$2" 2>&1) + _status=$? + else + get_ciphersuites_for_wget + _ciphersuites="$RETVAL" + if [ -n "$_ciphersuites" ]; then + _err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1) + _status=$? + else + echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure" + if ! check_help_for "$3" wget --https-only --secure-protocol; then + echo "Warning: Not enforcing TLS v1.2, this is potentially less secure" + _err=$(wget "$1" -O "$2" 2>&1) + _status=$? + else + _err=$(wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2" 2>&1) + _status=$? + fi + fi + fi + if [ -n "$_err" ]; then + echo "$_err" >&2 + if echo "$_err" | grep -q ' 404 Not Found$'; then + err "installer for platform '$3' not found, this may be unsupported" + fi + fi + return $_status + else + err "Unknown downloader" # should not reach here + fi +} + +check_help_for() { + local _arch + local _cmd + local _arg + _arch="$1" + shift + _cmd="$1" + shift + + local _category + if "$_cmd" --help | grep -q 'For all options use the manual or "--help all".'; then + _category="all" + else + _category="" + fi + + case "$_arch" in + + *darwin*) + if check_cmd sw_vers; then + case $(sw_vers -productVersion) in + 10.*) + # If we're running on macOS, older than 10.13, then we always + # fail to find these options to force fallback + if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then + # Older than 10.13 + echo "Warning: Detected macOS platform older than 10.13" + return 1 + fi + ;; + 11.*) + # We assume Big Sur will be OK for now + ;; + *) + # Unknown product version, warn and continue + echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)" + echo "Warning TLS capabilities detection may fail" + ;; + esac + fi + ;; + + esac + + for _arg in "$@"; do + if ! "$_cmd" --help "$_category" | grep -q -- "$_arg"; then + return 1 + fi + done + + true # not strictly needed +} + +# Check if curl supports the --retry flag, then pass it to the curl invocation. +check_curl_for_retry_support() { + local _retry_supported="" + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. + if check_help_for "notspecified" "curl" "--retry"; then + _retry_supported="--retry 3" + if check_help_for "notspecified" "curl" "--continue-at"; then + # "-C -" tells curl to automatically find where to resume the download when retrying. + _retry_supported="--retry 3 -C -" + fi + fi + + RETVAL="$_retry_supported" +} + +# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites +# if support by local tools is detected. Detection currently supports these curl backends: +# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. +get_ciphersuites_for_curl() { + if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then + # user specified custom cipher suites, assume they know what they're doing + RETVAL="$RUSTUP_TLS_CIPHERSUITES" + return + fi + + local _openssl_syntax="no" + local _gnutls_syntax="no" + local _backend_supported="yes" + if curl -V | grep -q ' OpenSSL/'; then + _openssl_syntax="yes" + elif curl -V | grep -iq ' LibreSSL/'; then + _openssl_syntax="yes" + elif curl -V | grep -iq ' BoringSSL/'; then + _openssl_syntax="yes" + elif curl -V | grep -iq ' GnuTLS/'; then + _gnutls_syntax="yes" + else + _backend_supported="no" + fi + + local _args_supported="no" + if [ "$_backend_supported" = "yes" ]; then + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. + if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then + _args_supported="yes" + fi + fi + + local _cs="" + if [ "$_args_supported" = "yes" ]; then + if [ "$_openssl_syntax" = "yes" ]; then + _cs=$(get_strong_ciphersuites_for "openssl") + elif [ "$_gnutls_syntax" = "yes" ]; then + _cs=$(get_strong_ciphersuites_for "gnutls") + fi + fi + + RETVAL="$_cs" +} + +# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites +# if support by local tools is detected. Detection currently supports these wget backends: +# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty. +get_ciphersuites_for_wget() { + if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then + # user specified custom cipher suites, assume they know what they're doing + RETVAL="$RUSTUP_TLS_CIPHERSUITES" + return + fi + + local _cs="" + if wget -V | grep -q '\-DHAVE_LIBSSL'; then + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. + if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then + _cs=$(get_strong_ciphersuites_for "openssl") + fi + elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then + # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc. + if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then + _cs=$(get_strong_ciphersuites_for "gnutls") + fi + fi + + RETVAL="$_cs" +} + +# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2 +# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad +# DH params often found on servers (see RFC 7919). Sequence matches or is +# similar to Firefox 68 ESR with weak cipher suites disabled via about:config. +# $1 must be openssl or gnutls. +get_strong_ciphersuites_for() { + if [ "$1" = "openssl" ]; then + # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet. + echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384" + elif [ "$1" = "gnutls" ]; then + # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't. + # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order. + echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM" + fi +} + +main "$@" || exit 1 diff --git a/node/build.sh b/node/build.sh new file mode 100755 index 0000000..f7606c5 --- /dev/null +++ b/node/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -euxo pipefail + +# This script builds the node binary for the current platform and statically links it with VDF static lib. + +ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}" + +NODE_DIR="$ROOT_DIR/node" +BINARIES_DIR="$ROOT_DIR/target/release" + +pushd "$NODE_DIR" > /dev/null + +export CGO_ENABLED=1 +export GOEXPERIMENT=arenas + +os_type="$(uname)" +case "$os_type" in + "Darwin") + # Check if the architecture is ARM + if [[ "$(uname -m)" == "arm64" ]]; then + # MacOS ld doesn't support -Bstatic and -Bdynamic, so it's important that there is only a static version of the library + go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -lvdf -ldl -lm'" "$@" + else + echo "Unsupported platform" + exit 1 + fi + ;; + "Linux") + go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -Wl,-Bstatic -lvdf -Wl,-Bdynamic -ldl -lm'" "$@" + ;; + *) + echo "Unsupported platform" + exit 1 + ;; +esac diff --git a/node/crypto/wesolowski_frame_prover.go b/node/crypto/wesolowski_frame_prover.go index f550dce..a2bcb9d 100644 --- a/node/crypto/wesolowski_frame_prover.go +++ b/node/crypto/wesolowski_frame_prover.go @@ -13,11 +13,11 @@ import ( "github.com/pkg/errors" "go.uber.org/zap" "golang.org/x/crypto/sha3" - "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/keys" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" "source.quilibrium.com/quilibrium/monorepo/node/tries" + "source.quilibrium.com/quilibrium/monorepo/vdf" ) type WesolowskiFrameProver struct { @@ -42,9 +42,7 @@ func (w *WesolowskiFrameProver) ProveMasterClockFrame( input = append(input, previousFrame.Output[:]...) b := sha3.Sum256(input) - v := vdf.New(difficulty, b) - v.Execute() - o := v.GetOutput() + o := vdf.WesolowskiSolve(b, difficulty) previousSelectorBytes := [516]byte{} copy(previousSelectorBytes[:], previousFrame.Output[:516]) @@ -113,11 +111,10 @@ func (w *WesolowskiFrameProver) VerifyMasterClockFrame( } b := sha3.Sum256(input) - v := vdf.New(frame.Difficulty, b) proof := [516]byte{} copy(proof[:], frame.Output) - if !v.Verify(proof) { + if !vdf.WesolowskiVerify(b, frame.Difficulty, proof) { w.logger.Error("invalid proof", zap.Binary("filter", frame.Filter), zap.Uint64("frame_number", frame.FrameNumber), @@ -159,10 +156,7 @@ func (w *WesolowskiFrameProver) CreateMasterGenesisFrame( error, ) { b := sha3.Sum256(seed) - v := vdf.New(difficulty, b) - - v.Execute() - o := v.GetOutput() + o := vdf.WesolowskiSolve(b, difficulty) inputMessage := o[:] w.logger.Debug("proving genesis frame") @@ -178,10 +172,7 @@ func (w *WesolowskiFrameProver) CreateMasterGenesisFrame( } b = sha3.Sum256(input) - v = vdf.New(difficulty, b) - - v.Execute() - o = v.GetOutput() + o = vdf.WesolowskiSolve(b, difficulty) frame := &protobufs.ClockFrame{ Filter: filter, @@ -248,10 +239,7 @@ func (w *WesolowskiFrameProver) ProveDataClockFrame( input = append(input, commitmentInput...) b := sha3.Sum256(input) - v := vdf.New(difficulty, b) - - v.Execute() - o := v.GetOutput() + o := vdf.WesolowskiSolve(b, difficulty) // TODO: make this configurable for signing algorithms that allow // user-supplied hash functions @@ -341,10 +329,7 @@ func (w *WesolowskiFrameProver) CreateDataGenesisFrame( } b := sha3.Sum256(input) - v := vdf.New(difficulty, b) - - v.Execute() - o := v.GetOutput() + o := vdf.WesolowskiSolve(b, difficulty) commitments := []*protobufs.InclusionCommitment{} for i, commit := range inclusionProof.InclusionCommitments { @@ -438,7 +423,6 @@ func (w *WesolowskiFrameProver) VerifyDataClockFrame( } b := sha3.Sum256(input) - v := vdf.New(frame.Difficulty, b) proof := [516]byte{} copy(proof[:], frame.Output) @@ -458,7 +442,7 @@ func (w *WesolowskiFrameProver) VerifyDataClockFrame( ) } } - if !v.Verify(proof) { + if !vdf.WesolowskiVerify(b, frame.Difficulty, proof) { return errors.Wrap( errors.New("invalid proof"), "verify clock frame", @@ -585,11 +569,10 @@ func (w *WesolowskiFrameProver) VerifyWeakRecursiveProof( } b := sha3.Sum256(input[:len(input)-516]) - v := vdf.New(difficulty, b) output := [516]byte{} copy(output[:], input[len(input)-516:]) - if v.Verify(output) { + if vdf.WesolowskiVerify(b, difficulty, output) { w.logger.Debug("verification succeeded") return true } else { @@ -613,10 +596,7 @@ func (w *WesolowskiFrameProver) CalculateChallengeProof( instanceInput := binary.BigEndian.AppendUint32([]byte{}, core) instanceInput = append(instanceInput, input...) b := sha3.Sum256(instanceInput) - v := vdf.New(uint32(calibratedDifficulty), b) - - v.Execute() - o := v.GetOutput() + o := vdf.WesolowskiSolve(b, uint32(calibratedDifficulty)) output := make([]byte, 516) copy(output[:], o[:]) @@ -653,15 +633,13 @@ func (w *WesolowskiFrameProver) VerifyChallengeProof( skew := (assertedDifficulty * 12) / 10 calibratedDifficulty := (int64(proofDuration) * 10000) / skew - v := vdf.New(uint32(calibratedDifficulty), b) - check := v.Verify([516]byte(proof[i])) + check := vdf.WesolowskiVerify(b, uint32(calibratedDifficulty), [516]byte(proof[i])) if !check { // TODO: Remove after 2024-05-28 if time.Now().Before(config.GetMinimumVersionCutoff()) { calibratedDifficulty = (int64(proofDuration) / skew) * 10000 - v = vdf.New(uint32(calibratedDifficulty), sha3.Sum256(input)) - check = v.Verify([516]byte(proof[i])) + check = vdf.WesolowskiVerify(sha3.Sum256(input), uint32(calibratedDifficulty), [516]byte(proof[i])) if !check { return false } diff --git a/node/go.mod b/node/go.mod index e5e19bd..9f7af8b 100644 --- a/node/go.mod +++ b/node/go.mod @@ -5,6 +5,8 @@ go 1.20 // A necessary hack until source.quilibrium.com is open to all replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology +replace source.quilibrium.com/quilibrium/monorepo/vdf => ../vdf + replace github.com/libp2p/go-libp2p => ../go-libp2p replace github.com/libp2p/go-libp2p-gostream => ../go-libp2p-gostream @@ -23,6 +25,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 + source.quilibrium.com/quilibrium/monorepo/vdf v0.0.0-00010101000000-000000000000 ) require ( @@ -64,7 +67,7 @@ require ( github.com/quic-go/qtls-go1-19 v0.3.3 // indirect github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect - golang.org/x/term v0.16.0 + golang.org/x/term v0.21.0 google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -144,7 +147,7 @@ require ( github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect @@ -164,14 +167,14 @@ require ( go.uber.org/fx v1.20.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.18.0 + golang.org/x/crypto v0.24.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.21.0 + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/grpc v1.58.2 lukechampine.com/blake3 v1.2.1 // indirect diff --git a/node/go.sum b/node/go.sum index 477ae9e..32098ba 100644 --- a/node/go.sum +++ b/node/go.sum @@ -111,6 +111,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -161,6 +162,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= @@ -229,11 +231,14 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -315,6 +320,7 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -353,6 +359,7 @@ github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -512,6 +519,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= @@ -528,6 +537,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -548,6 +559,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -563,6 +576,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -585,14 +600,20 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -616,6 +637,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/node/test.sh b/node/test.sh new file mode 100755 index 0000000..0c3845e --- /dev/null +++ b/node/test.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -euxo pipefail + +# Run tests for the node package. Takes care of linking the native VDF. +# Assumes that the VDF library has been built by running the generate.sh script in the `../vdf` directory. + +ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}" + +NODE_DIR="$ROOT_DIR/node" +BINARIES_DIR="$ROOT_DIR/target/release" + +# Link the native VDF and execute tests +pushd "$NODE_DIR" > /dev/null + CGO_LDFLAGS="-L$BINARIES_DIR -lvdf -ldl" \ + CGO_ENABLED=1 \ + GOEXPERIMENT=arenas \ + go test "$@" diff --git a/vdf/.gitignore b/vdf/.gitignore new file mode 100644 index 0000000..86d4c2d --- /dev/null +++ b/vdf/.gitignore @@ -0,0 +1 @@ +generated diff --git a/vdf/REAMDE.md b/vdf/REAMDE.md new file mode 100644 index 0000000..de9a57c --- /dev/null +++ b/vdf/REAMDE.md @@ -0,0 +1,9 @@ +# VDF + +Wrapper for the Rust implementation of the VDF (Verifiable Delay Function) in [crates/vdf](../crates/vdf). + +## Generate Go bindings + +```sh +go generate +``` diff --git a/vdf/generate.sh b/vdf/generate.sh new file mode 100755 index 0000000..45b706a --- /dev/null +++ b/vdf/generate.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -euxo pipefail + +ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}" + +RUST_VDF_PACKAGE="$ROOT_DIR/crates/vdf" +BINDINGS_DIR="$ROOT_DIR/vdf" + +# Build the Rust VDF package in release mode +RUSTFLAGS='-L /opt/homebrew/Cellar/gmp/6.3.0/lib' cargo build -p vdf --release + +# Generate Go bindings +pushd "$RUST_VDF_PACKAGE" > /dev/null +uniffi-bindgen-go src/lib.udl -o "$BINDINGS_DIR"/generated diff --git a/vdf/go.mod b/vdf/go.mod new file mode 100644 index 0000000..db9b44d --- /dev/null +++ b/vdf/go.mod @@ -0,0 +1,12 @@ +module source.quilibrium.com/quilibrium/monorepo/vdf + +go 1.20 + +// A necessary hack until source.quilibrium.com is open to all +replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology + +require ( + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/sys v0.21.0 // indirect + source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect +) diff --git a/vdf/go.sum b/vdf/go.sum new file mode 100644 index 0000000..3983382 --- /dev/null +++ b/vdf/go.sum @@ -0,0 +1,4 @@ +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/vdf/test.sh b/vdf/test.sh new file mode 100755 index 0000000..cb42e34 --- /dev/null +++ b/vdf/test.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -euxo pipefail + +# Run tests for the vdf package. Takes care of linking the native VDF. +# Assumes that the VDF library has been built by running the generate.sh script in the same directory. + +ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}" + +NODE_DIR="$ROOT_DIR/vdf" +BINARIES_DIR="$ROOT_DIR/target/release" + +# Link the native VDF and execute tests +pushd "$NODE_DIR" > /dev/null + CGO_LDFLAGS="-L$BINARIES_DIR -lvdf -ldl" \ + CGO_ENABLED=1 \ + GOEXPERIMENT=arenas \ + go test "$@" diff --git a/vdf/vdf.go b/vdf/vdf.go new file mode 100644 index 0000000..78ce931 --- /dev/null +++ b/vdf/vdf.go @@ -0,0 +1,21 @@ +package vdf + +import ( + generated "source.quilibrium.com/quilibrium/monorepo/vdf/generated/vdf" +) + +//go:generate ./generate.sh + +const intSizeBits = uint16(2048) + +// WesolowskiSolve Solve and prove with the Wesolowski VDF using the given parameters. +// Outputs the concatenated solution and proof (in this order). +func WesolowskiSolve(challenge [32]byte, difficulty uint32) [516]byte { + return [516]byte(generated.WesolowskiSolve(intSizeBits, challenge[:], difficulty)) +} + +// WesolowskiVerify Verify with the Wesolowski VDF using the given parameters. +// `allegedSolution` is the output of `WesolowskiSolve`. +func WesolowskiVerify(challenge [32]byte, difficulty uint32, allegedSolution [516]byte) bool { + return generated.WesolowskiVerify(intSizeBits, challenge[:], difficulty, allegedSolution[:]) +} diff --git a/vdf/vdf_test.go b/vdf/vdf_test.go new file mode 100644 index 0000000..dd3e56a --- /dev/null +++ b/vdf/vdf_test.go @@ -0,0 +1,53 @@ +package vdf_test + +import ( + "golang.org/x/crypto/sha3" + nekrovdf "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" + "source.quilibrium.com/quilibrium/monorepo/vdf" + "testing" +) + +func getChallenge(seed string) [32]byte { + return sha3.Sum256([]byte(seed)) +} + +func TestProveVerify(t *testing.T) { + difficulty := uint32(10000) + challenge := getChallenge("TestProveVerify") + solution := vdf.WesolowskiSolve(challenge, difficulty) + isOk := vdf.WesolowskiVerify(challenge, difficulty, solution) + if !isOk { + t.Fatalf("Verification failed") + } +} + +func TestProveRustVerifyNekro(t *testing.T) { + difficulty := uint32(100) + challenge := getChallenge("TestProveRustVerifyNekro") + + for i := 0; i < 100; i++ { + solution := vdf.WesolowskiSolve(challenge, difficulty) + nekroVdf := nekrovdf.New(difficulty, challenge) + isOk := nekroVdf.Verify(solution) + if !isOk { + t.Fatalf("Verification failed") + } + challenge = sha3.Sum256(solution[:]) + } +} + +func TestProveNekroVerifyRust(t *testing.T) { + difficulty := uint32(100) + challenge := getChallenge("TestProveNekroVerifyRust") + + for i := 0; i < 100; i++ { + nekroVdf := nekrovdf.New(difficulty, challenge) + nekroVdf.Execute() + proof := nekroVdf.GetOutput() + isOk := vdf.WesolowskiVerify(challenge, difficulty, proof) + if !isOk { + t.Fatalf("Verification failed") + } + challenge = sha3.Sum256(proof[:]) + } +}