commit 43ca2132fd12fb5fc6d130e549b4778a769258fc Author: Pratyush Mishra Date: Sun Oct 11 19:50:41 2020 -0700 Initial commit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f2aa4fa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,128 @@ +name: CI +on: + pull_request: + push: + branches: + - master +env: + RUST_BACKTRACE: 1 + +jobs: + style: + name: Check Style + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v1 + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + + - name: cargo fmt --check + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + test: + name: Test + runs-on: ubuntu-latest + env: + RUSTFLAGS: -Dwarnings + strategy: + matrix: + rust: + - stable + - nightly + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install Rust (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: Check examples + uses: actions-rs/cargo@v1 + with: + command: check + args: --examples --all + + - name: Check examples with all features on stable + uses: actions-rs/cargo@v1 + with: + command: check + args: --examples --all-features --all + if: matrix.rust == 'stable' + + - name: Check benchmarks on nightly + uses: actions-rs/cargo@v1 + with: + command: check + args: --all-features --examples --workspace --benches + if: matrix.rust == 'nightly' + + - name: Test + uses: actions-rs/cargo@v1 + with: + command: test + args: "--workspace \ + --all-features \ + --exclude curve-benches" + + check_no_std: + name: Check no_std + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install Rust (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: thumbv6m-none-eabi + override: true + + - name: Install Rust ARM64 (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: aarch64-unknown-none + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: check + uses: actions-rs/cargo@v1 + with: + command: check + args: --examples --workspace --exclude ark-curve-tests --exclude ark-curve-benches --target thumbv6m-none-eabi + + - name: build + uses: actions-rs/cargo@v1 + with: + command: build + args: --workspace --exclude ark-curve-tests --exclude ark-curve-benches --target thumbv6m-none-eabi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b5e101 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +target +Cargo.lock +.DS_Store +.idea +*.iml +*.ipynb_checkpoints +*.pyc +*.sage.py +params +*.swp +*.swo diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5edf2d7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,458 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ark-bls12-377" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-bls12-381" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-bn254" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-bw6-761" +version = "0.1.0" +dependencies = [ + "ark-bls12-377", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-cp6-782" +version = "0.1.0" +dependencies = [ + "ark-bls12-377", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-curve-benches" +version = "0.1.1-alpha.0" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-bn254", + "ark-bw6-761", + "ark-cp6-782", + "ark-ec", + "ark-ff", + "ark-mnt4-298", + "ark-mnt4-753", + "ark-mnt6-298", + "ark-mnt6-753", + "ark-serialize", + "paste", + "rand", + "rand_xorshift", + "rustc_version", +] + +[[package]] +name = "ark-curve-tests" +version = "0.1.0" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ec" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/algebra#d5202f896ca9700c5c22d7a1266ada600f913dc4" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "num-traits", + "rand", +] + +[[package]] +name = "ark-ed-on-bls12-377" +version = "0.1.0" +dependencies = [ + "ark-bls12-377", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ed-on-bls12-381" +version = "0.1.0" +dependencies = [ + "ark-bls12-381", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ed-on-bn254" +version = "0.1.0" +dependencies = [ + "ark-bn254", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ed-on-bw6-761" +version = "0.1.0" +dependencies = [ + "ark-ed-on-cp6-782", +] + +[[package]] +name = "ark-ed-on-cp6-782" +version = "0.1.0" +dependencies = [ + "ark-bls12-377", + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ed-on-mnt4-298" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-mnt4-298", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-ff" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/algebra#d5202f896ca9700c5c22d7a1266ada600f913dc4" +dependencies = [ + "ark-ff-asm", + "ark-serialize", + "ark-std", + "derivative", + "num-traits", + "rand", + "rustc_version", +] + +[[package]] +name = "ark-ff-asm" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/algebra#d5202f896ca9700c5c22d7a1266ada600f913dc4" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-mnt4-298" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-mnt4-753" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-mnt6-298" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-mnt4-298", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-mnt6-753" +version = "0.1.0" +dependencies = [ + "ark-curve-tests", + "ark-ec", + "ark-ff", + "ark-mnt4-753", + "ark-serialize", + "ark-std", + "rand", + "rand_xorshift", +] + +[[package]] +name = "ark-serialize" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/algebra#d5202f896ca9700c5c22d7a1266ada600f913dc4" +dependencies = [ + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/utils#7bde3ab01799da8429b8fa9c3f152201415cdfe7" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "derivative" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0520af26d4cf99643dbbe093a61507922b57232d9978d8491fdc8f7b44573c8c" + +[[package]] +name = "ppv-lite86" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xorshift" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "syn" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..418d5b0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,52 @@ +[workspace] + +members = [ + "curve-benches", + "curve-tests", + + "bls12_377", + "ed_on_bls12_377", + + "bw6_761", + "ed_on_bw6_761", + + "cp6_782", + "ed_on_cp6_782", + + "bls12_381", + "ed_on_bls12_381", + + "bn254", + "ed_on_bn254", + + "mnt4_298", + "mnt6_298", + "ed_on_mnt4_298", + + "mnt4_753", + "mnt6_753", + "ed_on_mnt4_298", +] + +[profile.release] +opt-level = 3 +lto = "thin" +incremental = true + +[profile.bench] +opt-level = 3 +debug = false +rpath = false +lto = "thin" +incremental = true +debug-assertions = false + +[profile.dev] +opt-level = 0 + +[profile.test] +opt-level = 3 +lto = "thin" +incremental = true +debug-assertions = true +debug = true diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6fdb938 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Curve implementations + +This directory contains implementations of some popular elliptic curves. + +### BLS12-381 and embedded curves +* [`ark-bls12-381`](bls12-381): Implements the BLS12-381 pairing-friendly curve +* [`ark-ed-on-bls12-381`](ed-on-bls12-381): Implements a Twisted Edwards curve atop the scalar field of BLS12-381 + +### BLS12-377 and related curves +* [`ark-bls12-377`](bls12-377): Implements the BLS12-377 pairing-friendly curve +* [`ark-ed-on-bls12-377`](ed-on-bls12-377): Implements a Twisted Edwards curve atop the scalar field of BLS12-377 + +* [`ark-bw6-761`](bw6-761): Implements the BW6-761 pairing-friendly curve, which is a curve whose scalar field equals the base field of BLS12-377 +* [`ark-ed-on-bw6-761`](ed-on-bw6-761): Implements a Twisted Edwards curve atop the scalar field of BW6-761 + +* [`ark-cp6-782`](cp6-782): Implements the CP6-782 pairing-friendly curve, which is a curve whose scalar field equals the base field of BLS12-377 +* [`ark-ed-on-cp6-782`](ed-on-cp6-782): Implements a Twisted Edwards curve atop the scalar field of CP6-782. This is the same curve as in `ark-ed-on-bw6-761` + +### BN254 and related curves +* [`ark-bn254`](bn254): Implements the BN254 pairing-friendly curve +* [`ark-ed-on-bn254`](ed-on-bn254): Implements a Twisted Edwards curve atop the scalar field of BN254 + +### MNT-298 cycle of curves and related curves +* [`ark-mnt4-298`](mnt4-298): Implements the MNT4-298 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT6-298 +* [`ark-mnt6-298`](mnt6-298): Implements the MNT6-298 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT4-298 +* [`ark-ed-on-mnt4-298`](ed-on-mnt4-298): Implements a Twisted Edwards curve atop the scalar field of MNT4-298 + +### MNT-753 cycle of curves and related curves +* [`ark-mnt4-753`](mnt4-753): Implements the MNT4-753 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT6-753 +* [`ark-mnt6-753`](mnt6-753): Implements the MNT6-753 pairing-friendly curve. This curve forms a pairing-friendly cycle with MNT4-753 +* [`ark-ed-on-mnt4-753`](ed-on-mnt4-753): Implements a Twisted Edwards curve atop the scalar field of MNT4-753 \ No newline at end of file diff --git a/bls12_377/Cargo.toml b/bls12_377/Cargo.toml new file mode 100644 index 0000000..66860ce --- /dev/null +++ b/bls12_377/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ark-bls12-377" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The BLS12-377 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-bls12-377/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field", "base_field" ] +scalar_field = [] +base_field = [] diff --git a/bls12_377/LICENSE-APACHE b/bls12_377/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/bls12_377/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/bls12_377/LICENSE-MIT b/bls12_377/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/bls12_377/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/bls12_377/src/curves/g1.rs b/bls12_377/src/curves/g1.rs new file mode 100644 index 0000000..5eb7d17 --- /dev/null +++ b/bls12_377/src/curves/g1.rs @@ -0,0 +1,77 @@ +use ark_ec::models::{ModelParameters, SWModelParameters}; +use ark_ff::{ + biginteger::{BigInteger256, BigInteger384}, + field_new, Zero, +}; + +use crate::{Fq, Fr}; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 0 + const COEFF_A: Fq = field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])); + + /// COEFF_B = 1 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger384([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])); + + /// COFACTOR = (x - 1)^2 / 3 = 30631250834960419227450344600217059328 + const COFACTOR: &'static [u64] = &[0x0, 0x170b5d4430000000]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r + /// = 5285428838741532253824584287042945485047145357130994810877 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 2013239619100046060, + 4201184776506987597, + 2526766393982337036, + 1114629510922847535, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G1_GENERATOR_X = +/// 81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger384([ + 0x260f33b9772451f4, + 0xc54dd773169d5658, + 0x5c1551c469a510dd, + 0x761662e4425e1698, + 0xc97d78cc6f065272, + 0xa41206b361fd4d, +])); + +/// G1_GENERATOR_Y = +/// 241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger384([ + 0x8193961fb8cb81f3, + 0x638d4c5f44adb8, + 0xfafaf3dad4daf54a, + 0xc27849e2d655cd18, + 0x2ec3ddb401d52814, + 0x7da93326303c71, +])); diff --git a/bls12_377/src/curves/g2.rs b/bls12_377/src/curves/g2.rs new file mode 100644 index 0000000..abd97c5 --- /dev/null +++ b/bls12_377/src/curves/g2.rs @@ -0,0 +1,129 @@ +use ark_ec::models::{ModelParameters, SWModelParameters}; +use ark_ff::{ + biginteger::{BigInteger256, BigInteger384}, + field_new, Zero, +}; + +use crate::{g1, Fq, Fq2, Fr}; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq2; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = [0, 0] + #[rustfmt::skip] + const COEFF_A: Fq2 = field_new!(Fq2, + g1::Parameters::COEFF_A, + g1::Parameters::COEFF_A, + ); + + // As per https://eprint.iacr.org/2012/072.pdf, + // this curve has b' = b/i, where b is the COEFF_B of G1, and x^6 -i is + // the irreducible poly used to extend from Fp2 to Fp12. + // In our case, i = u (App A.3, T_6). + /// COEFF_B = [0, + /// 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906] + #[rustfmt::skip] + const COEFF_B: Fq2 = field_new!(Fq2, + field_new!(Fq, BigInteger384([0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger384([ + 9255502405446297221, + 10229180150694123945, + 9215585410771530959, + 13357015519562362907, + 5437107869987383107, + 16259554076827459, + ])), + ); + + /// COFACTOR = + /// 7923214915284317143930293550643874566881017850177945424769256759165301436616933228209277966774092486467289478618404761412630691835764674559376407658497 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x0000000000000001, + 0x452217cc90000000, + 0xa0f3622fba094800, + 0xd693e8c36676bd09, + 0x8c505634fae2e189, + 0xfbb36b00e1dcc40c, + 0xddd88d99a6f6a829, + 0x26ba558ae9562a, + ]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r + /// = 6764900296503390671038341982857278410319949526107311149686707033187604810669 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 15499857013495546999, + 4613531467548868169, + 14546778081091178013, + 549402535258503313, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +#[rustfmt::skip] +pub const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); +#[rustfmt::skip] +pub const G2_GENERATOR_Y: Fq2 = field_new!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1); + +/// G2_GENERATOR_X_C0 = +/// 233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger384([ + 0x68904082f268725b, + 0x668f2ea74f45328b, + 0xebca7a65802be84f, + 0x1e1850f4c1ada3e6, + 0x830dc22d588ef1e9, + 0x1862a81767c0982, +])); + +/// G2_GENERATOR_X_C1 = +/// 140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger384([ + 0x5f02a915c91c7f39, + 0xf8c553ba388da2a7, + 0xd51a416dbd198850, + 0xe943c6f38ae3073a, + 0xffe24aa8259a4981, + 0x11853391e73dfdd, +])); + +/// G2_GENERATOR_Y_C0 = +/// 63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger384([ + 0xd5b19b897881430f, + 0x5be9118a5b371ed, + 0x6063f91f86c131ee, + 0x3244a61be8f4ec19, + 0xa02e425b9f9a3a12, + 0x18af8c04f3360d2, +])); + +/// G2_GENERATOR_Y_C1 = +/// 149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger384([ + 0x57601ac71a5b96f5, + 0xe99acc1714f2440e, + 0x2339612f10118ea9, + 0x8321e68a3b1cd722, + 0x2b543b050cc74917, + 0x590182b396c112, +])); diff --git a/bls12_377/src/curves/mod.rs b/bls12_377/src/curves/mod.rs new file mode 100644 index 0000000..33a87fd --- /dev/null +++ b/bls12_377/src/curves/mod.rs @@ -0,0 +1,33 @@ +use crate::*; +use ark_ec::{ + bls12, + bls12::{Bls12, Bls12Parameters, TwistType}, +}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub struct Parameters; + +impl Bls12Parameters for Parameters { + const X: &'static [u64] = &[0x8508c00000000001]; + /// `x` is positive. + const X_IS_NEGATIVE: bool = false; + const TWIST_TYPE: TwistType = TwistType::D; + type Fp = Fq; + type Fp2Params = Fq2Parameters; + type Fp6Params = Fq6Parameters; + type Fp12Params = Fq12Parameters; + type G1Parameters = g1::Parameters; + type G2Parameters = g2::Parameters; +} + +pub type Bls12_377 = Bls12; + +pub type G1Affine = bls12::G1Affine; +pub type G1Projective = bls12::G1Projective; +pub type G2Affine = bls12::G2Affine; +pub type G2Projective = bls12::G2Projective; diff --git a/bls12_377/src/curves/tests.rs b/bls12_377/src/curves/tests.rs new file mode 100644 index 0000000..506125c --- /dev/null +++ b/bls12_377/src/curves/tests.rs @@ -0,0 +1,121 @@ +#![allow(unused_imports)] +use ark_ff::{ + fields::{Field, FpParameters, PrimeField, SquareRootField}, + test_rng, One, Zero, +}; +use ark_serialize::CanonicalSerialize; + +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use core::ops::{AddAssign, MulAssign}; +use rand::Rng; + +use crate::{g1, g2, Bls12_377, Fq, Fq12, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; + +use ark_curve_tests::{ + curves::{curve_tests, sw_tests}, + groups::group_test, +}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let mut sa = a; + sa.mul_assign(s); + let mut sb = b; + sb.mul_assign(s); + + let ans1 = Bls12_377::pairing(sa, b); + let ans2 = Bls12_377::pairing(a, sb); + let ans3 = Bls12_377::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq12::one()); + assert_ne!(ans2, Fq12::one()); + assert_ne!(ans3, Fq12::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq12::one()); +} + +#[test] +fn test_g1_generator_raw() { + let mut x = Fq::zero(); + let mut i = 0; + loop { + // y^2 = x^3 + b + let mut rhs = x; + rhs.square_in_place(); + rhs.mul_assign(&x); + rhs.add_assign(&g1::Parameters::COEFF_B); + + if let Some(y) = rhs.sqrt() { + let p = G1Affine::new(x, if y < -y { y } else { -y }, false); + assert!(!p.is_in_correct_subgroup_assuming_on_curve()); + + let g1 = p.scale_by_cofactor(); + if !g1.is_zero() { + assert_eq!(i, 1); + let g1 = G1Affine::from(g1); + + assert!(g1.is_in_correct_subgroup_assuming_on_curve()); + + assert_eq!(g1, G1Affine::prime_subgroup_generator()); + break; + } + } + + i += 1; + x.add_assign(&Fq::one()); + } +} diff --git a/bls12_377/src/fields/fq.rs b/bls12_377/src/fields/fq.rs new file mode 100644 index 0000000..85bbae1 --- /dev/null +++ b/bls12_377/src/fields/fq.rs @@ -0,0 +1,114 @@ +use ark_ff::{biginteger::BigInteger384 as BigInteger, field_new, fields::*}; + +pub type Fq = Fp384; + +pub struct FqParameters; + +impl Fp384Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 46u32; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 2022196864061697551u64, + 17419102863309525423u64, + 8564289679875062096u64, + 17152078065055548215u64, + 17966377291017729567u64, + 68610905582439508u64, + ]); +} +impl FpParameters for FqParameters { + /// MODULUS = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0x8508c00000000001, + 0x170b5d4430000000, + 0x1ef3622fba094800, + 0x1a22d9f300f5138f, + 0xc63b05c06ca1493b, + 0x1ae3a4617c510ea, + ]); + + const MODULUS_BITS: u32 = 377; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 7; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 202099033278250856u64, + 5854854902718660529u64, + 11492539364873682930u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xb786686c9400cd22, + 0x329fcaab00431b1, + 0x22a5f11162d6b46d, + 0xbfdf7d03827dc3ac, + 0x837e92f041790bf9, + 0x6dfccb1e914b88, + ]); + + const INV: u64 = 9586122913090633727u64; + + // GENERATOR = -5 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0xfc0b8000000002fa, + 0x97d39cf6e000018b, + 0x2072420fbfa05044, + 0xcbbcbd50d97c3802, + 0xbaf1ec35813f9eb, + 0x9974a2c0945ad2, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x4284600000000000, + 0xb85aea218000000, + 0x8f79b117dd04a400, + 0x8d116cf9807a89c7, + 0x631d82e03650a49d, + 0xd71d230be28875, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + // T = (MODULUS - 1) // 2^S = + // 3675842578061421676390135839012792950148785745837396071634149488243117337281387659330802195819009059 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x7510c00000021423, + 0x88bee82520005c2d, + 0x67cc03d44e3c7bcd, + 0x1701b28524ec688b, + 0xe9185f1443ab18ec, + 0x6b8, + ]); + + // (T - 1) // 2 = + // 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xba88600000010a11, + 0xc45f741290002e16, + 0xb3e601ea271e3de6, + 0xb80d94292763445, + 0x748c2f8a21d58c76, + 0x35c, + ]); +} + +#[allow(dead_code)] +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +#[allow(dead_code)] +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0])); diff --git a/bls12_377/src/fields/fq12.rs b/bls12_377/src/fields/fq12.rs new file mode 100644 index 0000000..fea9ab9 --- /dev/null +++ b/bls12_377/src/fields/fq12.rs @@ -0,0 +1,161 @@ +use super::*; +use ark_ff::{biginteger::BigInteger384, field_new, fields::*}; + +pub type Fq12 = Fp12; + +#[derive(Clone, Copy)] +pub struct Fq12Parameters; + +impl Fp12Parameters for Fq12Parameters { + type Fp6Params = Fq6Parameters; + + const NONRESIDUE: Fq6 = field_new!(Fq6, FQ2_ZERO, FQ2_ONE, FQ2_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP12_C1: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^(((q^0) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^1) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x6ec47a04a3f7ca9e, + 0xa42e0cb968c1fa44, + 0x578d5187fbd2bd23, + 0x930eeb0ac79dd4bd, + 0xa24883de1e09a9ee, + 0xdaa7058067d46f, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^2) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x5892506da58478da, + 0x133366940ac2a74b, + 0x9b64a150cdf726cf, + 0x5cc426090a9c587e, + 0x5cf848adfdcd640c, + 0x4702bf3ac02380, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^3) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x982c13d9d084771f, + 0xfd49de0c6da34a32, + 0x61a530d183ab0e53, + 0xdf8fe44106dd9879, + 0x40f29b58d88472bc, + 0x158723199046d5d, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^4) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xdacd106da5847973, + 0xd8fe2454bac2a79a, + 0x1ada4fd6fd832edc, + 0xfb9868449d150908, + 0xd63eb8aeea32285e, + 0x167d6a36f873fd0, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^5) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x296799d52c8cac81, + 0x591bd15304e14fee, + 0xa17df4987d85130, + 0x4c80f9363f3fc3bc, + 0x9eaa177aba7ac8ce, + 0x7dcb2c189c98ed, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^6) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x823ac00000000099, + 0xc5cabdc0b000004f, + 0x7f75ae862f8c080d, + 0x9ed4423b9278b089, + 0x79467000ec64c452, + 0x120d3e434c71c50, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^7) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x164445fb5c083563, + 0x72dd508ac73e05bc, + 0xc76610a7be368adc, + 0x8713eee839573ed1, + 0x23f281e24e979f4c, + 0xd39340975d3c7b, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^8) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2c766f925a7b8727, + 0x3d7f6b0253d58b5, + 0x838ec0deec122131, + 0xbd5eb3e9f658bb10, + 0x6942bd126ed3e52e, + 0x1673786dd04ed6a, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^9) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xecdcac262f7b88e2, + 0x19c17f37c25cb5cd, + 0xbd4e315e365e39ac, + 0x3a92f5b1fa177b15, + 0x85486a67941cd67e, + 0x55c8147ec0a38d, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^10) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xaa3baf925a7b868e, + 0x3e0d38ef753d5865, + 0x4191258bc861923, + 0x1e8a71ae63e00a87, + 0xeffc4d11826f20dc, + 0x4663a2a83dd119, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^11) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x5ba1262ad3735380, + 0xbdef8bf12b1eb012, + 0x14db82e63230f6cf, + 0xcda1e0bcc1b54fd3, + 0x2790ee45b226806c, + 0x1306f19ff2877fd, + ])), + FQ_ZERO, + ), + ]; +} diff --git a/bls12_377/src/fields/fq2.rs b/bls12_377/src/fields/fq2.rs new file mode 100644 index 0000000..f91fbb2 --- /dev/null +++ b/bls12_377/src/fields/fq2.rs @@ -0,0 +1,69 @@ +use super::*; +use ark_ff::{biginteger::BigInteger384 as BigInteger, field_new, fields::*}; + +pub type Fq2 = Fp2; + +pub struct Fq2Parameters; + +impl Fp2Parameters for Fq2Parameters { + type Fp = Fq; + + /// NONRESIDUE = -5 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0xfc0b8000000002fa, + 0x97d39cf6e000018b, + 0x2072420fbfa05044, + 0xcbbcbd50d97c3802, + 0xbaf1ec35813f9eb, + 0x9974a2c0945ad2, + ])); + + /// QUADRATIC_NONRESIDUE = U + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE: (Fq, Fq) = ( + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger([ + 202099033278250856u64, + 5854854902718660529u64, + 11492539364873682930u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ])), + ); + + /// Coefficients for the Frobenius automorphism. + #[rustfmt::skip] + const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[ + // NONRESIDUE**(((q^0) - 1) / 2) + field_new!(Fq, BigInteger([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])), + // NONRESIDUE**(((q^1) - 1) / 2) + field_new!(Fq, BigInteger([ + 0x823ac00000000099, + 0xc5cabdc0b000004f, + 0x7f75ae862f8c080d, + 0x9ed4423b9278b089, + 0x79467000ec64c452, + 0x120d3e434c71c50, + ])), + ]; + + #[inline(always)] + fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { + let original = fe; + let mut fe = -fe.double(); + fe.double_in_place(); + fe - original + } +} + +pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO); diff --git a/bls12_377/src/fields/fq6.rs b/bls12_377/src/fields/fq6.rs new file mode 100644 index 0000000..e224852 --- /dev/null +++ b/bls12_377/src/fields/fq6.rs @@ -0,0 +1,184 @@ +use super::*; +use ark_ff::{biginteger::BigInteger384, field_new, fields::*}; + +pub type Fq6 = Fp6; + +#[derive(Clone, Copy)] +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp2Params = Fq2Parameters; + + /// NONRESIDUE = U + #[rustfmt::skip] + const NONRESIDUE: Fq2 = field_new!(Fq2, + field_new!(Fq, BigInteger384([0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger384([ + 202099033278250856u64, + 5854854902718660529u64, + 11492539364873682930u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ])), + ); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^(((q^0) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^1) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x5892506da58478da, + 0x133366940ac2a74b, + 0x9b64a150cdf726cf, + 0x5cc426090a9c587e, + 0x5cf848adfdcd640c, + 0x4702bf3ac02380, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^2) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xdacd106da5847973, + 0xd8fe2454bac2a79a, + 0x1ada4fd6fd832edc, + 0xfb9868449d150908, + 0xd63eb8aeea32285e, + 0x167d6a36f873fd0, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^3) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x823ac00000000099, + 0xc5cabdc0b000004f, + 0x7f75ae862f8c080d, + 0x9ed4423b9278b089, + 0x79467000ec64c452, + 0x120d3e434c71c50, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^4) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2c766f925a7b8727, + 0x3d7f6b0253d58b5, + 0x838ec0deec122131, + 0xbd5eb3e9f658bb10, + 0x6942bd126ed3e52e, + 0x1673786dd04ed6a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^5) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xaa3baf925a7b868e, + 0x3e0d38ef753d5865, + 0x4191258bc861923, + 0x1e8a71ae63e00a87, + 0xeffc4d11826f20dc, + 0x4663a2a83dd119, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + ]; + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^((2*(q^0) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^1) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xdacd106da5847973, + 0xd8fe2454bac2a79a, + 0x1ada4fd6fd832edc, + 0xfb9868449d150908, + 0xd63eb8aeea32285e, + 0x167d6a36f873fd0, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^2) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2c766f925a7b8727, + 0x3d7f6b0253d58b5, + 0x838ec0deec122131, + 0xbd5eb3e9f658bb10, + 0x6942bd126ed3e52e, + 0x1673786dd04ed6a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^3) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2cdffffffffff68, + 0x51409f837fffffb1, + 0x9f7db3a98a7d3ff2, + 0x7b4e97b76e7c6305, + 0x4cf495bf803c84e8, + 0x8d6661e2fdf49a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^4) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xdacd106da5847973, + 0xd8fe2454bac2a79a, + 0x1ada4fd6fd832edc, + 0xfb9868449d150908, + 0xd63eb8aeea32285e, + 0x167d6a36f873fd0, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^5) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x2c766f925a7b8727, + 0x3d7f6b0253d58b5, + 0x838ec0deec122131, + 0xbd5eb3e9f658bb10, + 0x6942bd126ed3e52e, + 0x1673786dd04ed6a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + ]; + + #[inline(always)] + fn mul_fp2_by_nonresidue(fe: &Fq2) -> Fq2 { + // Karatsuba multiplication with constant other = u. + let c0 = Fq2Parameters::mul_fp_by_nonresidue(&fe.c1); + let c1 = fe.c0; + field_new!(Fq2, c0, c1) + } +} diff --git a/bls12_377/src/fields/fr.rs b/bls12_377/src/fields/fr.rs new file mode 100644 index 0000000..73a7d85 --- /dev/null +++ b/bls12_377/src/fields/fr.rs @@ -0,0 +1,95 @@ +use ark_ff::{biginteger::BigInteger256 as BigInteger, fields::*}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 47; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x3c3d3ca739381fb2, + 0x9a14cda3ec99772b, + 0xd7aacc7c59724826, + 0xd1ba211c5cc349c, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 8444461749428370424248824938781546531375899335154063827935233455917409239041 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 725501752471715841u64, + 6461107452199829505u64, + 6968279316240510977u64, + 1345280370688173398u64, + ]); + + const MODULUS_BITS: u32 = 253; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 3; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 9015221291577245683u64, + 8239323489949974514u64, + 1646089257421115374u64, + 958099254763297437u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 2726216793283724667u64, + 14712177743343147295u64, + 12091039717619697043u64, + 81024008013859129u64, + ]); + + const INV: u64 = 725501752471715839u64; + + // GENERATOR = 11 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 1855201571499933546u64, + 8511318076631809892u64, + 6222514765367795509u64, + 1122129207579058019u64, + ]); + + /// (r - 1)/2 = + /// 4222230874714185212124412469390773265687949667577031913967616727958704619520 + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x8508c00000000000, + 0xacd53b7f68000000, + 0x305a268f2e1bd800, + 0x955b2af4d1652ab, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where r - 1 = 2^s * t + + /// t = (r - 1) / 2^s = + /// 60001509534603559531609739528203892656505753216962260608619555 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0xedfda00000021423, + 0x9a3cb86f6002b354, + 0xcabd34594aacc168, + 0x2556, + ]); + + /// (t - 1) / 2 = + /// 30000754767301779765804869764101946328252876608481130304309777 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x76fed00000010a11, + 0x4d1e5c37b00159aa, + 0x655e9a2ca55660b4, + 0x12ab, + ]); +} diff --git a/bls12_377/src/fields/mod.rs b/bls12_377/src/fields/mod.rs new file mode 100644 index 0000000..401c07b --- /dev/null +++ b/bls12_377/src/fields/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(feature = "base_field")] +pub mod fq; +#[cfg(feature = "base_field")] +pub use self::fq::*; + +#[cfg(feature = "curve")] +pub mod fq2; +#[cfg(feature = "curve")] +pub use self::fq2::*; + +#[cfg(feature = "curve")] +pub mod fq6; +#[cfg(feature = "curve")] +pub use self::fq6::*; + +#[cfg(feature = "curve")] +pub mod fq12; +#[cfg(feature = "curve")] +pub use self::fq12::*; + +#[cfg(all(feature = "curve", test))] +mod tests; diff --git a/bls12_377/src/fields/tests.rs b/bls12_377/src/fields/tests.rs new file mode 100644 index 0000000..a131570 --- /dev/null +++ b/bls12_377/src/fields/tests.rs @@ -0,0 +1,530 @@ +use ark_ff::{ + biginteger::{BigInteger, BigInteger384}, + fields::{ + fp6_3over2::Fp6Parameters, FftField, FftParameters, Field, Fp2Parameters, FpParameters, + PrimeField, SquareRootField, + }, + test_rng, One, UniformRand, Zero, +}; +use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize}; +use core::{ + cmp::Ordering, + ops::{AddAssign, MulAssign, SubAssign}, +}; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +use crate::{Fq, Fq12, Fq2, Fq2Parameters, Fq6, Fq6Parameters, FqParameters, Fr}; + +use ark_curve_tests::fields::*; + +pub(crate) const ITERATIONS: usize = 5; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(b); + let byte_size = a.serialized_size(); + field_serialization_test::(byte_size); + } +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(a); + let byte_size = a.serialized_size(); + let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits()); + assert_eq!(byte_size, buffer_size); + field_serialization_test::(byte_size); + } +} + +#[test] +fn test_fq2() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fq2 = rng.gen(); + let b: Fq2 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq2::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let g: Fq6 = rng.gen(); + let h: Fq6 = rng.gen(); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq6::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq12() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let g: Fq12 = rng.gen(); + let h: Fq12 = rng.gen(); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq12::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq_repr_from() { + assert_eq!( + BigInteger384::from(100), + BigInteger384([100, 0, 0, 0, 0, 0]) + ); +} + +#[test] +fn test_fq_repr_is_odd() { + assert!(!BigInteger384::from(0).is_odd()); + assert!(BigInteger384::from(0).is_even()); + assert!(BigInteger384::from(1).is_odd()); + assert!(!BigInteger384::from(1).is_even()); + assert!(!BigInteger384::from(324834872).is_odd()); + assert!(BigInteger384::from(324834872).is_even()); + assert!(BigInteger384::from(324834873).is_odd()); + assert!(!BigInteger384::from(324834873).is_even()); +} + +#[test] +fn test_fq_repr_is_zero() { + assert!(BigInteger384::from(0).is_zero()); + assert!(!BigInteger384::from(1).is_zero()); + assert!(!BigInteger384([0, 0, 0, 0, 1, 0]).is_zero()); +} + +#[test] +fn test_fq_repr_num_bits() { + let mut a = BigInteger384::from(0); + assert_eq!(0, a.num_bits()); + a = BigInteger384::from(1); + for i in 1..385 { + assert_eq!(i, a.num_bits()); + a.mul2(); + } + assert_eq!(0, a.num_bits()); +} + +#[test] +fn test_fq_add_assign() { + // Test associativity + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Generate a, b, c and ensure (a + b) + c == a + (b + c). + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + + let mut tmp2 = b; + tmp2.add_assign(&c); + tmp2.add_assign(&a); + + assert_eq!(tmp1, tmp2); + } +} + +#[test] +fn test_fq_sub_assign() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure that (a - b) + (b - a) = 0. + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.sub_assign(&b); + + let mut tmp2 = b; + tmp2.sub_assign(&a); + + tmp1.add_assign(&tmp2); + assert!(tmp1.is_zero()); + } +} + +#[test] +fn test_fq_mul_assign() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * b) * c = a * (b * c) + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.mul_assign(&b); + tmp1.mul_assign(&c); + + let mut tmp2 = b; + tmp2.mul_assign(&c); + tmp2.mul_assign(&a); + + assert_eq!(tmp1, tmp2); + } + + for _ in 0..1000000 { + // Ensure that r * (a + b + c) = r*a + r*b + r*c + + let r = Fq::rand(&mut rng); + let mut a = Fq::rand(&mut rng); + let mut b = Fq::rand(&mut rng); + let mut c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + tmp1.mul_assign(&r); + + a.mul_assign(&r); + b.mul_assign(&r); + c.mul_assign(&r); + + a.add_assign(&b); + a.add_assign(&c); + + assert_eq!(tmp1, a); + } +} + +#[test] +fn test_fq_squaring() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * a) = a^2 + let a = Fq::rand(&mut rng); + + let mut tmp = a; + tmp.square_in_place(); + + let mut tmp2 = a; + tmp2.mul_assign(&a); + + assert_eq!(tmp, tmp2); + } +} + +#[test] +fn test_fq_inverse() { + assert!(Fq::zero().inverse().is_none()); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let one = Fq::one(); + + for _ in 0..1000 { + // Ensure that a * a^-1 = 1 + let mut a = Fq::rand(&mut rng); + let ainv = a.inverse().unwrap(); + a.mul_assign(&ainv); + assert_eq!(a, one); + } +} + +#[test] +fn test_fq_double_in_place() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure doubling a is equivalent to adding a to itself. + let mut a = Fq::rand(&mut rng); + let mut b = a; + b.add_assign(&a); + a.double_in_place(); + assert_eq!(a, b); + } +} + +#[test] +fn test_fq_negate() { + { + let a = -Fq::zero(); + + assert!(a.is_zero()); + } + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure (a - (-a)) = 0. + let mut a = Fq::rand(&mut rng); + let b = -a; + a.add_assign(&b); + + assert!(a.is_zero()); + } +} + +#[test] +fn test_fq_pow() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for i in 0..1000 { + // Exponentiate by various small numbers and ensure it consists with repeated + // multiplication. + let a = Fq::rand(&mut rng); + let target = a.pow(&[i]); + let mut c = Fq::one(); + for _ in 0..i { + c.mul_assign(&a); + } + assert_eq!(c, target); + } + + for _ in 0..1000 { + // Exponentiating by the modulus should have no effect in a prime field. + let a = Fq::rand(&mut rng); + + assert_eq!(a, a.pow(Fq::characteristic())); + } +} + +#[test] +fn test_fq_sqrt() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); + + for _ in 0..1000 { + // Ensure sqrt(a^2) = a or -a + let a = Fq::rand(&mut rng); + let nega = -a; + let mut b = a; + b.square_in_place(); + + let b = b.sqrt().unwrap(); + + assert!(a == b || nega == b); + } + + for _ in 0..1000 { + // Ensure sqrt(a)^2 = a for random a + let a = Fq::rand(&mut rng); + + if let Some(mut tmp) = a.sqrt() { + tmp.square_in_place(); + + assert_eq!(a, tmp); + } + } +} + +#[test] +fn test_fq_num_bits() { + assert_eq!(FqParameters::MODULUS_BITS, 377); + assert_eq!(FqParameters::CAPACITY, 376); +} + +#[test] +fn test_fq_root_of_unity() { + assert_eq!(FqParameters::TWO_ADICITY, 46); + assert_eq!( + Fq::multiplicative_generator().pow([ + 0x7510c00000021423, + 0x88bee82520005c2d, + 0x67cc03d44e3c7bcd, + 0x1701b28524ec688b, + 0xe9185f1443ab18ec, + 0x6b8 + ]), + Fq::two_adic_root_of_unity() + ); + assert_eq!( + Fq::two_adic_root_of_unity().pow([1 << FqParameters::TWO_ADICITY]), + Fq::one() + ); + assert!(Fq::multiplicative_generator().sqrt().is_none()); +} + +#[test] +fn test_fq_ordering() { + // BigInteger384's ordering is well-tested, but we still need to make sure the + // Fq elements aren't being compared in Montgomery form. + for i in 0..100 { + assert!(Fq::from(BigInteger384::from(i + 1)) > Fq::from(BigInteger384::from(i))); + } +} + +#[test] +fn test_fq_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(QuadraticResidue, Fq::one().legendre()); + assert_eq!(Zero, Fq::zero().legendre()); + assert_eq!( + QuadraticResidue, + Fq::from(BigInteger384::from(4)).legendre() + ); + assert_eq!( + QuadraticNonResidue, + Fq::from(BigInteger384::from(5)).legendre() + ); +} + +#[test] +fn test_fq2_ordering() { + let mut a = Fq2::new(Fq::zero(), Fq::zero()); + let mut b = a.clone(); + + assert!(a.cmp(&b) == Ordering::Equal); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); + b.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Greater); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); +} + +#[test] +fn test_fq2_basics() { + assert_eq!(Fq2::new(Fq::zero(), Fq::zero(),), Fq2::zero()); + assert_eq!(Fq2::new(Fq::one(), Fq::zero(),), Fq2::one()); + assert!(Fq2::zero().is_zero()); + assert!(!Fq2::one().is_zero()); + assert!(!Fq2::new(Fq::zero(), Fq::one(),).is_zero()); +} + +#[test] +fn test_fq2_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(Zero, Fq2::zero().legendre()); + // i^2 = -1 + let mut m1 = -Fq2::one(); + assert_eq!(QuadraticResidue, m1.legendre()); + m1 = Fq6Parameters::mul_fp2_by_nonresidue(&m1); + assert_eq!(QuadraticNonResidue, m1.legendre()); +} + +#[test] +fn test_fq2_mul_nonresidue() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let nqr = Fq2::new(Fq::zero(), Fq::one()); + + let quadratic_non_residue = Fq2::new( + Fq2Parameters::QUADRATIC_NONRESIDUE.0, + Fq2Parameters::QUADRATIC_NONRESIDUE.1, + ); + for _ in 0..1000 { + let mut a = Fq2::rand(&mut rng); + let mut b = a; + a = quadratic_non_residue * &a; + b.mul_assign(&nqr); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_1() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_1(&c1); + b.mul_assign(&Fq6::new(Fq2::zero(), c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_01() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_01(&c0, &c1); + b.mul_assign(&Fq6::new(c0, c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_014() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let c5 = Fq2::rand(&mut rng); + let mut a = Fq12::rand(&mut rng); + let mut b = a; + + a.mul_by_014(&c0, &c1, &c5); + b.mul_assign(&Fq12::new( + Fq6::new(c0, c1, Fq2::zero()), + Fq6::new(Fq2::zero(), c5, Fq2::zero()), + )); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_034() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c3 = Fq2::rand(&mut rng); + let c4 = Fq2::rand(&mut rng); + let mut a = Fq12::rand(&mut rng); + let mut b = a; + + a.mul_by_034(&c0, &c3, &c4); + b.mul_assign(&Fq12::new( + Fq6::new(c0, Fq2::zero(), Fq2::zero()), + Fq6::new(c3, c4, Fq2::zero()), + )); + + assert_eq!(a, b); + } +} diff --git a/bls12_377/src/lib.rs b/bls12_377/src/lib.rs new file mode 100644 index 0000000..136c1f3 --- /dev/null +++ b/bls12_377/src/lib.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the BLS12_377 curve generated in [[BCGMMW20, “Zexe”]](https://eprint.iacr.org/2018/962). +//! The name denotes that it is a Barreto--Lynn--Scott curve of embedding degree 12, +//! defined over a 377-bit (prime) field. The main feature of this curve is that +//! both the scalar field and the base field are highly 2-adic. +//! (This is in contrast to the BLS12_381 curve for which only the scalar field is highly 2-adic.) +//! +//! +//! Curve information: +//! * Base field: q = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +//! * Scalar field: r = 8444461749428370424248824938781546531375899335154063827935233455917409239041 +//! * valuation(q - 1, 2) = 46 +//! * valuation(r - 1, 2) = 47 +//! * G1 curve equation: y^2 = x^3 + 1 +//! * G2 curve equation: y^2 = x^3 + B, where +//! * B = Fq2(0, 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906) + +#[cfg(feature = "curve")] +mod curves; + +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; + +pub use fields::*; diff --git a/bls12_381/Cargo.toml b/bls12_381/Cargo.toml new file mode 100644 index 0000000..5ebfd2b --- /dev/null +++ b/bls12_381/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "ark-bls12-381" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The BLS12-381 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-bls12-381/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field" ] +scalar_field = [] diff --git a/bls12_381/LICENSE-APACHE b/bls12_381/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/bls12_381/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/bls12_381/LICENSE-MIT b/bls12_381/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/bls12_381/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/bls12_381/src/curves/g1.rs b/bls12_381/src/curves/g1.rs new file mode 100644 index 0000000..c328725 --- /dev/null +++ b/bls12_381/src/curves/g1.rs @@ -0,0 +1,82 @@ +use crate::*; +use ark_ec::{ + bls12, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{ + biginteger::{BigInteger256, BigInteger384}, + field_new, Zero, +}; + +pub type G1Affine = bls12::G1Affine; +pub type G1Projective = bls12::G1Projective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 0 + const COEFF_A: Fq = field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])); + + /// COEFF_B = 4 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger384([ + 0xaa270000000cfff3, + 0x53cc0032fc34000a, + 0x478fe97a6b0a807f, + 0xb1d37ebee6ba24d7, + 0x8ec9733bbf78ab2f, + 0x9d645513d83de7e, + ])); + + /// COFACTOR = (x - 1)^2 / 3 = 76329603384216526031706109802092473003 + const COFACTOR: &'static [u64] = &[0x8c00aaab0000aaab, 0x396c8c005555e156]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r + /// = 52435875175126190458656871551744051925719901746859129887267498875565241663483 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 288839107172787499, + 1152722415086798946, + 2612889808468387987, + 5124657601728438008, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G1_GENERATOR_X = +/// 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger384([ + 0x5cb38790fd530c16, + 0x7817fc679976fff5, + 0x154f95c7143ba1c1, + 0xf0ae6acdf3d0e747, + 0xedce6ecc21dbf440, + 0x120177419e0bfb75, +])); + +/// G1_GENERATOR_Y = +/// 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger384([ + 0xbaac93d50ce72271, + 0x8c22631a7918fd8e, + 0xdd595f13570725ce, + 0x51ac582950405194, + 0xe1c8c3fad0059c0, + 0xbbc3efc5008a26a, +])); diff --git a/bls12_381/src/curves/g2.rs b/bls12_381/src/curves/g2.rs new file mode 100644 index 0000000..ba6a14f --- /dev/null +++ b/bls12_381/src/curves/g2.rs @@ -0,0 +1,113 @@ +use crate::*; +use ark_ec::{ + bls12, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{ + biginteger::{BigInteger256, BigInteger384}, + field_new, Zero, +}; + +pub type G2Affine = bls12::G2Affine; +pub type G2Projective = bls12::G2Projective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq2; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = [0, 0] + const COEFF_A: Fq2 = field_new!(Fq2, g1::Parameters::COEFF_A, g1::Parameters::COEFF_A,); + + /// COEFF_B = [4, 4] + const COEFF_B: Fq2 = field_new!(Fq2, g1::Parameters::COEFF_B, g1::Parameters::COEFF_B,); + + /// COFACTOR = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) // + /// 9 + /// = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0xcf1c38e31c7238e5, + 0x1616ec6e786f0c70, + 0x21537e293a6691ae, + 0xa628f1cb4d9e82ef, + 0xa68a205b2e5a7ddf, + 0xcd91de4547085aba, + 0x91d50792876a202, + 0x5d543a95414e7f1, + ]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r + /// 26652489039290660355457965112010883481355318854675681319708643586776743290055 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 6746407649509787816, + 1304054119431494378, + 2461312685643913071, + 5956596749362435284, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +pub const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); +pub const G2_GENERATOR_Y: Fq2 = field_new!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1); + +/// G2_GENERATOR_X_C0 = +/// 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger384([ + 0xf5f28fa202940a10, + 0xb3f5fb2687b4961a, + 0xa1a893b53e2ae580, + 0x9894999d1a3caee9, + 0x6f67b7631863366b, + 0x58191924350bcd7, +])); + +/// G2_GENERATOR_X_C1 = +/// 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger384([ + 0xa5a9c0759e23f606, + 0xaaa0c59dbccd60c3, + 0x3bb17e18e2867806, + 0x1b1ab6cc8541b367, + 0xc2b6ed0ef2158547, + 0x11922a097360edf3, +])); + +/// G2_GENERATOR_Y_C0 = +/// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger384([ + 0x4c730af860494c4a, + 0x597cfa1f5e369c5a, + 0xe7e6856caa0a635a, + 0xbbefb5e96e0d495f, + 0x7d3a975f0ef25a2, + 0x83fd8e7e80dae5, +])); + +/// G2_GENERATOR_Y_C1 = +/// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger384([ + 0xadc0fc92df64b05d, + 0x18aa270a2b1461dc, + 0x86adac6a3be4eba0, + 0x79495c4ec93da33a, + 0xe7175850a43ccaed, + 0xb2bc2a163de1bf2, +])); diff --git a/bls12_381/src/curves/mod.rs b/bls12_381/src/curves/mod.rs new file mode 100644 index 0000000..ffa7ed1 --- /dev/null +++ b/bls12_381/src/curves/mod.rs @@ -0,0 +1,30 @@ +use ark_ec::bls12::{Bls12, Bls12Parameters, TwistType}; + +use crate::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub use self::{ + g1::{G1Affine, G1Projective}, + g2::{G2Affine, G2Projective}, +}; + +pub type Bls12_381 = Bls12; + +pub struct Parameters; + +impl Bls12Parameters for Parameters { + const X: &'static [u64] = &[0xd201000000010000]; + const X_IS_NEGATIVE: bool = true; + const TWIST_TYPE: TwistType = TwistType::M; + type Fp = Fq; + type Fp2Params = Fq2Parameters; + type Fp6Params = Fq6Parameters; + type Fp12Params = Fq12Parameters; + type G1Parameters = self::g1::Parameters; + type G2Parameters = self::g2::Parameters; +} diff --git a/bls12_381/src/curves/tests.rs b/bls12_381/src/curves/tests.rs new file mode 100644 index 0000000..6490e3c --- /dev/null +++ b/bls12_381/src/curves/tests.rs @@ -0,0 +1,116 @@ +#![allow(unused_imports)] +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{ + fields::{Field, FpParameters, PrimeField, SquareRootField}, + test_rng, One, Zero, +}; +use ark_serialize::CanonicalSerialize; +use core::ops::{AddAssign, MulAssign}; +use rand::Rng; + +use crate::{g1, g2, Bls12_381, Fq, Fq12, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let mut sa = a; + sa.mul_assign(s); + let mut sb = b; + sb.mul_assign(s); + + let ans1 = Bls12_381::pairing(sa, b); + let ans2 = Bls12_381::pairing(a, sb); + let ans3 = Bls12_381::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq12::one()); + assert_ne!(ans2, Fq12::one()); + assert_ne!(ans3, Fq12::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq12::one()); +} + +#[test] +fn test_g1_generator_raw() { + let mut x = Fq::zero(); + let mut i = 0; + loop { + // y^2 = x^3 + b + let mut rhs = x; + rhs.square_in_place(); + rhs.mul_assign(&x); + rhs.add_assign(&g1::Parameters::COEFF_B); + + if let Some(y) = rhs.sqrt() { + let p = G1Affine::new(x, if y < -y { y } else { -y }, false); + assert!(!p.is_in_correct_subgroup_assuming_on_curve()); + + let g1 = p.scale_by_cofactor(); + if !g1.is_zero() { + assert_eq!(i, 4); + let g1 = G1Affine::from(g1); + + assert!(g1.is_in_correct_subgroup_assuming_on_curve()); + + assert_eq!(g1, G1Affine::prime_subgroup_generator()); + break; + } + } + + i += 1; + x.add_assign(&Fq::one()); + } +} diff --git a/bls12_381/src/fields/fq.rs b/bls12_381/src/fields/fq.rs new file mode 100644 index 0000000..3b7e790 --- /dev/null +++ b/bls12_381/src/fields/fq.rs @@ -0,0 +1,112 @@ +use ark_ff::{ + biginteger::BigInteger384 as BigInteger, + field_new, + fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, +}; + +pub type Fq = Fp384; + +pub struct FqParameters; + +impl Fp384Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ]); +} +impl FpParameters for FqParameters { + /// MODULUS = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xb9feffffffffaaab, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + ]); + + const MODULUS_BITS: u32 = 381; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 3; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xf4df1f341c341746, + 0xa76e6a609d104f1, + 0x8de5476c4c95b6d5, + 0x67eb88a9939d83c0, + 0x9a793e85b519952d, + 0x11988fe592cae3aa, + ]); + + const INV: u64 = 0x89f3fffcfffcfffd; + + // GENERATOR = 2 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0x321300000006554f, + 0xb93c0018d6c40005, + 0x57605e0db0ddbb51, + 0x8b256521ed1f9bcb, + 0x6cf28d7901622c03, + 0x11ebab9dbb81e28c, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]); + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xee7fbfffffffeaaa, + 0x7aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x680447a8e5ff9a6, + ]); +} + +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0])); diff --git a/bls12_381/src/fields/fq12.rs b/bls12_381/src/fields/fq12.rs new file mode 100644 index 0000000..8791ec0 --- /dev/null +++ b/bls12_381/src/fields/fq12.rs @@ -0,0 +1,193 @@ +use crate::*; +use ark_ff::{biginteger::BigInteger384, field_new, fields::*}; + +pub type Fq12 = Fp12; + +#[derive(Clone, Copy)] +pub struct Fq12Parameters; + +impl Fp12Parameters for Fq12Parameters { + type Fp6Params = Fq6Parameters; + + const NONRESIDUE: Fq6 = field_new!(Fq6, FQ2_ZERO, FQ2_ONE, FQ2_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP12_C1: &'static [Fq2] = &[ + // Fq2(u + 1)**(((q^0) - 1) / 6) + FQ2_ONE, + // Fq2(u + 1)**(((q^1) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x7089552b319d465, + 0xc6695f92b50a8313, + 0x97e83cccd117228f, + 0xa35baecab2dc29ee, + 0x1ce393ea5daace4d, + 0x8f2220fb0fb66eb, + ])), + field_new!(Fq, BigInteger384([ + 0xb2f66aad4ce5d646, + 0x5842a06bfc497cec, + 0xcf4895d42599d394, + 0xc11b9cba40a8e8d0, + 0x2e3813cbe5a0de89, + 0x110eefda88847faf, + ])), + ), + // Fq2(u + 1)**(((q^2) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xecfb361b798dba3a, + 0xc100ddb891865a2c, + 0xec08ff1232bda8e, + 0xd5c13cc6f1ca4721, + 0x47222a47bf7b5c04, + 0x110f184e51c5f59, + ])), + FQ_ZERO, + ), + // Fq2(u + 1)**(((q^3) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x3e2f585da55c9ad1, + 0x4294213d86c18183, + 0x382844c88b623732, + 0x92ad2afd19103e18, + 0x1d794e4fac7cf0b9, + 0xbd592fc7d825ec8, + ])), + field_new!(Fq, BigInteger384([ + 0x7bcfa7a25aa30fda, + 0xdc17dec12a927e7c, + 0x2f088dd86b4ebef1, + 0xd1ca2087da74d4a7, + 0x2da2596696cebc1d, + 0xe2b7eedbbfd87d2, + ])), + ), + // Fq2(u + 1)**(((q^4) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x30f1361b798a64e8, + 0xf3b8ddab7ece5a2a, + 0x16a8ca3ac61577f7, + 0xc26a2ff874fd029b, + 0x3636b76660701c6e, + 0x51ba4ab241b6160, + ])), + FQ_ZERO, + ), + // Fq2(u + 1)**(((q^5) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x3726c30af242c66c, + 0x7c2ac1aad1b6fe70, + 0xa04007fbba4b14a2, + 0xef517c3266341429, + 0x95ba654ed2226b, + 0x2e370eccc86f7dd, + ])), + field_new!(Fq, BigInteger384([ + 0x82d83cf50dbce43f, + 0xa2813e53df9d018f, + 0xc6f0caa53c65e181, + 0x7525cf528d50fe95, + 0x4a85ed50f4798a6b, + 0x171da0fd6cf8eebd, + ])), + ), + // Fq2(u + 1)**(((q^6) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ])), + FQ_ZERO, + ), + // Fq2(u + 1)**(((q^7) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xb2f66aad4ce5d646, + 0x5842a06bfc497cec, + 0xcf4895d42599d394, + 0xc11b9cba40a8e8d0, + 0x2e3813cbe5a0de89, + 0x110eefda88847faf, + ])), + field_new!(Fq, BigInteger384([ + 0x7089552b319d465, + 0xc6695f92b50a8313, + 0x97e83cccd117228f, + 0xa35baecab2dc29ee, + 0x1ce393ea5daace4d, + 0x8f2220fb0fb66eb, + ])), + ), + // Fq2(u + 1)**(((q^8) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x3f97d6e83d050d2, + 0x18f0206554638741, + ])), + FQ_ZERO, + ), + // Fq2(u + 1)**(((q^9) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x7bcfa7a25aa30fda, + 0xdc17dec12a927e7c, + 0x2f088dd86b4ebef1, + 0xd1ca2087da74d4a7, + 0x2da2596696cebc1d, + 0xe2b7eedbbfd87d2, + ])), + field_new!(Fq, BigInteger384([ + 0x3e2f585da55c9ad1, + 0x4294213d86c18183, + 0x382844c88b623732, + 0x92ad2afd19103e18, + 0x1d794e4fac7cf0b9, + 0xbd592fc7d825ec8, + ])), + ), + // Fq2(u + 1)**(((q^10) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x890dc9e4867545c3, + 0x2af322533285a5d5, + 0x50880866309b7e2c, + 0xa20d1b8c7e881024, + 0x14e4f04fe2db9068, + 0x14e56d3f1564853a, + ])), + FQ_ZERO, + ), + // Fq2(u + 1)**(((q^11) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x82d83cf50dbce43f, + 0xa2813e53df9d018f, + 0xc6f0caa53c65e181, + 0x7525cf528d50fe95, + 0x4a85ed50f4798a6b, + 0x171da0fd6cf8eebd, + ])), + field_new!(Fq, BigInteger384([ + 0x3726c30af242c66c, + 0x7c2ac1aad1b6fe70, + 0xa04007fbba4b14a2, + 0xef517c3266341429, + 0x95ba654ed2226b, + 0x2e370eccc86f7dd, + ])), + ), + ]; +} diff --git a/bls12_381/src/fields/fq2.rs b/bls12_381/src/fields/fq2.rs new file mode 100644 index 0000000..736dd25 --- /dev/null +++ b/bls12_381/src/fields/fq2.rs @@ -0,0 +1,73 @@ +use crate::*; +use ark_ff::{biginteger::BigInteger384 as BigInteger, field_new, fields::*}; + +pub type Fq2 = Fp2; + +pub struct Fq2Parameters; + +impl Fp2Parameters for Fq2Parameters { + type Fp = Fq; + + /// NONRESIDUE = -1 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ])); + + /// QUADRATIC_NONRESIDUE = (U + 1) + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE: (Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + field_new!(Fq, BigInteger([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + ); + + /// Coefficients for the Frobenius automorphism. + #[rustfmt::skip] + const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[ + // Fq(-1)**(((q^0) - 1) / 2) + field_new!(Fq, BigInteger([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + // Fq(-1)**(((q^1) - 1) / 2) + field_new!(Fq, BigInteger([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ])), + ]; + + #[inline(always)] + fn mul_fp_by_nonresidue(fp: &Self::Fp) -> Self::Fp { + -(*fp) + } +} + +pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO); diff --git a/bls12_381/src/fields/fq6.rs b/bls12_381/src/fields/fq6.rs new file mode 100644 index 0000000..18853ac --- /dev/null +++ b/bls12_381/src/fields/fq6.rs @@ -0,0 +1,194 @@ +use crate::*; +use ark_ff::{biginteger::BigInteger384, field_new, fields::*}; + +pub type Fq6 = Fp6; + +#[derive(Clone, Copy)] +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp2Params = Fq2Parameters; + + /// NONRESIDUE = (U + 1) + #[rustfmt::skip] + const NONRESIDUE: Fq2 = field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + field_new!(Fq, BigInteger384([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + ); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ + // Fq2(u + 1)**(((q^0) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((q^1) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + field_new!(Fq, BigInteger384([ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x3f97d6e83d050d2, + 0x18f0206554638741, + ])), + ), + // Fq2(u + 1)**(((q^2) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x30f1361b798a64e8, + 0xf3b8ddab7ece5a2a, + 0x16a8ca3ac61577f7, + 0xc26a2ff874fd029b, + 0x3636b76660701c6e, + 0x51ba4ab241b6160, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((q^3) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + field_new!(Fq, BigInteger384([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + ), + // Fq2(u + 1)**(((q^4) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x3f97d6e83d050d2, + 0x18f0206554638741, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((q^5) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + field_new!(Fq, BigInteger384([ + 0x30f1361b798a64e8, + 0xf3b8ddab7ece5a2a, + 0x16a8ca3ac61577f7, + 0xc26a2ff874fd029b, + 0x3636b76660701c6e, + 0x51ba4ab241b6160, + ])), + ), + ]; + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ + // Fq2(u + 1)**(((2q^0) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((2q^1) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x890dc9e4867545c3, + 0x2af322533285a5d5, + 0x50880866309b7e2c, + 0xa20d1b8c7e881024, + 0x14e4f04fe2db9068, + 0x14e56d3f1564853a, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((2q^2) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x3f97d6e83d050d2, + 0x18f0206554638741, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((2q^3) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((2q^4) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0x30f1361b798a64e8, + 0xf3b8ddab7ece5a2a, + 0x16a8ca3ac61577f7, + 0xc26a2ff874fd029b, + 0x3636b76660701c6e, + 0x51ba4ab241b6160, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + // Fq2(u + 1)**(((2q^5) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger384([ + 0xecfb361b798dba3a, + 0xc100ddb891865a2c, + 0xec08ff1232bda8e, + 0xd5c13cc6f1ca4721, + 0x47222a47bf7b5c04, + 0x110f184e51c5f59, + ])), + field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), + ), + ]; + + /// Multiply this element by the quadratic nonresidue 1 + u. + /// Make this generic. + fn mul_fp2_by_nonresidue(fe: &Fq2) -> Fq2 { + let mut copy = *fe; + let t0 = copy.c0; + copy.c0 -= &fe.c1; + copy.c1 += &t0; + copy + } +} diff --git a/bls12_381/src/fields/fr.rs b/bls12_381/src/fields/fr.rs new file mode 100644 index 0000000..caa0059 --- /dev/null +++ b/bls12_381/src/fields/fr.rs @@ -0,0 +1,96 @@ +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, +}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 32; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0xb9b58d8c5f0e466a, + 0x5b1b4c801819d7ec, + 0xaf53ae352a31e64, + 0x5bf3adda19e9b27b, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xffffffff00000001, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48, + ]); + + const MODULUS_BITS: u32 = 255; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 1; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0x1fffffffe, + 0x5884b7fa00034802, + 0x998c4fefecbc4ff5, + 0x1824b159acc5056f, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xc999e990f3f29c6d, + 0x2b6cedcb87925c23, + 0x5d314967254398f, + 0x748d9d99f59ff11, + ]); + + const INV: u64 = 0xfffffffeffffffff; + + // + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0xefffffff1, + 0x17e363d300189c0f, + 0xff9c57876f8457b0, + 0x351332208fc5a8c4, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x7fffffff80000000, + 0xa9ded2017fff2dff, + 0x199cec0404d0ec02, + 0x39f6d3a994cebea4, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + // T = (MODULUS - 1) / 2^S = + // 12208678567578594777604504606729831043093128246378069236549469339647 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0xfffe5bfeffffffff, + 0x9a1d80553bda402, + 0x299d7d483339d808, + 0x73eda753, + ]); + + // (T - 1) / 2 = + // 6104339283789297388802252303364915521546564123189034618274734669823 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x7fff2dff7fffffff, + 0x4d0ec02a9ded201, + 0x94cebea4199cec04, + 0x39f6d3a9, + ]); +} diff --git a/bls12_381/src/fields/mod.rs b/bls12_381/src/fields/mod.rs new file mode 100644 index 0000000..c9c69eb --- /dev/null +++ b/bls12_381/src/fields/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(feature = "curve")] +pub mod fq; +#[cfg(feature = "curve")] +pub use self::fq::*; + +#[cfg(feature = "curve")] +pub mod fq2; +#[cfg(feature = "curve")] +pub use self::fq2::*; + +#[cfg(feature = "curve")] +pub mod fq6; +#[cfg(feature = "curve")] +pub use self::fq6::*; + +#[cfg(feature = "curve")] +pub mod fq12; +#[cfg(feature = "curve")] +pub use self::fq12::*; + +#[cfg(all(feature = "curve", feature = "std", test))] +mod tests; diff --git a/bls12_381/src/fields/tests.rs b/bls12_381/src/fields/tests.rs new file mode 100644 index 0000000..a79615a --- /dev/null +++ b/bls12_381/src/fields/tests.rs @@ -0,0 +1,2322 @@ +use ark_ff::{ + biginteger::{BigInteger, BigInteger384}, + fields::{ + FftField, FftParameters, Field, Fp12Parameters, Fp2Parameters, Fp6Parameters, FpParameters, + SquareRootField, + }, + One, UniformRand, Zero, +}; +use core::{ + cmp::Ordering, + ops::{AddAssign, MulAssign, SubAssign}, +}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +use crate::{Fq, Fq12, Fq12Parameters, Fq2, Fq2Parameters, Fq6, Fq6Parameters, FqParameters, Fr}; +use ark_curve_tests::fields::*; + +pub(crate) const ITERATIONS: usize = 5; + +#[test] +fn test_fr() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..ITERATIONS { + let a: Fr = UniformRand::rand(&mut rng); + let b: Fr = UniformRand::rand(&mut rng); + field_test(a, b); + primefield_test::(); + sqrt_field_test(b); + } +} + +#[test] +fn test_fq() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..ITERATIONS { + let a: Fq = UniformRand::rand(&mut rng); + let b: Fq = UniformRand::rand(&mut rng); + field_test(a, b); + primefield_test::(); + sqrt_field_test(a); + } +} + +#[test] +fn test_fq2() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..ITERATIONS { + let a: Fq2 = UniformRand::rand(&mut rng); + let b: Fq2 = UniformRand::rand(&mut rng); + field_test(a, b); + sqrt_field_test(a); + } + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq6() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..ITERATIONS { + let g: Fq6 = UniformRand::rand(&mut rng); + let h: Fq6 = UniformRand::rand(&mut rng); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq12() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..ITERATIONS { + let g: Fq12 = UniformRand::rand(&mut rng); + let h: Fq12 = UniformRand::rand(&mut rng); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_negative_one() { + let neg_one = Fq::new(BigInteger384([ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ])); + assert_eq!(neg_one, -Fq::one()); +} + +#[test] +fn test_frob_coeffs() { + let nqr = -Fq::one(); + + assert_eq!(Fq2Parameters::FROBENIUS_COEFF_FP2_C1[0], Fq::one()); + assert_eq!( + Fq2Parameters::FROBENIUS_COEFF_FP2_C1[1], + nqr.pow([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]) + ); + + let nqr = Fq2::new(Fq::one(), Fq::one()); + + assert_eq!(Fq6Parameters::FROBENIUS_COEFF_FP6_C1[0], Fq2::one()); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C1[1], + nqr.pow([ + 0x9354ffffffffe38e, + 0xa395554e5c6aaaa, + 0xcd104635a790520c, + 0xcc27c3d6fbd7063f, + 0x190937e76bc3e447, + 0x8ab05f8bdd54cde, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C1[2], + nqr.pow([ + 0xb78e0000097b2f68, + 0xd44f23b47cbd64e3, + 0x5cb9668120b069a9, + 0xccea85f9bf7b3d16, + 0xdba2c8d7adb356d, + 0x9cd75ded75d7429, + 0xfc65c31103284fab, + 0xc58cb9a9b249ee24, + 0xccf734c3118a2e9a, + 0xa0f4304c5a256ce6, + 0xc3f0d2f8e0ba61f8, + 0xe167e192ebca97, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C1[3], + nqr.pow([ + 0xdbc6fcd6f35b9e06, + 0x997dead10becd6aa, + 0x9dbbd24c17206460, + 0x72b97acc6057c45e, + 0xf8e9a230bf0c628e, + 0x647ccb1885c63a7, + 0xce80264fc55bf6ee, + 0x94d8d716c3939fc4, + 0xad78f0eb77ee6ee1, + 0xd6fe49bfe57dc5f9, + 0x2656d6c15c63647, + 0xdf6282f111fa903, + 0x1bdba63e0632b4bb, + 0x6883597bcaa505eb, + 0xa56d4ec90c34a982, + 0x7e4c42823bbe90b2, + 0xf64728aa6dcb0f20, + 0x16e57e16ef152f, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C1[4], + nqr.pow([ + 0x4649add3c71c6d90, + 0x43caa6528972a865, + 0xcda8445bbaaa0fbb, + 0xc93dea665662aa66, + 0x2863bc891834481d, + 0x51a0c3f5d4ccbed8, + 0x9210e660f90ccae9, + 0xe2bd6836c546d65e, + 0xf223abbaa7cf778b, + 0xd4f10b222cf11680, + 0xd540f5eff4a1962e, + 0xa123a1f140b56526, + 0x31ace500636a59f6, + 0x3a82bc8c8dfa57a9, + 0x648c511e217fc1f8, + 0x36c17ffd53a4558f, + 0x881bef5fd684eefd, + 0x5d648dbdc5dbb522, + 0x8fd07bf06e5e59b8, + 0x8ddec8a9acaa4b51, + 0x4cc1f8688e2def26, + 0xa74e63cb492c03de, + 0x57c968173d1349bb, + 0x253674e02a866, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C1[5], + nqr.pow([ + 0xf896f792732eb2be, + 0x49c86a6d1dc593a1, + 0xe5b31e94581f91c3, + 0xe3da5cc0a6b20d7f, + 0x822caef950e0bfed, + 0x317ed950b9ee67cd, + 0xffd664016ee3f6cd, + 0x77d991c88810b122, + 0x62e72e635e698264, + 0x905e1a1a2d22814a, + 0xf5b7ab3a3f33d981, + 0x175871b0bc0e25dd, + 0x1e2e9a63df5c3772, + 0xe888b1f7445b149d, + 0x9551c19e5e7e2c24, + 0xecf21939a3d2d6be, + 0xd830dbfdab72dbd4, + 0x7b34af8d622d40c0, + 0x3df6d20a45671242, + 0xaf86bee30e21d98, + 0x41064c1534e5df5d, + 0xf5f6cabd3164c609, + 0xa5d14bdf2b7ee65, + 0xa718c069defc9138, + 0xdb1447e770e3110e, + 0xc1b164a9e90af491, + 0x7180441f9d251602, + 0x1fd3a5e6a9a893e, + 0x1e17b779d54d5db, + 0x3c7afafe3174, + ]) + ); + + assert_eq!(Fq6Parameters::FROBENIUS_COEFF_FP6_C2[0], Fq2::one()); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C2[1], + nqr.pow([ + 0x26a9ffffffffc71c, + 0x1472aaa9cb8d5555, + 0x9a208c6b4f20a418, + 0x984f87adf7ae0c7f, + 0x32126fced787c88f, + 0x11560bf17baa99bc, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C2[2], + nqr.pow([ + 0x6f1c000012f65ed0, + 0xa89e4768f97ac9c7, + 0xb972cd024160d353, + 0x99d50bf37ef67a2c, + 0x1b74591af5b66adb, + 0x139aebbdaebae852, + 0xf8cb862206509f56, + 0x8b1973536493dc49, + 0x99ee698623145d35, + 0x41e86098b44ad9cd, + 0x87e1a5f1c174c3f1, + 0x1c2cfc325d7952f, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C2[3], + nqr.pow([ + 0xb78df9ade6b73c0c, + 0x32fbd5a217d9ad55, + 0x3b77a4982e40c8c1, + 0xe572f598c0af88bd, + 0xf1d344617e18c51c, + 0xc8f996310b8c74f, + 0x9d004c9f8ab7eddc, + 0x29b1ae2d87273f89, + 0x5af1e1d6efdcddc3, + 0xadfc937fcafb8bf3, + 0x4cadad82b8c6c8f, + 0x1bec505e223f5206, + 0x37b74c7c0c656976, + 0xd106b2f7954a0bd6, + 0x4ada9d9218695304, + 0xfc988504777d2165, + 0xec8e5154db961e40, + 0x2dcafc2dde2a5f, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C2[4], + nqr.pow([ + 0x8c935ba78e38db20, + 0x87954ca512e550ca, + 0x9b5088b775541f76, + 0x927bd4ccacc554cd, + 0x50c779123068903b, + 0xa34187eba9997db0, + 0x2421ccc1f21995d2, + 0xc57ad06d8a8dacbd, + 0xe44757754f9eef17, + 0xa9e2164459e22d01, + 0xaa81ebdfe9432c5d, + 0x424743e2816aca4d, + 0x6359ca00c6d4b3ed, + 0x750579191bf4af52, + 0xc918a23c42ff83f0, + 0x6d82fffaa748ab1e, + 0x1037debfad09ddfa, + 0xbac91b7b8bb76a45, + 0x1fa0f7e0dcbcb370, + 0x1bbd9153595496a3, + 0x9983f0d11c5bde4d, + 0x4e9cc796925807bc, + 0xaf92d02e7a269377, + 0x4a6ce9c0550cc, + ]) + ); + assert_eq!( + Fq6Parameters::FROBENIUS_COEFF_FP6_C2[5], + nqr.pow([ + 0xf12def24e65d657c, + 0x9390d4da3b8b2743, + 0xcb663d28b03f2386, + 0xc7b4b9814d641aff, + 0x4595df2a1c17fdb, + 0x62fdb2a173dccf9b, + 0xffacc802ddc7ed9a, + 0xefb3239110216245, + 0xc5ce5cc6bcd304c8, + 0x20bc34345a450294, + 0xeb6f56747e67b303, + 0x2eb0e361781c4bbb, + 0x3c5d34c7beb86ee4, + 0xd11163ee88b6293a, + 0x2aa3833cbcfc5849, + 0xd9e4327347a5ad7d, + 0xb061b7fb56e5b7a9, + 0xf6695f1ac45a8181, + 0x7beda4148ace2484, + 0x15f0d7dc61c43b30, + 0x820c982a69cbbeba, + 0xebed957a62c98c12, + 0x14ba297be56fdccb, + 0x4e3180d3bdf92270, + 0xb6288fcee1c6221d, + 0x8362c953d215e923, + 0xe300883f3a4a2c05, + 0x3fa74bcd535127c, + 0x3c2f6ef3aa9abb6, + 0x78f5f5fc62e8, + ]) + ); + + assert_eq!(Fq12Parameters::FROBENIUS_COEFF_FP12_C1[0], Fq2::one()); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[1], + nqr.pow([ + 0x49aa7ffffffff1c7, + 0x51caaaa72e35555, + 0xe688231ad3c82906, + 0xe613e1eb7deb831f, + 0xc849bf3b5e1f223, + 0x45582fc5eeaa66f, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[2], + nqr.pow([ + 0xdbc7000004bd97b4, + 0xea2791da3e5eb271, + 0x2e5cb340905834d4, + 0xe67542fcdfbd9e8b, + 0x86dd1646bd6d9ab6, + 0x84e6baef6baeba14, + 0x7e32e188819427d5, + 0x62c65cd4d924f712, + 0x667b9a6188c5174d, + 0x507a18262d12b673, + 0xe1f8697c705d30fc, + 0x70b3f0c975e54b, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[3], + nqr.pow(vec![ + 0x6de37e6b79adcf03, + 0x4cbef56885f66b55, + 0x4edde9260b903230, + 0x395cbd66302be22f, + 0xfc74d1185f863147, + 0x323e658c42e31d3, + 0x67401327e2adfb77, + 0xca6c6b8b61c9cfe2, + 0xd6bc7875bbf73770, + 0xeb7f24dff2bee2fc, + 0x8132b6b60ae31b23, + 0x86fb1417888fd481, + 0x8dedd31f03195a5d, + 0x3441acbde55282f5, + 0x52b6a764861a54c1, + 0x3f2621411ddf4859, + 0xfb23945536e58790, + 0xb72bf0b778a97, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[4], + nqr.pow(vec![ + 0xa324d6e9e38e36c8, + 0xa1e5532944b95432, + 0x66d4222ddd5507dd, + 0xe49ef5332b315533, + 0x1431de448c1a240e, + 0xa8d061faea665f6c, + 0x490873307c866574, + 0xf15eb41b62a36b2f, + 0x7911d5dd53e7bbc5, + 0x6a78859116788b40, + 0x6aa07af7fa50cb17, + 0x5091d0f8a05ab293, + 0x98d6728031b52cfb, + 0x1d415e4646fd2bd4, + 0xb246288f10bfe0fc, + 0x9b60bffea9d22ac7, + 0x440df7afeb42777e, + 0x2eb246dee2edda91, + 0xc7e83df8372f2cdc, + 0x46ef6454d65525a8, + 0x2660fc344716f793, + 0xd3a731e5a49601ef, + 0x2be4b40b9e89a4dd, + 0x129b3a7015433, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[5], + nqr.pow(vec![ + 0xfc4b7bc93997595f, + 0xa4e435368ee2c9d0, + 0xf2d98f4a2c0fc8e1, + 0xf1ed2e60535906bf, + 0xc116577ca8705ff6, + 0x98bf6ca85cf733e6, + 0x7feb3200b771fb66, + 0x3becc8e444085891, + 0x31739731af34c132, + 0xc82f0d0d169140a5, + 0xfadbd59d1f99ecc0, + 0xbac38d85e0712ee, + 0x8f174d31efae1bb9, + 0x744458fba22d8a4e, + 0x4aa8e0cf2f3f1612, + 0x76790c9cd1e96b5f, + 0x6c186dfed5b96dea, + 0x3d9a57c6b116a060, + 0x1efb690522b38921, + 0x857c35f718710ecc, + 0xa083260a9a72efae, + 0xfafb655e98b26304, + 0x52e8a5ef95bf732, + 0x538c6034ef7e489c, + 0xed8a23f3b8718887, + 0x60d8b254f4857a48, + 0x38c0220fce928b01, + 0x80fe9d2f354d449f, + 0xf0bdbbceaa6aed, + 0x1e3d7d7f18ba, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[6], + nqr.pow(vec![ + 0x21219610a012ba3c, + 0xa5c19ad35375325, + 0x4e9df1e497674396, + 0xfb05b717c991c6ef, + 0x4a1265bca93a32f2, + 0xd875ff2a7bdc1f66, + 0xc6d8754736c771b2, + 0x2d80c759ba5a2ae7, + 0x138a20df4b03cc1a, + 0xc22d07fe68e93024, + 0xd1dc474d3b433133, + 0xc22aa5e75044e5c, + 0xf657c6fbf9c17ebf, + 0xc591a794a58660d, + 0x2261850ee1453281, + 0xd17d3bd3b7f5efb4, + 0xf00cec8ec507d01, + 0x2a6a775657a00ae6, + 0x5f098a12ff470719, + 0x409d194e7b5c5afa, + 0x1d66478e982af5b, + 0xda425a5b5e01ca3f, + 0xf77e4f78747e903c, + 0x177d49f73732c6fc, + 0xa9618fecabe0e1f4, + 0xba5337eac90bd080, + 0x66fececdbc35d4e7, + 0xa4cd583203d9206f, + 0x98391632ceeca596, + 0x4946b76e1236ad3f, + 0xa0dec64e60e711a1, + 0xfcb41ed3605013, + 0x8ca8f9692ae1e3a9, + 0xd3078bfc28cc1baf, + 0xf0536f764e982f82, + 0x3125f1a2656, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[7], + nqr.pow(vec![ + 0x742754a1f22fdb, + 0x2a1955c2dec3a702, + 0x9747b28c796d134e, + 0xc113a0411f59db79, + 0x3bb0fa929853bfc1, + 0x28c3c25f8f6fb487, + 0xbc2b6c99d3045b34, + 0x98fb67d6badde1fd, + 0x48841d76a24d2073, + 0xd49891145fe93ae6, + 0xc772b9c8e74d4099, + 0xccf4e7b9907755bb, + 0x9cf47b25d42fd908, + 0x5616a0c347fc445d, + 0xff93b7a7ad1b8a6d, + 0xac2099256b78a77a, + 0x7804a95b02892e1c, + 0x5cf59ca7bfd69776, + 0xa7023502acd3c866, + 0xc76f4982fcf8f37, + 0x51862a5a57ac986e, + 0x38b80ed72b1b1023, + 0x4a291812066a61e1, + 0xcd8a685eff45631, + 0x3f40f708764e4fa5, + 0x8aa0441891285092, + 0x9eff60d71cdf0a9, + 0x4fdd9d56517e2bfa, + 0x1f3c80d74a28bc85, + 0x24617417c064b648, + 0x7ddda1e4385d5088, + 0xf9e132b11dd32a16, + 0xcc957cb8ef66ab99, + 0xd4f206d37cb752c5, + 0x40de343f28ad616b, + 0x8d1f24379068f0e3, + 0x6f31d7947ea21137, + 0x27311f9c32184061, + 0x9eea0664cc78ce5f, + 0x7d4151f6fea9a0da, + 0x454096fa75bd571a, + 0x4fe0f20ecb, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[8], + nqr.pow(vec![ + 0x802f5720d0b25710, + 0x6714f0a258b85c7c, + 0x31394c90afdf16e, + 0xe9d2b0c64f957b19, + 0xe67c0d9c5e7903ee, + 0x3156fdc5443ea8ef, + 0x7c4c50524d88c892, + 0xc99dc8990c0ad244, + 0xd37ababf3649a896, + 0x76fe4b838ff7a20c, + 0xcf69ee2cec728db3, + 0xb83535548e5f41, + 0x371147684ccb0c23, + 0x194f6f4fa500db52, + 0xc4571dc78a4c5374, + 0xe4d46d479999ca97, + 0x76b6785a615a151c, + 0xcceb8bcea7eaf8c1, + 0x80d87a6fbe5ae687, + 0x6a97ddddb85ce85, + 0xd783958f26034204, + 0x7144506f2e2e8590, + 0x948693d377aef166, + 0x8364621ed6f96056, + 0xf021777c4c09ee2d, + 0xc6cf5e746ecd50b, + 0xa2337b7aa22743df, + 0xae753f8bbacab39c, + 0xfc782a9e34d3c1cc, + 0x21b827324fe494d9, + 0x5692ce350ed03b38, + 0xf323a2b3cd0481b0, + 0xe859c97a4ccad2e3, + 0x48434b70381e4503, + 0x46042d62e4132ed8, + 0x48c4d6f56122e2f2, + 0xf87711ab9f5c1af7, + 0xb14b7a054759b469, + 0x8eb0a96993ffa9aa, + 0x9b21fb6fc58b760c, + 0xf3abdd115d2e7d25, + 0xf7beac3d4d12409c, + 0x40a5585cce69bf03, + 0x697881e1ba22d5a8, + 0x3d6c04e6ad373fd9, + 0x849871bf627be886, + 0x550f4b9b71b28ef9, + 0x81d2e0d78, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[9], + nqr.pow(vec![ + 0x4af4accf7de0b977, + 0x742485e21805b4ee, + 0xee388fbc4ac36dec, + 0x1e199da57ad178a, + 0xc27c12b292c6726a, + 0x162e6ed84505b5e8, + 0xe191683f336e09df, + 0x17deb7e8d1e0fce6, + 0xd944f19ad06f5836, + 0x4c5f5e59f6276026, + 0xf1ba9c7c148a38a8, + 0xd205fe2dba72b326, + 0x9a2cf2a4c289824e, + 0x4f47ad512c39e24d, + 0xc5894d984000ea09, + 0x2974c03ff7cf01fa, + 0xfcd243b48cb99a22, + 0x2b5150c9313ac1e8, + 0x9089f37c7fc80eda, + 0x989540cc9a7aea56, + 0x1ab1d4e337e63018, + 0x42b546c30d357e43, + 0x1c6abc04f76233d9, + 0x78b3b8d88bf73e47, + 0x151c4e4c45dc68e6, + 0x519a79c4f54397ed, + 0x93f5b51535a127c5, + 0x5fc51b6f52fa153e, + 0x2e0504f2d4a965c3, + 0xc85bd3a3da52bffe, + 0x98c60957a46a89ef, + 0x48c03b5976b91cae, + 0xc6598040a0a61438, + 0xbf0b49dc255953af, + 0xb78dff905b628ab4, + 0x68140b797ba74ab8, + 0x116cf037991d1143, + 0x2f7fe82e58acb0b8, + 0xc20bf7a8f7be5d45, + 0x86c2905c338d5709, + 0xff13a3ae6c8ace3d, + 0xb6f95e2282d08337, + 0xd49f7b313e9cbf29, + 0xf794517193a1ce8c, + 0x39641fecb596a874, + 0x411c4c4edf462fb3, + 0x3f8cd55c10cf25b4, + 0x2bdd7ea165e860b6, + 0xacd7d2cef4caa193, + 0x6558a1d09a05f96, + 0x1f52b5f5b546fc20, + 0x4ee22a5a8c250c12, + 0xd3a63a54a205b6b3, + 0xd2ff5be8, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[10], + nqr.pow(vec![ + 0xe5953a4f96cdda44, + 0x336b2d734cbc32bb, + 0x3f79bfe3cd7410e, + 0x267ae19aaa0f0332, + 0x85a9c4db78d5c749, + 0x90996b046b5dc7d8, + 0x8945eae9820afc6a, + 0x2644ddea2b036bd, + 0x39898e35ac2e3819, + 0x2574eab095659ab9, + 0x65953d51ac5ea798, + 0xc6b8c7afe6752466, + 0x40e9e993e9286544, + 0x7e0ad34ad9700ea0, + 0xac1015eba2c69222, + 0x24f057a19239b5d8, + 0x2043b48c8a3767eb, + 0x1117c124a75d7ff4, + 0x433cfd1a09fb3ce7, + 0x25b087ce4bcf7fb, + 0xbcee0dc53a3e5bdb, + 0xbffda040cf028735, + 0xf7cf103a25512acc, + 0x31d4ecda673130b9, + 0xea0906dab18461e6, + 0x5a40585a5ac3050d, + 0x803358fc14fd0eda, + 0x3678ca654eada770, + 0x7b91a1293a45e33e, + 0xcd5e5b8ea8530e43, + 0x21ae563ab34da266, + 0xecb00dad60df8894, + 0x77fe53e652facfef, + 0x9b7d1ad0b00244ec, + 0xe695df5ca73f801, + 0x23cdb21feeab0149, + 0x14de113e7ea810d9, + 0x52600cd958dac7e7, + 0xc83392c14667e488, + 0x9f808444bc1717fc, + 0x56facb4bcf7c788f, + 0x8bcad53245fc3ca0, + 0xdef661e83f27d81c, + 0x37d4ebcac9ad87e5, + 0x6fe8b24f5cdb9324, + 0xee08a26c1197654c, + 0xc98b22f65f237e9a, + 0xf54873a908ed3401, + 0x6e1cb951d41f3f3, + 0x290b2250a54e8df6, + 0x7f36d51eb1db669e, + 0xb08c7ed81a6ee43e, + 0x95e1c90fb092f680, + 0x429e4afd0e8b820, + 0x2c14a83ee87d715c, + 0xf37267575cfc8af5, + 0xb99e9afeda3c2c30, + 0x8f0f69da75792d5a, + 0x35074a85a533c73, + 0x156ed119, + ]) + ); + assert_eq!( + Fq12Parameters::FROBENIUS_COEFF_FP12_C1[11], + nqr.pow(vec![ + 0x107db680942de533, + 0x6262b24d2052393b, + 0x6136df824159ebc, + 0xedb052c9970c5deb, + 0xca813aea916c3777, + 0xf49dacb9d76c1788, + 0x624941bd372933bb, + 0xa5e60c2520638331, + 0xb38b661683411074, + 0x1d2c9af4c43d962b, + 0x17d807a0f14aa830, + 0x6e6581a51012c108, + 0x668a537e5b35e6f5, + 0x6c396cf3782dca5d, + 0x33b679d1bff536ed, + 0x736cce41805d90aa, + 0x8a562f369eb680bf, + 0x9f61aa208a11ded8, + 0x43dd89dd94d20f35, + 0xcf84c6610575c10a, + 0x9f318d49cf2fe8e6, + 0xbbc6e5f25a6e434e, + 0x6528c433d11d987b, + 0xffced71cc48c0e8a, + 0x4cbb1474f4cb2a26, + 0x66a035c0b28b7231, + 0xa6f2875faa1a82ae, + 0xdd1ea3deff818b02, + 0xe0cfdf0dcdecf701, + 0x9aefa231f2f6d23, + 0xfb251297efa06746, + 0x5a40d367df985538, + 0x1ea31d69ab506fed, + 0xc64ea8280e89a73f, + 0x969acf9f2d4496f4, + 0xe84c9181ee60c52c, + 0xc60f27fc19fc6ca4, + 0x760b33d850154048, + 0x84f69080f66c8457, + 0xc0192ba0fabf640e, + 0xd2c338765c23a3a8, + 0xa7838c20f02cec6c, + 0xb7cf01d020572877, + 0xd63ffaeba0be200a, + 0xf7492baeb5f041ac, + 0x8602c5212170d117, + 0xad9b2e83a5a42068, + 0x2461829b3ba1083e, + 0x7c34650da5295273, + 0xdc824ba800a8265a, + 0xd18d9b47836af7b2, + 0x3af78945c58cbf4d, + 0x7ed9575b8596906c, + 0x6d0c133895009a66, + 0x53bc1247ea349fe1, + 0x6b3063078d41aa7a, + 0x6184acd8cd880b33, + 0x76f4d15503fd1b96, + 0x7a9afd61eef25746, + 0xce974aadece60609, + 0x88ca59546a8ceafd, + 0x6d29391c41a0ac07, + 0x443843a60e0f46a6, + 0xa1590f62fd2602c7, + 0x536d5b15b514373f, + 0x22d582b, + ]) + ); +} + +#[test] +fn test_neg_one() { + let o = -Fq::one(); + + let thing: [u64; 6] = [ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x7e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x40ab3263eff0206, + ]; + println!("{:?}", thing); + let negative_one = Fq::new(BigInteger384(thing)); + + assert_eq!(negative_one, o); +} + +#[test] +fn test_fq_repr_from() { + assert_eq!( + BigInteger384::from(100), + BigInteger384([100, 0, 0, 0, 0, 0]) + ); +} + +#[test] +fn test_fq_repr_is_odd() { + assert!(!BigInteger384::from(0).is_odd()); + assert!(BigInteger384::from(0).is_even()); + assert!(BigInteger384::from(1).is_odd()); + assert!(!BigInteger384::from(1).is_even()); + assert!(!BigInteger384::from(324834872).is_odd()); + assert!(BigInteger384::from(324834872).is_even()); + assert!(BigInteger384::from(324834873).is_odd()); + assert!(!BigInteger384::from(324834873).is_even()); +} + +#[test] +fn test_fq_repr_is_zero() { + assert!(BigInteger384::from(0).is_zero()); + assert!(!BigInteger384::from(1).is_zero()); + assert!(!BigInteger384([0, 0, 0, 0, 1, 0]).is_zero()); +} + +#[test] +fn test_fq_repr_div2() { + let mut a = BigInteger384([ + 0x8b0ad39f8dd7482a, + 0x147221c9a7178b69, + 0x54764cb08d8a6aa0, + 0x8519d708e1d83041, + 0x41f82777bd13fdb, + 0xf43944578f9b771b, + ]); + a.div2(); + assert_eq!( + a, + BigInteger384([ + 0xc58569cfc6eba415, + 0xa3910e4d38bc5b4, + 0xaa3b265846c53550, + 0xc28ceb8470ec1820, + 0x820fc13bbde89fed, + 0x7a1ca22bc7cdbb8d, + ]) + ); + for _ in 0..10 { + a.div2(); + } + assert_eq!( + a, + BigInteger384([ + 0x6d31615a73f1bae9, + 0x54028e443934e2f1, + 0x82a8ec99611b14d, + 0xfb70a33ae11c3b06, + 0xe36083f04eef7a27, + 0x1e87288af1f36e, + ]) + ); + for _ in 0..300 { + a.div2(); + } + assert_eq!( + a, + BigInteger384([0x7288af1f36ee3608, 0x1e8, 0x0, 0x0, 0x0, 0x0]) + ); + for _ in 0..50 { + a.div2(); + } + assert_eq!(a, BigInteger384([0x7a1ca2, 0x0, 0x0, 0x0, 0x0, 0x0])); + for _ in 0..22 { + a.div2(); + } + assert_eq!(a, BigInteger384([0x1, 0x0, 0x0, 0x0, 0x0, 0x0])); + a.div2(); + assert!(a.is_zero()); +} + +#[test] +fn test_fq_repr_divn() { + let mut a = BigInteger384([ + 0xaa5cdd6172847ffd, + 0x43242c06aed55287, + 0x9ddd5b312f3dd104, + 0xc5541fd48046b7e7, + 0x16080cf4071e0b05, + 0x1225f2901aea514e, + ]); + a.divn(0); + assert_eq!( + a, + BigInteger384([ + 0xaa5cdd6172847ffd, + 0x43242c06aed55287, + 0x9ddd5b312f3dd104, + 0xc5541fd48046b7e7, + 0x16080cf4071e0b05, + 0x1225f2901aea514e, + ]) + ); + a.divn(1); + assert_eq!( + a, + BigInteger384([ + 0xd52e6eb0b9423ffe, + 0x21921603576aa943, + 0xceeead98979ee882, + 0xe2aa0fea40235bf3, + 0xb04067a038f0582, + 0x912f9480d7528a7, + ]) + ); + a.divn(50); + assert_eq!( + a, + BigInteger384([ + 0x8580d5daaa50f54b, + 0xab6625e7ba208864, + 0x83fa9008d6fcf3bb, + 0x19e80e3c160b8aa, + 0xbe52035d4a29c2c1, + 0x244, + ]) + ); + a.divn(130); + assert_eq!( + a, + BigInteger384([ + 0xa0fea40235bf3cee, + 0x4067a038f0582e2a, + 0x2f9480d7528a70b0, + 0x91, + 0x0, + 0x0, + ]) + ); + a.divn(64); + assert_eq!( + a, + BigInteger384([0x4067a038f0582e2a, 0x2f9480d7528a70b0, 0x91, 0x0, 0x0, 0x0]) + ); +} + +#[test] +fn test_fq_repr_mul2() { + let mut a = BigInteger384::from(23712937547); + a.mul2(); + assert_eq!(a, BigInteger384([0xb0acd6c96, 0x0, 0x0, 0x0, 0x0, 0x0])); + for _ in 0..60 { + a.mul2(); + } + assert_eq!( + a, + BigInteger384([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0, 0x0, 0x0]) + ); + for _ in 0..300 { + a.mul2(); + } + assert_eq!( + a, + BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0xcd6c960000000000]) + ); + for _ in 0..17 { + a.mul2(); + } + assert_eq!( + a, + BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x2c00000000000000]) + ); + for _ in 0..6 { + a.mul2(); + } + assert!(a.is_zero()); +} + +#[test] +fn test_fq_repr_num_bits() { + let mut a = BigInteger384::from(0); + assert_eq!(0, a.num_bits()); + a = BigInteger384::from(1); + for i in 1..385 { + assert_eq!(i, a.num_bits()); + a.mul2(); + } + assert_eq!(0, a.num_bits()); +} + +#[test] +fn test_fq_repr_sub_noborrow() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut t = BigInteger384([ + 0x827a4a08041ebd9, + 0x3c239f3dcc8f0d6b, + 0x9ab46a912d555364, + 0x196936b17b43910b, + 0xad0eb3948a5c34fd, + 0xd56f7b5ab8b5ce8, + ]); + t.sub_noborrow(&BigInteger384([ + 0xc7867917187ca02b, + 0x5d75679d4911ffef, + 0x8c5b3e48b1a71c15, + 0x6a427ae846fd66aa, + 0x7a37e7265ee1eaf9, + 0x7c0577a26f59d5, + ])); + assert!( + t == BigInteger384([ + 0x40a12b8967c54bae, + 0xdeae37a0837d0d7b, + 0xe592c487bae374e, + 0xaf26bbc934462a61, + 0x32d6cc6e2b7a4a03, + 0xcdaf23e091c0313, + ]) + ); + + for _ in 0..1000 { + let mut a = BigInteger384::rand(&mut rng); + a.0[5] >>= 30; + let mut b = a; + for _ in 0..10 { + b.mul2(); + } + let mut c = b; + for _ in 0..10 { + c.mul2(); + } + + assert!(a < b); + assert!(b < c); + + let mut csub_ba = c; + csub_ba.sub_noborrow(&b); + csub_ba.sub_noborrow(&a); + + let mut csub_ab = c; + csub_ab.sub_noborrow(&a); + csub_ab.sub_noborrow(&b); + + assert_eq!(csub_ab, csub_ba); + } + + // Subtracting q+1 from q should produce -1 (mod 2**384) + let mut qplusone = BigInteger384([ + 0xb9feffffffffaaab, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + ]); + qplusone.sub_noborrow(&BigInteger384([ + 0xb9feffffffffaaac, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + ])); + assert_eq!( + qplusone, + BigInteger384([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + ]) + ); +} + +#[test] +fn test_fq_repr_add_nocarry() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut t = BigInteger384([ + 0x827a4a08041ebd9, + 0x3c239f3dcc8f0d6b, + 0x9ab46a912d555364, + 0x196936b17b43910b, + 0xad0eb3948a5c34fd, + 0xd56f7b5ab8b5ce8, + ]); + t.add_nocarry(&BigInteger384([ + 0xc7867917187ca02b, + 0x5d75679d4911ffef, + 0x8c5b3e48b1a71c15, + 0x6a427ae846fd66aa, + 0x7a37e7265ee1eaf9, + 0x7c0577a26f59d5, + ])); + assert!( + t == BigInteger384([ + 0xcfae1db798be8c04, + 0x999906db15a10d5a, + 0x270fa8d9defc6f79, + 0x83abb199c240f7b6, + 0x27469abae93e1ff6, + 0xdd2fd2d4dfab6be, + ]) + ); + + // Test for the associativity of addition. + for _ in 0..1000 { + let mut a = BigInteger384::rand(&mut rng); + let mut b = BigInteger384::rand(&mut rng); + let mut c = BigInteger384::rand(&mut rng); + + // Unset the first few bits, so that overflow won't occur. + a.0[5] >>= 3; + b.0[5] >>= 3; + c.0[5] >>= 3; + + let mut abc = a; + abc.add_nocarry(&b); + abc.add_nocarry(&c); + + let mut acb = a; + acb.add_nocarry(&c); + acb.add_nocarry(&b); + + let mut bac = b; + bac.add_nocarry(&a); + bac.add_nocarry(&c); + + let mut bca = b; + bca.add_nocarry(&c); + bca.add_nocarry(&a); + + let mut cab = c; + cab.add_nocarry(&a); + cab.add_nocarry(&b); + + let mut cba = c; + cba.add_nocarry(&b); + cba.add_nocarry(&a); + + assert_eq!(abc, acb); + assert_eq!(abc, bac); + assert_eq!(abc, bca); + assert_eq!(abc, cab); + assert_eq!(abc, cba); + } + + // Adding 1 to (2^384 - 1) should produce zero + let mut x = BigInteger384([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + ]); + x.add_nocarry(&BigInteger384::from(1)); + assert!(x.is_zero()); +} + +#[test] +fn test_fq_add_assign() { + { + // Random number + let mut tmp = Fq::new(BigInteger384([ + 0x624434821df92b69, + 0x503260c04fd2e2ea, + 0xd9df726e0d16e8ce, + 0xfbcb39adfd5dfaeb, + 0x86b8a22b0c88b112, + 0x165a2ed809e4201b, + ])); + // Test that adding zero has no effect. + tmp.add_assign(&Fq::new(BigInteger384::from(0))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0x624434821df92b69, + 0x503260c04fd2e2ea, + 0xd9df726e0d16e8ce, + 0xfbcb39adfd5dfaeb, + 0x86b8a22b0c88b112, + 0x165a2ed809e4201b, + ])) + ); + // Add one and test for the result. + tmp.add_assign(&Fq::new(BigInteger384::from(1))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0x624434821df92b6a, + 0x503260c04fd2e2ea, + 0xd9df726e0d16e8ce, + 0xfbcb39adfd5dfaeb, + 0x86b8a22b0c88b112, + 0x165a2ed809e4201b, + ])) + ); + // Add another random number that exercises the reduction. + tmp.add_assign(&Fq::new(BigInteger384([ + 0x374d8f8ea7a648d8, + 0xe318bb0ebb8bfa9b, + 0x613d996f0a95b400, + 0x9fac233cb7e4fef1, + 0x67e47552d253c52, + 0x5c31b227edf25da, + ]))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0xdf92c410c59fc997, + 0x149f1bd05a0add85, + 0xd3ec393c20fba6ab, + 0x37001165c1bde71d, + 0x421b41c9f662408e, + 0x21c38104f435f5b, + ])) + ); + // Add one to (q - 1) and test for the result. + tmp = Fq::new(BigInteger384([ + 0xb9feffffffffaaaa, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + ])); + tmp.add_assign(&Fq::new(BigInteger384::from(1))); + assert!(tmp.0.is_zero()); + // Add a random number to another one such that the result is q - 1 + tmp = Fq::new(BigInteger384([ + 0x531221a410efc95b, + 0x72819306027e9717, + 0x5ecefb937068b746, + 0x97de59cd6feaefd7, + 0xdc35c51158644588, + 0xb2d176c04f2100, + ])); + tmp.add_assign(&Fq::new(BigInteger384([ + 0x66ecde5bef0fe14f, + 0xac2a6cf8aed568e8, + 0x861d70d86483edd, + 0xcc98f1b7839a22e8, + 0x6ee5e2a4eae7674e, + 0x194e40737930c599, + ]))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0xb9feffffffffaaaa, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + ])) + ); + // Add one to the result and test for it. + tmp.add_assign(&Fq::new(BigInteger384::from(1))); + assert!(tmp.0.is_zero()); + } + + // Test associativity + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Generate a, b, c and ensure (a + b) + c == a + (b + c). + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + + let mut tmp2 = b; + tmp2.add_assign(&c); + tmp2.add_assign(&a); + + assert_eq!(tmp1, tmp2); + } +} + +#[test] +fn test_fq_sub_assign() { + { + // Test arbitrary subtraction that tests reduction. + let mut tmp = Fq::new(BigInteger384([ + 0x531221a410efc95b, + 0x72819306027e9717, + 0x5ecefb937068b746, + 0x97de59cd6feaefd7, + 0xdc35c51158644588, + 0xb2d176c04f2100, + ])); + tmp.sub_assign(&Fq::new(BigInteger384([ + 0x98910d20877e4ada, + 0x940c983013f4b8ba, + 0xf677dc9b8345ba33, + 0xbef2ce6b7f577eba, + 0xe1ae288ac3222c44, + 0x5968bb602790806, + ]))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0x748014838971292c, + 0xfd20fad49fddde5c, + 0xcf87f198e3d3f336, + 0x3d62d6e6e41883db, + 0x45a3443cd88dc61b, + 0x151d57aaf755ff94, + ])) + ); + + // Test the opposite subtraction which doesn't test reduction. + tmp = Fq::new(BigInteger384([ + 0x98910d20877e4ada, + 0x940c983013f4b8ba, + 0xf677dc9b8345ba33, + 0xbef2ce6b7f577eba, + 0xe1ae288ac3222c44, + 0x5968bb602790806, + ])); + tmp.sub_assign(&Fq::new(BigInteger384([ + 0x531221a410efc95b, + 0x72819306027e9717, + 0x5ecefb937068b746, + 0x97de59cd6feaefd7, + 0xdc35c51158644588, + 0xb2d176c04f2100, + ]))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0x457eeb7c768e817f, + 0x218b052a117621a3, + 0x97a8e10812dd02ed, + 0x2714749e0f6c8ee3, + 0x57863796abde6bc, + 0x4e3ba3f4229e706, + ])) + ); + + // Test for sensible results with zero + tmp = Fq::new(BigInteger384::from(0)); + tmp.sub_assign(&Fq::new(BigInteger384::from(0))); + assert!(tmp.is_zero()); + + tmp = Fq::new(BigInteger384([ + 0x98910d20877e4ada, + 0x940c983013f4b8ba, + 0xf677dc9b8345ba33, + 0xbef2ce6b7f577eba, + 0xe1ae288ac3222c44, + 0x5968bb602790806, + ])); + tmp.sub_assign(&Fq::new(BigInteger384::from(0))); + assert_eq!( + tmp, + Fq::new(BigInteger384([ + 0x98910d20877e4ada, + 0x940c983013f4b8ba, + 0xf677dc9b8345ba33, + 0xbef2ce6b7f577eba, + 0xe1ae288ac3222c44, + 0x5968bb602790806, + ])) + ); + } + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure that (a - b) + (b - a) = 0. + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.sub_assign(&b); + + let mut tmp2 = b; + tmp2.sub_assign(&a); + + tmp1.add_assign(&tmp2); + assert!(tmp1.is_zero()); + } +} + +#[test] +fn test_fq_mul_assign() { + let mut tmp = Fq::new(BigInteger384([ + 0xcc6200000020aa8a, + 0x422800801dd8001a, + 0x7f4f5e619041c62c, + 0x8a55171ac70ed2ba, + 0x3f69cc3a3d07d58b, + 0xb972455fd09b8ef, + ])); + tmp.mul_assign(&Fq::new(BigInteger384([ + 0x329300000030ffcf, + 0x633c00c02cc40028, + 0xbef70d925862a942, + 0x4f7fa2a82a963c17, + 0xdf1eb2575b8bc051, + 0x1162b680fb8e9566, + ]))); + assert!( + tmp == Fq::new(BigInteger384([ + 0x9dc4000001ebfe14, + 0x2850078997b00193, + 0xa8197f1abb4d7bf, + 0xc0309573f4bfe871, + 0xf48d0923ffaf7620, + 0x11d4b58c7a926e66, + ])) + ); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * b) * c = a * (b * c) + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.mul_assign(&b); + tmp1.mul_assign(&c); + + let mut tmp2 = b; + tmp2.mul_assign(&c); + tmp2.mul_assign(&a); + + assert_eq!(tmp1, tmp2); + } + + for _ in 0..1000000 { + // Ensure that r * (a + b + c) = r*a + r*b + r*c + + let r = Fq::rand(&mut rng); + let mut a = Fq::rand(&mut rng); + let mut b = Fq::rand(&mut rng); + let mut c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + tmp1.mul_assign(&r); + + a.mul_assign(&r); + b.mul_assign(&r); + c.mul_assign(&r); + + a.add_assign(&b); + a.add_assign(&c); + + assert_eq!(tmp1, a); + } +} + +#[test] +fn test_fq_squaring() { + let mut a = Fq::new(BigInteger384([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x19ffffffffffffff, + ])); + a.square_in_place(); + assert_eq!( + a, + Fq::from(BigInteger384([ + 0x1cfb28fe7dfbbb86, + 0x24cbe1731577a59, + 0xcce1d4edc120e66e, + 0xdc05c659b4e15b27, + 0x79361e5a802c6a23, + 0x24bcbe5d51b9a6f, + ])) + ); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * a) = a^2 + let a = Fq::rand(&mut rng); + + let mut tmp = a; + tmp.square_in_place(); + + let mut tmp2 = a; + tmp2.mul_assign(&a); + + assert_eq!(tmp, tmp2); + } +} + +#[test] +fn test_fq_inverse() { + assert!(Fq::zero().inverse().is_none()); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let one = Fq::one(); + + for _ in 0..1000 { + // Ensure that a * a^-1 = 1 + let mut a = Fq::rand(&mut rng); + let ainv = a.inverse().unwrap(); + a.mul_assign(&ainv); + assert_eq!(a, one); + } +} + +#[test] +fn test_fq_double_in_place() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure doubling a is equivalent to adding a to itself. + let mut a = Fq::rand(&mut rng); + let mut b = a; + b.add_assign(&a); + a.double_in_place(); + assert_eq!(a, b); + } +} + +#[test] +fn test_fq_negate() { + { + let a = -Fq::zero(); + + assert!(a.is_zero()); + } + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure (a - (-a)) = 0. + let mut a = Fq::rand(&mut rng); + let b = -a; + a.add_assign(&b); + + assert!(a.is_zero()); + } +} + +#[test] +fn test_fq_pow() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for i in 0..1000 { + // Exponentiate by various small numbers and ensure it consists with repeated + // multiplication. + let a = Fq::rand(&mut rng); + let target = a.pow(&[i]); + let mut c = Fq::one(); + for _ in 0..i { + c.mul_assign(&a); + } + assert_eq!(c, target); + } + + for _ in 0..1000 { + // Exponentiating by the modulus should have no effect in a prime field. + let a = Fq::rand(&mut rng); + + assert_eq!(a, a.pow(Fq::characteristic())); + } +} + +#[test] +fn test_fq_sqrt() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); + + for _ in 0..1000 { + // Ensure sqrt(a^2) = a or -a + let a = Fq::rand(&mut rng); + let nega = -a; + let mut b = a; + b.square_in_place(); + + let b = b.sqrt().unwrap(); + + assert!(a == b || nega == b); + } + + for _ in 0..1000 { + // Ensure sqrt(a)^2 = a for random a + let a = Fq::rand(&mut rng); + + if let Some(mut tmp) = a.sqrt() { + tmp.square_in_place(); + + assert_eq!(a, tmp); + } + } +} + +#[test] +fn test_fq_num_bits() { + assert_eq!(FqParameters::MODULUS_BITS, 381); + assert_eq!(FqParameters::CAPACITY, 380); +} + +#[test] +fn test_fq_root_of_unity() { + assert_eq!(FqParameters::TWO_ADICITY, 1); + assert_eq!( + Fq::multiplicative_generator(), + Fq::from(BigInteger384::from(2)) + ); + assert_eq!( + Fq::multiplicative_generator().pow([ + 0xdcff7fffffffd555, + 0xf55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0xd0088f51cbff34d, + ]), + Fq::two_adic_root_of_unity() + ); + assert_eq!( + Fq::two_adic_root_of_unity().pow([1 << FqParameters::TWO_ADICITY]), + Fq::one() + ); + assert!(Fq::multiplicative_generator().sqrt().is_none()); +} + +// #[test] +// fn fq_field_tests() { +// ::tests::field::random_field_tests::(); +// ::tests::field::random_sqrt_tests::(); +// ::tests::field::random_frobenius_tests::(Fq::char(), 13); +// ::tests::field::from_str_tests::(); +// } + +#[test] +fn test_fq_ordering() { + // BigInteger384's ordering is well-tested, but we still need to make sure the + // Fq elements aren't being compared in Montgomery form. + for i in 0..100 { + assert!(Fq::from(BigInteger384::from(i + 1)) > Fq::from(BigInteger384::from(i))); + } +} + +// #[test] +// fn fq_repr_tests() { +// ::tests::repr::random_repr_tests::(); +// } + +#[test] +fn test_fq_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(QuadraticResidue, Fq::one().legendre()); + assert_eq!(Zero, Fq::zero().legendre()); + + assert_eq!( + QuadraticNonResidue, + Fq::from(BigInteger384::from(2)).legendre() + ); + assert_eq!( + QuadraticResidue, + Fq::from(BigInteger384::from(4)).legendre() + ); + + let e = BigInteger384([ + 0x52a112f249778642, + 0xd0bedb989b7991f, + 0xdad3b6681aa63c05, + 0xf2efc0bb4721b283, + 0x6057a98f18c24733, + 0x1022c2fd122889e4, + ]); + assert_eq!(QuadraticNonResidue, Fq::from(e).legendre()); + let e = BigInteger384([ + 0x6dae594e53a96c74, + 0x19b16ca9ba64b37b, + 0x5c764661a59bfc68, + 0xaa346e9b31c60a, + 0x346059f9d87a9fa9, + 0x1d61ac6bfd5c88b, + ]); + assert_eq!(QuadraticResidue, Fq::from(e).legendre()); +} + +#[test] +fn test_fq2_ordering() { + let mut a = Fq2::new(Fq::zero(), Fq::zero()); + + let mut b = a.clone(); + + assert!(a.cmp(&b) == Ordering::Equal); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); + b.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Greater); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); +} + +#[test] +fn test_fq2_basics() { + assert_eq!(Fq2::new(Fq::zero(), Fq::zero(),), Fq2::zero()); + assert_eq!(Fq2::new(Fq::one(), Fq::zero(),), Fq2::one()); + assert!(Fq2::zero().is_zero()); + assert!(!Fq2::one().is_zero()); + assert!(!Fq2::new(Fq::zero(), Fq::one(),).is_zero()); +} + +#[test] +fn test_fq2_squaring() { + let a = Fq2::new(Fq::one(), Fq::one()).square(); // u + 1 + assert_eq!(a, Fq2::new(Fq::zero(), Fq::from(BigInteger384::from(2)),)); // 2u + + let a = Fq2::new(Fq::zero(), Fq::one()).square(); // u + assert_eq!(a, { + let neg1 = -Fq::one(); + Fq2::new(neg1, Fq::zero()) + }); // -1 + + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x9c2c6309bbf8b598, + 0x4eef5c946536f602, + 0x90e34aab6fb6a6bd, + 0xf7f295a94e58ae7c, + 0x41b76dcc1c3fbe5e, + 0x7080c5fa1d8e042, + ])), + Fq::from(BigInteger384([ + 0x38f473b3c870a4ab, + 0x6ad3291177c8c7e5, + 0xdac5a4c911a4353e, + 0xbfb99020604137a0, + 0xfc58a7b7be815407, + 0x10d1615e75250a21, + ])), + ); + a.square_in_place(); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0xf262c28c538bcf68, + 0xb9f2a66eae1073ba, + 0xdc46ab8fad67ae0, + 0xcb674157618da176, + 0x4cf17b5893c3d327, + 0x7eac81369c43361, + ])), + Fq::from(BigInteger384([ + 0xc1579cf58e980cf8, + 0xa23eb7e12dd54d98, + 0xe75138bce4cec7aa, + 0x38d0d7275a9689e1, + 0x739c983042779a65, + 0x1542a61c8a8db994, + ])), + ) + ); +} + +#[test] +fn test_fq2_mul() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x85c9f989e1461f03, + 0xa2e33c333449a1d6, + 0x41e461154a7354a3, + 0x9ee53e7e84d7532e, + 0x1c202d8ed97afb45, + 0x51d3f9253e2516f, + ])), + Fq::from(BigInteger384([ + 0xa7348a8b511aedcf, + 0x143c215d8176b319, + 0x4cc48081c09b8903, + 0x9533e4a9a5158be, + 0x7a5e1ecb676d65f9, + 0x180c3ee46656b008, + ])), + ); + a.mul_assign(&Fq2::new( + Fq::from(BigInteger384([ + 0xe21f9169805f537e, + 0xfc87e62e179c285d, + 0x27ece175be07a531, + 0xcd460f9f0c23e430, + 0x6c9110292bfa409, + 0x2c93a72eb8af83e, + ])), + Fq::from(BigInteger384([ + 0x4b1c3f936d8992d4, + 0x1d2a72916dba4c8a, + 0x8871c508658d1e5f, + 0x57a06d3135a752ae, + 0x634cd3c6c565096d, + 0x19e17334d4e93558, + ])), + )); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x95b5127e6360c7e4, + 0xde29c31a19a6937e, + 0xf61a96dacf5a39bc, + 0x5511fe4d84ee5f78, + 0x5310a202d92f9963, + 0x1751afbe166e5399, + ])), + Fq::from(BigInteger384([ + 0x84af0e1bd630117a, + 0x6c63cd4da2c2aa7, + 0x5ba6e5430e883d40, + 0xc975106579c275ee, + 0x33a9ac82ce4c5083, + 0x1ef1a36c201589d, + ])), + ) + ); +} + +#[test] +fn test_fq2_inverse() { + assert!(Fq2::zero().inverse().is_none()); + + let a = Fq2::new( + Fq::from(BigInteger384([ + 0x85c9f989e1461f03, + 0xa2e33c333449a1d6, + 0x41e461154a7354a3, + 0x9ee53e7e84d7532e, + 0x1c202d8ed97afb45, + 0x51d3f9253e2516f, + ])), + Fq::from(BigInteger384([ + 0xa7348a8b511aedcf, + 0x143c215d8176b319, + 0x4cc48081c09b8903, + 0x9533e4a9a5158be, + 0x7a5e1ecb676d65f9, + 0x180c3ee46656b008, + ])), + ); + let a = a.inverse().unwrap(); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x70300f9bcb9e594, + 0xe5ecda5fdafddbb2, + 0x64bef617d2915a8f, + 0xdfba703293941c30, + 0xa6c3d8f9586f2636, + 0x1351ef01941b70c4, + ])), + Fq::from(BigInteger384([ + 0x8c39fd76a8312cb4, + 0x15d7b6b95defbff0, + 0x947143f89faedee9, + 0xcbf651a0f367afb2, + 0xdf4e54f0d3ef15a6, + 0x103bdf241afb0019, + ])), + ) + ); +} + +#[test] +fn test_fq2_addition() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ); + a.add_assign(&Fq2::new( + Fq::from(BigInteger384([ + 0x619a02d78dc70ef2, + 0xb93adfc9119e33e8, + 0x4bf0b99a9f0dca12, + 0x3b88899a42a6318f, + 0x986a4a62fa82a49d, + 0x13ce433fa26027f5, + ])), + Fq::from(BigInteger384([ + 0x66323bf80b58b9b9, + 0xa1379b6facf6e596, + 0x402aef1fb797e32f, + 0x2236f55246d0d44d, + 0x4c8c1800eb104566, + 0x11d6e20e986c2085, + ])), + )); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x8e9a7adaf6eb0eb9, + 0xcb207e6b3341eaba, + 0xd70b0c7b481d23ff, + 0xf4ef57d604b6bca2, + 0x65309427b3d5d090, + 0x14c715d5553f01d2, + ])), + Fq::from(BigInteger384([ + 0xfdb032e7d9079a94, + 0x35a2809d15468d83, + 0xfe4b23317e0796d5, + 0xd62fa51334f560fa, + 0x9ad265eb46e01984, + 0x1303f3465112c8bc, + ])), + ) + ); +} + +#[test] +fn test_fq2_subtraction() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ); + a.sub_assign(&Fq2::new( + Fq::from(BigInteger384([ + 0x619a02d78dc70ef2, + 0xb93adfc9119e33e8, + 0x4bf0b99a9f0dca12, + 0x3b88899a42a6318f, + 0x986a4a62fa82a49d, + 0x13ce433fa26027f5, + ])), + Fq::from(BigInteger384([ + 0x66323bf80b58b9b9, + 0xa1379b6facf6e596, + 0x402aef1fb797e32f, + 0x2236f55246d0d44d, + 0x4c8c1800eb104566, + 0x11d6e20e986c2085, + ])), + )); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x8565752bdb5c9b80, + 0x7756bed7c15982e9, + 0xa65a6be700b285fe, + 0xe255902672ef6c43, + 0x7f77a718021c342d, + 0x72ba14049fe9881, + ])), + Fq::from(BigInteger384([ + 0xeb4abaf7c255d1cd, + 0x11df49bc6cacc256, + 0xe52617930588c69a, + 0xf63905f39ad8cb1f, + 0x4cd5dd9fb40b3b8f, + 0x957411359ba6e4c, + ])), + ) + ); +} + +#[test] +fn test_fq2_negation() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ); + a = -a; + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x8cfe87fc96dbaae4, + 0xcc6615c8fb0492d, + 0xdc167fc04da19c37, + 0xab107d49317487ab, + 0x7e555df189f880e3, + 0x19083f5486a10cbd, + ])), + Fq::from(BigInteger384([ + 0x228109103250c9d0, + 0x8a411ad149045812, + 0xa9109e8f3041427e, + 0xb07e9bc405608611, + 0xfcd559cbe77bd8b8, + 0x18d400b280d93e62, + ])), + ) + ); +} + +#[test] +fn test_fq2_doubling() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ); + a.double_in_place(); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x5a00f006d247ff8e, + 0x23cb3d4443476da4, + 0x1634a5c1521eb3da, + 0x72cd9c7784211627, + 0x998c938972a657e7, + 0x1f1a52b65bdb3b9, + ])), + Fq::from(BigInteger384([ + 0x2efbeddf9b5dc1b6, + 0x28d5ca5ad09f4fdb, + 0x7c4068238cdf674b, + 0x67f15f81dc49195b, + 0x9c8c9bd4b79fa83d, + 0x25a226f714d506e, + ])), + ) + ); +} + +#[test] +fn test_fq2_frobenius_map() { + let mut a = Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ); + a.frobenius_map(0); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ) + ); + a.frobenius_map(1); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x228109103250c9d0, + 0x8a411ad149045812, + 0xa9109e8f3041427e, + 0xb07e9bc405608611, + 0xfcd559cbe77bd8b8, + 0x18d400b280d93e62, + ])), + ) + ); + a.frobenius_map(1); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ) + ); + a.frobenius_map(2); + assert_eq!( + a, + Fq2::new( + Fq::from(BigInteger384([ + 0x2d0078036923ffc7, + 0x11e59ea221a3b6d2, + 0x8b1a52e0a90f59ed, + 0xb966ce3bc2108b13, + 0xccc649c4b9532bf3, + 0xf8d295b2ded9dc, + ])), + Fq::from(BigInteger384([ + 0x977df6efcdaee0db, + 0x946ae52d684fa7ed, + 0xbe203411c66fb3a5, + 0xb3f8afc0ee248cad, + 0x4e464dea5bcfd41e, + 0x12d1137b8a6a837, + ])), + ) + ); +} + +#[test] +fn test_fq2_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(Zero, Fq2::zero().legendre()); + // i^2 = -1 + let mut m1 = -Fq2::one(); + assert_eq!(QuadraticResidue, m1.legendre()); + m1 = Fq6Parameters::mul_fp2_by_nonresidue(&m1); + assert_eq!(QuadraticNonResidue, m1.legendre()); +} + +#[test] +fn test_fq2_mul_nonresidue() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let nqr = Fq2::new(Fq::one(), Fq::one()); + + for _ in 0..1000 { + let mut a = Fq2::rand(&mut rng); + let mut b = a; + a = Fq6Parameters::mul_fp2_by_nonresidue(&a); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_nonresidue() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let nqr = Fq6::new(Fq2::zero(), Fq2::one(), Fq2::zero()); + + for _ in 0..1000 { + let mut a = Fq6::rand(&mut rng); + let mut b = a; + a = Fq12Parameters::mul_fp6_by_nonresidue(&a); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_1() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_1(&c1); + b.mul_assign(&Fq6::new(Fq2::zero(), c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_01() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_01(&c0, &c1); + b.mul_assign(&Fq6::new(c0, c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_014() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let c5 = Fq2::rand(&mut rng); + let mut a = Fq12::rand(&mut rng); + let mut b = a; + + a.mul_by_014(&c0, &c1, &c5); + b.mul_assign(&Fq12::new( + Fq6::new(c0, c1, Fq2::zero()), + Fq6::new(Fq2::zero(), c5, Fq2::zero()), + )); + + assert_eq!(a, b); + } +} diff --git a/bls12_381/src/lib.rs b/bls12_381/src/lib.rs new file mode 100644 index 0000000..a9142c2 --- /dev/null +++ b/bls12_381/src/lib.rs @@ -0,0 +1,32 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the BLS12_381 curve generated by [Sean Bowe](https://electriccoin.co/blog/new-snark-curve/). +//! The name denotes that it is a Barreto--Lynn--Scott curve of embedding degree 12, +//! defined over a 381-bit (prime) field. +//! This curve was intended to replace the BN254 curve to provide a higher security +//! level without incurring a large performance overhead. +//! +//! +//! Curve information: +//! * Base field: q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 +//! * Scalar field: r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +//! * valuation(q - 1, 2) = 1 +//! * valuation(r - 1, 2) = 32 +//! * G1 curve equation: y^2 = x^3 + 4 +//! * G2 curve equation: y^2 = x^3 + Fq2(4, 4) + +#[cfg(feature = "curve")] +mod curves; +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; +pub use fields::*; diff --git a/bn254/Cargo.toml b/bn254/Cargo.toml new file mode 100644 index 0000000..896e5e9 --- /dev/null +++ b/bn254/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "ark-bn254" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The BN254 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-bn254/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field" ] +scalar_field = [] diff --git a/bn254/LICENSE-APACHE b/bn254/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/bn254/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/bn254/LICENSE-MIT b/bn254/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/bn254/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/bn254/src/curves/g1.rs b/bn254/src/curves/g1.rs new file mode 100644 index 0000000..8a5eb84 --- /dev/null +++ b/bn254/src/curves/g1.rs @@ -0,0 +1,67 @@ +use ark_ec::models::{ModelParameters, SWModelParameters}; +use ark_ff::{biginteger::BigInteger256, field_new, Zero}; + +use crate::{Fq, Fr}; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 0 + const COEFF_A: Fq = field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])); + + /// COEFF_B = 3 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger256([ + 0x7a17caa950ad28d7, + 0x1f6ac17ae15521b9, + 0x334bea4e696bd284, + 0x2a1f6744ce179d8e, + ])); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[0x1]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r = 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 0xac96341c4ffffffb, + 0x36fc76959f60cd29, + 0x666ea36f7879462e, + 0xe0a77c19a07df2f, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +/// G1_GENERATOR_X = +/// 1 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger256([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, +])); + +/// G1_GENERATOR_Y = +/// 2 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger256([ + 0xa6ba871b8b1e1b3a, + 0x14f1d651eb8e167b, + 0xccdd46def0f28c58, + 0x1c14ef83340fbe5e, +])); diff --git a/bn254/src/curves/g2.rs b/bn254/src/curves/g2.rs new file mode 100644 index 0000000..21ec78e --- /dev/null +++ b/bn254/src/curves/g2.rs @@ -0,0 +1,112 @@ +use ark_ec::models::{ModelParameters, SWModelParameters}; +use ark_ff::{biginteger::BigInteger256, field_new, Zero}; + +use crate::{g1, Fq, Fq2, Fr}; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq2; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = [0, 0] + #[rustfmt::skip] + const COEFF_A: Fq2 = field_new!(Fq2, + g1::Parameters::COEFF_A, + g1::Parameters::COEFF_A, + ); + + /// COEFF_B = 3/(u+9) + /// = (19485874751759354771024239261021720505790618469301721065564631296452457478373, 266929791119991161246907387137283842545076965332900288569378510910307636690) + #[rustfmt::skip] + const COEFF_B: Fq2 = field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x3bf938e377b802a8, + 0x020b1b273633535d, + 0x26b7edf049755260, + 0x2514c6324384a86d, + ])), + field_new!(Fq, BigInteger256([ + 0x38e7ecccd1dcff67, + 0x65f0b37d93ce0d3e, + 0xd749d0dd22ac00aa, + 0x0141b9ce4a688d4d, + ])), + ); + + /// COFACTOR = (36 * X^4) + (36 * X^3) + (30 * X^2) + 6*X + 1 + /// = 21888242871839275222246405745257275088844257914179612981679871602714643921549 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x345f2299c0f9fa8d, + 0x06ceecda572a2489, + 0xb85045b68181585e, + 0x30644e72e131a029, + ]; + + /// COFACTOR_INV = COFACTOR^{-1} mod r + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 0x7fff17d53ff2895e, + 0xd0617390cf7919e5, + 0xb9af426b22d0eb61, + 0x270485e31bd72a4d, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(_: &Self::BaseField) -> Self::BaseField { + Self::BaseField::zero() + } +} + +#[rustfmt::skip] +pub const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); +#[rustfmt::skip] +pub const G2_GENERATOR_Y: Fq2 = field_new!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1); + +/// G2_GENERATOR_X_C0 = +/// 10857046999023057135944570762232829481370756359578518086990519993285655852781 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger256([ + 0x8e83b5d102bc2026, + 0xdceb1935497b0172, + 0xfbb8264797811adf, + 0x19573841af96503b, +])); + +/// G2_GENERATOR_X_C1 = +/// 11559732032986387107991004021392285783925812861821192530917403151452391805634 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger256([ + 0xafb4737da84c6140, + 0x6043dd5a5802d8c4, + 0x09e950fc52a02f86, + 0x14fef0833aea7b6b, +])); + +/// G2_GENERATOR_Y_C0 = +/// 8495653923123431417604973247489272438418190587263600148770280649306958101930 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger256([ + 0x619dfa9d886be9f6, + 0xfe7fd297f59e9b78, + 0xff9e1a62231b7dfe, + 0x28fd7eebae9e4206, +])); + +/// G2_GENERATOR_Y_C1 = +/// 4082367875863433681332203403145435568316851327593401208105741076214120093531 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger256([ + 0x64095b56c71856ee, + 0xdc57f922327d3cbb, + 0x55f935be33351076, + 0x0da4a0e693fd6482, +])); diff --git a/bn254/src/curves/mod.rs b/bn254/src/curves/mod.rs new file mode 100644 index 0000000..43a3f3a --- /dev/null +++ b/bn254/src/curves/mod.rs @@ -0,0 +1,82 @@ +use crate::*; +use ark_ec::{ + bn, + bn::{Bn, BnParameters, TwistType}, +}; +use ark_ff::{biginteger::BigInteger256, field_new}; +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub struct Parameters; + +impl BnParameters for Parameters { + const X: &'static [u64] = &[4965661367192848881]; + /// `x` is positive. + const X_IS_NEGATIVE: bool = false; + const ATE_LOOP_COUNT: &'static [i8] = &[ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, + -1, 0, 0, 1, 0, 1, 1, + ]; + /// `ate_loop_count` is positive. + const ATE_LOOP_COUNT_IS_NEGATIVE: bool = false; + const TWIST_MUL_BY_Q_X: Fq2 = field_new!( + Fq2, + field_new!( + Fq, + BigInteger256([ + 0xb5773b104563ab30, + 0x347f91c8a9aa6454, + 0x7a007127242e0991, + 0x1956bcd8118214ec, + ]) + ), + field_new!( + Fq, + BigInteger256([ + 0x6e849f1ea0aa4757, + 0xaa1c7b6d89f89141, + 0xb6e713cdfae0ca3a, + 0x26694fbb4e82ebc3, + ]) + ), + ); + const TWIST_MUL_BY_Q_Y: Fq2 = field_new!( + Fq2, + field_new!( + Fq, + BigInteger256([ + 0xe4bbdd0c2936b629, + 0xbb30f162e133bacb, + 0x31a9d1b6f9645366, + 0x253570bea500f8dd, + ]) + ), + field_new!( + Fq, + BigInteger256([ + 0xa1d77ce45ffe77c7, + 0x07affd117826d1db, + 0x6d16bd27bb7edc6b, + 0x2c87200285defecc, + ]) + ), + ); + const TWIST_TYPE: TwistType = TwistType::D; + type Fp = Fq; + type Fp2Params = Fq2Parameters; + type Fp6Params = Fq6Parameters; + type Fp12Params = Fq12Parameters; + type G1Parameters = g1::Parameters; + type G2Parameters = g2::Parameters; +} + +pub type Bn254 = Bn; + +pub type G1Affine = bn::G1Affine; +pub type G1Projective = bn::G1Projective; +pub type G2Affine = bn::G2Affine; +pub type G2Projective = bn::G2Projective; diff --git a/bn254/src/curves/tests.rs b/bn254/src/curves/tests.rs new file mode 100644 index 0000000..753feca --- /dev/null +++ b/bn254/src/curves/tests.rs @@ -0,0 +1,85 @@ +#![allow(unused_imports)] +use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{ + fields::{Field, FpParameters, PrimeField, SquareRootField}, + test_rng, One, Zero, +}; +use ark_serialize::CanonicalSerialize; +use core::ops::{AddAssign, MulAssign}; +use rand::Rng; + +use crate::{g1, g2, Bn254, Fq, Fq12, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let mut sa = a; + sa.mul_assign(s); + let mut sb = b; + sb.mul_assign(s); + + let ans1 = Bn254::pairing(sa, b); + let ans2 = Bn254::pairing(a, sb); + let ans3 = Bn254::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq12::one()); + assert_ne!(ans2, Fq12::one()); + assert_ne!(ans3, Fq12::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq12::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq12::one()); +} diff --git a/bn254/src/fields/fq.rs b/bn254/src/fields/fq.rs new file mode 100644 index 0000000..92ae6e0 --- /dev/null +++ b/bn254/src/fields/fq.rs @@ -0,0 +1,96 @@ +use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, fields::*}; + +pub type Fq = Fp256; + +pub struct FqParameters; + +impl Fp256Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ]); +} +impl FpParameters for FqParameters { + /// MODULUS = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + + const MODULUS_BITS: u32 = 254; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 2; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0xe0a77c19a07df2f, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xf32cfc5b538afa89, + 0xb5e71911d44501fb, + 0x47ab1eff0a417ff6, + 0x6d89f71cab8351f, + ]); + + const INV: u64 = 9786893198990664585u64; + + // GENERATOR = 3 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0x7a17caa950ad28d7, + 0x1f6ac17ae15521b9, + 0x334bea4e696bd284, + 0x2a1f6744ce179d8e, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x9e10460b6c3e7ea3, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + // T = (MODULUS - 1) // 2^S = + // 10944121435919637611123202872628637544348155578648911831344518947322613104291 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x9e10460b6c3e7ea3, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]); + + // (T - 1) // 2 = + // 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x4f082305b61f3f51, + 0x65e05aa45a1c72a3, + 0x6e14116da0605617, + 0xc19139cb84c680a, + ]); +} + +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0])); diff --git a/bn254/src/fields/fq12.rs b/bn254/src/fields/fq12.rs new file mode 100644 index 0000000..aded28e --- /dev/null +++ b/bn254/src/fields/fq12.rs @@ -0,0 +1,159 @@ +use super::*; +use ark_ff::{biginteger::BigInteger256, field_new, fields::*}; + +pub type Fq12 = Fp12; + +#[derive(Clone, Copy)] +pub struct Fq12Parameters; + +impl Fp12Parameters for Fq12Parameters { + type Fp6Params = Fq6Parameters; + + const NONRESIDUE: Fq6 = field_new!(Fq6, FQ2_ZERO, FQ2_ONE, FQ2_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP12_C1: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^(((q^0) - 1) / 6) + FQ2_ONE, + // Fp2::NONRESIDUE^(((q^1) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xaf9ba69633144907, + 0xca6b1d7387afb78a, + 0x11bded5ef08a2087, + 0x02f34d751a1f3a7c, + ])), + field_new!(Fq, BigInteger256([ + 0xa222ae234c492d72, + 0xd00f02a4565de15b, + 0xdc2ff3a253dfc926, + 0x10a75716b3899551, + ])), + ), + // Fp2::NONRESIDUE^(((q^2) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xca8d800500fa1bf2, + 0xf0c5d61468b39769, + 0x0e201271ad0d4418, + 0x04290f65bad856e6, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^3) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x365316184e46d97d, + 0x0af7129ed4c96d9f, + 0x659da72fca1009b5, + 0x08116d8983a20d23, + ])), + field_new!(Fq, BigInteger256([ + 0xb1df4af7c39c1939, + 0x3d9f02878a73bf7f, + 0x9b2220928caf0ae0, + 0x26684515eff054a6, + ])), + ), + // Fp2::NONRESIDUE^(((q^4) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^5) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x86b76f821b329076, + 0x408bf52b4d19b614, + 0x53dfb9d0d985e92d, + 0x051e20146982d2a7, + ])), + field_new!(Fq, BigInteger256([ + 0x0fbc9cd47752ebc7, + 0x6d8fffe33415de24, + 0xbef22cf038cf41b9, + 0x15c0edff3c66bf54, + ])), + ), + // Fp2::NONRESIDUE^(((q^6) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^7) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x8c84e580a568b440, + 0xcd164d1de0c21302, + 0xa692585790f737d5, + 0x2d7100fdc71265ad, + ])), + field_new!(Fq, BigInteger256([ + 0x99fdddf38c33cfd5, + 0xc77267ed1213e931, + 0xdc2052142da18f36, + 0x1fbcf75c2da80ad7, + ])), + ), + // Fp2::NONRESIDUE^(((q^8) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^9) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x05cd75fe8a3623ca, + 0x8c8a57f293a85cee, + 0x52b29e86b7714ea8, + 0x2852e0e95d8f9306, + ])), + field_new!(Fq, BigInteger256([ + 0x8a41411f14e0e40e, + 0x59e26809ddfe0b0d, + 0x1d2e2523f4d24d7d, + 0x09fc095cf1414b83, + ])), + ), + // Fp2::NONRESIDUE^(((q^10) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x08cfc388c494f1ab, + 0x19b315148d1373d4, + 0x584e90fdcb6c0213, + 0x09e1685bdf2f8849, + ])), + FQ_ZERO, + ), + // Fp2::NONRESIDUE^(((q^11) - 1) / 6) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xb5691c94bd4a6cd1, + 0x56f575661b581478, + 0x64708be5a7fb6f30, + 0x2b462e5e77aecd82, + ])), + field_new!(Fq, BigInteger256([ + 0x2c63ef42612a1180, + 0x29f16aae345bec69, + 0xf95e18c648b216a4, + 0x1aa36073a4cae0d4, + ])), + ), + ]; +} diff --git a/bn254/src/fields/fq2.rs b/bn254/src/fields/fq2.rs new file mode 100644 index 0000000..fa7b2aa --- /dev/null +++ b/bn254/src/fields/fq2.rs @@ -0,0 +1,63 @@ +use super::*; +use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, fields::*}; + +pub type Fq2 = Fp2; + +pub struct Fq2Parameters; + +impl Fp2Parameters for Fq2Parameters { + type Fp = Fq; + + /// NONRESIDUE = -1 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ])); + + /// QUADRATIC_NONRESIDUE = U+2 + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE: (Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 12014063508332092218u64, + 1509222997478479483u64, + 14762033076929465432u64, + 2023505479389396574u64, + ])), + field_new!(Fq, BigInteger([ + 202099033278250856u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ])), + ); + + /// Coefficients for the Frobenius automorphism. + #[rustfmt::skip] + const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[ + // NONRESIDUE**(((q^0) - 1) / 2) + field_new!(Fq, BigInteger([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0xe0a77c19a07df2f, + ])), + // NONRESIDUE**(((q^1) - 1) / 2) + field_new!(Fq, BigInteger([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ])), + ]; + + #[inline(always)] + fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { + -(*fe) + } +} + +pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO); +pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO); diff --git a/bn254/src/fields/fq6.rs b/bn254/src/fields/fq6.rs new file mode 100644 index 0000000..d6e27e5 --- /dev/null +++ b/bn254/src/fields/fq6.rs @@ -0,0 +1,195 @@ +use super::*; +use ark_ff::{biginteger::BigInteger256, field_new, fields::*}; + +pub type Fq6 = Fp6; + +#[derive(Clone, Copy)] +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp2Params = Fq2Parameters; + + /// NONRESIDUE = U+9 + #[rustfmt::skip] + const NONRESIDUE: Fq2 = field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xf60647ce410d7ff7, + 0x2f3d6f4dd31bd011, + 0x2943337e3940c6d1, + 0x1d9598e8a7e39857, + ])), + field_new!(Fq, BigInteger256([ + 202099033278250856u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ])), + ); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^(((q^0) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0xe0a77c19a07df2f, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^1) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xb5773b104563ab30, + 0x347f91c8a9aa6454, + 0x7a007127242e0991, + 0x1956bcd8118214ec, + ])), + field_new!(Fq, BigInteger256([ + 0x6e849f1ea0aa4757, + 0xaa1c7b6d89f89141, + 0xb6e713cdfae0ca3a, + 0x26694fbb4e82ebc3, + ])), + ), + // Fp2::NONRESIDUE^(((q^2) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^3) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xc9af22f716ad6bad, + 0xb311782a4aa662b2, + 0x19eeaf64e248c7f4, + 0x20273e77e3439f82, + ])), + field_new!(Fq, BigInteger256([ + 0xacc02860f7ce93ac, + 0x3933d5817ba76b4c, + 0x69e6188b446c8467, + 0xa46036d4417cc55, + ])), + ), + // Fp2::NONRESIDUE^(((q^4) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^(((q^5) - 1) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xf91aba2654e8e3b1, + 0x4771cb2fdc92ce12, + 0xdcb16ae0fc8bdf35, + 0x274aa195cd9d8be4, + ])), + field_new!(Fq, BigInteger256([ + 0x5cfc50ae18811f8b, + 0x4bb28433cb43988c, + 0x4fd35f13c3b56219, + 0x301949bd2fc8883a, + ])), + ), + ]; + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[ + // Fp2::NONRESIDUE^((2*(q^0) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0xe0a77c19a07df2f, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^1) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x7361d77f843abe92, + 0xa5bb2bd3273411fb, + 0x9c941f314b3e2399, + 0x15df9cddbb9fd3ec, + ])), + field_new!(Fq, BigInteger256([ + 0x5dddfd154bd8c949, + 0x62cb29a5a4445b60, + 0x37bc870a0c7dd2b9, + 0x24830a9d3171f0fd, + ])), + ), + // Fp2::NONRESIDUE^((2*(q^2) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^3) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x448a93a57b6762df, + 0xbfd62df528fdeadf, + 0xd858f5d00e9bd47a, + 0x6b03d4d3476ec58, + ])), + field_new!(Fq, BigInteger256([ + 0x2b19daf4bcc936d1, + 0xa1a54e7a56f4299f, + 0xb533eee05adeaef1, + 0x170c812b84dda0b2, + ])), + ), + // Fp2::NONRESIDUE^((2*(q^4) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ])), + field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])), + ), + // Fp2::NONRESIDUE^((2*(q^5) - 2) / 3) + field_new!(Fq2, + field_new!(Fq, BigInteger256([ + 0x843420f1d8dadbd6, + 0x31f010c9183fcdb2, + 0x436330b527a76049, + 0x13d47447f11adfe4, + ])), + field_new!(Fq, BigInteger256([ + 0xef494023a857fa74, + 0x2a925d02d5ab101a, + 0x83b015829ba62f10, + 0x2539111d0c13aea3, + ])), + ), + ]; + + #[inline(always)] + fn mul_fp2_by_nonresidue(fe: &Fq2) -> Fq2 { + // (c0+u*c1)*(9+u) = (9*c0-c1)+u*(9*c1+c0) + let mut f = *fe; + f.double_in_place().double_in_place().double_in_place(); + let c0 = f.c0 + fe.c0 + Fq2Parameters::mul_fp_by_nonresidue(&fe.c1); + let c1 = f.c1 + fe.c1 + fe.c0; + field_new!(Fq2, c0, c1) + } +} diff --git a/bn254/src/fields/fr.rs b/bn254/src/fields/fr.rs new file mode 100644 index 0000000..6df8d1a --- /dev/null +++ b/bn254/src/fields/fr.rs @@ -0,0 +1,95 @@ +use ark_ff::{biginteger::BigInteger256 as BigInteger, fields::*}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 28; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 7164790868263648668u64, + 11685701338293206998u64, + 6216421865291908056u64, + 1756667274303109607u64, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 4891460686036598785u64, + 2896914383306846353u64, + 13281191951274694749u64, + 3486998266802970665u64, + ]); + + const MODULUS_BITS: u32 = 254; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 2; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 12436184717236109307u64, + 3962172157175319849u64, + 7381016538464732718u64, + 1011752739694698287u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 1997599621687373223u64, + 6052339484930628067u64, + 10108755138030829701u64, + 150537098327114917u64, + ]); + + const INV: u64 = 14042775128853446655u64; + + // GENERATOR = 5 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 1949230679015292902u64, + 16913946402569752895u64, + 5177146667339417225u64, + 1571765431670520771u64, + ]); + + /// (r - 1)/2 = + /// 10944121435919637611123202872628637544274182200208017171849102093287904247808 + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xa1f0fac9f8000000, + 0x9419f4243cdcb848, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where r - 1 = 2^s * t + + /// t = (r - 1) / 2^s = + /// 81540058820840996586704275553141814055101440848469862132140264610111 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x9b9709143e1f593f, + 0x181585d2833e8487, + 0x131a029b85045b68, + 0x30644e72e, + ]); + + /// (t - 1) / 2 = + /// 40770029410420498293352137776570907027550720424234931066070132305055 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xcdcb848a1f0fac9f, + 0x0c0ac2e9419f4243, + 0x098d014dc2822db4, + 0x183227397, + ]); +} diff --git a/bn254/src/fields/mod.rs b/bn254/src/fields/mod.rs new file mode 100644 index 0000000..030e938 --- /dev/null +++ b/bn254/src/fields/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(feature = "curve")] +pub mod fq; +#[cfg(feature = "curve")] +pub use self::fq::*; + +#[cfg(feature = "curve")] +pub mod fq2; +#[cfg(feature = "curve")] +pub use self::fq2::*; + +#[cfg(feature = "curve")] +pub mod fq6; +#[cfg(feature = "curve")] +pub use self::fq6::*; + +#[cfg(feature = "curve")] +pub mod fq12; +#[cfg(feature = "curve")] +pub use self::fq12::*; + +#[cfg(all(feature = "curve", test))] +mod tests; diff --git a/bn254/src/fields/tests.rs b/bn254/src/fields/tests.rs new file mode 100644 index 0000000..0c48a9f --- /dev/null +++ b/bn254/src/fields/tests.rs @@ -0,0 +1,504 @@ +use ark_ff::{ + biginteger::{BigInteger, BigInteger256}, + fields::{ + fp6_3over2::Fp6Parameters, FftField, FftParameters, Field, FpParameters, PrimeField, + SquareRootField, + }, + test_rng, One, UniformRand, Zero, +}; +use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize}; +use core::{ + cmp::Ordering, + ops::{AddAssign, MulAssign, SubAssign}, +}; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +use crate::{Fq, Fq12, Fq2, Fq6, Fq6Parameters, FqParameters, Fr}; +use ark_curve_tests::fields::*; + +pub(crate) const ITERATIONS: usize = 5; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(b); + let byte_size = a.serialized_size(); + field_serialization_test::(byte_size); + } +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(a); + let byte_size = a.serialized_size(); + let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits()); + assert_eq!(byte_size, buffer_size); + field_serialization_test::(byte_size); + } +} + +#[test] +fn test_fq2() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let a: Fq2 = rng.gen(); + let b: Fq2 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq2::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let g: Fq6 = rng.gen(); + let h: Fq6 = rng.gen(); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq6::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq12() { + let mut rng = test_rng(); + for _ in 0..ITERATIONS { + let g: Fq12 = rng.gen(); + let h: Fq12 = rng.gen(); + field_test(g, h); + } + frobenius_test::(Fq::characteristic(), 13); + let byte_size = Fq12::zero().serialized_size(); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq_repr_from() { + assert_eq!(BigInteger256::from(100), BigInteger256([100, 0, 0, 0])); +} + +#[test] +fn test_fq_repr_is_odd() { + assert!(!BigInteger256::from(0).is_odd()); + assert!(BigInteger256::from(0).is_even()); + assert!(BigInteger256::from(1).is_odd()); + assert!(!BigInteger256::from(1).is_even()); + assert!(!BigInteger256::from(324834872).is_odd()); + assert!(BigInteger256::from(324834872).is_even()); + assert!(BigInteger256::from(324834873).is_odd()); + assert!(!BigInteger256::from(324834873).is_even()); +} + +#[test] +fn test_fq_repr_is_zero() { + assert!(BigInteger256::from(0).is_zero()); + assert!(!BigInteger256::from(1).is_zero()); + assert!(!BigInteger256([0, 0, 1, 0]).is_zero()); +} + +#[test] +fn test_fq_repr_num_bits() { + let mut a = BigInteger256::from(0); + assert_eq!(0, a.num_bits()); + a = BigInteger256::from(1); + for i in 1..257 { + assert_eq!(i, a.num_bits()); + a.mul2(); + } + assert_eq!(0, a.num_bits()); +} + +#[test] +fn test_fq_add_assign() { + // Test associativity + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Generate a, b, c and ensure (a + b) + c == a + (b + c). + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + + let mut tmp2 = b; + tmp2.add_assign(&c); + tmp2.add_assign(&a); + + assert_eq!(tmp1, tmp2); + } +} + +#[test] +fn test_fq_sub_assign() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure that (a - b) + (b - a) = 0. + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.sub_assign(&b); + + let mut tmp2 = b; + tmp2.sub_assign(&a); + + tmp1.add_assign(&tmp2); + assert!(tmp1.is_zero()); + } +} + +#[test] +fn test_fq_mul_assign() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * b) * c = a * (b * c) + let a = Fq::rand(&mut rng); + let b = Fq::rand(&mut rng); + let c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.mul_assign(&b); + tmp1.mul_assign(&c); + + let mut tmp2 = b; + tmp2.mul_assign(&c); + tmp2.mul_assign(&a); + + assert_eq!(tmp1, tmp2); + } + + for _ in 0..1000000 { + // Ensure that r * (a + b + c) = r*a + r*b + r*c + + let r = Fq::rand(&mut rng); + let mut a = Fq::rand(&mut rng); + let mut b = Fq::rand(&mut rng); + let mut c = Fq::rand(&mut rng); + + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.add_assign(&c); + tmp1.mul_assign(&r); + + a.mul_assign(&r); + b.mul_assign(&r); + c.mul_assign(&r); + + a.add_assign(&b); + a.add_assign(&c); + + assert_eq!(tmp1, a); + } +} + +#[test] +fn test_fq_squaring() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000000 { + // Ensure that (a * a) = a^2 + let a = Fq::rand(&mut rng); + + let mut tmp = a; + tmp.square_in_place(); + + let mut tmp2 = a; + tmp2.mul_assign(&a); + + assert_eq!(tmp, tmp2); + } +} + +#[test] +fn test_fq_inverse() { + assert!(Fq::zero().inverse().is_none()); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let one = Fq::one(); + + for _ in 0..1000 { + // Ensure that a * a^-1 = 1 + let mut a = Fq::rand(&mut rng); + let ainv = a.inverse().unwrap(); + a.mul_assign(&ainv); + assert_eq!(a, one); + } +} + +#[test] +fn test_fq_double_in_place() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure doubling a is equivalent to adding a to itself. + let mut a = Fq::rand(&mut rng); + let mut b = a; + b.add_assign(&a); + a.double_in_place(); + assert_eq!(a, b); + } +} + +#[test] +fn test_fq_negate() { + { + let a = -Fq::zero(); + + assert!(a.is_zero()); + } + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + // Ensure (a - (-a)) = 0. + let mut a = Fq::rand(&mut rng); + let b = -a; + a.add_assign(&b); + + assert!(a.is_zero()); + } +} + +#[test] +fn test_fq_pow() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for i in 0..1000 { + // Exponentiate by various small numbers and ensure it consists with repeated + // multiplication. + let a = Fq::rand(&mut rng); + let target = a.pow(&[i]); + let mut c = Fq::one(); + for _ in 0..i { + c.mul_assign(&a); + } + assert_eq!(c, target); + } + + for _ in 0..1000 { + // Exponentiating by the modulus should have no effect in a prime field. + let a = Fq::rand(&mut rng); + + assert_eq!(a, a.pow(Fq::characteristic())); + } +} + +#[test] +fn test_fq_sqrt() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); + + for _ in 0..1000 { + // Ensure sqrt(a^2) = a or -a + let a = Fq::rand(&mut rng); + let nega = -a; + let mut b = a; + b.square_in_place(); + + let b = b.sqrt().unwrap(); + + assert!(a == b || nega == b); + } + + for _ in 0..1000 { + // Ensure sqrt(a)^2 = a for random a + let a = Fq::rand(&mut rng); + + if let Some(mut tmp) = a.sqrt() { + tmp.square_in_place(); + + assert_eq!(a, tmp); + } + } +} + +#[test] +fn test_fq_num_bits() { + assert_eq!(FqParameters::MODULUS_BITS, 254); + assert_eq!(FqParameters::CAPACITY, 253); +} + +#[test] +fn test_fq_root_of_unity() { + assert_eq!(FqParameters::TWO_ADICITY, 1); + assert_eq!( + Fq::multiplicative_generator().pow([ + 0x9e10460b6c3e7ea3, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]), + Fq::two_adic_root_of_unity() + ); + assert_eq!( + Fq::two_adic_root_of_unity().pow([1 << FqParameters::TWO_ADICITY]), + Fq::one() + ); + assert!(Fq::multiplicative_generator().sqrt().is_none()); +} + +#[test] +fn test_fq_ordering() { + // BigInteger256's ordering is well-tested, but we still need to make sure the + // Fq elements aren't being compared in Montgomery form. + for i in 0..100 { + assert!(Fq::from(BigInteger256::from(i + 1)) > Fq::from(BigInteger256::from(i))); + } +} + +#[test] +fn test_fq_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(QuadraticResidue, Fq::one().legendre()); + assert_eq!(Zero, Fq::zero().legendre()); + assert_eq!( + QuadraticResidue, + Fq::from(BigInteger256::from(4)).legendre() + ); + assert_eq!( + QuadraticNonResidue, + Fq::from(BigInteger256::from(5)).legendre() + ); +} + +#[test] +fn test_fq2_ordering() { + let mut a = Fq2::new(Fq::zero(), Fq::zero()); + let mut b = a.clone(); + + assert!(a.cmp(&b) == Ordering::Equal); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); + b.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Less); + a.c1.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Greater); + b.c0.add_assign(&Fq::one()); + assert!(a.cmp(&b) == Ordering::Equal); +} + +#[test] +fn test_fq2_basics() { + assert_eq!(Fq2::new(Fq::zero(), Fq::zero(),), Fq2::zero()); + assert_eq!(Fq2::new(Fq::one(), Fq::zero(),), Fq2::one()); + assert!(Fq2::zero().is_zero()); + assert!(!Fq2::one().is_zero()); + assert!(!Fq2::new(Fq::zero(), Fq::one(),).is_zero()); +} + +#[test] +fn test_fq2_legendre() { + use ark_ff::fields::LegendreSymbol::*; + + assert_eq!(Zero, Fq2::zero().legendre()); + // i^2 = -1 + let mut m1 = -Fq2::one(); + assert_eq!(QuadraticResidue, m1.legendre()); + m1 = Fq6Parameters::mul_fp2_by_nonresidue(&m1); + assert_eq!(QuadraticNonResidue, m1.legendre()); +} + +#[test] +fn test_fq6_mul_by_1() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_1(&c1); + b.mul_assign(&Fq6::new(Fq2::zero(), c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_01() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let mut a = Fq6::rand(&mut rng); + let mut b = a; + + a.mul_by_01(&c0, &c1); + b.mul_assign(&Fq6::new(c0, c1, Fq2::zero())); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_014() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c1 = Fq2::rand(&mut rng); + let c5 = Fq2::rand(&mut rng); + let mut a = Fq12::rand(&mut rng); + let mut b = a; + + a.mul_by_014(&c0, &c1, &c5); + b.mul_assign(&Fq12::new( + Fq6::new(c0, c1, Fq2::zero()), + Fq6::new(Fq2::zero(), c5, Fq2::zero()), + )); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_034() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let c0 = Fq2::rand(&mut rng); + let c3 = Fq2::rand(&mut rng); + let c4 = Fq2::rand(&mut rng); + let mut a = Fq12::rand(&mut rng); + let mut b = a; + + a.mul_by_034(&c0, &c3, &c4); + b.mul_assign(&Fq12::new( + Fq6::new(c0, Fq2::zero(), Fq2::zero()), + Fq6::new(c3, c4, Fq2::zero()), + )); + + assert_eq!(a, b); + } +} diff --git a/bn254/src/lib.rs b/bn254/src/lib.rs new file mode 100644 index 0000000..ee8b4d7 --- /dev/null +++ b/bn254/src/lib.rs @@ -0,0 +1,40 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the BN254 curve that was sampled as part of the [[BCTV14]][https://eprint.iacr.org/2013/879.pdf] paper . +//! The name denotes that it is a Barreto--Naehrig curve of embedding degree 12, +//! defined over a 254-bit (prime) field. The scalar field is highly 2-adic. +//! +//! This curve is also implemented in [libff](https://github.com/scipr-lab/libff/tree/master/libff/algebra/curves/alt_bn128) under the name `bn128`. +//! It is the same as the `bn256` curve used in Ethereum (eg: [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn254/cloudflare)). +//! +//! #CAUTION +//! **This curve does not satisfy the 128-bit security level anymore.** +//! +//! +//! Curve information: +//! * Base field: q = 21888242871839275222246405745257275088696311157297823662689037894645226208583 +//! * Scalar field: r = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +//! * valuation(q - 1, 2) = 1 +//! * valuation(r - 1, 2) = 28 +//! * G1 curve equation: y^2 = x^3 + 3 +//! * G2 curve equation: y^2 = x^3 + B, where +//! * B = 3/(u+9) where Fq2[u]=Fq/u+1 +//! = Fq2(19485874751759354771024239261021720505790618469301721065564631296452457478373, 266929791119991161246907387137283842545076965332900288569378510910307636690) + +#[cfg(feature = "curve")] +mod curves; + +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; + +pub use fields::*; diff --git a/bw6_761/Cargo.toml b/bw6_761/Cargo.toml new file mode 100644 index 0000000..3960012 --- /dev/null +++ b/bw6_761/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-bw6-761" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The BW6-761 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-bw6-761/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bls12-377 = { path = "../bls12_377", default-features = false, features = [ "base_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-377/std" ] diff --git a/bw6_761/src/curves/g1.rs b/bw6_761/src/curves/g1.rs new file mode 100644 index 0000000..cef7018 --- /dev/null +++ b/bw6_761/src/curves/g1.rs @@ -0,0 +1,113 @@ +use crate::{Fq, Fr}; +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{ + biginteger::{BigInteger384, BigInteger768}, + field_new, +}; + +pub type G1Affine = GroupAffine; +pub type G1Projective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 0 + #[rustfmt::skip] + + const COEFF_A: Fq = field_new!(Fq, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); + + /// COEFF_B = -1 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger768([ + 0xf29a000000007ab6, + 0x8c391832e000739b, + 0x77738a6b6870f959, + 0xbe36179047832b03, + 0x84f3089e56574722, + 0xc5a3614ac0b1d984, + 0x5c81153f4906e9fe, + 0x4d28be3a9f55c815, + 0xd72c1d6f77d5f5c5, + 0x73a18e069ac04458, + 0xf9dfaa846595555f, + 0xd0f0a60a5be58c, + ])); + + /// COFACTOR = + /// 26642435879335816683987677701488073867751118270052650655942102502312977592501693353047140953112195348280268661194876 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x3de580000000007c, + 0x832ba4061000003b, + 0xc61c554757551c0c, + 0xc856a0853c9db94c, + 0x2c77d5ac34cb12ef, + 0xad1972339049ce76, + ]; + + /// COFACTOR^(-1) mod r = + /// 91141326767669940707819291241958318717982251277713150053234367522357946997763584490607453720072232540829942217804 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger384([ + 489703175600125849, + 3883341943836920852, + 1678256062427438196, + 5848789333018172718, + 7127967896440782320, + 71512347676739162, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); + #[inline(always)] + fn mul_by_a(_elem: &Self::BaseField) -> Self::BaseField { + use ark_ff::Zero; + Self::BaseField::zero() + } +} + +/// G1_GENERATOR_X = +/// 6238772257594679368032145693622812838779005809760824733138787810501188623461307351759238099287535516224314149266511977132140828635950940021790489507611754366317801811090811367945064510304504157188661901055903167026722666149426237 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ + 0xd6e42d7614c2d770, + 0x4bb886eddbc3fc21, + 0x64648b044098b4d2, + 0x1a585c895a422985, + 0xf1a9ac17cf8685c9, + 0x352785830727aea5, + 0xddf8cb12306266fe, + 0x6913b4bfbc9e949a, + 0x3a4b78d67ba5f6ab, + 0x0f481c06a8d02a04, + 0x91d4e7365c43edac, + 0xf4d17cd48beca5, +])); + +/// G1_GENERATOR_Y = +/// 2101735126520897423911504562215834951148127555913367997162789335052900271653517958562461315794228241561913734371411178226936527683203879553093934185950470971848972085321797958124416462268292467002957525517188485984766314758624099 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ + 0x97e805c4bd16411f, + 0x870d844e1ee6dd08, + 0x1eba7a37cb9eab4d, + 0xd544c4df10b9889a, + 0x8fe37f21a33897be, + 0xe9bf99a43a0885d2, + 0xd7ee0c9e273de139, + 0xaa6a9ec7a38dd791, + 0x8f95d3fcf765da8e, + 0x42326e7db7357c99, + 0xe217e407e218695f, + 0x9d1eb23b7cf684, +])); diff --git a/bw6_761/src/curves/g2.rs b/bw6_761/src/curves/g2.rs new file mode 100644 index 0000000..5fda4a0 --- /dev/null +++ b/bw6_761/src/curves/g2.rs @@ -0,0 +1,113 @@ +use crate::{Fq, Fr}; +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{ + biginteger::{BigInteger384, BigInteger768}, + field_new, +}; + +pub type G2Affine = GroupAffine; +pub type G2Projective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 0 + #[rustfmt::skip] + + const COEFF_A: Fq = field_new!(Fq, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); + + /// COEFF_B = 4 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger768([ + 0x136efffffffe16c9, + 0x82cf5a6dcffe3319, + 0x6458c05f1f0e0741, + 0xd10ae605e52a4eda, + 0x41ca591c0266e100, + 0x7d0fd59c3626929f, + 0x9967dc004d00c112, + 0x1ccff9c033379af5, + 0x9ad6ec10a23f63af, + 0x5cec11251a72c235, + 0x8d18b1ae789ba83e, + 10403402007434220, + ])); + + /// COFACTOR = + /// 26642435879335816683987677701488073867751118270052650655942102502312977592501693353047140953112195348280268661194869 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x3de5800000000075, + 0x832ba4061000003b, + 0xc61c554757551c0c, + 0xc856a0853c9db94c, + 0x2c77d5ac34cb12ef, + 0xad1972339049ce76, + ]; + + /// COFACTOR^(-1) mod r = + /// 214911522365886453591244899095480747723790054550866810551297776298664428889000553861210287833206024638187939842124 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger384([ + 14378295991815829998, + 14586153992421458638, + 9788477762582722914, + 12654821707953664524, + 15185631607604703397, + 26723985783783076, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + #[inline(always)] + fn mul_by_a(_elem: &Self::BaseField) -> Self::BaseField { + use ark_ff::Zero; + Self::BaseField::zero() + } +} + +/// G2_GENERATOR_X = +/// 6445332910596979336035888152774071626898886139774101364933948236926875073754470830732273879639675437155036544153105017729592600560631678554299562762294743927912429096636156401171909259073181112518725201388196280039960074422214428 +#[rustfmt::skip] +pub const G2_GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ + 0x3d902a84cd9f4f78, + 0x864e451b8a9c05dd, + 0xc2b3c0d6646c5673, + 0x17a7682def1ecb9d, + 0xbe31a1e0fb768fe3, + 0x4df125e09b92d1a6, + 0x0943fce635b02ee9, + 0xffc8e7ad0605e780, + 0x8165c00a39341e95, + 0x8ccc2ae90a0f094f, + 0x73a8b8cc0ad09e0c, + 0x11027e203edd9f4, +])); + +/// G2_GENERATOR_Y = +/// 562923658089539719386922163444547387757586534741080263946953401595155211934630598999300396317104182598044793758153214972605680357108252243146746187917218885078195819486220416605630144001533548163105316661692978285266378674355041 +#[rustfmt::skip] +pub const G2_GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ + 0x9a159be4e773f67c, + 0x6b957244aa8f4e6b, + 0xa27b70c9c945a38c, + 0xacb6a09fda11d0ab, + 0x3abbdaa9bb6b1291, + 0xdbdf642af5694c36, + 0xb6360bb9560b369f, + 0xac0bd1e822b8d6da, + 0xfa355d17afe6945f, + 0x8d6a0fc1fbcad35e, + 0x72a63c7874409840, + 0x114976e5b0db280, +])); diff --git a/bw6_761/src/curves/mod.rs b/bw6_761/src/curves/mod.rs new file mode 100644 index 0000000..cfc54ee --- /dev/null +++ b/bw6_761/src/curves/mod.rs @@ -0,0 +1,61 @@ +use crate::*; +use ark_ec::{ + bw6, + bw6::{BW6Parameters, TwistType, BW6}, +}; +use ark_ff::biginteger::BigInteger768 as BigInteger; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +#[derive(PartialEq, Eq)] +pub struct Parameters; + +impl BW6Parameters for Parameters { + const X: BigInteger = BigInteger([ + 0x8508c00000000001, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + ]); + /// `x` is positive. + const X_IS_NEGATIVE: bool = false; + // X+1 + const ATE_LOOP_COUNT_1: &'static [u64] = &[0x8508c00000000002]; + const ATE_LOOP_COUNT_1_IS_NEGATIVE: bool = false; + // X^3-X^2-X + const ATE_LOOP_COUNT_2: &'static [i8] = &[ + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, + 1, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 1, 0, 1, 0, 0, 0, 1, + 0, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 1, + ]; + const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool = false; + const TWIST_TYPE: TwistType = TwistType::M; + type Fp = Fq; + type Fp3Params = Fq3Parameters; + type Fp6Params = Fq6Parameters; + type G1Parameters = g1::Parameters; + type G2Parameters = g2::Parameters; +} + +pub type BW6_761 = BW6; + +pub type G1Affine = bw6::G1Affine; +pub type G1Projective = bw6::G1Projective; +pub type G2Affine = bw6::G2Affine; +pub type G2Projective = bw6::G2Projective; diff --git a/bw6_761/src/curves/tests.rs b/bw6_761/src/curves/tests.rs new file mode 100644 index 0000000..94e65d8 --- /dev/null +++ b/bw6_761/src/curves/tests.rs @@ -0,0 +1,77 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = BW6_761::pairing(sa, b); + let ans2 = BW6_761::pairing(a, sb); + let ans3 = BW6_761::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq6::one()); + assert_ne!(ans2, Fq6::one()); + assert_ne!(ans3, Fq6::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq6::one()); +} diff --git a/bw6_761/src/fields/fq.rs b/bw6_761/src/fields/fq.rs new file mode 100644 index 0000000..d410cb4 --- /dev/null +++ b/bw6_761/src/fields/fq.rs @@ -0,0 +1,175 @@ +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, +}; + +pub type Fq = Fp768; + +pub struct FqParameters; + +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); + +impl Fp768Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + // The internal representation of this type is six 64-bit unsigned + // integers in little-endian order. Values are always in + // Montgomery form; i.e., Scalar(a) = aR mod p, with R=2^768. + + // (MODULUS - 1) % 2^TWO_ADICITY == 0 + const TWO_ADICITY: u32 = 1; + + // least_quadratic_nonresidue(MODULUS) in Sage. + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 17481284903592032950u64, + 10104133845767975835u64, + 8607375506753517913u64, + 13706168424391191299u64, + 9580010308493592354u64, + 14241333420363995524u64, + 6665632285037357566u64, + 5559902898979457045u64, + 15504799981718861253u64, + 8332096944629367896u64, + 18005297320867222879u64, + 58811391084848524u64, + ]); +} +impl FpParameters for FqParameters { + /// MODULUS = 6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xf49d00000000008b, + 0xe6913e6870000082, + 0x160cf8aeeaf0a437, + 0x98a116c25667a8f8, + 0x71dcd3dc73ebff2e, + 0x8689c8ed12f9fd90, + 0x03cebaff25b42304, + 0x707ba638e584e919, + 0x528275ef8087be41, + 0xb926186a81d14688, + 0xd187c94004faff3e, + 0x122e824fb83ce0a + ]); + + const MODULUS_BITS: u32 = 761; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + // gap to 64-bit machine word + const REPR_SHAVE_BITS: u32 = 7; + + // 2^768 % MODULUS + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 144959613005956565u64, + 6509995272855063783u64, + 11428286765660613342u64, + 15738672438262922740u64, + 17071399330169272331u64, + 13899911246788437003u64, + 12055474021000362245u64, + 2545351818702954755u64, + 8887388221587179644u64, + 5009280847225881135u64, + 15539704305423854047u64, + 23071597697427581u64, + ]); + + // R^2 + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 14305184132582319705u64, + 8868935336694416555u64, + 9196887162930508889u64, + 15486798265448570248u64, + 5402985275949444416u64, + 10893197322525159598u64, + 3204916688966998390u64, + 12417238192559061753u64, + 12426306557607898622u64, + 1305582522441154384u64, + 10311846026977660324u64, + 48736111365249031u64, + ]); + + // (-1/MODULUS) % 2^64 + const INV: u64 = 744663313386281181u64; + + /// GENERATOR = 2 + // primitive_root(MODULUS) + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 289919226011913130u64, + 13019990545710127566u64, + 4409829457611675068u64, + 13030600802816293865u64, + 15696054586628993047u64, + 9353078419867322391u64, + 5664203968291172875u64, + 5090703637405909511u64, + 17774776443174359288u64, + 10018561694451762270u64, + 12632664537138156478u64, + 46143195394855163u64, + ]); + + // (MODULUS - 1) / 2 + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x7a4e800000000045, + 0xf3489f3438000041, + 0x0b067c577578521b, + 0x4c508b612b33d47c, + 0x38ee69ee39f5ff97, + 0x4344e476897cfec8, + 0x81e75d7f92da1182, + 0xb83dd31c72c2748c, + 0x29413af7c043df20, + 0x5c930c3540e8a344, + 0x68c3e4a0027d7f9f, + 0x9174127dc1e705, + ]); + + // T = + // 3445725192157866269698394841137828771239834456268075054756895080104811711121745868043841591644705843820432283876893306725580879560277123879674755849562650799475802549689254425186271815711798397975949850214984556421382456559534149 + // (MODULUS - 1) / 2 ^ TWO_ADICITY + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x7a4e800000000045, + 0xf3489f3438000041, + 0x0b067c577578521b, + 0x4c508b612b33d47c, + 0x38ee69ee39f5ff97, + 0x4344e476897cfec8, + 0x81e75d7f92da1182, + 0xb83dd31c72c2748c, + 0x29413af7c043df20, + 0x5c930c3540e8a344, + 0x68c3e4a0027d7f9f, + 0x9174127dc1e705, + ]); + + // (T - 1)/2 = + // 1722862596078933134849197420568914385619917228134037527378447540052405855560872934021920795822352921910216141938446653362790439780138561939837377924781325399737901274844627212593135907855899198987974925107492278210691228279767074 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xbd27400000000022, + 0xf9a44f9a1c000020, + 0x05833e2bbabc290d, + 0xa62845b09599ea3e, + 0x1c7734f71cfaffcb, + 0x21a2723b44be7f64, + 0x40f3aebfc96d08c1, + 0x5c1ee98e39613a46, + 0x14a09d7be021ef90, + 0xae49861aa07451a2, + 0xb461f250013ebfcf, + 0x48ba093ee0f382, + ]); +} diff --git a/bw6_761/src/fields/fq3.rs b/bw6_761/src/fields/fq3.rs new file mode 100644 index 0000000..d651457 --- /dev/null +++ b/bw6_761/src/fields/fq3.rs @@ -0,0 +1,200 @@ +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp3::{Fp3, Fp3Parameters}, +}; + +use crate::Fq; + +pub type Fq3 = Fp3; + +pub struct Fq3Parameters; + +impl Fp3Parameters for Fq3Parameters { + type Fp = Fq; + + /// NONRESIDUE = -4 + // Fq3 = Fq[u]/u^3+4 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0xe12e00000001e9c2, + 0x63c1e3faa001cd69, + 0xb1b4384fcbe29cf6, + 0xc79630bc713d5a1d, + 0x30127ac071851e2d, + 0x0979f350dcd36af1, + 0x6a66defed8b361f2, + 0x53abac78b24d4e23, + 0xb7ab89dede485a92, + 0x5c3a0745675e8452, + 0x446f17918c5f5700, + 0xfdf24e3267fa1e, + ])); + + // (MODULUS^3 - 1) % 2^TWO_ADICITY == 0 + const TWO_ADICITY: u32 = 1; + + // (T-1)/2 with T = (MODULUS^3-1) / 2^TWO_ADICITY + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + 0xb5e7c000000a3eac, + 0xf79b99dbf41cf4ab, + 0xe9372b1919e55ee5, + 0xbb7bbc4936c1980b, + 0x7c0cb9d4399b36e1, + 0x73304a5507bb1ae0, + 0x92f639be8963936f, + 0x4f574ac2439ba816, + 0x670d9bd389dd29ef, + 0x606ddf900d2124f1, + 0x928fb14985ec3270, + 0x6b2f2428c5f420f3, + 0xac9ade29d5ab5fbe, + 0xec0d0434c4005822, + 0x973f10d7f3c5c108, + 0x6d5e83fc81095979, + 0xdac3e6e4e1647752, + 0x227febf93994603e, + 0x4ab8755d894167d1, + 0x4fd2d3f67d8b537a, + 0x33e196a4d5f4030a, + 0x88b51fb72092df1a, + 0xa67e5b1e8fc48316, + 0xb0855eb2a00d7dab, + 0xe875dd2da6751442, + 0x777594a243e25676, + 0x294e0f70376a85a8, + 0x83f431c7988e4f18, + 0x8e8fb6af3ca2f5f1, + 0x7297896b4b9e90f1, + 0xff38f54664d66123, + 0xb5ecf80bfff41e13, + 0x1662a3666bb8392a, + 0x07a0968e8742d3e1, + 0xf12927e564bcdfdc, + 0x5de9825a0e, + ]; + + // NONRESIDUE^T % q + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 0xf29a000000007ab6, + 0x8c391832e000739b, + 0x77738a6b6870f959, + 0xbe36179047832b03, + 0x84f3089e56574722, + 0xc5a3614ac0b1d984, + 0x5c81153f4906e9fe, + 0x4d28be3a9f55c815, + 0xd72c1d6f77d5f5c5, + 0x73a18e069ac04458, + 0xf9dfaa846595555f, + 0xd0f0a60a5be58c, + ])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + ); + + // NQR ^ (MODULUS^i - 1)/3, i=0,1,2 with NQR = u = (0,1,0) + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x0202ffffffff85d5, + 0x5a5826358fff8ce7, + 0x9e996e43827faade, + 0xda6aff320ee47df4, + 0xece9cb3e1d94b80b, + 0xc0e667a25248240b, + 0xa74da5bfdcad3905, + 0x2352e7fe462f2103, + 0x7b56588008b1c87c, + 0x45848a63e711022f, + 0xd7a81ebb9f65a9df, + 0x51f77ef127e87d, + ])), + field_new!(Fq, BigInteger([ + 0x7f96b51bd840c549, + 0xd59782096496171f, + 0x49b046fd9ce14bbc, + 0x4b6163bba7527a56, + 0xef6c92fb771d59f1, + 0x0425bedbac1dfdc7, + 0xd3ac39de759c0ffd, + 0x9f43ed0e063a81d0, + 0x5bd7d20b4f9a3ce2, + 0x0411f03c36cf5c3c, + 0x2d658fd49661c472, + 0x1100249ae760b93, + ])), + field_new!(Fq, BigInteger([ + 0x67a04ae427bfb5f8, + 0x9d32d491eb6a5cff, + 0x43d03c1cb68051d4, + 0x0b75ca96f69859a5, + 0x0763497f5325ec60, + 0x48076b5c278dd94d, + 0x8ca3965ff91efd06, + 0x1e6077657ea02f5d, + 0xcdd6c153a8c37724, + 0x28b5b634e5c22ea4, + 0x9e01e3efd42e902c, + 0xe3d6815769a804, + + ])), + ]; + + // NQR ^ (2*MODULUS^i - 2)/3, i=0,1,2 with NQR = u = (0,1,0) + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C2: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x0202ffffffff85d5, + 0x5a5826358fff8ce7, + 0x9e996e43827faade, + 0xda6aff320ee47df4, + 0xece9cb3e1d94b80b, + 0xc0e667a25248240b, + 0xa74da5bfdcad3905, + 0x2352e7fe462f2103, + 0x7b56588008b1c87c, + 0x45848a63e711022f, + 0xd7a81ebb9f65a9df, + 0x51f77ef127e87d, + ])), + field_new!(Fq, BigInteger([ + 0x67a04ae427bfb5f8, + 0x9d32d491eb6a5cff, + 0x43d03c1cb68051d4, + 0x0b75ca96f69859a5, + 0x0763497f5325ec60, + 0x48076b5c278dd94d, + 0x8ca3965ff91efd06, + 0x1e6077657ea02f5d, + 0xcdd6c153a8c37724, + 0x28b5b634e5c22ea4, + 0x9e01e3efd42e902c, + 0xe3d6815769a804, + ])), + field_new!(Fq, BigInteger([ + 0x7f96b51bd840c549, + 0xd59782096496171f, + 0x49b046fd9ce14bbc, + 0x4b6163bba7527a56, + 0xef6c92fb771d59f1, + 0x0425bedbac1dfdc7, + 0xd3ac39de759c0ffd, + 0x9f43ed0e063a81d0, + 0x5bd7d20b4f9a3ce2, + 0x0411f03c36cf5c3c, + 0x2d658fd49661c472, + 0x1100249ae760b93, + ])), + ]; + + #[inline(always)] + fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { + let original = -(*fe); + let double = original + &original; + double + &double + } +} diff --git a/bw6_761/src/fields/fq6.rs b/bw6_761/src/fields/fq6.rs new file mode 100644 index 0000000..47c8523 --- /dev/null +++ b/bw6_761/src/fields/fq6.rs @@ -0,0 +1,106 @@ +use crate::{Fq, Fq3, Fq3Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp6_2over3::{Fp6, Fp6Parameters}, +}; + +pub type Fq6 = Fp6; + +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp3Params = Fq3Parameters; + + /// NONRESIDUE = (0, 1, 0) + #[rustfmt::skip] + const NONRESIDUE: Fq3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x0202ffffffff85d5, + 0x5a5826358fff8ce7, + 0x9e996e43827faade, + 0xda6aff320ee47df4, + 0xece9cb3e1d94b80b, + 0xc0e667a25248240b, + 0xa74da5bfdcad3905, + 0x2352e7fe462f2103, + 0x7b56588008b1c87c, + 0x45848a63e711022f, + 0xd7a81ebb9f65a9df, + 0x51f77ef127e87d, + ])), + field_new!(Fq, BigInteger([ + 0x8cfcb51bd8404a93, + 0x495e69d68495a383, + 0xd23cbc9234705263, + 0x8d2b4c2b5fcf4f52, + 0x6a798a5d20c612ce, + 0x3e825d90eb6c2443, + 0x772b249f2c9525fe, + 0x521b2ed366e4b9bb, + 0x84abb49bd7c4471d, + 0x907062359c0f17e3, + 0x3385e55030cc6f12, + 0x3f11a3a41a2606, + ])), + field_new!(Fq, BigInteger([ + 0x7f96b51bd840c549, + 0xd59782096496171f, + 0x49b046fd9ce14bbc, + 0x4b6163bba7527a56, + 0xef6c92fb771d59f1, + 0x0425bedbac1dfdc7, + 0xd3ac39de759c0ffd, + 0x9f43ed0e063a81d0, + 0x5bd7d20b4f9a3ce2, + 0x0411f03c36cf5c3c, + 0x2d658fd49661c472, + 0x1100249ae760b93, + ])), + field_new!(Fq, BigInteger([ + 0xf29a000000007ab6, + 0x8c391832e000739b, + 0x77738a6b6870f959, + 0xbe36179047832b03, + 0x84f3089e56574722, + 0xc5a3614ac0b1d984, + 0x5c81153f4906e9fe, + 0x4d28be3a9f55c815, + 0xd72c1d6f77d5f5c5, + 0x73a18e069ac04458, + 0xf9dfaa846595555f, + 0xd0f0a60a5be58c, + ])), + field_new!(Fq, BigInteger([ + 0x67a04ae427bfb5f8, + 0x9d32d491eb6a5cff, + 0x43d03c1cb68051d4, + 0x0b75ca96f69859a5, + 0x0763497f5325ec60, + 0x48076b5c278dd94d, + 0x8ca3965ff91efd06, + 0x1e6077657ea02f5d, + 0xcdd6c153a8c37724, + 0x28b5b634e5c22ea4, + 0x9e01e3efd42e902c, + 0xe3d6815769a804, + ])), + field_new!(Fq, BigInteger([ + 0x75064ae427bf3b42, + 0x10f9bc5f0b69e963, + 0xcc5cb1b14e0f587b, + 0x4d3fb306af152ea1, + 0x827040e0fccea53d, + 0x82640a1166dbffc8, + 0x30228120b0181307, + 0xd137b92adf4a6748, + 0xf6aaa3e430ed815e, + 0xb514282e4b01ea4b, + 0xa422396b6e993acc, + 0x12e5db4d0dc277, + ])), + ]; +} diff --git a/bw6_761/src/fields/fr.rs b/bw6_761/src/fields/fr.rs new file mode 100644 index 0000000..63c94bb --- /dev/null +++ b/bw6_761/src/fields/fr.rs @@ -0,0 +1 @@ +pub use ark_bls12_377::{Fq as Fr, FqParameters as FrParameters}; diff --git a/bw6_761/src/fields/mod.rs b/bw6_761/src/fields/mod.rs new file mode 100644 index 0000000..7bfd333 --- /dev/null +++ b/bw6_761/src/fields/mod.rs @@ -0,0 +1,14 @@ +pub mod fr; +pub use self::fr::*; + +pub mod fq; +pub use self::fq::*; + +pub mod fq3; +pub use self::fq3::*; + +pub mod fq6; +pub use self::fq6::*; + +#[cfg(test)] +mod tests; diff --git a/bw6_761/src/fields/tests.rs b/bw6_761/src/fields/tests.rs new file mode 100644 index 0000000..0609b52 --- /dev/null +++ b/bw6_761/src/fields/tests.rs @@ -0,0 +1,51 @@ +use ark_ff::{test_rng, Field, PrimeField}; +use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(a); + + let byte_size = a.serialized_size(); + let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits()); + assert_eq!(byte_size, buffer_size); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq3() { + let mut rng = test_rng(); + let a: Fq3 = rng.gen(); + let b: Fq3 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + let a: Fq6 = rng.gen(); + let b: Fq6 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/bw6_761/src/lib.rs b/bw6_761/src/lib.rs new file mode 100644 index 0000000..f43087b --- /dev/null +++ b/bw6_761/src/lib.rs @@ -0,0 +1,34 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the BW6_761 curve generated in [[EG20]](https://eprint.iacr.org/2020/351). +//! The name denotes that it is a curve generated using the Brezing--Weng method, and that +//! its embedding degree is 6. +//! The main feature of this curve is that the scalar field equals the base field of the BLS12_377 curve. +//! +//! Curve information: +//! * Base field: q = 6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299 +//! * Scalar field: r = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +//! * valuation(q - 1, 2) = 1 +//! * valuation(r - 1, 2) = 46 +//! +//! G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 0, +//! * b = -1, +//! +//! G2 curve equation: y^2 = x^3 + Ax + B +//! * A = 0 +//! * B = 4 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/cp6_782/Cargo.toml b/cp6_782/Cargo.toml new file mode 100644 index 0000000..dde9a66 --- /dev/null +++ b/cp6_782/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-cp6-782" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The CP6-782 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-cp6-782/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bls12-377 = { path = "../bls12_377", default-features = false, features = [ "base_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-377/std" ] diff --git a/cp6_782/src/curves/g1.rs b/cp6_782/src/curves/g1.rs new file mode 100644 index 0000000..ab404f4 --- /dev/null +++ b/cp6_782/src/curves/g1.rs @@ -0,0 +1,126 @@ +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{ + biginteger::{BigInteger384, BigInteger832}, + field_new, +}; + +use crate::{Fq, Fr}; + +pub type G1Affine = GroupAffine; +pub type G1Projective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 5 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger832([ + 0x781c76643018bd7a, + 0x64f3a5a4f1d1ad48, + 0xd2f8a1eb4f72692d, + 0xc35eb123c6ed72ca, + 0xb58d6bcfd32de058, + 0x841eab13b02a492c, + 0x4b70dc5a54c487e7, + 0x2f231a8808a74c59, + 0x5e2915154d70b050, + 0x8a40fa16f37a6b37, + 0xd01980093a72c54b, + 0xef6845c25398004c, + 0x48, + ])); + + /// COEFF_B = 17764315118651679038286329069295091506801468118146712649886336045535808055361274148466772191243305528312843236347777260247138934336850548243151534538734724191505953341403463040067571652261229308333392040104884438208594329793895206056414 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger832([ + 0xec5bd271ad37429, + 0x9db8ac843ecca28a, + 0x94f29bcb7e01bc74, + 0x1b0bebb77bb5af0, + 0x75b8cef4aa27ee17, + 0xb5767ae80812cf6b, + 0x592fa41e377a0d8c, + 0xb6c6deedbb52df3e, + 0xcb1343e488737fd4, + 0x878020734d05b5a9, + 0x2f51354eddfa069a, + 0x498e2ecdc545243e, + 0x2c2, + ])); + + /// COFACTOR = + /// 86482221941698704497288378992285180119495364068003923046442785886272123124361700722982503222189455144364945735564951561028 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x5657b9b57b942344, + 0x84f9a65f3bd54eaf, + 0x5ea4214e35cd127, + 0xe3cbcbc14ec1501d, + 0xf196cb845a3092ab, + 0x7e14627ad0e19017, + 0x217db4, + ]; + + /// COFACTOR^(-1) mod r = + /// 163276846538158998893990986356139314746223949404500031940624325017036397274793417940375498603127780919653358641788 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger384([ + 4179837108212676264, + 15545810469293120493, + 13202863094424182470, + 9506285060796071546, + 9248558385029790142, + 87030208545296111, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); +} + +/// G1_GENERATOR_X = +/// 5511163824921585887915590525772884263960974614921003940645351443740084257508990841338974915037175497689287870585840954231884082785026301437744745393958283053278991955159266640440849940136976927372133743626748847559939620888818486853646 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger832([ + 0x5901480e5bc22290, + 0x20024afcdb9bd3a9, + 0x12dc18ff416e8138, + 0x28c69aa0ea223e18, + 0xafb1524a1eb7efe6, + 0x3d5c34edc3764ca2, + 0x736c2230c8466ce9, + 0xacfaa04e051014f1, + 0x5d5ff82f00ff2964, + 0x64c13ba270a26eaf, + 0x50e9864b56ab172e, + 0xd8370826a322499e, + 0x00000000000006f1, +])); + +/// G1_GENERATOR_Y = +/// 7913123550914612057135582061699117755797758113868200992327595317370485234417808273674357776714522052694559358668442301647906991623400754234679697332299689255516547752391831738454121261248793568285885897998257357202903170202349380518443 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger832([ + 0x8af8b64b402e1953, + 0xd1bbceb3a258ea51, + 0xdca9efa3140aaa0d, + 0x807a610058ddedb2, + 0xeb898562fe88076c, + 0x0e4342ca56dd8ce2, + 0x4f5528d29f1bde9a, + 0xf18b0c6c19feb372, + 0x94503ac2fac9199c, + 0xffc86a8aff08ea34, + 0xf7b1295214735d8c, + 0x44eda9e0f55edd10, + 0x0000000000000ef3, +])); diff --git a/cp6_782/src/curves/g2.rs b/cp6_782/src/curves/g2.rs new file mode 100644 index 0000000..bef909d --- /dev/null +++ b/cp6_782/src/curves/g2.rs @@ -0,0 +1,241 @@ +use ark_ec::{ + models::{ModelParameters, SWModelParameters}, + short_weierstrass_jacobian::{GroupAffine, GroupProjective}, +}; +use ark_ff::{ + biginteger::{BigInteger384, BigInteger832}, + field_new, +}; + +use crate::{Fq, Fq3, Fr, FQ_ZERO}; + +pub type G2Affine = GroupAffine; +pub type G2Projective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq3; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = (0, 0, COEFF_A * TWIST^2) = (0, 0, 5) + #[rustfmt::skip] + const COEFF_A: Fq3 = field_new!(Fq3, + FQ_ZERO, + FQ_ZERO, + field_new!(Fq, BigInteger832([ + 0x781c76643018bd7a, + 0x64f3a5a4f1d1ad48, + 0xd2f8a1eb4f72692d, + 0xc35eb123c6ed72ca, + 0xb58d6bcfd32de058, + 0x841eab13b02a492c, + 0x4b70dc5a54c487e7, + 0x2f231a8808a74c59, + 0x5e2915154d70b050, + 0x8a40fa16f37a6b37, + 0xd01980093a72c54b, + 0xef6845c25398004c, + 0x48, + ])), + ); + + /// COEFF_B = (G1::COEFF_B * TWIST^3, 0, 0) = + /// (7237353553714858194254855835825640240663090882935418626687402315497764195116318527743248304684159666286416318482685337633828994152723793439622384740540789612754127688659139509552568164770448654259255628317166934203899992395064470477612, + /// 0, 0) + #[rustfmt::skip] + const COEFF_B: Fq3 = field_new!(Fq3, + field_new!(Fq, BigInteger832([ + 0xc00a9afc5cbce615, + 0x0260c2b730644102, + 0x9051e955661691ec, + 0x15f9af8514839e37, + 0xfa62826ca407172b, + 0x37043dc868f48874, + 0x876b5588d132b025, + 0x481952128335562a, + 0x4ffa729aeddd7dcd, + 0xe181a5dae94a399f, + 0x671fb50145b255d8, + 0xbc3860730482d728, + 0x00000000000023dd, + ])), + FQ_ZERO, + FQ_ZERO, + ); + + /// COFACTOR = + /// 43276679045916726782882096851503554444292580777869919574700824986947162516693702667493938255647666346010819253090121562084993205202476199057555142869892665220155573207800985012241638987472334344174208389303164492698303448192856551557283997344470334833850065978668184377503856699635686872344035470027430053642178229054516302338812152178131995800255516474185251732445975837621097393375441662426280154371264547168198834382681059556891327702516519955053315674076980350109237328216856859758931256208439575383786363605925879337208599843910819433766160937121108797819223653884174994325142959644019600 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 0x4b77fca151d50b90, + 0x8c98a12bd486d2fb, + 0x1f0c9a51593693f8, + 0x1d6f388069c063c1, + 0x556e918748f06793, + 0x2cea7dc01aae2140, + 0x4216f0595cee44d0, + 0x7a5e400154f633cf, + 0xbb74eb9b6630846b, + 0x8eb48c92998f3358, + 0xbedd37f629e8e634, + 0xc541018fe4d10cc7, + 0x574956a099ace2c3, + 0xa597504275948226, + 0x7ecaaf050acb91f3, + 0x0f25b044f4e9c932, + 0xf8c39cbf0df97780, + 0xd8f9eda95d6abf3e, + 0xd1d80da227dd39c1, + 0x8b589c61531dbce7, + 0xfee4439281455474, + 0x9eea59baa2aeb4a1, + 0xa3b8a42c4e1e6f5a, + 0xc4b99b0d9b077d21, + 0xd09033887d09b4d2, + 0x4a86d8ebb7fdf52a, + 0xbe7ce44dd084e05d, + 0x4ed25f7ebe6c44b3, + 0xd7f8e3ef00255961, + 0xa1ad2ad61580ef78, + 0x19e70d3618ca3, + ]; + + /// COFACTOR^(-1) mod r = + /// 45586359457219724873147353901735745013467692594291916855200979604570630929674383405372210802279573887880950375598 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger384([ + 7373687189387546408, + 11284009518041539892, + 301575489693670883, + 13203058298476577559, + 18441611830097862156, + 4115759498196698, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); +} + +const G2_GENERATOR_X: Fq3 = + field_new!(Fq3, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1, G2_GENERATOR_X_C2); +const G2_GENERATOR_Y: Fq3 = + field_new!(Fq3, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1, G2_GENERATOR_Y_C2); + +/// G2_GENERATOR_X_C0 = +/// 13426761183630949215425595811885033211332897733228446437546263564078445562454176776915160094418980045665397361295624472103734543457352048745726512354895954850428989867542989474136256025045975283415690491751906307188562464175510373683338 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger832([ + 0x03b3fe4c8d4ecac7, + 0x9568212677524d1e, + 0xf5de3f2228d187c1, + 0x7bac772e31a420ef, + 0x0255cf59968a612b, + 0x991d4676f6b5d605, + 0x02dd2ae4831d29ea, + 0xbeca7c9a62e392c2, + 0xfc1d0633d48d2fc5, + 0x7867813be5f7d2a1, + 0x6f567b6617030028, + 0xf08c9fa6ca6809df, + 0x0000000000000de9, +])); + +/// G2_GENERATOR_X_C1 = +/// 20471601555918880743198170952645906008198510944268658573129351735028343217532386920456705632337352161031960990613816401042894531220068552819818037605513359562118363589199569321421558696125646867661360498323171027455638052943806292028610 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger832([ + 0xefd1b506e5fbe05f, + 0xad27d47a4975140c, + 0xfa11540132dbc27a, + 0x8dca42b6da7c4717, + 0x66d30fd7fd76207a, + 0xb8e4f65c68932b1d, + 0x3b7f971e93ad14be, + 0xf860a89f4e582f9f, + 0x7d438aaa3986f73b, + 0xa37ec0c18c6e106a, + 0x9f2dfb98b5185b54, + 0x19995e421ca939bc, + 0x0000000000002f4f, +])); + +/// G2_GENERATOR_X_C2 = +/// 3905053196875761830053608605277158152930144841844497593936739534395003062685449846381431331169369910535935138116320442345524758217411779027270883193856999691582831339845600938304719916501940381093815781408183227875600753651697934495980 +#[rustfmt::skip] +pub const G2_GENERATOR_X_C2: Fq = field_new!(Fq, BigInteger832([ + 0xc081ed832bdf911e, + 0xb85ff7aeebdfe7b3, + 0x96dce6bb307b14eb, + 0x578f7ded84bd824c, + 0xb799305a9971d184, + 0x0116ad33c2874b90, + 0x862dce68efdca245, + 0x4190947c70534c1d, + 0x1b1aa80334248d03, + 0xb13b07aff63fcf27, + 0x5727687b73ab4fff, + 0xf559a7f4eb8d180a, + 0x0000000000002d37, +])); + +/// G2_GENERATOR_Y_C0 = +/// 8567517639523571619872938228644013584947463594196306323477160496987712111576624702939472765993995586889532559039169098780892505598589581147768095093536988446010255611523736706017580686335404469207486594272103717837888228343074699140243 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger832([ + 0x3f680b59e26b33d1, + 0x720fdf65b9e15b17, + 0x0f0b56def11247b1, + 0x5ea05417c8a4a52c, + 0x4ad59dc4f7c47a09, + 0xf393e0db62107115, + 0xde3b16404a53d2bb, + 0xeaa74961636280e0, + 0x2d16ccd14cf5a88c, + 0x5667565a06187d0e, + 0xb446fdc7565d0261, + 0xd3ad395d6fd0faab, + 0x0000000000000655, +])); + +/// G2_GENERATOR_Y_C1 = +/// 3890537069205870914984502594450293167889863914413852788876350245583932846980126025043974070704295857226211547108005650399870458089721518559480870503159804530091559886149680718531004778697982910253701559194337987238111062202037698927752 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger832([ + 0x9e86cc63207679dd, + 0x4e16d9a9d87c3e47, + 0xdbee3524db80627d, + 0x137322b87d93befc, + 0x24a7ca2f9aae90a0, + 0x44abea538df3e854, + 0xc01d176c6e042eee, + 0xf5fcc4caabc75699, + 0x1f99972699a38960, + 0x30d4cc8256bf963d, + 0xa3634826edcfefff, + 0x34f3bd0c8e5a4b38, + 0x0000000000001d28, +])); + +/// G2_GENERATOR_Y_C2 = +/// 10936269922612615564271188303104593362724754284143779051599749016735041389483971486958818324356025479751246744831831158558101688599198721653921723013062333636402617118847009085485166284126970598561393411916461254016145116183331671450721 +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C2: Fq = field_new!(Fq, BigInteger832([ + 0xfc478105dedf3654, + 0xa6fcfcfdd2710d6a, + 0x05a68c283d5d4c65, + 0x9fab8d94c667a679, + 0x009b0a616ea54ff9, + 0xf0df517bc7bc6382, + 0xdb44338e7491f5b7, + 0xcd192a7e53453f45, + 0xa041a7a60982d92c, + 0x4dd01c62bae4c7ff, + 0x79a69a54e6b66178, + 0xd47b0bfe832b05f8, + 0x00000000000000ef, +])); diff --git a/cp6_782/src/curves/mod.rs b/cp6_782/src/curves/mod.rs new file mode 100644 index 0000000..b6fdebb --- /dev/null +++ b/cp6_782/src/curves/mod.rs @@ -0,0 +1,223 @@ +use ark_ec::{models::SWModelParameters, PairingEngine}; +use ark_ff::{ + biginteger::BigInteger832, + field_new, + fields::{BitIteratorBE, Field, FpParameters}, + One, +}; + +use crate::{Fq, Fq3, Fq6, FqParameters, Fr}; + +pub mod g1; +pub use self::g1::{G1Affine, G1Projective}; + +pub mod g2; +pub use self::g2::{G2Affine, G2Projective}; + +#[cfg(test)] +mod tests; + +pub type GT = Fq6; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CP6_782; + +impl PairingEngine for CP6_782 { + type Fr = Fr; + type G1Projective = G1Projective; + type G1Affine = G1Affine; + type G1Prepared = G1Affine; + type G2Projective = G2Projective; + type G2Affine = G2Affine; + type G2Prepared = G2Affine; + type Fq = Fq; + type Fqe = Fq3; + type Fqk = Fq6; + + fn miller_loop<'a, I>(i: I) -> Self::Fqk + where + I: IntoIterator, + { + let mut result = Self::Fqk::one(); + for &(ref p, ref q) in i { + result *= &CP6_782::ate_miller_loop(p, q); + } + result + } + + fn final_exponentiation(r: &Self::Fqk) -> Option { + Some(CP6_782::final_exponentiation(r)) + } +} + +impl CP6_782 { + pub fn ate_pairing(p: &G1Affine, q: &G2Affine) -> GT { + CP6_782::final_exponentiation(&CP6_782::ate_miller_loop(p, q)) + } + + fn ate_miller_loop(p: &G1Affine, q: &G2Affine) -> Fq6 { + let px = p.x; + let py = p.y; + let qx = q.x; + let qy = q.y; + let mut py_twist_squared = TWIST.square(); + py_twist_squared.mul_assign_by_fp(&py); + + let mut old_rx; + let mut old_ry; + let mut rx = qx; + let mut ry = qy; + let mut f = Fq6::one(); + + // The for loop is executed for all bits (EXCEPT the MSB itself) of + // cp6_782_param_p (skipping leading zeros) in MSB to LSB order + for bit in BitIteratorBE::without_leading_zeros(ATE_LOOP_COUNT).skip(1) { + old_rx = rx; + old_ry = ry; + + let old_rx_square = old_rx.square(); + let old_rx_square_3 = old_rx_square.double() + &old_rx_square; + let old_rx_square_3_a = old_rx_square_3 + &g2::Parameters::COEFF_A; + let old_ry_double_inverse = old_ry.double().inverse().unwrap(); + + let gamma = old_rx_square_3_a * &old_ry_double_inverse; + let gamma_twist = gamma * &TWIST; + let gamma_old_rx = gamma * &old_rx; + let mut gamma_twist_px = gamma_twist; + gamma_twist_px.mul_assign_by_fp(&px); + + let x = py_twist_squared; + let y = gamma_old_rx - &old_ry - &gamma_twist_px; + let ell_rr_at_p = Fq6::new(x, y); + + rx = gamma.square() - &old_rx.double(); + ry = gamma * &(old_rx - &rx) - &old_ry; + f = f.square() * &ell_rr_at_p; + + if bit { + old_rx = rx; + old_ry = ry; + + let gamma = (old_ry - &qy) * &((old_rx - &qx).inverse().unwrap()); + let gamma_twist = gamma * &TWIST; + let gamma_qx = gamma * &qx; + let mut gamma_twist_px = gamma_twist; + gamma_twist_px.mul_assign_by_fp(&px); + + let x = py_twist_squared; + let y = gamma_qx - &qy - &gamma_twist_px; + let ell_rq_at_p = Fq6::new(x, y); + + rx = gamma.square() - &old_rx - &qx; + ry = gamma * &(old_rx - &rx) - &old_ry; + f = f * &ell_rq_at_p; + } + } + f + } + + fn final_exponentiation(value: &Fq6) -> GT { + let value_inv = value.inverse().unwrap(); + let value_to_first_chunk = CP6_782::final_exponentiation_first(value, &value_inv); + let value_inv_to_first_chunk = CP6_782::final_exponentiation_first(&value_inv, value); + CP6_782::final_exponentiation_last(&value_to_first_chunk, &value_inv_to_first_chunk) + } + + fn final_exponentiation_first(elt: &Fq6, elt_inv: &Fq6) -> Fq6 { + // (q^3-1)*(q+1) + + // elt_q3 = elt^(q^3) + let mut elt_q3 = elt.clone(); + elt_q3.frobenius_map(3); + // elt_q3_over_elt = elt^(q^3-1) + let elt_q3_over_elt = elt_q3 * elt_inv; + // alpha = elt^((q^3-1) * q) + let mut alpha = elt_q3_over_elt.clone(); + alpha.frobenius_map(1); + // beta = elt^((q^3-1)*(q+1) + alpha * &elt_q3_over_elt + } + + fn final_exponentiation_last(elt: &Fq6, elt_inv: &Fq6) -> Fq6 { + let mut elt_q = elt.clone(); + elt_q.frobenius_map(1); + + let w1_part = elt_q.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_W1); + let w0_part = if FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG { + elt_inv.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0) + } else { + elt.cyclotomic_exp(&FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0) + }; + + w1_part * &w0_part + } +} + +/// FQ_ZERO = 0 +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger832([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); + +/// FQ_ONE = 1 +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); + +/// TWIST = (0, 1, 0) +pub const TWIST: Fq3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + +/// ATE_IS_LOOP_COUNT_NEG = false +pub const ATE_IS_LOOP_COUNT_NEG: bool = false; + +/// ATE_LOOP_COUNT = +/// 506464946133393486072777102926336625944849939610982267859828541006717966526573193706126370441346337661774335955699621 +pub const ATE_LOOP_COUNT: [u64; 13] = [ + 0x55c5b9b57b942ae8, + 0x3d52287d3dfd424a, + 0xcf1ff9d6a543deb7, + 0x820c9c5711ceeebc, + 0x549a2d44305d20fe, + 0x50f5c131afd70235, + 0xab3596c8617c5792, + 0x830c728d80f9d78b, + 0x6a7223ee72023d07, + 0xbc5d176b746af026, + 0xe959283d8f526663, + 0xc4d2263babf8941f, + 0x3848, +]; + +/// FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG = true +pub const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = true; + +/// FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0 = +/// 7000705447348627246181409558336018323010329260726930841638672011287206690002601216854775649561085256265269640040570922609783227469279331691880282815325569032149343779036142830666859805506518426649197067288711084398033 +pub const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger832 = BigInteger832([ + 0xb62ef36af72855d1, + 0x676b5cef49d290fa, + 0xd17fcf3c60947427, + 0x5b93d992bc1b2849, + 0x2171887cecd072cb, + 0x879a2873f1516f4a, + 0x8cc6856bd2cdf24e, + 0xbff4fb6644d01993, + 0x5dcbeea3e31ea667, + 0x5f256f47681649f3, + 0x2355a2b0839967fe, + 0x144ed, + 0x0, +]); + +/// FINAL_EXPONENT_LAST_CHUNK_W1 = +/// 86482221941698704497288378992285180119495364068003923046442785886272123124361700722982503222189455144364945735564951562986 +pub const FINAL_EXPONENT_LAST_CHUNK_W1: BigInteger832 = BigInteger832([ + 0x5657b9b57b942aea, + 0x84f9a65f3bd54eaf, + 0x5ea4214e35cd127, + 0xe3cbcbc14ec1501d, + 0xf196cb845a3092ab, + 0x7e14627ad0e19017, + 0x217db4, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, +]); diff --git a/cp6_782/src/curves/tests.rs b/cp6_782/src/curves/tests.rs new file mode 100644 index 0000000..e002224 --- /dev/null +++ b/cp6_782/src/curves/tests.rs @@ -0,0 +1,77 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = CP6_782::pairing(sa, b); + let ans2 = CP6_782::pairing(a, sb); + let ans3 = CP6_782::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq6::one()); + assert_ne!(ans2, Fq6::one()); + assert_ne!(ans3, Fq6::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq6::one()); +} diff --git a/cp6_782/src/fields/fq.rs b/cp6_782/src/fields/fq.rs new file mode 100644 index 0000000..54ae116 --- /dev/null +++ b/cp6_782/src/fields/fq.rs @@ -0,0 +1,166 @@ +use ark_ff::{ + biginteger::BigInteger832 as BigInteger, + fields::{FftParameters, Fp832, Fp832Parameters, FpParameters}, +}; + +pub type Fq = Fp832; + +pub struct FqParameters; + +impl Fp832Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 3; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 18044746167194862600u64, + 63590321303744709u64, + 5009346151370959890u64, + 2859114157767503991u64, + 8301813204852325413u64, + 5629414263664332594u64, + 2637340888701394641u64, + 17433538052687852753u64, + 2230763098934759248u64, + 3785382115983092023u64, + 8895511354022222370u64, + 15792083141709071785u64, + 1328u64, + ]); +} +impl FpParameters for FqParameters { + /// MODULUS = 22369874298875696930346742206501054934775599465297184582183496627646774052458024540232479018147881220178054575403841904557897715222633333372134756426301062487682326574958588001132586331462553235407484089304633076250782629492557320825577 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xdace79b57b942ae9, + 0x545d85c16dfd424a, + 0xee135c065f4d26b7, + 0x9c2f764a12c4024b, + 0x1ad533049cfe6a39, + 0x52a3fb77c79c1320, + 0xab3596c8617c5792, + 0x830c728d80f9d78b, + 0x6a7223ee72023d07, + 0xbc5d176b746af026, + 0xe959283d8f526663, + 0xc4d2263babf8941f, + 0x3848, + ]); + + const MODULUS_BITS: u32 = 782; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 50; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 11190988450819017841u64, + 16170411717126802030u64, + 2265463223430229059u64, + 16946880912571045974u64, + 11155248462028513229u64, + 12855672356664541314u64, + 8489376931127408159u64, + 2655797810825538098u64, + 9648483887143916718u64, + 17514963461276738952u64, + 16777089214204267338u64, + 15649035958020076168u64, + 8659u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 13983406830510863714u64, + 17863856572171232656u64, + 1698388424046564526u64, + 1773634430448388392u64, + 8684647957094413275u64, + 3992637317298078843u64, + 18420879196616862245u64, + 3238482510270583127u64, + 7928200707794018216u64, + 10024831010452223910u64, + 9613847725664942650u64, + 15361265984156787358u64, + 7833u64, + ]); + + const INV: u64 = 14469047335842394791u64; + + /// GENERATOR = 13 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 16669393626057438558u64, + 1640520694378723217u64, + 1598646156981121135u64, + 12401834967100173388u64, + 2356467520877704673u64, + 14759118825104212161u64, + 5556628239575210651u64, + 5317520392768798654u64, + 16398429955031064995u64, + 3556102264904210145u64, + 8166834915717907988u64, + 11926665585800594452u64, + 11716u64, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x6d673cdabdca1574, + 0xaa2ec2e0b6fea125, + 0xf709ae032fa6935b, + 0xce17bb2509620125, + 0xd6a99824e7f351c, + 0x2951fdbbe3ce0990, + 0xd59acb6430be2bc9, + 0xc1863946c07cebc5, + 0x353911f739011e83, + 0xde2e8bb5ba357813, + 0xf4ac941ec7a93331, + 0x6269131dd5fc4a0f, + 0x1c24, + ]); + + // (T - 1)/2 = + // 1398117143679731058146671387906315933423474966581074036386468539227923378278626533764529938634242576261128410962740119034868607201414583335758422276643816405480145410934911750070786645716409577212967755581539567265673914343284832551598 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xadace79b57b942ae, + 0x7545d85c16dfd424, + 0xbee135c065f4d26b, + 0x99c2f764a12c4024, + 0x1ad533049cfe6a3, + 0x252a3fb77c79c132, + 0xbab3596c8617c579, + 0x7830c728d80f9d78, + 0x66a7223ee72023d0, + 0x3bc5d176b746af02, + 0xfe959283d8f52666, + 0x8c4d2263babf8941, + 0x384, + ]); + + // T = + // 2796234287359462116293342775812631866846949933162148072772937078455846756557253067529059877268485152522256821925480238069737214402829166671516844553287632810960290821869823500141573291432819154425935511163079134531347828686569665103197 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x5b59cf36af72855d, + 0xea8bb0b82dbfa849, + 0x7dc26b80cbe9a4d6, + 0x3385eec942588049, + 0x35aa660939fcd47, + 0x4a547f6ef8f38264, + 0x7566b2d90c2f8af2, + 0xf0618e51b01f3af1, + 0xcd4e447dce4047a0, + 0x778ba2ed6e8d5e04, + 0xfd2b2507b1ea4ccc, + 0x189a44c7757f1283, + 0x709, + ]); +} diff --git a/cp6_782/src/fields/fq3.rs b/cp6_782/src/fields/fq3.rs new file mode 100644 index 0000000..4f98d4c --- /dev/null +++ b/cp6_782/src/fields/fq3.rs @@ -0,0 +1,204 @@ +use crate::Fq; +use ark_ff::{ + biginteger::BigInteger832 as BigInteger, + field_new, + fields::fp3::{Fp3, Fp3Parameters}, + Field, +}; + +pub type Fq3 = Fp3; + +pub struct Fq3Parameters; + +impl Fp3Parameters for Fq3Parameters { + type Fp = Fq; + + /// NONRESIDUE = 13 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0xe755952f4650755e, + 0x16c44ce1331ef791, + 0x162f8835b467306f, + 0xac1c2b31e1062c4c, + 0x20b3dab9a2a935e1, + 0xccd2ec5fd01e00c1, + 0x4d1d1bf190c8da9b, + 0x49cba09fb0e13fbe, + 0xe392ed2957c061a3, + 0x3159d02b3c93d6e1, + 0x71566d160a9f8614, + 0xa5840728fc854414, + 0x2dc4, + ])); + + const TWO_ADICITY: u32 = 3; + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + 0x62730e2cd2029617, + 0x660647f735cb88cf, + 0x274359d60784f69d, + 0x83067194eb102629, + 0x54ea4a12a9381160, + 0xade0b24e398dac25, + 0xb476ae9f927e81cb, + 0x220fd4a9178adc3b, + 0x57e0cb9b0569745b, + 0xba15024addc8f52e, + 0x145b9bc116144ab6, + 0x6bc2260726e88b15, + 0x51da6bf151066474, + 0x9fd1b3190f6320cf, + 0x2097bfb7bf4167b0, + 0x27c35b1e7e628e09, + 0x94f80c9d623dd9bb, + 0x20bfa6d5bf31e7d3, + 0x19fb862c049d3a8, + 0xdf4c5efe04c0cec1, + 0x32c9a8abe9b50297, + 0x268d5c2076b44f0a, + 0x76027ec67b23ca21, + 0x248d61e0c45d270, + 0x419cd0d1d6be027e, + 0xbcd8dc3b1986ef18, + 0x73093d8719c862c2, + 0x651d60f8f9f6fcd9, + 0x8dabebe38a09b261, + 0xfa85b5a9e180cd3f, + 0x6a97fc618f319fb7, + 0xce08b93a5652a8e1, + 0x37525cbc4ba24cf9, + 0xb104c580df9d2150, + 0x1407c1bfe240a89d, + 0x34c96a73372daf9a, + 0x2b87fda171, + ]; + + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 0x59987c0ef8e31739, + 0x59578d750d6f57dd, + 0x9672547570dddab8, + 0x1a1f630e1d6dbdd5, + 0xde15f46e52d7613e, + 0x6a1b6e4f80179926, + 0x461ad119d93123b, + 0x12054e3654907ed9, + 0x85ea06b12bf811a0, + 0xc01d53d07347f9ec, + 0x70c424eb666c3922, + 0x1796ce4ed605d49e, + 0x68b, + ])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + ); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x9b4e60b420910c71, + 0xe068d7c83f284a6e, + 0x1f708acc7c452c43, + 0xeb2f6a66cca51856, + 0x9acf675f886e9fcd, + 0xb26885e567cc8082, + 0x75d05357183eb61f, + 0x24db4a09b5842a32, + 0x85e64cf9ba4b14ae, + 0xf311a6784358a588, + 0xe8d431c061aecb4a, + 0xd92c8b4aab19f288, + 0x21d3, + ])), + field_new!(Fq, BigInteger([ + 0xe793e750fc0c0fdc, + 0x28cd75f5634a867e, + 0xde5e9b1261eb3c33, + 0x68a0fb1c17595903, + 0x19626d2c9f392e46, + 0xc4d95794cb378b83, + 0x54870f1f582d67c9, + 0xf3f1a0ac4aceb56d, + 0x811361215ea4fd47, + 0x32cd6ee17d95bd00, + 0x725f9881049a9c52, + 0x5acb70be0613a307, + 0x11bb, + ])), + field_new!(Fq, BigInteger([ + 0x57ec31b05ef70e9c, + 0x4b273803cb8a715d, + 0xf0443627811cbe40, + 0x485f10c72ec590f1, + 0x66a35e7875569c25, + 0xdb621dfd9498071a, + 0xe0de3451f11039a8, + 0x6a3f87d780a6f7eb, + 0x637875d359122b11, + 0x967e0211b37c8d9d, + 0x8e255dfc2908fec6, + 0x90da2a32facafe8f, + 0x4b9, + ])), + ]; + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C2: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x9b4e60b420910c71, + 0xe068d7c83f284a6e, + 0x1f708acc7c452c43, + 0xeb2f6a66cca51856, + 0x9acf675f886e9fcd, + 0xb26885e567cc8082, + 0x75d05357183eb61f, + 0x24db4a09b5842a32, + 0x85e64cf9ba4b14ae, + 0xf311a6784358a588, + 0xe8d431c061aecb4a, + 0xd92c8b4aab19f288, + 0x21d3, + ])), + field_new!(Fq, BigInteger([ + 0x57ec31b05ef70e9c, + 0x4b273803cb8a715d, + 0xf0443627811cbe40, + 0x485f10c72ec590f1, + 0x66a35e7875569c25, + 0xdb621dfd9498071a, + 0xe0de3451f11039a8, + 0x6a3f87d780a6f7eb, + 0x637875d359122b11, + 0x967e0211b37c8d9d, + 0x8e255dfc2908fec6, + 0x90da2a32facafe8f, + 0x4b9, + ])), + field_new!(Fq, BigInteger([ + 0xe793e750fc0c0fdc, + 0x28cd75f5634a867e, + 0xde5e9b1261eb3c33, + 0x68a0fb1c17595903, + 0x19626d2c9f392e46, + 0xc4d95794cb378b83, + 0x54870f1f582d67c9, + 0xf3f1a0ac4aceb56d, + 0x811361215ea4fd47, + 0x32cd6ee17d95bd00, + 0x725f9881049a9c52, + 0x5acb70be0613a307, + 0x11bb, + ])), + ]; + + #[inline(always)] + fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp { + let original = *fe; + let mut four_fe = fe.double(); + four_fe.double_in_place(); + let eight_fe = four_fe.double(); + eight_fe + &four_fe + &original + } +} diff --git a/cp6_782/src/fields/fq6.rs b/cp6_782/src/fields/fq6.rs new file mode 100644 index 0000000..26f50b5 --- /dev/null +++ b/cp6_782/src/fields/fq6.rs @@ -0,0 +1,112 @@ +use crate::{Fq, Fq3, Fq3Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger832 as BigInteger, + field_new, + fields::fp6_2over3::{Fp6, Fp6Parameters}, +}; + +pub type Fq6 = Fp6; + +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp3Params = Fq3Parameters; + + /// NONRESIDUE = (0, 1, 0). + #[rustfmt::skip] + const NONRESIDUE: Fq3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0x9b4e60b420910c71, + 0xe068d7c83f284a6e, + 0x1f708acc7c452c43, + 0xeb2f6a66cca51856, + 0x9acf675f886e9fcd, + 0xb26885e567cc8082, + 0x75d05357183eb61f, + 0x24db4a09b5842a32, + 0x85e64cf9ba4b14ae, + 0xf311a6784358a588, + 0xe8d431c061aecb4a, + 0xd92c8b4aab19f288, + 0x21d3, + ])), + field_new!(Fq, BigInteger([ + 0x82e248051c9d1c4d, + 0x9364dbda272d0ed, + 0xfdcf25dede306877, + 0x53d06582e3fe7159, + 0xb431d48c27a7ce14, + 0x7741dd7a33040c05, + 0xca576276706c1de9, + 0x18cceab60052df9f, + 0x6f9ae1b18f011f6, + 0x25df1559c0ee6289, + 0x5b33ca416649679d, + 0x33f7fc08b12d9590, + 0x338f, + ])), + field_new!(Fq, BigInteger([ + 0xe793e750fc0c0fdc, + 0x28cd75f5634a867e, + 0xde5e9b1261eb3c33, + 0x68a0fb1c17595903, + 0x19626d2c9f392e46, + 0xc4d95794cb378b83, + 0x54870f1f582d67c9, + 0xf3f1a0ac4aceb56d, + 0x811361215ea4fd47, + 0x32cd6ee17d95bd00, + 0x725f9881049a9c52, + 0x5acb70be0613a307, + 0x11bb, + ])), + field_new!(Fq, BigInteger([ + 0x3f8019015b031e78, + 0x73f4adf92ed4f7dc, + 0xcea2d139e307fa73, + 0xb1000be3461ee9f5, + 0x8005cba5148fca6b, + 0xa03b75925fcf929d, + 0x35654371493da172, + 0x5e312883cb75ad59, + 0xe48bd6f4b7b72859, + 0xc94b70f331124a9d, + 0x84f67d2da39b18, + 0xeba59af100dea197, + 0x1674, + ])), + field_new!(Fq, BigInteger([ + 0x57ec31b05ef70e9c, + 0x4b273803cb8a715d, + 0xf0443627811cbe40, + 0x485f10c72ec590f1, + 0x66a35e7875569c25, + 0xdb621dfd9498071a, + 0xe0de3451f11039a8, + 0x6a3f87d780a6f7eb, + 0x637875d359122b11, + 0x967e0211b37c8d9d, + 0x8e255dfc2908fec6, + 0x90da2a32facafe8f, + 0x4b9, + ])), + field_new!(Fq, BigInteger([ + 0xf33a92647f881b0d, + 0x2b900fcc0ab2bbcb, + 0xfb4c0f3fd61ea84, + 0x338e7b2dfb6aa948, + 0x172c5d7fdc53bf3, + 0x8dcaa3e2fc64879d, + 0x56ae87a9094eefc8, + 0x8f1ad1e1362b221e, + 0xe95ec2cd135d3fbf, + 0x898fa889f6d53325, + 0x76f98fbc8ab7ca11, + 0x6a06b57da5e4f118, + 0x268d, + ])), + ]; +} diff --git a/cp6_782/src/fields/fr.rs b/cp6_782/src/fields/fr.rs new file mode 100644 index 0000000..63c94bb --- /dev/null +++ b/cp6_782/src/fields/fr.rs @@ -0,0 +1 @@ +pub use ark_bls12_377::{Fq as Fr, FqParameters as FrParameters}; diff --git a/cp6_782/src/fields/mod.rs b/cp6_782/src/fields/mod.rs new file mode 100644 index 0000000..2da6aa6 --- /dev/null +++ b/cp6_782/src/fields/mod.rs @@ -0,0 +1,14 @@ +pub mod fr; +pub use self::fr::*; + +pub mod fq; +pub use self::fq::*; + +pub mod fq3; +pub use self::fq3::*; + +pub mod fq6; +pub use self::fq6::*; + +#[cfg(all(feature = "cp6_782", test))] +mod tests; diff --git a/cp6_782/src/fields/tests.rs b/cp6_782/src/fields/tests.rs new file mode 100644 index 0000000..0609b52 --- /dev/null +++ b/cp6_782/src/fields/tests.rs @@ -0,0 +1,51 @@ +use ark_ff::{test_rng, Field, PrimeField}; +use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); + sqrt_field_test(a); + + let byte_size = a.serialized_size(); + let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits()); + assert_eq!(byte_size, buffer_size); + field_serialization_test::(byte_size); +} + +#[test] +fn test_fq3() { + let mut rng = test_rng(); + let a: Fq3 = rng.gen(); + let b: Fq3 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + let a: Fq6 = rng.gen(); + let b: Fq6 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/cp6_782/src/lib.rs b/cp6_782/src/lib.rs new file mode 100644 index 0000000..53ce5e7 --- /dev/null +++ b/cp6_782/src/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the CP6_782 curve generated in [[BCGMMW20, “Zexe”]](https://eprint.iacr.org/2018/962). +//! The name denotes that it was generated using the Cocks--Pinch method for the embedding degree 6. +//! The main feature of this curve is that the scalar field equals the base field of the BLS12_377 curve. +//! +//! Curve information: +//! * Base field: q = 22369874298875696930346742206501054934775599465297184582183496627646774052458024540232479018147881220178054575403841904557897715222633333372134756426301062487682326574958588001132586331462553235407484089304633076250782629492557320825577 +//! * Scalar field: r = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +//! * valuation(q - 1, 2) = 3 +//! * valuation(r - 1, 2) = 46 +//! +//! G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 5, +//! * b = 17764315118651679038286329069295091506801468118146712649886336045535808055361274148466772191243305528312843236347777260247138934336850548243151534538734724191505953341403463040067571652261229308333392040104884438208594329793895206056414, +//! +//! G2 curve equation: y^2 = x^3 + Ax + B +//! * A = Fq3(0, 0, 5) +//! * B = Fq3(7237353553714858194254855835825640240663090882935418626687402315497764195116318527743248304684159666286416318482685337633828994152723793439622384740540789612754127688659139509552568164770448654259255628317166934203899992395064470477612, 0, 0) + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/curve-benches/Cargo.toml b/curve-benches/Cargo.toml new file mode 100644 index 0000000..4acabba --- /dev/null +++ b/curve-benches/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "ark-curve-benches" +version = "0.1.1-alpha.0" +authors = [ + "Sean Bowe", + "Alessandro Chiesa", + "Matthew Green", + "Ian Miers", + "Pratyush Mishra", + "Howard Wu" +] +description = "A benchmark library for finite fields and elliptic curves" +homepage = "https://arkworks.rs" +repository = "https://github.com/arkworks-rs/algebra" +documentation = "https://docs.rs/algebra/" +keywords = ["cryptography", "finite fields", "elliptic curves", "pairing"] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" +publish = false +build = "build.rs" + +################################# Dependencies ################################ + +[dependencies] +ark-ec = { git = "https://github.com/arkworks-rs/algebra" } +ark-ff = { git = "https://github.com/arkworks-rs/algebra" } +ark-serialize = { git = "https://github.com/arkworks-rs/algebra" } + +ark-mnt4-298 = { path = "../mnt4_298", optional = true } +ark-mnt6-298 = { path = "../mnt6_298", optional = true } +ark-mnt4-753 = { path = "../mnt4_753", optional = true } +ark-mnt6-753 = { path = "../mnt6_753", optional = true } +ark-bn254 = { path = "../bn254", default-features = false, optional = true } +ark-bls12-377 = { path = "../bls12_377", optional = true } +ark-bls12-381 = { path = "../bls12_381", optional = true } +ark-bw6-761 = { path = "../bw6_761", optional = true } +ark-cp6-782 = { path = "../cp6_782", optional = true } + +rand = "0.7" +rand_xorshift = { version = "0.2" } +paste = "1.0" + +[features] +asm = [ "ark-ff/asm"] +n_fold = [] + +[build-dependencies] +rustc_version = "0.2" diff --git a/curve-benches/LICENSE-APACHE b/curve-benches/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/curve-benches/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/curve-benches/LICENSE-MIT b/curve-benches/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/curve-benches/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/curve-benches/build.rs b/curve-benches/build.rs new file mode 100644 index 0000000..f71f6fb --- /dev/null +++ b/curve-benches/build.rs @@ -0,0 +1,9 @@ +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if version_meta().expect("nightly check failed").channel == Channel::Nightly { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/curve-benches/src/curves/bls12_377.rs b/curve-benches/src/curves/bls12_377.rs new file mode 100644 index 0000000..3e7ea3c --- /dev/null +++ b/curve-benches/src/curves/bls12_377.rs @@ -0,0 +1,23 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_bls12_377::bls12_377::{ + fq::Fq, fq2::Fq2, fr::Fr, Bls12_377, Fq12, G1Affine, G1Projective as G1, G2Affine, + G2Projective as G2, Parameters, +}; +use ark_ec::{ + bls12::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::{BigInteger256 as FrRepr, BigInteger384 as FqRepr}, + BigInteger, Field, PrimeField, SquareRootField, UniformRand, +}; + +ec_bench!(); +f_bench!(1, Fq2, Fq2, fq2); +f_bench!(2, Fq12, Fq12, fq12); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +f_bench!(Fr, Fr, FrRepr, FrRepr, fr); +pairing_bench!(Bls12_377, Fq12, prepared_v); diff --git a/curve-benches/src/curves/bls12_381.rs b/curve-benches/src/curves/bls12_381.rs new file mode 100644 index 0000000..2b5e2ce --- /dev/null +++ b/curve-benches/src/curves/bls12_381.rs @@ -0,0 +1,23 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_bls12_381::bls12_381::{ + fq::Fq, fq2::Fq2, fr::Fr, Bls12_381, Fq12, G1Affine, G1Projective as G1, G2Affine, + G2Projective as G2, Parameters, +}; +use ark_ec::{ + bls12::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::{BigInteger256 as FrRepr, BigInteger384 as FqRepr}, + BigInteger, Field, PrimeField, SquareRootField, UniformRand, +}; + +ec_bench!(); +f_bench!(1, Fq2, Fq2, fq2); +f_bench!(2, Fq12, Fq12, fq12); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +f_bench!(Fr, Fr, FrRepr, FrRepr, fr); +pairing_bench!(Bls12_381, Fq12, prepared_v); diff --git a/curve-benches/src/curves/bn254.rs b/curve-benches/src/curves/bn254.rs new file mode 100644 index 0000000..9ef4b83 --- /dev/null +++ b/curve-benches/src/curves/bn254.rs @@ -0,0 +1,23 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_ec::{ + bn::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ef::{ + biginteger::{BigInteger256 as FrRepr, BigInteger256 as FqRepr}, + BigInteger, Field, PrimeField, SquareRootField, UniformRand, +}; +use ark_en254::bn254::{ + fq::Fq, fq2::Fq2, fr::Fr, Bls12_381, Fq12, G1Affine, G1Projective as G1, G2Affine, + G2Projective as G2, Parameters, +}; + +ec_bench!(); +f_bench!(1, Fq2, Fq2, fq2); +f_bench!(2, Fq12, Fq12, fq12); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +f_bench!(Fr, Fr, FrRepr, FrRepr, fr); +pairing_bench!(Bn254, Fq12, prepared_v); diff --git a/curve-benches/src/curves/bw6_761.rs b/curve-benches/src/curves/bw6_761.rs new file mode 100644 index 0000000..e0ec223 --- /dev/null +++ b/curve-benches/src/curves/bw6_761.rs @@ -0,0 +1,23 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_bls12_377::bw6_761::{ + fq::Fq, fq3::Fq3, fr::Fr, Fq6, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + Parameters, BW6_761, +}; +use ark_ec::{ + bw6::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::{BigInteger384 as FrRepr, BigInteger768 as FqRepr}, + BigInteger, Field, PrimeField, SquareRootField, UniformRand, +}; + +ec_bench!(); +f_bench!(1, Fq3, Fq3, fq3); +f_bench!(2, Fq6, Fq6, fq6); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +f_bench!(Fr, Fr, FrRepr, FrRepr, fr); +pairing_bench!(BW6_761, Fq6, prepared_v); diff --git a/curve-benches/src/curves/cp6_782.rs b/curve-benches/src/curves/cp6_782.rs new file mode 100644 index 0000000..ca3f5da --- /dev/null +++ b/curve-benches/src/curves/cp6_782.rs @@ -0,0 +1,20 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_bls12_377::cp6_782::{ + fq::Fq, fq3::Fq3, fr::Fr, Fq6, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + CP6_782, +}; +use ark_ec::{PairingEngine, ProjectiveCurve}; +use ark_ff::{ + biginteger::{BigInteger384 as FrRepr, BigInteger832 as FqRepr}, + BigInteger, Field, PrimeField, SquareRootField, UniformRand, +}; + +ec_bench!(); +f_bench!(1, Fq3, Fq3, fq3); +f_bench!(2, Fq6, Fq6, fq6); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +f_bench!(Fr, Fr, FrRepr, FrRepr, fr); +pairing_bench!(CP6_782, Fq6, affine_v); diff --git a/curve-benches/src/curves/mnt4_298.rs b/curve-benches/src/curves/mnt4_298.rs new file mode 100644 index 0000000..9b47966 --- /dev/null +++ b/curve-benches/src/curves/mnt4_298.rs @@ -0,0 +1,22 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_ec::{ + mnt4::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::BigInteger320 as FqRepr, BigInteger, Field, PrimeField, SquareRootField, + UniformRand, +}; +use ark_mnt_298::mnt4_298::{ + fq::Fq, fq2::Fq2, fr::Fr, Fq4, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + Parameters, MNT4_298, +}; + +ec_bench!(); +f_bench!(1, Fq2, Fq2, fq2); +f_bench!(2, Fq4, Fq4, fq4); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +pairing_bench!(MNT4_298, Fq4, prepared_v); diff --git a/curve-benches/src/curves/mnt4_753.rs b/curve-benches/src/curves/mnt4_753.rs new file mode 100644 index 0000000..d83d4f9 --- /dev/null +++ b/curve-benches/src/curves/mnt4_753.rs @@ -0,0 +1,22 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_ec::{ + mnt4::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::BigInteger768 as FqRepr, BigInteger, Field, PrimeField, SquareRootField, + UniformRand, +}; +use ark_mnt_753::mnt4_753::{ + fq::Fq, fq2::Fq2, fr::Fr, Fq4, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + Parameters, MNT4_753, +}; + +ec_bench!(); +f_bench!(1, Fq2, Fq2, fq2); +f_bench!(2, Fq4, Fq4, fq4); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +pairing_bench!(MNT4_753, Fq4, prepared_v); diff --git a/curve-benches/src/curves/mnt6_298.rs b/curve-benches/src/curves/mnt6_298.rs new file mode 100644 index 0000000..30dd06f --- /dev/null +++ b/curve-benches/src/curves/mnt6_298.rs @@ -0,0 +1,22 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_ec::{ + mnt6::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::BigInteger320 as FqRepr, BigInteger, Field, PrimeField, SquareRootField, + UniformRand, +}; +use ark_mnt_298::mnt6_298::{ + fq::Fq, fq3::Fq3, fr::Fr, Fq6, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + Parameters, MNT6_298, +}; + +ec_bench!(); +f_bench!(1, Fq3, Fq3, fq3); +f_bench!(2, Fq6, Fq6, fq6); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +pairing_bench!(MNT6_298, Fq6, prepared_v); diff --git a/curve-benches/src/curves/mnt6_753.rs b/curve-benches/src/curves/mnt6_753.rs new file mode 100644 index 0000000..77c57b0 --- /dev/null +++ b/curve-benches/src/curves/mnt6_753.rs @@ -0,0 +1,22 @@ +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use std::ops::{AddAssign, MulAssign, SubAssign}; + +use ark_ec::{ + mnt6::{G1Prepared, G2Prepared}, + PairingEngine, ProjectiveCurve, +}; +use ark_ff::{ + biginteger::BigInteger768 as FqRepr, BigInteger, Field, PrimeField, SquareRootField, + UniformRand, +}; +use ark_mnt_753::mnt6_753::{ + fq::Fq, fq3::Fq3, fr::Fr, Fq6, G1Affine, G1Projective as G1, G2Affine, G2Projective as G2, + Parameters, MNT6_753, +}; + +ec_bench!(); +f_bench!(1, Fq3, Fq3, fq3); +f_bench!(2, Fq6, Fq6, fq6); +f_bench!(Fq, Fq, FqRepr, FqRepr, fq); +pairing_bench!(MNT6_753, Fq6, prepared_v); diff --git a/curve-benches/src/curves/mod.rs b/curve-benches/src/curves/mod.rs new file mode 100644 index 0000000..3a1dab9 --- /dev/null +++ b/curve-benches/src/curves/mod.rs @@ -0,0 +1,18 @@ +#[cfg(feature = "bls12_377")] +mod bls12_377; +#[cfg(feature = "bls12_381")] +mod bls12_381; +#[cfg(feature = "bn254")] +mod bn254; +#[cfg(feature = "bw6_761")] +mod bw6_761; +#[cfg(feature = "cp6_782")] +mod cp6_782; +#[cfg(feature = "mnt4_298")] +mod mnt4_298; +#[cfg(feature = "mnt4_753")] +mod mnt4_753; +#[cfg(feature = "mnt6_298")] +mod mnt6_298; +#[cfg(feature = "mnt6_753")] +mod mnt6_753; diff --git a/curve-benches/src/lib.rs b/curve-benches/src/lib.rs new file mode 100644 index 0000000..0a70245 --- /dev/null +++ b/curve-benches/src/lib.rs @@ -0,0 +1,12 @@ +#![cfg_attr(nightly, feature(test))] +#![allow(unused_macros, unused_imports)] + +#[cfg(nightly)] +extern crate test; + +#[cfg(all(nightly, test))] +#[macro_use] +pub mod macros; + +#[cfg(all(nightly, test))] +mod curves; diff --git a/curve-benches/src/macros/ec.rs b/curve-benches/src/macros/ec.rs new file mode 100644 index 0000000..99c5288 --- /dev/null +++ b/curve-benches/src/macros/ec.rs @@ -0,0 +1,357 @@ +macro_rules! ec_bench { + () => { + #[bench] + fn bench_g1_rand(b: &mut ::test::Bencher) { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + b.iter(|| G1::rand(&mut rng)); + } + + #[bench] + fn bench_g1_mul_assign(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G1, Fr)> = (0..SAMPLES) + .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + tmp *= v[count].1; + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g1_add_assign(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G1, G1)> = (0..SAMPLES) + .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, add_assign, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G1, G1Affine)> = (0..SAMPLES) + .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, add_assign_mixed, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g1_double(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G1, G1)> = (0..SAMPLES) + .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, double_in_place); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g1_deser(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let tmp = G1::rand(&mut rng).into_affine(); + let v: Vec<_> = (0..SAMPLES) + .flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + tmp.serialize(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + G1Affine::deserialize(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn bench_g1_ser(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::CanonicalSerialize; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut v: Vec<_> = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); + let v = G1::batch_normalization_into_affine(v.as_mut_slice()); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize(&mut bytes) + }); + } + + #[bench] + fn bench_g1_deser_unchecked(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let tmp = G1::rand(&mut rng).into_affine(); + let v: Vec<_> = (0..SAMPLES) + .flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + tmp.serialize_unchecked(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + G1Affine::deserialize_unchecked(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn bench_g1_ser_unchecked(b: &mut ::test::Bencher) { + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut v: Vec<_> = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); + let v = G1::batch_normalization_into_affine(v.as_mut_slice()); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize_unchecked(&mut bytes) + }); + } + + #[bench] + fn bench_g2_rand(b: &mut ::test::Bencher) { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + b.iter(|| G2::rand(&mut rng)); + } + + #[bench] + fn bench_g2_mul_assign(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G2, Fr)> = (0..SAMPLES) + .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + tmp *= v[count].1; + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g2_add_assign(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G2, G2)> = (0..SAMPLES) + .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + tmp.add_assign(&v[count].1); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G2, G2Affine)> = (0..SAMPLES) + .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + tmp.add_assign_mixed(&v[count].1); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g2_double(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G2, G2)> = (0..SAMPLES) + .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + tmp.double_in_place(); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_g2_deser(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let tmp = G2::rand(&mut rng).into_affine(); + let v: Vec<_> = (0..SAMPLES) + .flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + tmp.serialize(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + G2Affine::deserialize(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn bench_g2_ser(b: &mut ::test::Bencher) { + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut v: Vec<_> = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); + let v = G2::batch_normalization_into_affine(v.as_mut_slice()); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize(&mut bytes) + }); + } + + #[bench] + fn bench_g2_deser_unchecked(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let tmp = G2::rand(&mut rng).into_affine(); + let v: Vec<_> = (0..SAMPLES) + .flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + tmp.serialize_unchecked(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + G2Affine::deserialize_unchecked(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn bench_g2_ser_unchecked(b: &mut ::test::Bencher) { + use ark_ec::ProjectiveCurve; + use ark_serialize::CanonicalSerialize; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut v: Vec<_> = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); + let v = G2::batch_normalization_into_affine(v.as_mut_slice()); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize_unchecked(&mut bytes) + }); + } + }; +} diff --git a/curve-benches/src/macros/field.rs b/curve-benches/src/macros/field.rs new file mode 100644 index 0000000..ee3d176 --- /dev/null +++ b/curve-benches/src/macros/field.rs @@ -0,0 +1,405 @@ +macro_rules! f_bench { + // Use this for base fields + ($f:ident, $f_type:ty, $f_repr:ident, $f_repr_type:ty, $field_ident:ident) => { + field_common!($f, $f_type, $field_ident); + sqrt!($f, $f_type, $field_ident); + field_base!($f, $f_type, $f_repr, $f_repr_type, $field_ident); + }; + // use this for intermediate fields + (1, $f:ident, $f_type:ty, $field_ident:ident) => { + field_common!($f, $f_type, $field_ident); + sqrt!($f, $f_type, $field_ident); + }; + // Use this for the full extension field Fqk + (2, $f:ident, $f_type:ty, $field_ident:ident) => { + field_common!($f, $f_type, $field_ident); + }; +} + +macro_rules! field_common { + ($f:ident, $f_type:ty, $field_ident:ident) => { + paste::item! { + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<_> = (0..SAMPLES) + .map(|_| ($f::rand(&mut rng), $f::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, add_assign, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<_> = (0..SAMPLES) + .map(|_| ($f::rand(&mut rng), $f::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, sub_assign, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<_> = (0..SAMPLES) + .map(|_| ($f::rand(&mut rng), $f::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, mul_assign, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count]; + n_fold!(tmp, double_in_place); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count]; + n_fold!(tmp, square_in_place); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let tmp = v[count].inverse(); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + use ark_serialize::{CanonicalSerialize, CanonicalDeserialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let v: Vec<_> = (0..SAMPLES).flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + let tmp = $f::rand(&mut rng); + tmp.serialize(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }).collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + $f_type::deserialize(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + use ark_serialize::CanonicalSerialize; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize(&mut bytes) + + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + use ark_serialize::{CanonicalSerialize, CanonicalDeserialize}; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let mut num_bytes = 0; + let v: Vec<_> = (0..SAMPLES).flat_map(|_| { + let mut bytes = Vec::with_capacity(1000); + let tmp = $f::rand(&mut rng); + tmp.serialize_unchecked(&mut bytes).unwrap(); + num_bytes = bytes.len(); + bytes + }).collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + let index = count * num_bytes; + $f_type::deserialize_unchecked(&v[index..(index + num_bytes)]).unwrap() + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + use ark_serialize::CanonicalSerialize; + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + let mut bytes = Vec::with_capacity(1000); + + let mut count = 0; + b.iter(|| { + let tmp = v[count]; + count = (count + 1) % SAMPLES; + bytes.clear(); + tmp.serialize_unchecked(&mut bytes) + + }); + } + } + }; +} + +macro_rules! sqrt { + ($f:ident, $f_type:ty, $field_ident:ident) => { + paste::item! { + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES) + .map(|_| { + let mut tmp = $f::rand(&mut rng); + tmp.square_in_place(); + tmp + }) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + v[count].sqrt() + }); + } + } + }; +} + +macro_rules! field_base { + ($f:ident, $f_type:ty, $f_repr:ident, $f_repr_type:ty, $field_ident:ident) => { + paste::item! { + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<_> = (0..SAMPLES) + .map(|_| { + let mut tmp1 = $f_repr::rand(&mut rng); + let mut tmp2 = $f_repr::rand(&mut rng); + // Shave a few bits off to avoid overflow. + for _ in 0..3 { + tmp1.div2(); + tmp2.div2(); + } + (tmp1, tmp2) + }) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, add_nocarry, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<_> = (0..SAMPLES) + .map(|_| { + let tmp1 = $f_repr::rand(&mut rng); + let mut tmp2 = tmp1; + // Ensure tmp2 is smaller than tmp1. + for _ in 0..10 { + tmp2.div2(); + } + (tmp1, tmp2) + }) + .collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count].0; + n_fold!(tmp, v, sub_noborrow, count); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_repr_type> = (0..SAMPLES).map(|_| $f_repr::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let tmp = v[count].num_bits(); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_repr_type> = (0..SAMPLES).map(|_| $f_repr::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count]; + n_fold!(tmp, mul2); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_repr_type> = (0..SAMPLES).map(|_| $f_repr::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count]; + n_fold!(tmp, div2); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + let mut tmp = v[count]; + tmp = -tmp; + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_type> = (0..SAMPLES).map(|_| $f::rand(&mut rng)).collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + v[count].into_repr() + }); + } + + #[bench] + fn [](b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$f_repr_type> = (0..SAMPLES) + .map(|_| $f::rand(&mut rng).into_repr()) + .collect(); + + let mut count = 0; + b.iter(|| { + count = (count + 1) % SAMPLES; + $f::from(v[count]) + }); + } + } + }; +} diff --git a/curve-benches/src/macros/mod.rs b/curve-benches/src/macros/mod.rs new file mode 100644 index 0000000..5c936a2 --- /dev/null +++ b/curve-benches/src/macros/mod.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod ec; + +#[macro_use] +mod field; + +#[macro_use] +mod pairing; + +#[macro_use] +mod utils; diff --git a/curve-benches/src/macros/pairing.rs b/curve-benches/src/macros/pairing.rs new file mode 100644 index 0000000..117391a --- /dev/null +++ b/curve-benches/src/macros/pairing.rs @@ -0,0 +1,61 @@ +macro_rules! pairing_bench { + ($curve:ident, $pairing_field:ident, $pairing_type:ident) => { + #[bench] + fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + $pairing_type!(v, rng); + + let mut count = 0; + b.iter(|| { + let tmp = $curve::miller_loop(&[(v[count].0.clone(), v[count].1.clone())]); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<$pairing_field> = (0..SAMPLES) + .map(|_| { + ( + G1Affine::from(G1::rand(&mut rng)).into(), + G2Affine::from(G2::rand(&mut rng)).into(), + ) + }) + .map(|(p, q)| $curve::miller_loop(&[(p, q)])) + .collect(); + + let mut count = 0; + b.iter(|| { + let tmp = $curve::final_exponentiation(&v[count]); + count = (count + 1) % SAMPLES; + tmp + }); + } + + #[bench] + fn bench_pairing_full(b: &mut ::test::Bencher) { + const SAMPLES: usize = 1000; + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + let v: Vec<(G1, G2)> = (0..SAMPLES) + .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) + .collect(); + + let mut count = 0; + b.iter(|| { + let tmp = $curve::pairing(v[count].0, v[count].1); + count = (count + 1) % SAMPLES; + tmp + }); + } + }; +} diff --git a/curve-benches/src/macros/utils.rs b/curve-benches/src/macros/utils.rs new file mode 100644 index 0000000..8d9881a --- /dev/null +++ b/curve-benches/src/macros/utils.rs @@ -0,0 +1,49 @@ +macro_rules! n_fold { + ($tmp:ident, $v:ident, $func:ident, $count:ident) => { + const ITERS: usize = 1000; + + #[cfg(not(feature = "n_fold"))] + $tmp.$func(&$v[$count].1); + #[cfg(feature = "n_fold")] + for _ in 0..ITERS { + $tmp.$func(&$v[$count].1); + } + }; + + ($tmp:ident, $func:ident) => { + const ITERS: usize = 1000; + + #[cfg(not(feature = "n_fold"))] + $tmp.$func(); + #[cfg(feature = "n_fold")] + for _ in 0..ITERS { + $tmp.$func(); + } + }; +} + +macro_rules! prepared_v { + ($v:ident, $rng:ident) => { + let $v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) + .map(|_| { + ( + G1Affine::from(G1::rand(&mut $rng)).into(), + G2Affine::from(G2::rand(&mut $rng)).into(), + ) + }) + .collect(); + }; +} + +macro_rules! affine_v { + ($v:ident, $rng:ident) => { + let $v: Vec<(G1Affine, G2Affine)> = (0..SAMPLES) + .map(|_| { + ( + G1Affine::from(G1::rand(&mut $rng)).into(), + G2Affine::from(G2::rand(&mut $rng)).into(), + ) + }) + .collect(); + }; +} diff --git a/curve-tests/Cargo.toml b/curve-tests/Cargo.toml new file mode 100644 index 0000000..d9c1d5a --- /dev/null +++ b/curve-tests/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "ark-curve-tests" +version = "0.1.0" +authors = [ + "Sean Bowe", + "Alessandro Chiesa", + "Matthew Green", + "Ian Miers", + "Pratyush Mishra", + "Howard Wu", + "arkworks contributors" +] +description = "A library for tests for finite fields, elliptic curves, and pairings" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-curve-tests/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +rand = { version = "0.7", default-features = false} +rand_xorshift = { version = "0.2", default-features = false} + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-serialize/std", "ark-ec/std" ] \ No newline at end of file diff --git a/curve-tests/LICENSE-APACHE b/curve-tests/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/curve-tests/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/curve-tests/LICENSE-MIT b/curve-tests/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/curve-tests/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/curve-tests/src/curves.rs b/curve-tests/src/curves.rs new file mode 100644 index 0000000..c34f9f9 --- /dev/null +++ b/curve-tests/src/curves.rs @@ -0,0 +1,531 @@ +#![allow(unused)] +use ark_ec::{ + AffineCurve, MontgomeryModelParameters, ProjectiveCurve, SWModelParameters, TEModelParameters, +}; +use ark_ff::{Field, One, PrimeField, UniformRand, Zero}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SWFlags, SerializationError}; +use ark_std::{io::Cursor, vec::Vec}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +pub const ITERATIONS: usize = 10; + +fn random_addition_test() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = G::rand(&mut rng); + let b = G::rand(&mut rng); + let c = G::rand(&mut rng); + let a_affine = a.into_affine(); + let b_affine = b.into_affine(); + let c_affine = c.into_affine(); + + // a + a should equal the doubling + { + let mut aplusa = a; + aplusa.add_assign(&a); + + let mut aplusamixed = a; + aplusamixed.add_assign_mixed(&a.into_affine()); + + let mut adouble = a; + adouble.double_in_place(); + + assert_eq!(aplusa, adouble); + assert_eq!(aplusa, aplusamixed); + } + + let mut tmp = vec![G::zero(); 6]; + + // (a + b) + c + tmp[0] = (a + &b) + &c; + + // a + (b + c) + tmp[1] = a + &(b + &c); + + // (a + c) + b + tmp[2] = (a + &c) + &b; + + // Mixed addition + + // (a + b) + c + tmp[3] = a_affine.into_projective(); + tmp[3].add_assign_mixed(&b_affine); + tmp[3].add_assign_mixed(&c_affine); + + // a + (b + c) + tmp[4] = b_affine.into_projective(); + tmp[4].add_assign_mixed(&c_affine); + tmp[4].add_assign_mixed(&a_affine); + + // (a + c) + b + tmp[5] = a_affine.into_projective(); + tmp[5].add_assign_mixed(&c_affine); + tmp[5].add_assign_mixed(&b_affine); + + // Comparisons + for i in 0..6 { + for j in 0..6 { + if tmp[i] != tmp[j] { + println!("{} \n{}", tmp[i], tmp[j]); + } + assert_eq!(tmp[i], tmp[j], "Associativity failed {} {}", i, j); + assert_eq!( + tmp[i].into_affine(), + tmp[j].into_affine(), + "Associativity failed" + ); + } + + assert!(tmp[i] != a); + assert!(tmp[i] != b); + assert!(tmp[i] != c); + + assert!(a != tmp[i]); + assert!(b != tmp[i]); + assert!(c != tmp[i]); + } + } +} + +fn random_multiplication_test() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let mut a = G::rand(&mut rng); + let mut b = G::rand(&mut rng); + let a_affine = a.into_affine(); + let b_affine = b.into_affine(); + + let s = G::ScalarField::rand(&mut rng); + + // s ( a + b ) + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.mul_assign(s); + + // sa + sb + a.mul_assign(s); + b.mul_assign(s); + + let mut tmp2 = a; + tmp2.add_assign(&b); + + // Affine multiplication + let mut tmp3 = a_affine.mul(s.into_repr()); + tmp3.add_assign(&b_affine.mul(s.into_repr())); + + assert_eq!(tmp1, tmp2); + assert_eq!(tmp1, tmp3); + } +} + +fn random_doubling_test() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let mut a = G::rand(&mut rng); + let mut b = G::rand(&mut rng); + + // 2(a + b) + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.double_in_place(); + + // 2a + 2b + a.double_in_place(); + b.double_in_place(); + + let mut tmp2 = a; + tmp2.add_assign(&b); + + let mut tmp3 = a; + tmp3.add_assign_mixed(&b.into_affine()); + + assert_eq!(tmp1, tmp2); + assert_eq!(tmp1, tmp3); + } +} + +fn random_negation_test() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let r = G::rand(&mut rng); + + let s = G::ScalarField::rand(&mut rng); + let sneg = -s; + assert!((s + &sneg).is_zero()); + + let mut t1 = r; + t1.mul_assign(s); + + let mut t2 = r; + t2.mul_assign(sneg); + + let mut t3 = t1; + t3.add_assign(&t2); + assert!(t3.is_zero()); + + let mut t4 = t1; + t4.add_assign_mixed(&t2.into_affine()); + assert!(t4.is_zero()); + + t1 = -t1; + assert_eq!(t1, t2); + } +} + +fn random_transformation_test() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let g = G::rand(&mut rng); + let g_affine = g.into_affine(); + let g_projective = g_affine.into_projective(); + assert_eq!(g, g_projective); + } + + // Batch normalization + for _ in 0..10 { + let mut v = (0..ITERATIONS) + .map(|_| G::rand(&mut rng)) + .collect::>(); + + for i in &v { + assert!(!i.is_normalized()); + } + + use rand::distributions::{Distribution, Uniform}; + let between = Uniform::from(0..ITERATIONS); + // Sprinkle in some normalized points + for _ in 0..5 { + v[between.sample(&mut rng)] = G::zero(); + } + for _ in 0..5 { + let s = between.sample(&mut rng); + v[s] = v[s].into_affine().into_projective(); + } + + let expected_v = v + .iter() + .map(|v| v.into_affine().into_projective()) + .collect::>(); + G::batch_normalization(&mut v); + + for i in &v { + assert!(i.is_normalized()); + } + + assert_eq!(v, expected_v); + } +} + +pub fn curve_tests() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + // Negation edge case with zero. + { + let z = -G::zero(); + assert!(z.is_zero()); + } + + // Doubling edge case with zero. + { + let mut z = -G::zero(); + z.double_in_place(); + assert!(z.is_zero()); + } + + // Addition edge cases with zero + { + let mut r = G::rand(&mut rng); + let rcopy = r; + r.add_assign(&G::zero()); + assert_eq!(r, rcopy); + r.add_assign_mixed(&G::Affine::zero()); + assert_eq!(r, rcopy); + + let mut z = G::zero(); + z.add_assign(&G::zero()); + assert!(z.is_zero()); + z.add_assign_mixed(&G::Affine::zero()); + assert!(z.is_zero()); + + let mut z2 = z; + z2.add_assign(&r); + + z.add_assign_mixed(&r.into_affine()); + + assert_eq!(z, z2); + assert_eq!(z, r); + } + + // Transformations + { + let a = G::rand(&mut rng); + let b = a.into_affine().into_projective(); + let c = a + .into_affine() + .into_projective() + .into_affine() + .into_projective(); + assert_eq!(a, b); + assert_eq!(b, c); + } + + // Test COFACTOR and COFACTOR_INV + { + let a = G::rand(&mut rng); + let b = a.into_affine(); + let c = b.mul_by_cofactor_inv().mul_by_cofactor(); + assert_eq!(b, c); + } + + random_addition_test::(); + random_multiplication_test::(); + random_doubling_test::(); + random_negation_test::(); + random_transformation_test::(); +} + +pub fn sw_tests() { + sw_curve_serialization_test::

(); + sw_from_random_bytes::

(); +} + +pub fn sw_from_random_bytes() { + use ark_ec::models::short_weierstrass_jacobian::{GroupAffine, GroupProjective}; + + let buf_size = GroupAffine::

::zero().serialized_size(); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = GroupProjective::

::rand(&mut rng); + let mut a = a.into_affine(); + { + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let p1 = GroupAffine::

::deserialize(&mut cursor).unwrap(); + let p2 = GroupAffine::

::from_random_bytes(&serialized).unwrap(); + assert_eq!(p1, p2); + } + } +} + +pub fn sw_curve_serialization_test() { + use ark_ec::models::short_weierstrass_jacobian::{GroupAffine, GroupProjective}; + + let buf_size = GroupAffine::

::zero().serialized_size(); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = GroupProjective::

::rand(&mut rng); + let mut a = a.into_affine(); + { + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + a.y = -a.y; + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; buf_size - 1]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap_err(); + } + + { + let serialized = vec![0; buf_size - 1]; + let mut cursor = Cursor::new(&serialized[..]); + GroupAffine::

::deserialize(&mut cursor).unwrap_err(); + } + + { + let mut serialized = vec![0; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + a.y = -a.y; + let mut serialized = vec![0; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + } +} + +pub fn montgomery_conversion_test

() +where + P: TEModelParameters, +{ + // A = 2 * (a + d) / (a - d) + let a = P::BaseField::one().double() + * &(P::COEFF_A + &P::COEFF_D) + * &(P::COEFF_A - &P::COEFF_D).inverse().unwrap(); + // B = 4 / (a - d) + let b = P::BaseField::one().double().double() * &(P::COEFF_A - &P::COEFF_D).inverse().unwrap(); + + assert_eq!(a, P::MontgomeryModelParameters::COEFF_A); + assert_eq!(b, P::MontgomeryModelParameters::COEFF_B); +} + +pub fn edwards_tests() +where + P::BaseField: PrimeField, +{ + edwards_curve_serialization_test::

(); + edwards_from_random_bytes::

(); +} + +pub fn edwards_from_random_bytes() +where + P::BaseField: PrimeField, +{ + use ark_ec::models::twisted_edwards_extended::{GroupAffine, GroupProjective}; + use ark_ff::{to_bytes, ToBytes}; + + let buf_size = GroupAffine::

::zero().serialized_size(); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = GroupProjective::

::rand(&mut rng); + let mut a = a.into_affine(); + { + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let p1 = GroupAffine::

::deserialize(&mut cursor).unwrap(); + let p2 = GroupAffine::

::from_random_bytes(&serialized).unwrap(); + assert_eq!(p1, p2); + } + } + + for _ in 0..ITERATIONS { + let mut biginteger = + < as AffineCurve>::BaseField as PrimeField>::BigInt::rand(&mut rng); + let mut bytes = to_bytes![biginteger].unwrap(); + let mut g = GroupAffine::

::from_random_bytes(&bytes); + while g.is_none() { + bytes.iter_mut().for_each(|i| *i = i.wrapping_sub(1)); + g = GroupAffine::

::from_random_bytes(&bytes); + } + let _g = g.unwrap(); + } +} + +pub fn edwards_curve_serialization_test() { + use ark_ec::models::twisted_edwards_extended::{GroupAffine, GroupProjective}; + + let buf_size = GroupAffine::

::zero().serialized_size(); + + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = GroupProjective::

::rand(&mut rng); + let a = a.into_affine(); + { + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; buf_size - 1]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap_err(); + } + + { + let serialized = vec![0; buf_size - 1]; + let mut cursor = Cursor::new(&serialized[..]); + GroupAffine::

::deserialize(&mut cursor).unwrap_err(); + } + + { + let mut serialized = vec![0; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let a = GroupAffine::

::zero(); + let mut serialized = vec![0; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let b = GroupAffine::

::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + } +} diff --git a/curve-tests/src/fields.rs b/curve-tests/src/fields.rs new file mode 100644 index 0000000..acdaff4 --- /dev/null +++ b/curve-tests/src/fields.rs @@ -0,0 +1,466 @@ +#![allow(unused)] +use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField, SquareRootField}; +use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; +use ark_std::io::Cursor; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +pub const ITERATIONS: u32 = 40; + +fn random_negation_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let a = F::rand(rng); + let mut b = -a; + b += &a; + + assert!(b.is_zero()); + } +} + +fn random_addition_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let a = F::rand(rng); + let b = F::rand(rng); + let c = F::rand(rng); + + let t0 = (a + &b) + &c; // (a + b) + c + + let t1 = (a + &c) + &b; // (a + c) + b + + let t2 = (b + &c) + &a; // (b + c) + a + + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } +} + +fn random_subtraction_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let a = F::rand(rng); + let b = F::rand(rng); + + let t0 = a - &b; // (a - b) + + let mut t1 = b; // (b - a) + t1 -= &a; + + let mut t2 = t0; // (a - b) + (b - a) = 0 + t2 += &t1; + + assert!(t2.is_zero()); + } +} + +fn random_multiplication_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let a = F::rand(rng); + let b = F::rand(rng); + let c = F::rand(rng); + + let mut t0 = a; // (a * b) * c + t0 *= &b; + t0 *= &c; + + let mut t1 = a; // (a * c) * b + t1 *= &c; + t1 *= &b; + + let mut t2 = b; // (b * c) * a + t2 *= &c; + t2 *= &a; + + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } +} + +fn random_inversion_tests(rng: &mut R) { + assert!(F::zero().inverse().is_none()); + + for _ in 0..ITERATIONS { + let mut a = F::rand(rng); + let b = a.inverse().unwrap(); // probablistically nonzero + a *= &b; + + assert_eq!(a, F::one()); + } +} + +fn random_doubling_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let mut a = F::rand(rng); + let mut b = a; + a += &b; + b.double_in_place(); + + assert_eq!(a, b); + } +} + +fn random_squaring_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + let mut a = F::rand(rng); + let mut b = a; + a *= &b; + b.square_in_place(); + + assert_eq!(a, b); + } +} + +fn random_expansion_tests(rng: &mut R) { + for _ in 0..ITERATIONS { + // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) + + let a = F::rand(rng); + let b = F::rand(rng); + let c = F::rand(rng); + let d = F::rand(rng); + + let mut t0 = a; + t0 += &b; + let mut t1 = c; + t1 += &d; + t0 *= &t1; + + let mut t2 = a; + t2 *= &c; + let mut t3 = b; + t3 *= &c; + let mut t4 = a; + t4 *= &d; + let mut t5 = b; + t5 *= &d; + + t2 += &t3; + t2 += &t4; + t2 += &t5; + + assert_eq!(t0, t2); + } + + for _ in 0..ITERATIONS { + // Compare (a + b)c and (a*c + b*c) + + let a = F::rand(rng); + let b = F::rand(rng); + let c = F::rand(rng); + + let t0 = (a + &b) * &c; + let t2 = a * &c + &(b * &c); + + assert_eq!(t0, t2); + } +} + +fn random_field_tests() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + random_negation_tests::(&mut rng); + random_addition_tests::(&mut rng); + random_subtraction_tests::(&mut rng); + random_multiplication_tests::(&mut rng); + random_inversion_tests::(&mut rng); + random_doubling_tests::(&mut rng); + random_squaring_tests::(&mut rng); + random_expansion_tests::(&mut rng); + + assert!(F::zero().is_zero()); + { + let z = -F::zero(); + assert!(z.is_zero()); + } + + assert!(F::zero().inverse().is_none()); + + // Multiplication by zero + { + let a = F::rand(&mut rng) * &F::zero(); + assert!(a.is_zero()); + } + + // Addition by zero + { + let mut a = F::rand(&mut rng); + let copy = a; + a += &F::zero(); + assert_eq!(a, copy); + } +} + +fn random_sqrt_tests() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = F::rand(&mut rng); + let b = a.square(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + let b = b.sqrt().unwrap(); + assert!(a == b || a == -b); + } + + let mut c = F::one(); + for _ in 0..ITERATIONS { + let mut b = c.square(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + b = b.sqrt().unwrap(); + + if b != c { + b = -b; + } + + assert_eq!(b, c); + + c += &F::one(); + } +} + +pub fn from_str_test() { + { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let n: u64 = rng.gen(); + + let a = F::from_str(&ark_std::format!("{}", n)) + .map_err(|_| ()) + .unwrap(); + let b = F::from_repr(n.into()).unwrap(); + + assert_eq!(a, b); + } + } + + assert!(F::from_str("").is_err()); + assert!(F::from_str("0").map_err(|_| ()).unwrap().is_zero()); + assert!(F::from_str("00").is_err()); + assert!(F::from_str("00000000000").is_err()); +} + +pub fn field_test(a: F, b: F) { + let zero = F::zero(); + assert_eq!(zero, zero); + assert_eq!(zero.is_zero(), true); + assert_eq!(zero.is_one(), false); + + let one = F::one(); + assert_eq!(one, one); + assert_eq!(one.is_zero(), false); + assert_eq!(one.is_one(), true); + assert_eq!(zero + &one, one); + + let two = one + &one; + assert_eq!(two, two); + assert_ne!(zero, two); + assert_ne!(one, two); + + // a == a + assert_eq!(a, a); + // a + 0 = a + assert_eq!(a + &zero, a); + // a - 0 = a + assert_eq!(a - &zero, a); + // a - a = 0 + assert_eq!(a - &a, zero); + // 0 - a = -a + assert_eq!(zero - &a, -a); + // a.double() = a + a + assert_eq!(a.double(), a + &a); + // b.double() = b + b + assert_eq!(b.double(), b + &b); + // a + b = b + a + assert_eq!(a + &b, b + &a); + // a - b = -(b - a) + assert_eq!(a - &b, -(b - &a)); + // (a + b) + a = a + (b + a) + assert_eq!((a + &b) + &a, a + &(b + &a)); + // (a + b).double() = (a + b) + (b + a) + assert_eq!((a + &b).double(), (a + &b) + &(b + &a)); + + // a * 0 = 0 + assert_eq!(a * &zero, zero); + // a * 1 = a + assert_eq!(a * &one, a); + // a * 2 = a.double() + assert_eq!(a * &two, a.double()); + // a * a^-1 = 1 + assert_eq!(a * &a.inverse().unwrap(), one); + // a * a = a^2 + assert_eq!(a * &a, a.square()); + // a * a * a = a^3 + assert_eq!(a * &(a * &a), a.pow([0x3, 0x0, 0x0, 0x0])); + // a * b = b * a + assert_eq!(a * &b, b * &a); + // (a * b) * a = a * (b * a) + assert_eq!((a * &b) * &a, a * &(b * &a)); + // (a + b)^2 = a^2 + 2ab + b^2 + assert_eq!( + (a + &b).square(), + a.square() + &((a * &b) + &(a * &b)) + &b.square() + ); + // (a - b)^2 = (-(b - a))^2 + assert_eq!((a - &b).square(), (-(b - &a)).square()); + random_field_tests::(); +} + +pub fn fft_field_test() { + assert_eq!( + F::two_adic_root_of_unity().pow([1 << F::FftParams::TWO_ADICITY]), + F::one() + ); + + if let Some(small_subgroup_base) = F::FftParams::SMALL_SUBGROUP_BASE { + let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); + let large_subgroup_root_of_unity = F::large_subgroup_root_of_unity().unwrap(); + assert_eq!( + large_subgroup_root_of_unity.pow([(1 << F::FftParams::TWO_ADICITY) + * (small_subgroup_base as u64).pow(small_subgroup_base_adicity)]), + F::one() + ); + + for i in 0..F::FftParams::TWO_ADICITY { + for j in 0..small_subgroup_base_adicity { + use core::convert::TryFrom; + let size = usize::try_from(1 << i as usize).unwrap() + * usize::try_from((small_subgroup_base as u64).pow(j)).unwrap(); + let root = F::get_root_of_unity(size).unwrap(); + assert_eq!(root.pow([size as u64]), F::one()); + } + } + } else { + for i in 0..F::FftParams::TWO_ADICITY { + let size = 1 << i; + let root = F::get_root_of_unity(size).unwrap(); + assert_eq!(root.pow([size as u64]), F::one()); + } + } +} + +pub fn primefield_test() { + from_str_test::(); + let one = F::one(); + assert_eq!(F::from(one.into_repr()), one); + + fft_field_test::(); +} + +pub fn sqrt_field_test(elem: F) { + let square = elem.square(); + let sqrt = square.sqrt().unwrap(); + assert!(sqrt == elem || sqrt == -elem); + if let Some(sqrt) = elem.sqrt() { + assert!(sqrt.square() == elem || sqrt.square() == -elem); + } + random_sqrt_tests::(); +} + +pub fn frobenius_test>(characteristic: C, maxpower: usize) { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = F::rand(&mut rng); + + let mut a_0 = a; + a_0.frobenius_map(0); + assert_eq!(a, a_0); + + let mut a_q = a.pow(&characteristic); + for power in 1..maxpower { + let mut a_qi = a; + a_qi.frobenius_map(power); + assert_eq!(a_qi, a_q); + + a_q = a_q.pow(&characteristic); + } + } +} + +pub fn field_serialization_test(buf_size: usize) { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..ITERATIONS { + let a = F::rand(&mut rng); + { + let mut serialized = vec![0u8; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = F::deserialize(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let mut serialized = vec![0u8; a.uncompressed_size()]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_uncompressed(&mut cursor).unwrap(); + + let mut cursor = Cursor::new(&serialized[..]); + let b = F::deserialize_uncompressed(&mut cursor).unwrap(); + assert_eq!(a, b); + } + + { + let mut serialized = vec![0u8; buf_size]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize_with_flags(&mut cursor, SWFlags::from_y_sign(true)) + .unwrap(); + let mut cursor = Cursor::new(&serialized[..]); + let (b, flags) = F::deserialize_with_flags::<_, SWFlags>(&mut cursor).unwrap(); + assert_eq!(flags.is_positive(), Some(true)); + assert!(!flags.is_infinity()); + assert_eq!(a, b); + } + + #[derive(Default, Clone, Copy, Debug)] + struct DummyFlags; + impl Flags for DummyFlags { + fn u8_bitmask(&self) -> u8 { + 0 + } + + fn from_u8(_value: u8) -> Self { + DummyFlags + } + + fn from_u8_remove_flags(_value: &mut u8) -> Self { + DummyFlags + } + + fn len() -> usize { + 200 + } + } + + use ark_serialize::SerializationError; + { + let mut serialized = vec![0; buf_size]; + assert!(if let SerializationError::NotEnoughSpace = a + .serialize_with_flags(&mut &mut serialized[..], DummyFlags) + .unwrap_err() + { + true + } else { + false + }); + assert!(if let SerializationError::NotEnoughSpace = + F::deserialize_with_flags::<_, DummyFlags>(&mut &serialized[..]).unwrap_err() + { + true + } else { + false + }); + } + + { + let mut serialized = vec![0; buf_size - 1]; + let mut cursor = Cursor::new(&mut serialized[..]); + a.serialize(&mut cursor).unwrap_err(); + + let mut cursor = Cursor::new(&serialized[..]); + F::deserialize(&mut cursor).unwrap_err(); + } + } +} diff --git a/curve-tests/src/groups.rs b/curve-tests/src/groups.rs new file mode 100644 index 0000000..71d8729 --- /dev/null +++ b/curve-tests/src/groups.rs @@ -0,0 +1,75 @@ +#![allow(unused)] +use ark_ec::group::Group; +use ark_ff::{One, UniformRand, Zero}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +pub fn group_test(a: G, mut b: G) { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + let zero = G::zero(); + let fr_zero = G::ScalarField::zero(); + let fr_one = G::ScalarField::one(); + let fr_two = fr_one + &fr_one; + assert_eq!(zero, zero); + assert_eq!(zero.is_zero(), true); + assert_eq!(a.mul(&fr_one), a); + assert_eq!(a.mul(&fr_two), a + &a); + assert_eq!(a.mul(&fr_zero), zero); + assert_eq!(a.mul(&fr_zero) - &a, -a); + assert_eq!(a.mul(&fr_one) - &a, zero); + assert_eq!(a.mul(&fr_two) - &a, a); + + // a == a + assert_eq!(a, a); + // a + 0 = a + assert_eq!(a + &zero, a); + // a - 0 = a + assert_eq!(a - &zero, a); + // a - a = 0 + assert_eq!(a - &a, zero); + // 0 - a = -a + assert_eq!(zero - &a, -a); + // a.double() = a + a + assert_eq!(a.double(), a + &a); + // b.double() = b + b + assert_eq!(b.double(), b + &b); + // a + b = b + a + assert_eq!(a + &b, b + &a); + // a - b = -(b - a) + assert_eq!(a - &b, -(b - &a)); + // (a + b) + a = a + (b + a) + assert_eq!((a + &b) + &a, a + &(b + &a)); + // (a + b).double() = (a + b) + (b + a) + assert_eq!((a + &b).double(), (a + &b) + &(b + &a)); + + // Check that double_in_place and double give the same result + let original_b = b; + b.double_in_place(); + assert_eq!(original_b.double(), b); + + let fr_rand1 = G::ScalarField::rand(&mut rng); + let fr_rand2 = G::ScalarField::rand(&mut rng); + let a_rand1 = a.mul(&fr_rand1); + let a_rand2 = a.mul(&fr_rand2); + let fr_three = fr_two + &fr_rand1; + let a_two = a.mul(&fr_two); + assert_eq!(a_two, a.double(), "(a * 2) != a.double()"); + let a_six = a.mul(&(fr_three * &fr_two)); + assert_eq!(a_two.mul(&fr_three), a_six, "(a * 2) * 3 != a * (2 * 3)"); + + assert_eq!( + a_rand1.mul(&fr_rand2), + a_rand2.mul(&fr_rand1), + "(a * r1) * r2 != (a * r2) * r1" + ); + assert_eq!( + a_rand2.mul(&fr_rand1), + a.mul(&(fr_rand1 * &fr_rand2)), + "(a * r2) * r1 != a * (r1 * r2)" + ); + assert_eq!( + a_rand1.mul(&fr_rand2), + a.mul(&(fr_rand1 * &fr_rand2)), + "(a * r1) * r2 != a * (r1 * r2)" + ); +} diff --git a/curve-tests/src/lib.rs b/curve-tests/src/lib.rs new file mode 100644 index 0000000..53f9013 --- /dev/null +++ b/curve-tests/src/lib.rs @@ -0,0 +1,4 @@ +pub mod curves; +pub mod fields; +pub mod groups; +pub mod msm; diff --git a/curve-tests/src/msm.rs b/curve-tests/src/msm.rs new file mode 100644 index 0000000..3e7f391 --- /dev/null +++ b/curve-tests/src/msm.rs @@ -0,0 +1,35 @@ +use ark_ec::{msm::VariableBaseMSM, AffineCurve, ProjectiveCurve}; +use ark_ff::{PrimeField, UniformRand, Zero}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +fn naive_var_base_msm( + bases: &[G], + scalars: &[::BigInt], +) -> G::Projective { + let mut acc = G::Projective::zero(); + + for (base, scalar) in bases.iter().zip(scalars.iter()) { + acc += &base.mul(*scalar); + } + acc +} + +pub fn test_var_base_msm() { + const SAMPLES: usize = 1 << 10; + + let mut rng = XorShiftRng::seed_from_u64(234872845u64); + + let v = (0..SAMPLES - 1) + .map(|_| G::ScalarField::rand(&mut rng).into_repr()) + .collect::>(); + let g = (0..SAMPLES) + .map(|_| G::Projective::rand(&mut rng)) + .collect::>(); + let g = ::batch_normalization_into_affine(&g); + + let naive = naive_var_base_msm(g.as_slice(), v.as_slice()); + let fast = VariableBaseMSM::multi_scalar_mul(g.as_slice(), v.as_slice()); + + assert_eq!(naive.into_affine(), fast.into_affine()); +} diff --git a/ed_on_bls12_377/Cargo.toml b/ed_on_bls12_377/Cargo.toml new file mode 100644 index 0000000..2aeecb8 --- /dev/null +++ b/ed_on_bls12_377/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-bls12-377" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the BLS12-377 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-bls12-377/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bls12-377 = { path = "../bls12_377", default-features = false, features = [ "scalar_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-377/std" ] diff --git a/ed_on_bls12_377/src/curves/mod.rs b/ed_on_bls12_377/src/curves/mod.rs new file mode 100644 index 0000000..0f66ac2 --- /dev/null +++ b/ed_on_bls12_377/src/curves/mod.rs @@ -0,0 +1,106 @@ +use crate::{fq::Fq, fr::Fr}; +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger256, field_new}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = -1 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 0x8cf500000000000e, + 0xe75281ef6000000e, + 0x49dc37a90b0ba012, + 0x55f8b2c6e710ab9, + ])); + + /// COEFF_D = 3021 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger256([ + 0xd047ffffffff5e30, + 0xf0a91026ffff57d2, + 0x9013f560d102582, + 0x9fd242ca7be5700, + ])); + + /// COFACTOR = 4 + const COFACTOR: &'static [u64] = &[4]; + + /// COFACTOR_INV = + /// 527778859339273151515551558673846658209717731602102048798421311598680340096 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 10836190823041854989, + 14880086764632731920, + 5023208332782666747, + 239524813690824359, + ])); + + /// Generated randomly + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; + + /// Multiplication by `a` is just negation. + /// Is `a` 1 or -1? + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -*elem + } +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 0x8D26E3FADA9010A26949031ECE3971B93952AD84D4753DDEDB748DA37E8F552 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 13800168384327121454u64, + 6841573379969807446u64, + 12529593083398462246u64, + 853978956621483129u64, + ])); + /// COEFF_B = 0x9D8F71EEC83A44C3A1FBCEC6F5418E5C6154C2682B8AC231C5A3725C8170AAD + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger256([ + 7239382437352637935u64, + 14509846070439283655u64, + 5083066350480839936u64, + 1265663645916442191u64, + ])); + + type TEModelParameters = EdwardsParameters; +} + +/// GENERATOR_X = +/// 7810607721416582242904415504650443951498042435501746664987470571546413371306 +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger256([ + 0x5bbc9878d817221d, + 0xd2b03489424e720, + 0x6b66f128c16bb3c9, + 0xdd3bff78733576d, +])); + +/// GENERATOR_Y = +/// 1867362672570137759132108893390349941423731440336755218616442213142473202417 +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger256([ + 0x471517ae5e5e979e, + 0xd9c97f6a73a7ff83, + 0x85a95b45a5494402, + 0xfad27c9b545b1f0, +])); diff --git a/ed_on_bls12_377/src/curves/tests.rs b/ed_on_bls12_377/src/curves/tests.rs new file mode 100644 index 0000000..79942a0 --- /dev/null +++ b/ed_on_bls12_377/src/curves/tests.rs @@ -0,0 +1,62 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_bls12_377/src/fields/fq.rs b/ed_on_bls12_377/src/fields/fq.rs new file mode 100644 index 0000000..b743999 --- /dev/null +++ b/ed_on_bls12_377/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_bls12_377::{Fr as Fq, FrParameters as FqParameters}; diff --git a/ed_on_bls12_377/src/fields/fr.rs b/ed_on_bls12_377/src/fields/fr.rs new file mode 100644 index 0000000..0a08752 --- /dev/null +++ b/ed_on_bls12_377/src/fields/fr.rs @@ -0,0 +1,78 @@ +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, +}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 15170730761708361161u64, + 13670723686578117817u64, + 12803492266614043665u64, + 50861023252832611u64, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 2111115437357092606062206234695386632838870926408408195193685246394721360383 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 13356249993388743167u64, + 5950279507993463550u64, + 10965441865914903552u64, + 336320092672043349u64, + ]); + + const MODULUS_BITS: u32 = 251; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 5; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 16632263305389933622u64, + 10726299895124897348u64, + 16608693673010411502u64, + 285459069419210737u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 3987543627614508126u64, + 17742427666091596403u64, + 14557327917022607905u64, + 322810149704226881u64, + ]); + + const INV: u64 = 9659935179256617473u64; + + // 70865795004005329077606947863872807680085016823885970091001235374859923341923 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 11289572479685143826u64, + 11383637369941080925u64, + 2288212753973340071u64, + 82014976407880291u64, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 6678124996694371583u64, + 2975139753996731775u64, + 14706092969812227584u64, + 168160046336021674u64, + ]); + + const T: BigInteger = BigInteger([0x0, 0x0, 0x0, 0x0]); + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([0x0, 0x0, 0x0, 0x0]); +} diff --git a/ed_on_bls12_377/src/fields/mod.rs b/ed_on_bls12_377/src/fields/mod.rs new file mode 100644 index 0000000..10e71c5 --- /dev/null +++ b/ed_on_bls12_377/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_bls12_377", test))] +mod tests; diff --git a/ed_on_bls12_377/src/fields/tests.rs b/ed_on_bls12_377/src/fields/tests.rs new file mode 100644 index 0000000..07657e9 --- /dev/null +++ b/ed_on_bls12_377/src/fields/tests.rs @@ -0,0 +1,24 @@ +use ark_ff::test_rng; +use rand::Rng; + +use crate::{Fq, Fr}; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} diff --git a/ed_on_bls12_377/src/lib.rs b/ed_on_bls12_377/src/lib.rs new file mode 100644 index 0000000..204896a --- /dev/null +++ b/ed_on_bls12_377/src/lib.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve BLS12-377. This allows defining cryptographic primitives that use elliptic curves over +//! the scalar field of the latter curve. This curve was generated as part of the paper +//! [[BCGMMW20, “Zexe”]](https://eprint.iacr.org/2018/962). +//! +//! Curve information: +//! * Base field: q = 8444461749428370424248824938781546531375899335154063827935233455917409239041 +//! * Scalar field: r = 2111115437357092606062206234695386632838870926408408195193685246394721360383 +//! * Valuation(q - 1, 2) = 47 +//! * Valuation(r - 1, 2) = 1 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = 3021 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_bls12_381/Cargo.toml b/ed_on_bls12_381/Cargo.toml new file mode 100644 index 0000000..647076c --- /dev/null +++ b/ed_on_bls12_381/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-bls12-381" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the BLS12-381 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-bls12-381/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bls12-381 = { path = "../bls12_381", default-features = false, features = [ "scalar_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-381/std" ] diff --git a/ed_on_bls12_381/src/curves/mod.rs b/ed_on_bls12_381/src/curves/mod.rs new file mode 100644 index 0000000..103438f --- /dev/null +++ b/ed_on_bls12_381/src/curves/mod.rs @@ -0,0 +1,121 @@ +use crate::{Fq, Fr}; +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger256, field_new}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger256([ + 14080349899812819339, + 4104857150246327429, + 8293216003873356624, + 7400363483732984990, +])); +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger256([ + 13388310974700241893, + 7654361511478576605, + 8037907163910805792, + 5188938133920569885, +])); + +/// `JubJub` is a twisted Edwards curve. These curves have equations of the +/// form: ax² + y² = 1 - dx²y². +/// over some base finite field Fq. +/// +/// JubJub's curve equation: -x² + y² = 1 - (10240/10241)x²y² +/// +/// q = 52435875175126190479447740508185965837690552500527637822603658699938581184513. +/// +/// a = -1. +/// d = (10240/10241) mod q +/// = 19257038036680949359750312669786877991949435402254120286184196891950884077233. +/// +/// Sage script to calculate these: +/// +/// ```text +/// q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +/// Fq = GF(q) +/// d = -(Fq(10240)/Fq(10241)) +/// ``` +/// These parameters and the sage script obtained from: +/// +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = -1 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 18446744060824649731, + 18102478225614246908, + 11073656695919314959, + 6613806504683796440, + ])); + + /// COEFF_D = (10240/10241) mod q + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger256([ + 3049539848285517488, + 18189135023605205683, + 8793554888777148625, + 6339087681201251886, + ])); + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR^(-1) mod r = + /// 819310549611346726241370945440405716213240158234039660170669895299022906775 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 6832491983681988242, + 12911748493335322362, + 17523939349049608702, + 217463794347581613, + ])); + + /// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; + + /// Multiplication by `a` is simply negation here. + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -(*elem) + } +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 0xA002 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 388496971701930u64, + 6855257088226130262u64, + 553476580979119549u64, + 6516741293351590684u64, + ])); + /// COEFF_B = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFEFFFF5FFD + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger256([ + 18446355550968045916u64, + 10902955289292811939u64, + 3147092737149958754u64, + 6710871716016002197u64, + ])); + + type TEModelParameters = EdwardsParameters; +} diff --git a/ed_on_bls12_381/src/curves/tests.rs b/ed_on_bls12_381/src/curves/tests.rs new file mode 100644 index 0000000..6a2c2df --- /dev/null +++ b/ed_on_bls12_381/src/curves/tests.rs @@ -0,0 +1,106 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::{bytes::FromBytes, test_rng, Zero}; +use core::str::FromStr; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_scalar_multiplication() { + let f1 = Fr::from_str( + "4691331900926794624732159288782398864809513177368446695323460897088210774597", + ) + .unwrap(); + let f2 = Fr::from_str( + "1305028103380024953477151132159456965337646722479526711736847301646466538045", + ) + .unwrap(); + + let g = EdwardsAffine::from_str( + "(1158870117176967269192899343636553522971009777237254192973081388797299308391, \ + 36933624999642413792569726058244472742169727126562409632889593958355839948294)", + ) + .unwrap(); + let f1f2g = EdwardsAffine::from_str( + "(12638652891150111215300246576936483137884466359309882317048163368620501191944, \ + 38385045634663742820428406709832518145724237919360177362175527604556651918148)", + ) + .unwrap(); + + assert!(!g.is_zero()); + assert!(!f1f2g.is_zero()); + + let f1g = g.mul(f1).into_affine(); + assert_eq!(g.mul(f1 * &f2).into_affine(), f1f2g); + assert_eq!(f1g.mul(f2).into_affine(), f1f2g); +} + +#[test] +fn test_bytes() { + let g_from_repr = EdwardsAffine::from_str( + "(1158870117176967269192899343636553522971009777237254192973081388797299308391, \ + 36933624999642413792569726058244472742169727126562409632889593958355839948294)", + ) + .unwrap(); + + let g_bytes = ark_ff::to_bytes![g_from_repr].unwrap(); + let g = EdwardsAffine::read(g_bytes.as_slice()).unwrap(); + assert_eq!(g_from_repr, g); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_bls12_381/src/fields/fq.rs b/ed_on_bls12_381/src/fields/fq.rs new file mode 100644 index 0000000..46c052b --- /dev/null +++ b/ed_on_bls12_381/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_bls12_381::{Fr as Fq, FrParameters as FqParameters}; diff --git a/ed_on_bls12_381/src/fields/fr.rs b/ed_on_bls12_381/src/fields/fr.rs new file mode 100644 index 0000000..82cd18a --- /dev/null +++ b/ed_on_bls12_381/src/fields/fr.rs @@ -0,0 +1,81 @@ +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, +}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0xaa9f02ab1d6124de, + 0xb3524a6466112932, + 0x7342261215ac260b, + 0x4d6b87b1da259e2, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 6554484396890773809930967563523245729705921265872317281365359162392183254199. + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xd0970e5ed6f72cb7, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9, + ]); + + const MODULUS_BITS: u32 = 252; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 4; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0x25f80bb3b99607d9, + 0xf315d62f66b6e750, + 0x932514eeeb8814f4, + 0x9a6fc6f479155c6, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0x67719aa495e57731, + 0x51b0cef09ce3fc26, + 0x69dab7fac026e9a5, + 0x4f6547b8d127688, + ]); + + const INV: u64 = 0x1ba3a358ef788ef9; + + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0x720b1b19d49ea8f1, + 0xbf4aa36101f13a58, + 0x5fa8cc968193ccbb, + 0xe70cbdc7dccf3ac, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 7515249040934278747, + 5995434913520945217, + 9454073218019761536, + 522094803716528084, + ]); + + const T: BigInteger = Self::MODULUS_MINUS_ONE_DIV_TWO; + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 12980996557321915181, + 2997717456760472608, + 4727036609009880768, + 261047401858264042, + ]); +} diff --git a/ed_on_bls12_381/src/fields/mod.rs b/ed_on_bls12_381/src/fields/mod.rs new file mode 100644 index 0000000..6e99b4b --- /dev/null +++ b/ed_on_bls12_381/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_bls12_381", test))] +mod tests; diff --git a/ed_on_bls12_381/src/fields/tests.rs b/ed_on_bls12_381/src/fields/tests.rs new file mode 100644 index 0000000..20cd07a --- /dev/null +++ b/ed_on_bls12_381/src/fields/tests.rs @@ -0,0 +1,426 @@ +use crate::{Fq, Fr}; +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + bytes::{FromBytes, ToBytes}, + fields::{Field, LegendreSymbol::*, SquareRootField}, + test_rng, One, Zero, +}; + +use ark_curve_tests::fields::*; + +use core::str::FromStr; +use rand::Rng; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq_add() { + let f1 = Fq::from_str( + "18386742314266644595564329008376577163854043021652781768352795308532764650733", + ) + .unwrap(); + let f2 = Fq::from_str( + "39786307610986038981023499868190793548353538256264351797285876981647142458383", + ) + .unwrap(); + let f3 = Fq::from_str( + "5737174750126493097140088368381404874517028777389495743035013590241325924603", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 + &f2, f3); +} + +#[test] +fn test_fq_add_one() { + let f1 = Fq::from_str( + "4946875394261337176810256604189376311946643975348516311606738923340201185904", + ) + .unwrap(); + let f2 = Fq::from_str( + "4946875394261337176810256604189376311946643975348516311606738923340201185905", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert_eq!(f1 + &Fq::one(), f2); +} + +#[test] +fn test_fq_mul() { + let f1 = Fq::from_str( + "24703123148064348394273033316595937198355721297494556079070134653139656190956", + ) + .unwrap(); + let f2 = Fq::from_str( + "38196797080882758914424853878212529985425118523754343117256179679117054302131", + ) + .unwrap(); + let f3 = Fq::from_str( + "38057113854472161555556064369220825628027487067886761874351491955834635348140", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 * &f2, f3); +} + +#[test] +fn test_fq_triple_mul() { + let f1 = Fq::from_str( + "23834398828139479510988224171342199299644042568628082836691700490363123893905", + ) + .unwrap(); + let f2 = Fq::from_str( + "48343809612844640454129919255697536258606705076971130519928764925719046689317", + ) + .unwrap(); + let f3 = Fq::from_str( + "22704845471524346880579660022678666462201713488283356385810726260959369106033", + ) + .unwrap(); + let f4 = Fq::from_str( + "18897508522635316277030308074760673440128491438505204942623624791502972539393", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 * &f2 * &f3, f4); +} + +#[test] +fn test_fq_div() { + let f1 = Fq::from_str( + "31892744363926593013886463524057935370302352424137349660481695792871889573091", + ) + .unwrap(); + let f2 = Fq::from_str( + "47695868328933459965610498875668250916462767196500056002116961816137113470902", + ) + .unwrap(); + let f3 = Fq::from_str( + "29049672724678710659792141917402891276693777283079976086581207190825261000580", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 / &f2, f3); +} + +#[test] +fn test_fq_sub() { + let f1 = Fq::from_str( + "18695869713129401390241150743745601908470616448391638969502807001833388904079", + ) + .unwrap(); + let f2 = Fq::from_str( + "10105476028534616828778879109836101003805485072436929139123765141153277007373", + ) + .unwrap(); + let f3 = Fq::from_str( + "8590393684594784561462271633909500904665131375954709830379041860680111896706", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 - &f2, f3); +} + +#[test] +fn test_fq_double_in_place() { + let mut f1 = Fq::from_str( + "29729289787452206300641229002276778748586801323231253291984198106063944136114", + ) + .unwrap(); + let f3 = Fq::from_str( + "7022704399778222121834717496367591659483050145934868761364737512189307087715", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.double_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_double_in_place_thrice() { + let mut f1 = Fq::from_str( + "32768907806651393940832831055386272949401004221411141755415956893066040832473", + ) + .unwrap(); + let f3 = Fq::from_str( + "52407761752706389608871686410346320244445823769178582752913020344774001921732", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.double_in_place(); + f1.double_in_place(); + f1.double_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_generate_random_ed_on_bls12_381_point() { + let d = Fq::from_str( + "19257038036680949359750312669786877991949435402254120286184196891950884077233", + ) + .unwrap(); + let y = Fq::from_str( + "20269054604167148422407276086932743904275456233139568486008667107872965128512", + ) + .unwrap(); + let x2 = Fq::from_str( + "35041048504708632193693740149219726446678304552734087046982753200179718192840", + ) + .unwrap(); + + let computed_y2 = y.square(); + let y2 = Fq::from_str( + "22730681238307918419349440108285755984465605552827817317611903495170775437833", + ) + .unwrap(); + assert_eq!(y2, computed_y2); + + let computed_dy2 = d * &computed_y2; + let dy2 = Fq::from_str( + "24720347560552809545835752815204882739669031262711919770503096707526812943411", + ) + .unwrap(); + assert_eq!(dy2, computed_dy2); + + let computed_divisor = computed_dy2 + &Fq::one(); + let divisor = Fq::from_str( + "24720347560552809545835752815204882739669031262711919770503096707526812943412", + ) + .unwrap(); + assert_eq!(divisor, computed_divisor); + + let computed_x2 = (computed_y2 - &Fq::one()) / &computed_divisor; + assert_eq!(x2, computed_x2); + + let x = Fq::from_str( + "15337652609730546173818014678723269532482775720866471265774032070871608223361", + ) + .unwrap(); + let computed_x = computed_x2.sqrt().unwrap(); + assert_eq!(computed_x.square(), x2); + assert_eq!(x, computed_x); + + fn add<'a>(curr: (Fq, Fq), other: &'a (Fq, Fq)) -> (Fq, Fq) { + let y1y2 = curr.1 * &other.1; + let x1x2 = curr.0 * &other.0; + let d = Fq::from_str( + "19257038036680949359750312669786877991949435402254120286184196891950884077233", + ) + .unwrap(); + let dx1x2y1y2 = d * &y1y2 * &x1x2; + + let d1 = Fq::one() + &dx1x2y1y2; + let d2 = Fq::one() - &dx1x2y1y2; + + let x1y2 = curr.0 * &other.1; + let y1x2 = curr.1 * &other.0; + + let x = (x1y2 + &y1x2) / &d1; + let y = (y1y2 + &x1x2) / &d2; + + (x, y) + } + + let result = add((x, y), &(x, y)); + let result = add(result, &result); + let result = add(result, &result); + + let point_x = Fq::from_str( + "47259664076168047050113154262636619161204477920503059672059915868534495873964", + ) + .unwrap(); + let point_y = Fq::from_str( + "19016409245280491801573912449420132838852726543024859389273314249842195919690", + ) + .unwrap(); + assert_eq!((point_x, point_y), result); +} + +#[test] +fn test_fq_square_in_place() { + let mut f1 = Fq::from_str( + "34864651240005695523200639428464570946052769938774601449735727714436878540682", + ) + .unwrap(); + let f3 = + Fq::from_str("213133100629336594719108316042277780359104840987226496279264105585804377948") + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.square_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_sqrt() { + let f1 = Fq::from_str( + "10875927553327821418567659853801220899541454800710193788767706167237535308235", + ) + .unwrap(); + let f3 = Fq::from_str( + "10816221372957505053219354782681292880545918527618367765651802809826238616708", + ) + .unwrap(); + assert_eq!(f1.sqrt().unwrap(), f3); +} + +#[test] +fn test_fq_from_str() { + let f1_from_repr = Fq::from(BigInteger([ + 0xab8a2535947d1a77, + 0x9ba74cbfda0bbcda, + 0xe928b59724d60baf, + 0x1cccaaeb9bb1680a, + ])); + let f1 = Fq::from_str( + "13026376210409056429264774981357153555336288129100724591327877625017068755575", + ) + .unwrap(); + let f2_from_repr = Fq::from(BigInteger([ + 0x97e9103775d2f35c, + 0xbe6756b6c587544b, + 0x6ee38c3afd88ef4b, + 0x2bacd150f540c677, + ])); + let f2 = Fq::from_str( + "19754794831832707859764530223239420866832328728734160755396495950822165902172", + ) + .unwrap(); + assert_eq!(f1_from_repr, f1); + assert_eq!(f2_from_repr, f2); +} + +#[test] +fn test_fq_legendre() { + assert_eq!(QuadraticResidue, Fq::one().legendre()); + assert_eq!(Zero, Fq::zero().legendre()); + + let e = BigInteger([ + 0x0dbc5349cd5664da, + 0x8ac5b6296e3ae29d, + 0x127cb819feceaa3b, + 0x3a6b21fb03867191, + ]); + assert_eq!(QuadraticResidue, Fq::from(e).legendre()); + let e = BigInteger([ + 0x96341aefd047c045, + 0x9b5f4254500a4d65, + 0x1ee08223b68ac240, + 0x31d9cd545c0ec7c6, + ]); + assert_eq!(QuadraticNonResidue, Fq::from(e).legendre()); +} + +#[test] +fn test_fq_bytes() { + let f1_from_repr = Fq::from(BigInteger([ + 0xab8a2535947d1a77, + 0x9ba74cbfda0bbcda, + 0xe928b59724d60baf, + 0x1cccaaeb9bb1680a, + ])); + + let mut f1_bytes = [0u8; 32]; + f1_from_repr.write(f1_bytes.as_mut()).unwrap(); + + let f1 = Fq::read(f1_bytes.as_ref()).unwrap(); + assert_eq!(f1_from_repr, f1); +} + +#[test] +fn test_fr_add() { + let f1 = Fr::from(BigInteger([ + 0xc81265fb4130fe0c, + 0xb308836c14e22279, + 0x699e887f96bff372, + 0x84ecc7e76c11ad, + ])); + let f2 = Fr::from(BigInteger([ + 0x71875719b422efb8, + 0x43658e68a93612, + 0x9fa756be2011e833, + 0xaa2b2cb08dac497, + ])); + let f3 = Fr::from(BigInteger([ + 0x3999bd14f553edc4, + 0xb34be8fa7d8b588c, + 0x945df3db6d1dba5, + 0xb279f92f046d645, + ])); + assert_eq!(f1 + &f2, f3); +} + +#[test] +fn test_fr_mul() { + let f1 = Fr::from(BigInteger([ + 0xc81265fb4130fe0c, + 0xb308836c14e22279, + 0x699e887f96bff372, + 0x84ecc7e76c11ad, + ])); + let f2 = Fr::from(BigInteger([ + 0x71875719b422efb8, + 0x43658e68a93612, + 0x9fa756be2011e833, + 0xaa2b2cb08dac497, + ])); + let f3 = Fr::from(BigInteger([ + 0x6d6618ac6b4a8381, + 0x5b9eb35d711ee1da, + 0xce83310e6ac4105d, + 0x98032e0f206320a, + ])); + assert_eq!(f1 * &f2, f3); +} + +#[test] +fn test_fr_bytes() { + let f1_from_repr = Fr::from(BigInteger([ + 0xc81265fb4130fe0c, + 0xb308836c14e22279, + 0x699e887f96bff372, + 0x84ecc7e76c11ad, + ])); + + let mut f1_bytes = [0u8; 32]; + f1_from_repr.write(f1_bytes.as_mut()).unwrap(); + + let f1 = Fr::read(f1_bytes.as_ref()).unwrap(); + assert_eq!(f1_from_repr, f1); +} + +#[test] +fn test_fr_from_str() { + let f100_from_repr = Fr::from(BigInteger([0x64, 0, 0, 0])); + let f100 = Fr::from_str("100").unwrap(); + assert_eq!(f100_from_repr, f100); +} diff --git a/ed_on_bls12_381/src/lib.rs b/ed_on_bls12_381/src/lib.rs new file mode 100644 index 0000000..a7346e1 --- /dev/null +++ b/ed_on_bls12_381/src/lib.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve BLS12-377. This allows defining cryptographic primitives that use elliptic curves over +//! the scalar field of the latter curve. This curve was generated by Sean Bowe, and is also known +//! as [Jubjub](https://github.com/zkcrypto/jubjub). +//! +//! Curve information: +//! * Base field: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +//! * Scalar field: r = 6554484396890773809930967563523245729705921265872317281365359162392183254199 +//! * Valuation(q - 1, 2) = 32 +//! * Valuation(r - 1, 2) = 1 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = -(10240/10241) + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_bn254/Cargo.toml b/ed_on_bn254/Cargo.toml new file mode 100644 index 0000000..eb321db --- /dev/null +++ b/ed_on_bn254/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-bn254" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the BN254 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-bn254/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bn254 = { path = "../bn254", default-features = false, features = [ "scalar_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bn254/std" ] diff --git a/ed_on_bn254/src/curves/mod.rs b/ed_on_bn254/src/curves/mod.rs new file mode 100644 index 0000000..541d46d --- /dev/null +++ b/ed_on_bn254/src/curves/mod.rs @@ -0,0 +1,108 @@ +use crate::{Fq, Fr}; +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger256, field_new}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger256([ + 0x3db6612c2863cc99, + 0x8a9e4521b36347dc, + 0x310a1a625c16a534, + 0x23ceae2710df4a14, +])); +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger256([ + 0xb83342d20d0201aa, + 0x2ffef2f7cdcfeac7, + 0xbfa79a9425a6e625, + 0xdfb859dc3a44b70, +])); + +/// `Baby-JubJub` is a twisted Edwards curve. These curves have equations of the +/// form: ax² + y² = 1 + dx²y². +/// over some base finite field Fq. +/// +/// Baby-JubJub's curve equation: x² + y² = 1 + (168696/168700)x²y² +/// +/// q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +/// +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = 1 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 0xac96341c4ffffffb, + 0x36fc76959f60cd29, + 0x666ea36f7879462e, + 0xe0a77c19a07df2f, + ])); + + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + *elem + } + + /// COEFF_D = 168696/168700 mod q + /// = 9706598848417545097372247223557719406784115219466060233080913168975159366771 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger256([ + 0xe7a66d1d9fb08e74, + 0xd775bbd5e17629dc, + 0x70ccd097286ef1e7, + 0x45809398fdf98, + ])); + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR^(-1) mod r = + /// 2394026564107420727433200628387514462817212225638746351800188703329891451411 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ + 0xfac308b2e25a3d4b, + 0xa7c55b66e25b59cb, + 0xeccdd46def0f28c5, + 0x1c14ef83340fbe5, + ])); + + /// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 168698 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger256([ + 9251058552732279275u64, + 16047179255329565110u64, + 14708493084570629864u64, + 2559515811206512830u64, + ])); + /// COEFF_B = 168700 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger256([ + 10785223227458347488u64, + 2627865112663806840u64, + 16189334210225400552u64, + 1096023023792938739u64, + ])); + + type TEModelParameters = EdwardsParameters; +} diff --git a/ed_on_bn254/src/curves/tests.rs b/ed_on_bn254/src/curves/tests.rs new file mode 100644 index 0000000..25038fa --- /dev/null +++ b/ed_on_bn254/src/curves/tests.rs @@ -0,0 +1,106 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::{bytes::FromBytes, test_rng, Zero}; +use core::str::FromStr; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_scalar_multiplication() { + let f1 = Fr::from_str( + "4691331900926794624732159288782398864809513177368446695323460897088210774597", + ) + .unwrap(); + let f2 = Fr::from_str( + "1305028103380024953477151132159456965337646722479526711736847301646466538045", + ) + .unwrap(); + + let g = EdwardsAffine::from_str( + "(15863623088992515880085393097393553694825975317405843389771115419751650972659, \ + 16950150798460657717958625567821834550301663161624707787222815936182638968203)", + ) + .unwrap(); + let f1f2g = EdwardsAffine::from_str( + "(20773645713088336957786354488799297695596635653208610804806657050882264237947, \ + 19987327827845206670850937090314462639017692512983955920885166014935289314257)", + ) + .unwrap(); + + assert!(!g.is_zero()); + assert!(!f1f2g.is_zero()); + + let f1g = g.mul(f1).into_affine(); + assert_eq!(g.mul(f1 * &f2).into_affine(), f1f2g); + assert_eq!(f1g.mul(f2).into_affine(), f1f2g); +} + +#[test] +fn test_bytes() { + let g_from_repr = EdwardsAffine::from_str( + "(15863623088992515880085393097393553694825975317405843389771115419751650972659, \ + 16950150798460657717958625567821834550301663161624707787222815936182638968203)", + ) + .unwrap(); + + let g_bytes = ark_ff::to_bytes![g_from_repr].unwrap(); + let g = EdwardsAffine::read(g_bytes.as_slice()).unwrap(); + assert_eq!(g_from_repr, g); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_bn254/src/fields/fq.rs b/ed_on_bn254/src/fields/fq.rs new file mode 100644 index 0000000..800a203 --- /dev/null +++ b/ed_on_bn254/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_bn254::{Fr as Fq, FrParameters as FqParameters}; diff --git a/ed_on_bn254/src/fields/fr.rs b/ed_on_bn254/src/fields/fr.rs new file mode 100644 index 0000000..7d210f4 --- /dev/null +++ b/ed_on_bn254/src/fields/fr.rs @@ -0,0 +1,87 @@ +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, +}; + +pub type Fr = Fp256; + +pub struct FrParameters; + +impl Fp256Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 4; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x1721ada8d4d27255, + 0xcda0f5264e0e35bb, + 0x961a936922086fe6, + 0x1ab00857387dd52, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 2736030358979909402780800718157159386076813972158567259200215660948447373041 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0x677297dc392126f1, + 0xab3eedb83920ee0a, + 0x370a08b6d0302b0b, + 0x60c89ce5c263405, + ]); + + const MODULUS_BITS: u32 = 251; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 5; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0x073315dea08f9c76, + 0xe7acffc6a098f24b, + 0xf85a9201d818f015, + 0x1f16424e1bb7724, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0x35e44abee7ecb21e, + 0x74646cacf5f84ec4, + 0xe472df203faa158f, + 0x445b524f1ba50a8, + ]); + + const INV: u64 = 0x532ce5aebc48f5ef; + + #[rustfmt::skip] + /// GENERATOR = 31 + const GENERATOR: BigInteger = BigInteger([ + 0x3c284f376f3993d1, + 0x08bc9d93705cf8b8, + 0x239d5fcbd9538f3e, + 0x5ca4836185b994b, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x33b94bee1c909378, + 0xd59f76dc1c907705, + 0x9b85045b68181585, + 0x30644e72e131a02, + ]); + + const T: BigInteger = BigInteger([ + 0xa677297dc392126f, + 0xbab3eedb83920ee0, + 0x5370a08b6d0302b0, + 0x60c89ce5c26340, + ]); + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x533b94bee1c90937, + 0x5d59f76dc1c90770, + 0x29b85045b6818158, + 0x30644e72e131a0, + ]); +} diff --git a/ed_on_bn254/src/fields/mod.rs b/ed_on_bn254/src/fields/mod.rs new file mode 100644 index 0000000..9e3fbaa --- /dev/null +++ b/ed_on_bn254/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_bn254", test))] +mod tests; diff --git a/ed_on_bn254/src/fields/tests.rs b/ed_on_bn254/src/fields/tests.rs new file mode 100644 index 0000000..8988406 --- /dev/null +++ b/ed_on_bn254/src/fields/tests.rs @@ -0,0 +1,420 @@ +use crate::{Fq, Fr}; +use ark_ff::{ + biginteger::BigInteger256 as BigInteger, + bytes::{FromBytes, ToBytes}, + fields::{Field, LegendreSymbol::*, SquareRootField}, + test_rng, One, Zero, +}; + +use ark_curve_tests::fields::*; + +use core::str::FromStr; +use rand::Rng; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq_add() { + let f1 = Fq::from_str( + "18386742314266644595564329008376577163854043021652781768352795308532764650733", + ) + .unwrap(); + let f2 = Fq::from_str( + "39786307610986038981023499868190793548353538256264351797285876981647142458383", + ) + .unwrap(); + let f3 = Fq::from_str( + "14396564181574133132095017386052820535110852477085064878242263917028290117882", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 + &f2, f3); +} + +#[test] +fn test_fq_add_one() { + let f1 = Fq::from_str( + "4946875394261337176810256604189376311946643975348516311606738923340201185904", + ) + .unwrap(); + let f2 = Fq::from_str( + "4946875394261337176810256604189376311946643975348516311606738923340201185905", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert_eq!(f1 + &Fq::one(), f2); +} + +#[test] +fn test_fq_mul() { + let f1 = Fq::from_str( + "24703123148064348394273033316595937198355721297494556079070134653139656190956", + ) + .unwrap(); + let f2 = Fq::from_str( + "38196797080882758914424853878212529985425118523754343117256179679117054302131", + ) + .unwrap(); + let f3 = Fq::from_str( + "1321267396236123309645330145349353750536542060403774171357889269349508194307", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 * &f2, f3); +} + +#[test] +fn test_fq_triple_mul() { + let f1 = Fq::from_str( + "23834398828139479510988224171342199299644042568628082836691700490363123893905", + ) + .unwrap(); + let f2 = Fq::from_str( + "48343809612844640454129919255697536258606705076971130519928764925719046689317", + ) + .unwrap(); + let f3 = Fq::from_str( + "22704845471524346880579660022678666462201713488283356385810726260959369106033", + ) + .unwrap(); + let f4 = Fq::from_str( + "7747776931431194635550680695131420638163057297019399136408144301550822179875", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 * &f2 * &f3, f4); +} + +#[test] +fn test_fq_div() { + let f1 = Fq::from_str( + "31892744363926593013886463524057935370302352424137349660481695792871889573091", + ) + .unwrap(); + let f2 = Fq::from_str( + "47695868328933459965610498875668250916462767196500056002116961816137113470902", + ) + .unwrap(); + let f3 = Fq::from_str( + "7301086967624450577859019086314322648061398679982346993011603220910508457334", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 / &f2, f3); +} + +#[test] +fn test_fq_sub() { + let f1 = Fq::from_str( + "18695869713129401390241150743745601908470616448391638969502807001833388904079", + ) + .unwrap(); + let f2 = Fq::from_str( + "10105476028534616828778879109836101003805485072436929139123765141153277007373", + ) + .unwrap(); + let f3 = Fq::from_str( + "8590393684594784561462271633909500904665131375954709830379041860680111896706", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f2.is_zero()); + assert!(!f3.is_zero()); + assert_eq!(f1 - &f2, f3); +} + +#[test] +fn test_fq_double_in_place() { + let mut f1 = Fq::from_str( + "29729289787452206300641229002276778748586801323231253291984198106063944136114", + ) + .unwrap(); + let f3 = Fq::from_str( + "15682093831225862156789646514039007320076873845630437896571987838976271280994", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.double_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_double_in_place_thrice() { + let mut f1 = Fq::from_str( + "32768907806651393940832831055386272949401004221411141755415956893066040832473", + ) + .unwrap(); + let f3 = Fq::from_str( + "21380590862979124081952185245260157621176025366712756262647409092194433207997", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.double_in_place(); + f1.double_in_place(); + f1.double_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_generate_random_ed_on_bn254_point() { + let a = Fq::from_str("168700").unwrap(); + + let d = Fq::from_str("168696").unwrap(); + let y = Fq::from_str( + "19987327827845206670850937090314462639017692512983955920885166014935289314257", + ) + .unwrap(); + let x2 = Fq::from_str( + "2144239075372598103060889495211040948751593385312551803225522963913923559328", + ) + .unwrap(); + + let computed_y2 = y.square(); + let y2 = Fq::from_str( + "11134206686211572308995578277928848431421308813024790181507137950838333998633", + ) + .unwrap(); + assert_eq!(y2, computed_y2); + + let computed_dy2 = d * &computed_y2; + let dy2 = + Fq::from_str("345576003677591687256955722467813448317229128849323754147891993737799010947") + .unwrap(); + assert_eq!(dy2, computed_dy2); + + let computed_divisor = computed_dy2 - a; + let divisor = + Fq::from_str("345576003677591687256955722467813448317229128849323754147891993737798842247") + .unwrap(); + assert_eq!(divisor, computed_divisor); + + let computed_x2 = (computed_y2 - &Fq::one()) / &computed_divisor; + assert_eq!(x2, computed_x2); + + let x = Fq::from_str( + "4801447892755635304907919953550459075619191823587157449340656925102682829025", + ) + .unwrap(); + let computed_x = computed_x2.sqrt().unwrap(); + assert_eq!(computed_x.square(), x2); + assert_eq!(x, computed_x); + + fn add<'a>(curr: (Fq, Fq), other: &'a (Fq, Fq)) -> (Fq, Fq) { + let y1y2 = curr.1 * &other.1; + let x1x2 = curr.0 * &other.0; + let a = Fq::from_str("168700").unwrap(); + let d = Fq::from_str("168696").unwrap(); + let dx1x2y1y2 = d * &y1y2 * &x1x2; + + let d1 = Fq::one() + &dx1x2y1y2; + let d2 = Fq::one() - &dx1x2y1y2; + + let x1y2 = curr.0 * &other.1; + let y1x2 = curr.1 * &other.0; + + let x = (x1y2 + &y1x2) / &d1; + let y = (y1y2 - a * &x1x2) / &d2; + + (x, y) + } + + let result = add((x, y), &(x, y)); + let result = add(result, &result); + let result = add(result, &result); + + let point_x = + Fq::from_str("380676173762867192861894055350059333852732198308367125138259398265363727587") + .unwrap(); + let point_y = Fq::from_str( + "8435074244857818446059206728316702149733931432112984450960434710303841866985", + ) + .unwrap(); + assert_eq!((point_x, point_y), result); +} + +#[test] +fn test_fq_square_in_place() { + let mut f1 = Fq::from_str( + "6060110850233386730847324622937480088943976359504617699731744947670229990461", + ) + .unwrap(); + let f3 = Fq::from_str( + "17018926051730832095053393285350575966874590491719897015583930476179087429684", + ) + .unwrap(); + assert!(!f1.is_zero()); + assert!(!f3.is_zero()); + f1.square_in_place(); + assert_eq!(f1, f3); +} + +#[test] +fn test_fq_sqrt() { + let f1 = Fq::from_str( + "5830207146824777307592559303161432403393380070279905260050870500920682305217", + ) + .unwrap(); + let f3 = Fq::from_str( + "2108183130040740552565127577293974960058698876185401671087892009247563211475", + ) + .unwrap(); + assert_eq!(f1.sqrt().unwrap(), f3); +} + +#[test] +fn test_fq_from_str() { + let f1_from_repr = Fq::from(BigInteger([ + 0xab8a2535947d1a77, + 0x9ba74cbfda0bbcda, + 0xe928b59724d60baf, + 0x1cccaaeb9bb1680a, + ])); + let f1 = Fq::from_str( + "13026376210409056429264774981357153555336288129100724591327877625017068755575", + ) + .unwrap(); + let f2_from_repr = Fq::from(BigInteger([ + 0x97e9103775d2f35c, + 0xbe6756b6c587544b, + 0x6ee38c3afd88ef4b, + 0x2bacd150f540c677, + ])); + let f2 = Fq::from_str( + "19754794831832707859764530223239420866832328728734160755396495950822165902172", + ) + .unwrap(); + assert_eq!(f1_from_repr, f1); + assert_eq!(f2_from_repr, f2); +} + +#[test] +fn test_fq_legendre() { + assert_eq!(QuadraticResidue, Fq::one().legendre()); + assert_eq!(Zero, Fq::zero().legendre()); + + let e = BigInteger([ + 0x2e8de1a676c03be8, + 0x73350d34fe25a560, + 0x7ea085919029688e, + 0x1d0868cb993cf28, + ]); + assert_eq!(QuadraticResidue, Fq::from(e).legendre()); + let e = BigInteger([ + 0x891d8cc23c8d0706, + 0xe91800e007db2698, + 0xfff380321e9ac7a7, + 0x2659e28bd17eab6, + ]); + assert_eq!(QuadraticNonResidue, Fq::from(e).legendre()); +} + +#[test] +fn test_fq_bytes() { + let f1_from_repr = Fq::from(BigInteger([ + 0xab8a2535947d1a77, + 0x9ba74cbfda0bbcda, + 0xe928b59724d60baf, + 0x1cccaaeb9bb1680a, + ])); + + let mut f1_bytes = [0u8; 32]; + f1_from_repr.write(f1_bytes.as_mut()).unwrap(); + + let f1 = Fq::read(f1_bytes.as_ref()).unwrap(); + assert_eq!(f1_from_repr, f1); +} + +#[test] +fn test_fr_add() { + let f1 = Fr::from(BigInteger([ + 0xccfc9a195e0f5c46, + 0xaed4874d13fb1285, + 0x27368f86ca2848eb, + 0x4f8adcfeb44fccc, + ])); + let f2 = Fr::from(BigInteger([ + 0x661ff05bf8570851, + 0x1b171f4c59be97ef, + 0x5d2ce7f9b4d701f3, + 0x1e0e794623e0f68, + ])); + let f3 = Fr::from(BigInteger([ + 0xcba9f2991d453da6, + 0x1eacb8e13498bc6a, + 0x4d596ec9aecf1fd3, + 0xcd0b95f15cd82f, + ])); + assert_eq!(f1 + &f2, f3); +} + +#[test] +fn test_fr_mul() { + let f1 = Fr::from(BigInteger([ + 0xc2964d2dd5fb980f, + 0xbab64d599c57e496, + 0x39cae13e7d1d4f78, + 0x1aa995aa4de205c, + ])); + let f2 = Fr::from(BigInteger([ + 0xc256e720cd43533b, + 0x3bfbadf6247e13bb, + 0x94c3d63a53714f63, + 0x10f8a7bf74efd57, + ])); + let f3 = Fr::from(BigInteger([ + 0x5eac88be41e0e1fd, + 0x57aab36675b11e24, + 0x835582d896b4d13f, + 0x4808736e213036e, + ])); + assert_eq!(f1 * &f2, f3); +} +#[test] +fn test_fr_bytes() { + let f1_from_repr = Fr::from(BigInteger([ + 0xc81265fb4130fe0c, + 0xb308836c14e22279, + 0x699e887f96bff372, + 0x84ecc7e76c11ad, + ])); + + let mut f1_bytes = [0u8; 32]; + f1_from_repr.write(f1_bytes.as_mut()).unwrap(); + + let f1 = Fr::read(f1_bytes.as_ref()).unwrap(); + assert_eq!(f1_from_repr, f1); +} + +#[test] +fn test_fr_from_str() { + let f100_from_repr = Fr::from(BigInteger([0x64, 0, 0, 0])); + let f100 = Fr::from_str("100").unwrap(); + assert_eq!(f100_from_repr, f100); +} diff --git a/ed_on_bn254/src/lib.rs b/ed_on_bn254/src/lib.rs new file mode 100644 index 0000000..b7dca55 --- /dev/null +++ b/ed_on_bn254/src/lib.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve BN254. This allows defining cryptographic primitives that use elliptic curves over +//! the scalar field of the latter curve. This curve is also known as [Baby-Jubjub](https://github.com/barryWhiteHat/baby_jubjub). +//! +//! Curve information: +//! * Base field: q = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +//! * Scalar field: r = 2736030358979909402780800718157159386076813972158567259200215660948447373041 +//! * Valuation(q - 1, 2) = 28 +//! * Valuation(r - 1, 2) = 4 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = 1 +//! * d = 168696/168700 mod q +//! = 9706598848417545097372247223557719406784115219466060233080913168975159366771 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_bw6_761/Cargo.toml b/ed_on_bw6_761/Cargo.toml new file mode 100644 index 0000000..6e81fef --- /dev/null +++ b/ed_on_bw6_761/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ark-ed-on-bw6-761" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the BW6-761 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-bw6-761/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ed-on-cp6-782 = { path = "../ed_on_cp6_782", default-features = false } + +[features] +default = [] +std = [ "ark-ed-on-cp6-782/std" ] diff --git a/ed_on_bw6_761/src/lib.rs b/ed_on_bw6_761/src/lib.rs new file mode 100644 index 0000000..9eb58dc --- /dev/null +++ b/ed_on_bw6_761/src/lib.rs @@ -0,0 +1,18 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![forbid(unsafe_code)] +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve BW6_761. *It is the same curve as that in `ark-ed_on_cp6_782`.* +//! This allows defining cryptographic primitives that use elliptic curves over the scalar field of +//! the latter curve. This curve was generated as part of the paper +//! [[BCGMMW20, “Zexe”]](https://eprint.iacr.org/2018/962). +//! +//! Curve information: +//! * Base field: q = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +//! * Scalar field: r = 32333053251621136751331591711861691692049189094364332567435817881934511297123972799646723302813083835942624121493 +//! * Valuation(q - 1, 2) = 46 +//! * Valuation(r - 1, 2) = 2 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = 79743 + +pub use ark_ed_on_cp6_782::*; diff --git a/ed_on_cp6_782/Cargo.toml b/ed_on_cp6_782/Cargo.toml new file mode 100644 index 0000000..5e1942a --- /dev/null +++ b/ed_on_cp6_782/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-cp6-782" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the CP6-782 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-cp6-782/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-bls12-377 = { path = "../bls12_377", default-features = false, features = [ "base_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-bls12-377/std" ] diff --git a/ed_on_cp6_782/src/curves/mod.rs b/ed_on_cp6_782/src/curves/mod.rs new file mode 100644 index 0000000..97107c6 --- /dev/null +++ b/ed_on_cp6_782/src/curves/mod.rs @@ -0,0 +1,121 @@ +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger384 as BigInteger, field_new}; + +use crate::{fq::Fq, fr::Fr}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = -1 = + /// 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger([ + 9384023879812382873, + 14252412606051516495, + 9184438906438551565, + 11444845376683159689, + 8738795276227363922, + 81297770384137296, + ])); + + /// COEFF_D = 79743 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger([ + 0x4669ffffff46a638, + 0xa56bbe0a7f9fae05, + 0x403b425466a710b4, + 0xf6648db6ea4e988b, + 0x74d51b5923d35a8d, + 0xf8ed90b17fe903, + ])); + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR^(-1) mod r = + /// 12124894969357926281749346891948134384518445910386624712788431705725441736421489799867521238554906438478484045560 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger([ + 7353538464571651976, + 2030910049503177537, + 16726103313845754033, + 1110650741117127777, + 5304838729792721053, + 4975067790294675, + ])); + + /// AFFINE_GENERATOR_COEFFS = (GENERATOR_X, GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; + + /// Multiplication by `a` is just negation. + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -*elem + } +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 0x95D53EB3F6AC3F7A53C26020144439DC6073BCAE513E03FD06B6B3BAA390F25E51534B26719E33F4CD906D4DA9B535 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger([ + 7594254284108454966u64, + 14287343397973578077u64, + 6490358977072726023u64, + 8023375322051995268u64, + 8242802613686040715u64, + 100541941146122331u64, + ])); + /// COEFF_B = 0x118650763CE64AB4BE743604C8D05013DC2663652A3D58B21ECAB7BFF65B70DB8BA09F9098E61CC903B2F92B2564ACA + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger([ + 11173793475516310780u64, + 14217481814129454913u64, + 11878518835804377107u64, + 14866315431314324110u64, + 9234787938768687129u64, + 62053599622152261u64, + ])); + + type TEModelParameters = EdwardsParameters; +} + +/// GENERATOR_X = +/// 174701772324485506941690903512423551998294352968833659960042362742684869862495746426366187462669992073196420267127 +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger([ + 3737364149926089590, + 13002967008679663837, + 9954144214462864555, + 3365719140389487049, + 8643066672427471196, + 120355578793479865, +])); + +/// GENERATOR_Y = +/// 208487200052258845495340374451540775445408439654930191324011635560142523886549663106522691296420655144190624954833 +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger([ + 6027299446526298157, + 12854429557810467099, + 11207279014226687864, + 17040621363687352702, + 6112671509202865855, + 44040319652922447, +])); diff --git a/ed_on_cp6_782/src/curves/tests.rs b/ed_on_cp6_782/src/curves/tests.rs new file mode 100644 index 0000000..79942a0 --- /dev/null +++ b/ed_on_cp6_782/src/curves/tests.rs @@ -0,0 +1,62 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_cp6_782/src/fields/fq.rs b/ed_on_cp6_782/src/fields/fq.rs new file mode 100644 index 0000000..4361a41 --- /dev/null +++ b/ed_on_cp6_782/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_bls12_377::{Fq, FqParameters}; diff --git a/ed_on_cp6_782/src/fields/fr.rs b/ed_on_cp6_782/src/fields/fr.rs new file mode 100644 index 0000000..33bb997 --- /dev/null +++ b/ed_on_cp6_782/src/fields/fr.rs @@ -0,0 +1,90 @@ +use ark_ff::{ + biginteger::BigInteger384 as BigInteger, + fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, +}; + +pub type Fr = Fp384; + +pub struct FrParameters; + +impl Fp384Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 2u32; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 12119792640622387781u64, + 8318439284650634613u64, + 6931324077796168275u64, + 12851391603681523141u64, + 6881015057611215092u64, + 1893962574900431u64, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 32333053251621136751331591711861691692049189094364332567435817881934511297123972799646723302813083835942624121493 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 4684667634276979349u64, + 3748803659444032385u64, + 16273581227874629698u64, + 7152942431629910641u64, + 6397188139321141543u64, + 15137289088311837u64, + ]); + + const MODULUS_BITS: u32 = 374; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 10; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 12565484300600153878u64, + 8749673077137355528u64, + 9027943686469014788u64, + 13026065139386752555u64, + 11197589485989933721u64, + 9525964145733727u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 17257035094703902127u64, + 16096159112880350050u64, + 3498553494623421763u64, + 333405339929360058u64, + 1125865524035793947u64, + 1586246138566285u64, + ]); + + const INV: u64 = 16242011933465909059u64; + + // 2 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 1999556893213776791u64, + 13750542494830678672u64, + 1782306145063399878u64, + 452443773434042853u64, + 15997990832658725900u64, + 3914639203155617u64, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 11565705853993265482u64, + 1874401829722016192u64, + 17360162650792090657u64, + 12799843252669731128u64, + 12421966106515346579u64, + 7568644544155918u64, + ]); + + const T: BigInteger = BigInteger([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); + + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); +} diff --git a/ed_on_cp6_782/src/fields/mod.rs b/ed_on_cp6_782/src/fields/mod.rs new file mode 100644 index 0000000..208333f --- /dev/null +++ b/ed_on_cp6_782/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_cp6_782", test))] +mod tests; diff --git a/ed_on_cp6_782/src/fields/tests.rs b/ed_on_cp6_782/src/fields/tests.rs new file mode 100644 index 0000000..07657e9 --- /dev/null +++ b/ed_on_cp6_782/src/fields/tests.rs @@ -0,0 +1,24 @@ +use ark_ff::test_rng; +use rand::Rng; + +use crate::{Fq, Fr}; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} diff --git a/ed_on_cp6_782/src/lib.rs b/ed_on_cp6_782/src/lib.rs new file mode 100644 index 0000000..c6e69c9 --- /dev/null +++ b/ed_on_cp6_782/src/lib.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the curve CP6. +//! This allows defining cryptographic primitives that use elliptic curves over the scalar field of the latter curve. +//! This curve was generated as part of the paper [[BCGMMW20, “Zexe”]](https://eprint.iacr.org/2018/962). +//! +//! Curve information: +//! * Base field: q = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +//! * Scalar field: r = 32333053251621136751331591711861691692049189094364332567435817881934511297123972799646723302813083835942624121493 +//! * Valuation(q - 1, 2) = 46 +//! * Valuation(r - 1, 2) = 2 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = 79743 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_mnt4_298/Cargo.toml b/ed_on_mnt4_298/Cargo.toml new file mode 100644 index 0000000..c6673cd --- /dev/null +++ b/ed_on_mnt4_298/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-mnt4-298" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the MNT4-298 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-mnt4-298/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-mnt4-298 = { path = "../mnt4_298", default-features = false, features = [ "scalar_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-mnt4-298/std" ] diff --git a/ed_on_mnt4_298/src/curves/mod.rs b/ed_on_mnt4_298/src/curves/mod.rs new file mode 100644 index 0000000..101a828 --- /dev/null +++ b/ed_on_mnt4_298/src/curves/mod.rs @@ -0,0 +1,139 @@ +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger320, field_new}; + +use crate::{fq::Fq, fr::Fr}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +// Many parameters need to be written down in the Montgomery residue form, +// discussed below. Some useful numbers: +// R for Fq: 223364648326281414938801705359223029554923725549792420683051274872200260503540791531766876 +// R for Fr: 104384076783966083500464392945960916666734135485183910065100558776489954102951241798239545 + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = -1 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., -1 * R for Fq + /// = 252557637842979910814547544293825421990201153003031094870216460866964386803867699028196261 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger320([ + 17882590928154426277u64, + 6901912683734848330u64, + 364575608937879866u64, + 8740893163049517815u64, + 2181130330288u64, + ])); + + /// COEFF_D = 4212 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., 4212 * R for Fq + /// = 389461279836940033614665658623660232171971995346409183754923941118154161474636585314923000 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger320([ + 8040159930071495160u64, + 16503302848883893212u64, + 4541498709509651666u64, + 11429056610118256373u64, + 3363453258354u64, + ])); + + /// COFACTOR = 4 + const COFACTOR: &'static [u64] = &[4]; + + /// COFACTOR_INV (mod r) = + /// 29745142885578832859584328103315528221570304936126890280067991221921526670592508030983158 + /// Needs to be in the Montgomery residue form in Fr + /// I.e., 29745142885578832859584328103315528221570304936126890280067991221921526670592508030983158 * R for Fr + /// = 55841162081570353734700426339805757388253838807422867796343130916044015196330318480543044 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger320([ + 6539529304383425860u64, + 7567022062893857598u64, + 17399624368177871129u64, + 14575354999847441509u64, + 482253688048u64, + ])); + + /// Generated randomly + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; + + /// Multiplication by `a` is just negation. + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -*elem + } +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 203563247015667910991582090642011229452721346107806307863040223071914240315202967004285204 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., 203563247015667910991582090642011229452721346107806307863040223071914240315202967004285204 * R for Fq + /// = 184958108588233737086787169006685138672129232027042887479256778022373554352621152610883766 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger320([ + 13866101745789245622u64, + 14126297534943667090u64, + 11307578615387704385u64, + 8263080598809044705u64, + 1597329401399u64, + ])); + /// COEFF_B = 272359039153593414761767159011037222092403532445017207690227512667250406992205523555677931 + /// Needs to be in the Montgomery residue form in Fq + // I.e., 272359039153593414761767159011037222092403532445017207690227512667250406992205523555677931 * R for Fq + // = 320157167097726084542307919580965705308273073979019302261176143711555219255114245445508756 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger320([ + 3452336036810055316u64, + 18124271906235581187u64, + 7868316676197606962u64, + 9218705727289990924u64, + 2764931259177u64, + ])); + + type TEModelParameters = EdwardsParameters; +} + +/// GENERATOR_X = +/// 282406820114868156776872298252698015906762052916420164316497572033519876761239463633892227 +/// Needs to be in the Montgomery residue form in Fq +/// I.e., 282406820114868156776872298252698015906762052916420164316497572033519876761239463633892227 * R for Fq +/// = 6917556742108450905978293995070573074174231920036503115659104908111915200040057661385715 +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger320([ + 797921980254612467u64, + 14323677897559322103u64, + 16879595040064082265u64, + 5138786402348661261u64, + 59741186014u64, +])); + +/// GENERATOR_Y = +/// 452667754940241021433619311795265643711152068500301853535337412655162600774122192283142703 +/// Needs to be in the Montgomery residue form in Fq +/// I.e., 452667754940241021433619311795265643711152068500301853535337412655162600774122192283142703 * R for Fq +/// = 411219337323952690830344109182130393590959634960952808951091963301565250764467583592890490 +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger320([ + 16522567711648317562u64, + 4273808507945498262u64, + 17459848913470201097u64, + 16519670308098023011u64, + 3551359510243u64, +])); diff --git a/ed_on_mnt4_298/src/curves/tests.rs b/ed_on_mnt4_298/src/curves/tests.rs new file mode 100644 index 0000000..8530221 --- /dev/null +++ b/ed_on_mnt4_298/src/curves/tests.rs @@ -0,0 +1,63 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_mnt4_298/src/fields/fq.rs b/ed_on_mnt4_298/src/fields/fq.rs new file mode 100644 index 0000000..f587b1a --- /dev/null +++ b/ed_on_mnt4_298/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_mnt4_298::{Fr as Fq, FrParameters as FqParameters}; diff --git a/ed_on_mnt4_298/src/fields/fr.rs b/ed_on_mnt4_298/src/fields/fr.rs new file mode 100644 index 0000000..6d3c5ea --- /dev/null +++ b/ed_on_mnt4_298/src/fields/fr.rs @@ -0,0 +1,127 @@ +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + fields::{FftParameters, Fp320, Fp320Parameters, FpParameters}, +}; + +pub type Fr = Fp320; + +pub struct FrParameters; + +impl Fp320Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 1u32; + + // ROOT_OF_UNITY = GENERATOR ^ t = + // 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932630 + // t is defined below + // This number needs to be in the Montgomery residue form. + // I.e., write + // 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932630 + // * R + // = 14596494758349247937872919467301196219547084259323651055171406111196152579418790325693086 + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 4913018085921565342u64, + 18164325898792356216u64, + 11499902056485864693u64, + 12113224729248979119u64, + 126057789046u64, + ]); +} +impl FpParameters for FrParameters { + // MODULUS = 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932631 + // Factors of MODULUS - 1: + // 2 + // 5 + // 17 + // 47 + // 3645289 + // 42373926857 + // 96404785755712297250936212793128201320333033128042968811755970858369 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 15535567651727634391u64, + 14992835038329117496u64, + 12879083654034347181u64, + 16760578290609820963u64, + 1027536270620u64, + ]); + + const MODULUS_BITS: u32 = 296; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 24; + + // see ark-ff/src/fields/mod.rs for more information + // R = pow(2,320) % + // 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932631 + // R = 104384076783966083500464392945960916666734135485183910065100558776489954102951241798239545 + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 10622549565806069049u64, + 15275253213246312896u64, + 1379181597548482487u64, + 4647353561360841844u64, + 901478481574u64 + ]); + + // R2 = R * R % + // 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932631 + // R2 = 64940318866745953005690402896764745514897573584912026577721076893188083397226247459368768 + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 16858329796171722560u64, + 12060416575249219689u64, + 17034911964548502611u64, + 14718631438675169669u64, + 560835539754u64 + ]); + + // INV = -(118980571542315331438337312413262112886281219744507561120271964887686106682370032123932631)^(-1) % 2^64 + const INV: u64 = 9223688842165816345u64; + + // GENERATOR = 7 + // This number needs to be in the Montgomery residue form. + // I.e., write 7 * R = + // 16805108233870595873226876142153739349451629929242003734072122109313038626438499844081029 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 18037929197695780229u64, + 16969762262749485294u64, + 6166745553471500787u64, + 5754981480705173590u64, + 145131747294u64, + ]); + + // (n-1)/2 = 59490285771157665719168656206631056443140609872253780560135982443843053341185016061966315 + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 7767783825863817195u64, + 16719789556019334556u64, + 15662913863871949398u64, + 8380289145304910481u64, + 513768135310u64, + ]); + + // t = (n - 1) / 2^{TWO_ADICITY} = + // 59490285771157665719168656206631056443140609872253780560135982443843053341185016061966315 + const T: BigInteger = BigInteger([ + 7767783825863817195u64, + 16719789556019334556u64, + 15662913863871949398u64, + 8380289145304910481u64, + 513768135310u64, + ]); + + // (t-1)/2 = 29745142885578832859584328103315528221570304936126890280067991221921526670592508030983157 + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 3883891912931908597u64, + 8359894778009667278u64, + 17054828968790750507u64, + 4190144572652455240u64, + 256884067655u64, + ]); +} diff --git a/ed_on_mnt4_298/src/fields/mod.rs b/ed_on_mnt4_298/src/fields/mod.rs new file mode 100644 index 0000000..2b2e27c --- /dev/null +++ b/ed_on_mnt4_298/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_mnt4_298", test))] +mod tests; diff --git a/ed_on_mnt4_298/src/fields/tests.rs b/ed_on_mnt4_298/src/fields/tests.rs new file mode 100644 index 0000000..3776db0 --- /dev/null +++ b/ed_on_mnt4_298/src/fields/tests.rs @@ -0,0 +1,24 @@ +use ark_ff::test_rng; +use rand::Rng; + +use crate::fields::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} diff --git a/ed_on_mnt4_298/src/lib.rs b/ed_on_mnt4_298/src/lib.rs new file mode 100644 index 0000000..8ded9b4 --- /dev/null +++ b/ed_on_mnt4_298/src/lib.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve MNT4-298. This allows defining cryptographic primitives that use elliptic curves over +//! the scalar field of the latter curve. +//! +//! Curve information: +//! * Base field: q = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +//! * Scalar field: r = 118980571542315331438337312413262112886281219744507561120271964887686106682370032123932631 +//! * Valuation(q - 1, 2) = 30 +//! * Valuation(r - 1, 2) = 1 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = 4212 mod q + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_mnt4_298/src/mod.rs b/ed_on_mnt4_298/src/mod.rs new file mode 100644 index 0000000..cd5e758 --- /dev/null +++ b/ed_on_mnt4_298/src/mod.rs @@ -0,0 +1,5 @@ +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/ed_on_mnt4_753/Cargo.toml b/ed_on_mnt4_753/Cargo.toml new file mode 100644 index 0000000..213a09e --- /dev/null +++ b/ed_on_mnt4_753/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-ed-on-mnt4-753" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A Twisted Edwards curve defined over the scalar field of the MNT4-753 curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ed-on-mnt4-753/" +keywords = ["cryptography", "finite fields", "elliptic curves" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-mnt4-753 = { path = "../mnt4_753", default-features = false, features = [ "scalar_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std", "ark-mnt4-753/std" ] diff --git a/ed_on_mnt4_753/src/curves/mod.rs b/ed_on_mnt4_753/src/curves/mod.rs new file mode 100644 index 0000000..73f0597 --- /dev/null +++ b/ed_on_mnt4_753/src/curves/mod.rs @@ -0,0 +1,188 @@ +use ark_ec::{ + models::{ModelParameters, MontgomeryModelParameters, TEModelParameters}, + twisted_edwards_extended::{GroupAffine, GroupProjective}, +}; +use ark_ff::{biginteger::BigInteger768, field_new}; + +use crate::{fq::Fq, fr::Fr}; + +#[cfg(test)] +mod tests; + +pub type EdwardsAffine = GroupAffine; +pub type EdwardsProjective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct EdwardsParameters; + +impl ModelParameters for EdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +// Many parameters need to be written down in the Montgomery residue form, +// discussed below. Some useful numbers: +// R for Fq: 11407975440035778516953587871987109648531742722982233186120790377529569367095961954159305159259556262528904776132787438725571821295685691762729353555475679813615501328617736020411951837995932262333059670631633855898874183380802 +// R for Fr: 933352698056040166367534174176950366489065242993745918174914647273231163953185260894581718311971532174387033963715296372791285468903747270837716556902938133611910788060028435531754797383796835009316018259656953442114538695438 + +impl TEModelParameters for EdwardsParameters { + /// COEFF_A = -1 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., -1 * R for Fq + /// = 30490515527883174885390626919253527479638967196971715885662712543495783445475144818899588604530782658889166195755671038597601236195908163306966888299320716352105914996732328421058466299850466207278876048428274308321910292779199 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger768([ + 2265581976117350591u64, + 18442012872391748519u64, + 3807704300793525789u64, + 12280644139289115082u64, + 10655371227771325282u64, + 1346491763263331896u64, + 7477357615964975877u64, + 12570239403004322603u64, + 2180620924574446161u64, + 12129628062772479841u64, + 8853285699251153944u64, + 362282887012814u64, + ])); + + /// COEFF_D = 317690 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., 317690 * R for Fq + /// = 22147310944926701613095824060993292411108298129020138512675871596899298127988454048404371067902679066037332245471578749765607461010546427833106841035248048771826362113332201923280907352099197626899000000763383579702914883060881 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, BigInteger768([ + 17599538631181665425u64, + 541385733032329781u64, + 10984951882154109942u64, + 6745898816867096302u64, + 8606788232777167026u64, + 17697068798460151905u64, + 7726746940317276687u64, + 16708084840201435716u64, + 10141323747759975110u64, + 6527904409415579649u64, + 18367733563217133340u64, + 263150412834478u64, + ])); + + /// COFACTOR = 8 + const COFACTOR: &'static [u64] = &[8]; + + /// COFACTOR_INV (mod r) = + /// 4582647449616135528381398492791944685893671397494963179726320631987147963874964803303316505414568319530101512550297775574042810022553679071007001162683923594233560231270043634777390699589793776691858866199511300853468155295505 + /// Needs to be in the Montgomery residue form in Fr + /// I.e., COFACTOR_INV * R for Fr + /// = 1425996930004472314619198483998388706066467840372779148265098797191196170886995244269913144907444532816113097116978062210611142118628305286285286330379702579339648914584658878663580978127201397716695606910888919424112361707074 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger768([ + 18349096995079034434u64, + 12232096963923221952u64, + 10313403112747203584u64, + 7266093872567585103u64, + 9102010985112647012u64, + 11539789563873699451u64, + 5062476400815403157u64, + 3112383580531982668u64, + 9803941911066678468u64, + 11670110706913295633u64, + 5956199581925454898u64, + 16943442107464u64, + ])); + + /// Generated randomly + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = EdwardsParameters; + + /// Multiplication by `a` is just negation. + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -*elem + } +} + +impl MontgomeryModelParameters for EdwardsParameters { + /// COEFF_A = 40212480635445336270302172549278415015971955924352275480357619589919378421241453024646804979794897776496091377551124233752850182852486874251193367187677349266115879541798515219680194853352256809837126277708211496794264654247419 + /// Needs to be in the Montgomery residue form in Fq + /// I.e., COEFF_A * R for Fq + /// = 30548714567617468394128273134168309733495884043859854416819409495212098575586848195824755026287273763308450716502830186864520759966983420083939453225231731740328282532297868204762840705631404761799649264638732114864775402781225 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger768([ + 4717325759818398249u64, + 9984799932299155706u64, + 1320735555238925850u64, + 17027346723122076572u64, + 2632519042034336982u64, + 15439824589583270152u64, + 8351651296737343223u64, + 11351622927160584696u64, + 3108522085485690820u64, + 6958456540352275598u64, + 16034686916204205245u64, + 362974397660347u64, + ])); + /// COEFF_B = 1686010332473617132042042241962222112198753995601673591425883331105974391329653748412088783995441144921979594337334243570322874639106980818502874667119046899605536783551549221790223284494141659774809441351696667426519821912580 + /// Needs to be in the Montgomery residue form in Fq + // I.e., COEFF_B * R for Fq + // = 30432316488148881376652980704338745225782050350083577354506015591779468315363441441974422182774291554469881675008511890330681712424832906529994323373409700963883547461166788637354091894069527652758102832217816501779045182777173 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger768([ + 18260582266125854549u64, + 8452481738774789715u64, + 6294673046348125729u64, + 7533941555456153592u64, + 231479339798761966u64, + 5699903010652945257u64, + 6603063935192608530u64, + 13788855878848060510u64, + 1252719763663201502u64, + 17300799585192684084u64, + 1671884482298102643u64, + 361591376365281u64, + ])); + + type TEModelParameters = EdwardsParameters; +} + +/// GENERATOR_X = +/// 41126137307536311801428235632419266329480236393691483739251051053325519918069469184425962602019877935619960143044210127218431046103600632347238890180171944971817510488009355627861577881883236134824745174469522277738875418206826 +/// Needs to be in the Montgomery residue form in Fq +/// I.e., GENERATOR_X * R for Fq +/// = 17458296603084005843875564204476809882690765950143935590811069375604430769391871724158635621148427226413334766092842987247361751645959801401160673759590522483750685475882467271029344718076741595831312033991612062403782328664175 +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ + 13391543849638641775u64, + 1472718285337442467u64, + 1704796371472020786u64, + 1309193942690519845u64, + 11187264906425773918u64, + 11963130799714018220u64, + 10821241385017749516u64, + 4661882526685671286u64, + 8328914571224024668u64, + 17202160931109725769u64, + 4708938015393622850u64, + 207436377712515u64, +])); + +/// GENERATOR_Y = +/// 18249602579663240810999977712212098844157230095713722119136881953011435881503578209163288529034825612841855863913294174196656077002578342108932925693640046298989762289691399012056048139253937882385653600831389370198228562812681 +/// Needs to be in the Montgomery residue form in Fq +/// I.e., GENERATOR_Y * R for Fq +/// = 9017791529346511307345374145466037779022974291216533108328228023141994468888559894991603799439817566592668010556604996318161436165296215592281656017954181737938978992370627048110847574165717052386876801764386102664064737203581 +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ + 16764059510974436733u64, + 10694630934032454957u64, + 15899992550979352399u64, + 17663221529566141065u64, + 3780246386961240559u64, + 6062186621379836072u64, + 11042203340250178810u64, + 1263100291243127914u64, + 14407501552666806512u64, + 13385165116432280059u64, + 11978187531853934313u64, + 107147796394053u64, +])); diff --git a/ed_on_mnt4_753/src/curves/tests.rs b/ed_on_mnt4_753/src/curves/tests.rs new file mode 100644 index 0000000..8530221 --- /dev/null +++ b/ed_on_mnt4_753/src/curves/tests.rs @@ -0,0 +1,63 @@ +use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_ff::test_rng; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_projective_curve() { + curve_tests::(); + + edwards_tests::(); +} + +#[test] +fn test_projective_group() { + let mut rng = test_rng(); + let a = rng.gen(); + let b = rng.gen(); + + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_affine_group() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + for _i in 0..100 { + group_test::(a, b); + } +} + +#[test] +fn test_generator() { + let generator = EdwardsAffine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_conversion() { + let mut rng = test_rng(); + let a: EdwardsAffine = rng.gen(); + let b: EdwardsAffine = rng.gen(); + let a_b = { + use ark_ec::group::Group; + (a + &b).double().double() + }; + let a_b2 = (a.into_projective() + &b.into_projective()) + .double() + .double(); + assert_eq!(a_b, a_b2.into_affine()); + assert_eq!(a_b.into_projective(), a_b2); +} + +#[test] +fn test_montgomery_conversion() { + montgomery_conversion_test::(); +} diff --git a/ed_on_mnt4_753/src/fields/fq.rs b/ed_on_mnt4_753/src/fields/fq.rs new file mode 100644 index 0000000..33f3df1 --- /dev/null +++ b/ed_on_mnt4_753/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_mnt4_753::{Fr as Fq, FrParameters as FqParameters}; diff --git a/ed_on_mnt4_753/src/fields/fr.rs b/ed_on_mnt4_753/src/fields/fr.rs new file mode 100644 index 0000000..98e7871 --- /dev/null +++ b/ed_on_mnt4_753/src/fields/fr.rs @@ -0,0 +1,182 @@ +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, +}; + +pub type Fr = Fp768; + +pub struct FrParameters; + +impl Fp768Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 7u32; + + // ROOT_OF_UNITY = GENERATOR ^ t = + // 5051348772165646558710889803432238607797392809516000790038615454406641638798360636639094562941749878118669420392611632754442159525900729019616828636182878045303562497793780656635901271279409699078868658041674335385318499053954 + // t is defined below + // This number needs to be in the Montgomery residue form. + // I.e., write + // 5051348772165646558710889803432238607797392809516000790038615454406641638798360636639094562941749878118669420392611632754442159525900729019616828636182878045303562497793780656635901271279409699078868658041674335385318499053954 + // * R + // = 3163945077843586747114473523156080008349200300253316071422414259389979351386670787753361998953450578171951209600907861296956453653582402723399808696724060539858637307706671971132333536614595846054039300191656599533885935499352 + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 17630237153019476056u64, + 13843632041501582123u64, + 8277579215948731020u64, + 16543319700733887487u64, + 17904443422768964556u64, + 4398189354108552378u64, + 15178824470536352826u64, + 5393472405610595666u64, + 9815530206026813666u64, + 9111703519527971535u64, + 9880873531994141485u64, + 37593433148184u64, + ]); +} +impl FpParameters for FrParameters { + // MODULUS = 5237311370989869175293026848905079641021338739994243633972937865128169101571388346632361720473792365177258871486054600656048925740061347509722287043067341250552640264308621296888446513816907173362124418513727200975392177480577 + // Factors of MODULUS - 1: + // 2^7 + // 3 + // 67 + // 193189 + // 5324381 + // 20502324317011 + // 12991385268608969143 + // 743005941432538001939136029613828619428586060274612824031793373798492678674419102414979927623550862639644071557313558044209469997283394306590808303316688123808776073253386140931 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 1918157353135465345u64, + 963476667289301255u64, + 6719983938249379016u64, + 3655897403342429413u64, + 14998997414201165002u64, + 13135040821375901270u64, + 12914675130452106995u64, + 6989506515121216945u64, + 12382362535852178190u64, + 13186314214759855613u64, + 2451174275904461237u64, + 62228802984066u64, + ]); + + const MODULUS_BITS: u32 = 750; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 18; + + // see ark_ff/src/fields/mod.rs for more information + // R = pow(2,768) % MODULUS + // R = 933352698056040166367534174176950366489065242993745918174914647273231163953185260894581718311971532174387033963715296372791285468903747270837716556902938133611910788060028435531754797383796835009316018259656953442114538695438 + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 13829252738394483470u64, + 3696102008259415033u64, + 13727024804350215797u64, + 13923468026436718769u64, + 5924604905079742862u64, + 10708002647109138222u64, + 14670460945619011269u64, + 10920055614013427454u64, + 16773322069409968132u64, + 11648025004657998992u64, + 5853759956175613481u64, + 11089930891582u64, + ]); + + // R2 = R * R % MODULUS + // R2 = 2468731867191023344597744941938926307216338526282824416880609839804154918771848044056240157551420210981962520047623686977567450338290776997282473798413876535168711321018336215486289519735826959884564283681071791441993286279295 + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 10440129917231554687u64, + 8797934528693354276u64, + 14378434434829994158u64, + 7755707164286885667u64, + 16206546501540671680u64, + 8674228973811871262u64, + 12794601382709871071u64, + 17194287857269754157u64, + 2120600029739364160u64, + 15454005187782655500u64, + 18107041519543174727u64, + 29333033326005u64, + ]); + + // INV = -(MODULUS)^(-1) % 2^64 + const INV: u64 = 3079018560679650175u64; + + // GENERATOR = 5 + // This number needs to be in the Montgomery residue form. + // I.e., write 5 * R = + // 4666763490280200831837670870884751832445326214968729590874573236366155819765926304472908591559857660871935169818576481863956427344518736354188582784514690668059553940300142177658773986918984175046580091298284767210572693477190 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 13806031470843762502u64, + 33765967587523552u64, + 13294891800622424138u64, + 14277107911054939000u64, + 11176280451689162697u64, + 16646525088126587879u64, + 18012072506966401499u64, + 17706789922648034041u64, + 10079634052211634198u64, + 2899892802161340116u64, + 10822055707168515792u64, + 55449654457911u64, + ]); + + // (n-1)/2 = 2618655685494934587646513424452539820510669369997121816986468932564084550785694173316180860236896182588629435743027300328024462870030673754861143521533670625276320132154310648444223256908453586681062209256863600487696088740288 + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 10182450713422508480u64, + 481738333644650627u64, + 12583364005979465316u64, + 1827948701671214706u64, + 7499498707100582501u64, + 15790892447542726443u64, + 15680709602080829305u64, + 3494753257560608472u64, + 15414553304780864903u64, + 15816529144234703614u64, + 1225587137952230618u64, + 31114401492033u64, + ]); + + // t = (n - 1) / 2^{TWO_ADICITY} = + // 40916495085858352931976772257070934695479208906205028390413577071313821106026471458065325941201502852947334933484801567625382232344229277419705367523963603519942502064911103881940988389194587291891597019638493757620251386567 + const T: BigInteger = BigInteger([ + 1023791920852361927u64, + 10383820702924820450u64, + 14608133870179016345u64, + 10693085616076947257u64, + 12511085841822051593u64, + 16675864135140424508u64, + 7162540115173594813u64, + 2072218152711366715u64, + 18111135716793329142u64, + 7741123047823172587u64, + 307380175182215347u64, + 486162523313u64, + ]); + + // (t-1)/2 = 20458247542929176465988386128535467347739604453102514195206788535656910553013235729032662970600751426473667466742400783812691116172114638709852683761981801759971251032455551940970494194597293645945798509819246878810125693283 + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 511895960426180963u64, + 14415282388317186033u64, + 16527438971944283980u64, + 14569914844893249436u64, + 6255542920911025796u64, + 17561304104424988062u64, + 12804642094441573214u64, + 1036109076355683357u64, + 18278939895251440379u64, + 13093933560766362101u64, + 9377062124445883481u64, + 243081261656u64, + ]); +} diff --git a/ed_on_mnt4_753/src/fields/mod.rs b/ed_on_mnt4_753/src/fields/mod.rs new file mode 100644 index 0000000..e20037a --- /dev/null +++ b/ed_on_mnt4_753/src/fields/mod.rs @@ -0,0 +1,8 @@ +pub mod fq; +pub mod fr; + +pub use fq::*; +pub use fr::*; + +#[cfg(all(feature = "ed_on_mnt4_753", test))] +mod tests; diff --git a/ed_on_mnt4_753/src/fields/tests.rs b/ed_on_mnt4_753/src/fields/tests.rs new file mode 100644 index 0000000..d57fbf1 --- /dev/null +++ b/ed_on_mnt4_753/src/fields/tests.rs @@ -0,0 +1,23 @@ +use ark_ff::test_rng; +use rand::Rng; + +use crate::{Fq, Fr}; +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + primefield_test::(); +} diff --git a/ed_on_mnt4_753/src/lib.rs b/ed_on_mnt4_753/src/lib.rs new file mode 100644 index 0000000..505987d --- /dev/null +++ b/ed_on_mnt4_753/src/lib.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements a twisted Edwards curve whose base field is the scalar field of the +//! curve MNT4-753. This allows defining cryptographic primitives that use elliptic curves over +//! the scalar field of the latter curve. +//! +//! Curve information: +//! * Base field: q = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001 +//! * Scalar field: r = 5237311370989869175293026848905079641021338739994243633972937865128169101571388346632361720473792365177258871486054600656048925740061347509722287043067341250552640264308621296888446513816907173362124418513727200975392177480577 +//! * Valuation(q - 1, 2) = 30 +//! * Valuation(r - 1, 2) = 7 +//! * Curve equation: ax^2 + y^2 =1 + dx^2y^2, where +//! * a = -1 +//! * d = 317690 mod q + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/mnt4_298/Cargo.toml b/mnt4_298/Cargo.toml new file mode 100644 index 0000000..5d3f510 --- /dev/null +++ b/mnt4_298/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ark-mnt4-298" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The MNT4-298 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-mnt4-298/" +keywords = ["cryptography", "finite fields" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field", "base_field" ] +scalar_field = [] +base_field = [] diff --git a/mnt4_298/LICENSE-APACHE b/mnt4_298/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/mnt4_298/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/mnt4_298/LICENSE-MIT b/mnt4_298/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/mnt4_298/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/mnt4_298/src/curves/g1.rs b/mnt4_298/src/curves/g1.rs new file mode 100644 index 0000000..f3a625b --- /dev/null +++ b/mnt4_298/src/curves/g1.rs @@ -0,0 +1,79 @@ +use crate::{Fq, Fr, FR_ONE}; +use ark_ec::{ + mnt4, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger320, field_new}; + +pub type G1Affine = mnt4::G1Affine; +pub type G1Projective = mnt4::G1Projective; +pub type G1Prepared = mnt4::G1Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 2 + /// Reference: https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L116 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger320([ + 3568597988870129848, + 15257338106490985450, + 10069779447956199041, + 5922375556522222383, + 3858029504390, + ])); + + /// COEFF_B = 423894536526684178289416011533888240029318103673896002803341544124054745019340795360841685 + /// Reference: https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L117 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger320([ + 7842808090366692145, + 288200302308193399, + 4162060950790347941, + 5488589108190218591, + 1553456013645, + ])); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[1]; + + /// COFACTOR^(-1) mod r = + /// 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = FR_ONE; + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); +} + +// Generator of G1 +// X = 60760244141852568949126569781626075788424196370144486719385562369396875346601926534016838, +// Y = 363732850702582978263902770815145784459747722357071843971107674179038674942891694705904306, +/// G1_GENERATOR_X +/// Reference: https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L137 +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger320([ + 6046301378120906932, + 15105298306031900263, + 15757949605695610691, + 6113949277267426050, + 3063081829217, +])); + +/// G1_GENERATOR_Y +/// Reference: https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L138 +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger320([ + 8798367863963590781, + 9770379341721339603, + 17697354471293810920, + 15252694996423733496, + 3845520398052, +])); diff --git a/mnt4_298/src/curves/g2.rs b/mnt4_298/src/curves/g2.rs new file mode 100644 index 0000000..cdaa4a9 --- /dev/null +++ b/mnt4_298/src/curves/g2.rs @@ -0,0 +1,127 @@ +use crate::{Fq, Fq2, Fr, FQ_ZERO, G1_COEFF_A_NON_RESIDUE}; +use ark_ec::{ + mnt4, + mnt4::MNT4Parameters, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger320, field_new}; + +pub type G2Affine = mnt4::G2Affine; +pub type G2Projective = mnt4::G2Projective; +pub type G2Prepared = mnt4::G2Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq2; + type ScalarField = Fr; +} + +/// MUL_BY_A_C0 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C0: Fq = G1_COEFF_A_NON_RESIDUE; + +/// MUL_BY_A_C1 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C1: Fq = G1_COEFF_A_NON_RESIDUE; + +impl SWModelParameters for Parameters { + const COEFF_A: Fq2 = crate::Parameters::TWIST_COEFF_A; + // B coefficient of MNT4-298 G2 = + // ``` + // mnt4298_twist_coeff_b = mnt4298_Fq2(mnt4298_Fq::zero(), + // mnt4298_G1::coeff_b * mnt4298_Fq2::non_residue); + // non_residue = mnt4298_Fq2::non_residue = mnt4298_Fq("13"); + // = (ZERO, G1_B_COEFF * NON_RESIDUE); + // = + // (0, 67372828414711144619833451280373307321534573815811166723479321465776723059456513877937430) + // ``` + #[rustfmt::skip] + const COEFF_B: Fq2 = field_new!(Fq2, + FQ_ZERO, + field_new!(Fq, BigInteger320([ + 9511110677122940475, + 13403516020116973437, + 1464701424831086967, + 4646785117660390394, + 1747881737068, + ])), + ); + + /// COFACTOR = + /// 475922286169261325753349249653048451545124879932565935237842521413255878328503110407553025 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 15480692783052488705, + 9802782456999489873, + 14622846468721090623, + 11702080941310629006, + 4110145082483, + ]; + + /// COFACTOR^(-1) mod r = + /// 475922286169261325753349249653048451545124878207887910632124039320641839552134835598065665 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger320([ + 8065818351154103109, + 7537800592537321232, + 747075088561892445, + 6335802185495034136, + 1874289794052, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(elt: &Fq2) -> Fq2 { + field_new!(Fq2, MUL_BY_A_C0 * &elt.c0, MUL_BY_A_C1 * &elt.c1,) + } +} + +const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); +const G2_GENERATOR_Y: Fq2 = field_new!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1); + +// Generator of G2 +// These are two Fq elements each because X and Y (and Z) are elements of Fq^2 +// X = 438374926219350099854919100077809681842783509163790991847867546339851681564223481322252708, +// 37620953615500480110935514360923278605464476459712393277679280819942849043649216370485641, +// Y = 37437409008528968268352521034936931842973546441370663118543015118291998305624025037512482, +// 424621479598893882672393190337420680597584695892317197646113820787463109735345923009077489, +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger320([ + 5356671649366391794, + 2684151262065976452, + 4683110650642896126, + 10421299515941681582, + 1618695480960 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger320([ + 133394645290266480, + 15395232932057272770, + 18271324022738539173, + 9095178119640120034, + 2303787573609 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger320([ + 16920448081812496532, + 15580160192086626100, + 3974467672100342742, + 8216505962266760277, + 2643162835232 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger320([ + 73816197493558356, + 8663991890578965996, + 11575903875707445958, + 17953546933481201011, + 2167465829200 +])); diff --git a/mnt4_298/src/curves/mod.rs b/mnt4_298/src/curves/mod.rs new file mode 100644 index 0000000..4b51cd1 --- /dev/null +++ b/mnt4_298/src/curves/mod.rs @@ -0,0 +1,63 @@ +use ark_ec::models::mnt4::{MNT4Parameters, MNT4}; +use ark_ff::{biginteger::BigInteger320, field_new, fields::FpParameters, Fp2}; + +use crate::{Fq, Fq2, Fq2Parameters, Fq4Parameters, FqParameters, Fr, FrParameters}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub use self::{ + g1::{G1Affine, G1Prepared, G1Projective}, + g2::{G2Affine, G2Prepared, G2Projective}, +}; + +pub type MNT4_298 = MNT4; + +pub struct Parameters; + +impl MNT4Parameters for Parameters { + const TWIST: Fp2 = field_new!(Fq2, FQ_ZERO, FQ_ONE); + // A coefficient of MNT4-298 G2 = + // ``` + // mnt4298_twist_coeff_a = mnt4298_Fq2(mnt4298_G1::coeff_a * non_residue, mnt6298_Fq::zero()); + // = (A_COEFF * NONRESIDUE, ZERO) + // = (34, ZERO) + // ``` + #[rustfmt::skip] + const TWIST_COEFF_A: Fp2 = field_new!(Fq2, + G1_COEFF_A_NON_RESIDUE, + FQ_ZERO, + ); + + const ATE_LOOP_COUNT: &'static [u64] = &[993502997770534912, 5071219579242586943, 2027349]; + const ATE_IS_LOOP_COUNT_NEG: bool = false; + const FINAL_EXPONENT_LAST_CHUNK_1: BigInteger320 = BigInteger320([0x1, 0x0, 0x0, 0x0, 0x0]); + const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = false; + const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger320 = + BigInteger320([993502997770534913, 5071219579242586943, 2027349, 0, 0]); + type Fp = Fq; + type Fr = Fr; + type Fp2Params = Fq2Parameters; + type Fp4Params = Fq4Parameters; + type G1Parameters = self::g1::Parameters; + type G2Parameters = self::g2::Parameters; +} + +// 34 +pub const G1_COEFF_A_NON_RESIDUE: Fq = field_new!( + Fq, + BigInteger320([ + 9379015694948865065, + 3933863906897692531, + 7183785805598089445, + 17382890709766103498, + 3934325337380, + ]) +); +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger320([0, 0, 0, 0, 0])); +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FR_ZERO: Fr = field_new!(Fr, BigInteger320([0, 0, 0, 0, 0])); +pub const FR_ONE: Fr = field_new!(Fr, FrParameters::R); diff --git a/mnt4_298/src/curves/tests.rs b/mnt4_298/src/curves/tests.rs new file mode 100644 index 0000000..4167d71 --- /dev/null +++ b/mnt4_298/src/curves/tests.rs @@ -0,0 +1,90 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField, UniformRand}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = MNT4_298::pairing(sa, b); + let ans2 = MNT4_298::pairing(a, sb); + let ans3 = MNT4_298::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq4::one()); + assert_ne!(ans2, Fq4::one()); + assert_ne!(ans3, Fq4::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq4::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq4::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq4::one()); +} + +#[test] +fn test_product_of_pairings() { + let rng = &mut test_rng(); + + let a = G1Projective::rand(rng).into_affine(); + let b = G2Projective::rand(rng).into_affine(); + let c = G1Projective::rand(rng).into_affine(); + let d = G2Projective::rand(rng).into_affine(); + let ans1 = MNT4_298::pairing(a, b) * &MNT4_298::pairing(c, d); + let ans2 = MNT4_298::product_of_pairings(&[(a.into(), b.into()), (c.into(), d.into())]); + assert_eq!(ans1, ans2); +} diff --git a/mnt4_298/src/fields/fq.rs b/mnt4_298/src/fields/fq.rs new file mode 100644 index 0000000..028c75f --- /dev/null +++ b/mnt4_298/src/fields/fq.rs @@ -0,0 +1,115 @@ +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + fields::{FftParameters, Fp320, Fp320Parameters, FpParameters}, +}; + +pub type Fq = Fp320; + +pub struct FqParameters; + +impl Fp320Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 17; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 9821480371597472441u64, + 9468346035609379175u64, + 9963748368231707135u64, + 14865337659602750405u64, + 3984815592673u64, + ]); + + const SMALL_SUBGROUP_BASE: Option = Some(7); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); + + /// LARGE_SUBGROUP_ROOT_OF_UNITY = x * g + /// where x = (n - 1) / 2^17 / 7^2 + /// and represent this value in the Montgomery residue form. + /// I.e., write + /// 381811485921190977554243339163030148371175054922689353173385941180422489253833691237722982 + /// * R + /// = 260534023778902228073198316993669317435810479439368306496187170459125001342456918103569322 + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInteger([ + 7711798843682337706u64, + 16456007754393011187u64, + 7470854640069402569u64, + 10767969225751706229u64, + 2250015743691u64, + ])); +} +impl FpParameters for FqParameters { + /// MODULUS = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 14487189785281953793u64, + 4731562877756902930u64, + 14622846468719063274u64, + 11702080941310629006u64, + 4110145082483u64, + ]); + + const MODULUS_BITS: u32 = 298; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 22; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 1784298994435064924u64, + 16852041090100268533u64, + 14258261760832875328u64, + 2961187778261111191u64, + 1929014752195u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 28619103704175136u64, + 11702218449377544339u64, + 7403203599591297249u64, + 2248105543421449339u64, + 2357678148148u64, + ]); + + const INV: u64 = 12714121028002250751u64; + + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 2709730703260633621u64, + 13556085429182073539u64, + 10903316137158576359u64, + 5319113788683590444u64, + 4022235209932u64, + ]); + + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x70964866b2d38b3, + 0x987520d4f1af2890, + 0x2a47657764b1ae89, + 0x6a39d133124ed3d8, + 0x1de7bde, + ]); + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x384b24335969c59, + 0xcc3a906a78d79448, + 0x1523b2bbb258d744, + 0x351ce899892769ec, + 0xef3def, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x64866b2d38b30000, + 0x20d4f1af28900709, + 0x657764b1ae899875, + 0xd133124ed3d82a47, + 0x1de7bde6a39, + ]); +} diff --git a/mnt4_298/src/fields/fq2.rs b/mnt4_298/src/fields/fq2.rs new file mode 100644 index 0000000..666251e --- /dev/null +++ b/mnt4_298/src/fields/fq2.rs @@ -0,0 +1,58 @@ +use crate::{Fq, FQ_ONE}; +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + field_new, + fields::fp2::{Fp2, Fp2Parameters}, +}; + +pub type Fq2 = Fp2; + +pub struct Fq2Parameters; + +impl Fp2Parameters for Fq2Parameters { + type Fp = Fq; + + /// The quadratic non-residue (17) used to construct the extension is + /// the same as that used in [`libff`](https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L102). + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 2709730703260633621, + 13556085429182073539, + 10903316137158576359, + 5319113788683590444, + 4022235209932, + ])); + + /// The quadratic non-residue in Fp2 that is used + /// in the computation of square roots is (8, 1), the same as that in + /// [`libff`](https://github.com/scipr-lab/libff/blob/c927821ebe02e0a24b5e0f9170cec5e211a35f08/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp#L103) + const QUADRATIC_NONRESIDUE: (Self::Fp, Self::Fp) = ( + field_new!( + Fq, + BigInteger([ + 7706310747053761245, + 9941175645274129776, + 14857322459377157960, + 7030003475866554129, + 3101682770110 + ]) + ), + FQ_ONE, + ); + + /// Precomputed coefficients: + /// `[1, 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080]` + const FROBENIUS_COEFF_FP2_C1: &'static [Self::Fp] = &[ + FQ_ONE, + field_new!( + Fq, + BigInteger([ + 12702890790846888869, + 6326265861366186013, + 364584707886187945, + 8740893163049517815, + 2181130330288 + ]) + ), + ]; +} diff --git a/mnt4_298/src/fields/fq4.rs b/mnt4_298/src/fields/fq4.rs new file mode 100644 index 0000000..f0ee578 --- /dev/null +++ b/mnt4_298/src/fields/fq4.rs @@ -0,0 +1,56 @@ +use crate::{Fq, Fq2, Fq2Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + field_new, + fields::fp4::{Fp4, Fp4Parameters}, +}; + +pub type Fq4 = Fp4; + +pub struct Fq4Parameters; + +impl Fp4Parameters for Fq4Parameters { + type Fp2Params = Fq2Parameters; + + const NONRESIDUE: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ONE); + + // Coefficients for the Frobenius automorphism. + // c1[0] = 1, + // c1[1] = 7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308 + // c1[2] = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080 + // c1[3] = 468238122923807824137727898100575114475823797181717920390930116882062371863914936316755773 + #[rustfmt::skip] + const FROBENIUS_COEFF_FP4_C1: &'static [Fq] = &[ + FQ_ONE, + field_new!( + Fq, + BigInteger([ + 16439849825752526567, + 14772594681319164557, + 16175669228740845684, + 4590896976404796446, + 3810243174413 + ]) + ), + field_new!( + Fq, + BigInteger([ + 12702890790846888869, + 6326265861366186013, + 364584707886187945, + 8740893163049517815, + 2181130330288 + ]) + ), + field_new!( + Fq, + BigInteger([ + 16494084033238978842, + 8405712270147289988, + 16893921313687769205, + 7111183964905832559, + 299901908070 + ]) + ), + ]; +} diff --git a/mnt4_298/src/fields/fr.rs b/mnt4_298/src/fields/fr.rs new file mode 100644 index 0000000..3cfaf21 --- /dev/null +++ b/mnt4_298/src/fields/fr.rs @@ -0,0 +1,99 @@ +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + fields::{FftParameters, Fp320, Fp320Parameters, FpParameters}, +}; + +pub type Fr = Fp320; + +pub struct FrParameters; + +impl Fp320Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 34; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x818b361df1af7be4, + 0x2ae2750d46a53957, + 0x5784a8fe792c5f8a, + 0xf9bd39c0cdcf1bb6, + 0x6a24a0f8a8, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xbb4334a400000001, + 0xfb494c07925d6ad3, + 0xcaeec9635cf44194, + 0xa266249da7b0548e, + 0x3bcf7bcd473, + ]); + + const MODULUS_BITS: u32 = 298; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 22; + + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0xc3177aefffbb845c, + 0x9b80c702f9961788, + 0xc5df8dcdac70a85a, + 0x29184098647b5197, + 0x1c1223d33c3, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0x465a743c68e0596b, + 0x34f9102adb68371, + 0x4bbd6dcf1e3a8386, + 0x2ff00dced8e4b6d, + 0x149bb44a342, + ]); + + const INV: u64 = 0xbb4334a3ffffffff; + + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0xb1ddfacffd532b94, + 0x25e295ff76674008, + 0x8f00647b48958d36, + 0x1159f37d4e0fddb2, + 0x2977770b3d1, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xdda19a5200000000, + 0x7da4a603c92eb569, + 0x657764b1ae7a20ca, + 0xd133124ed3d82a47, + 0x1de7bde6a39, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0xe4975ab4eed0cd29, + 0xd73d10653ed25301, + 0x69ec1523b2bbb258, + 0x3def351ce8998927, + 0xef, + ]); + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xf24bad5a77686694, + 0x6b9e88329f692980, + 0xb4f60a91d95dd92c, + 0x9ef79a8e744cc493, + 0x77, + ]); +} diff --git a/mnt4_298/src/fields/mod.rs b/mnt4_298/src/fields/mod.rs new file mode 100644 index 0000000..719e03b --- /dev/null +++ b/mnt4_298/src/fields/mod.rs @@ -0,0 +1,22 @@ +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(feature = "base_field")] +pub mod fq; +#[cfg(feature = "base_field")] +pub use self::fq::*; + +#[cfg(feature = "curve")] +pub mod fq2; +#[cfg(feature = "curve")] +pub use self::fq2::*; + +#[cfg(feature = "curve")] +pub mod fq4; +#[cfg(feature = "curve")] +pub use self::fq4::*; + +#[cfg(all(feature = "curve", test))] +mod tests; diff --git a/mnt4_298/src/fields/tests.rs b/mnt4_298/src/fields/tests.rs new file mode 100644 index 0000000..9891d3a --- /dev/null +++ b/mnt4_298/src/fields/tests.rs @@ -0,0 +1,45 @@ +use ark_ff::{test_rng, Field}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq2() { + let mut rng = test_rng(); + let a: Fq2 = rng.gen(); + let b: Fq2 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq4() { + let mut rng = test_rng(); + let a: Fq4 = rng.gen(); + let b: Fq4 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/mnt4_298/src/lib.rs b/mnt4_298/src/lib.rs new file mode 100644 index 0000000..1847b0a --- /dev/null +++ b/mnt4_298/src/lib.rs @@ -0,0 +1,39 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the MNT4_298 curve generated by +//! [[BCTV14]](https://eprint.iacr.org/2014/595). The name denotes that it is a +//! Miyaji--Nakabayashi--Takano curve of embedding degree 4, defined over a 298-bit (prime) field. +//! The main feature of this curve is that its scalar field and base field respectively equal the +//! base field and scalar field of MNT6_298. +//! +//! +//! Curve information: +//! * Base field: q = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 +//! * Scalar field: r = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +//! * valuation(q - 1, 2) = 17 +//! * valuation(r - 1, 2) = 34 +//! * G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 2 +//! * b = 423894536526684178289416011533888240029318103673896002803341544124054745019340795360841685 +//! * G2 curve equation: y^2 = x^3 + Ax + B, where +//! * A = Fq2 = (a * NON_RESIDUE, 0) +//! * B = Fq2(0, b * NON_RESIDUE) +//! * NON_RESIDUE = 17 is the quadratic non-residue used for constructing the extension field Fq2 + +#[cfg(feature = "curve")] +mod curves; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +pub use fields::*; diff --git a/mnt4_753/Cargo.toml b/mnt4_753/Cargo.toml new file mode 100644 index 0000000..d025205 --- /dev/null +++ b/mnt4_753/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ark-mnt4-753" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The MNT4-753 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-mnt4-753/" +keywords = ["cryptography", "finite fields" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [ "curve" ] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] + +curve = [ "scalar_field", "base_field" ] +scalar_field = [] +base_field = [] diff --git a/mnt4_753/LICENSE-APACHE b/mnt4_753/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/mnt4_753/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/mnt4_753/LICENSE-MIT b/mnt4_753/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/mnt4_753/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/mnt4_753/src/curves/g1.rs b/mnt4_753/src/curves/g1.rs new file mode 100644 index 0000000..9a6e3db --- /dev/null +++ b/mnt4_753/src/curves/g1.rs @@ -0,0 +1,104 @@ +use ark_ec::{ + mnt4, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger768, field_new}; + +use crate::{Fq, Fr, FR_ONE}; + +pub type G1Affine = mnt4::G1Affine; +pub type G1Projective = mnt4::G1Projective; +pub type G1Prepared = mnt4::G1Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 2 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger768([ + 3553860551672651396, + 2565472393707818253, + 3424927325234966109, + 17487811826058095619, + 15730291918544907998, + 4332070408724822737, + 7212646118208244402, + 12904649141092619460, + 9289117987390442562, + 2254330573517213976, + 3065472942259520298, + 271095073719429, + ])); + + /// COEFF_B = 0x01373684A8C9DCAE7A016AC5D7748D3313CD8E39051C596560835DF0C9E50A5B59B882A92C78DC537E51A16703EC9855C77FC3D8BB21C8D68BB8CFB9DB4B8C8FBA773111C36C8B1B4E8F1ECE940EF9EAAD265458E06372009C9A0491678EF4 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger768([ + 2672638521926201442, + 17587766986973859626, + 1309143029066506763, + 1756412671449422902, + 5395165286423163724, + 589638022240022974, + 7360845090332416697, + 9829497896347590557, + 9341553552113883496, + 5888515763059971584, + 10173739464651404689, + 456607542322059, + ])); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[1]; + + /// COFACTOR^(-1) mod r = + /// 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = FR_ONE; + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); +} + +// Generator of G1 +// X = 7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569, +// Y = 6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648, +/// G1_GENERATOR_X = +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ + 9433494781491502420, + 373642694095780604, + 7974079134466535382, + 15325904219470166885, + 16825705122208020751, + 898733863352481713, + 3802318585082797759, + 14417069684372068941, + 4332882897981414838, + 15138727514183191816, + 16850594895992448907, + 30598511593902 +])); + +/// G1_GENERATOR_Y = +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ + 15710199097794077134, + 3645667958306606136, + 8298269426007169475, + 5277073422205725562, + 10451808582969862130, + 14392820246664025579, + 4365987620174557815, + 14007263953321073101, + 1355600847400958219, + 3872959105252355444, + 18016882244107198324, + 424779036457857 +])); diff --git a/mnt4_753/src/curves/g2.rs b/mnt4_753/src/curves/g2.rs new file mode 100644 index 0000000..98825d1 --- /dev/null +++ b/mnt4_753/src/curves/g2.rs @@ -0,0 +1,177 @@ +use ark_ec::{ + mnt4, + mnt4::MNT4Parameters, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger768, field_new}; + +use crate::{Fq, Fq2, Fr, FQ_ZERO, G1_COEFF_A_NON_RESIDUE}; + +pub type G2Affine = mnt4::G2Affine; +pub type G2Projective = mnt4::G2Projective; +pub type G2Prepared = mnt4::G2Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq2; + type ScalarField = Fr; +} + +/// MUL_BY_A_C0 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C0: Fq = G1_COEFF_A_NON_RESIDUE; + +/// MUL_BY_A_C1 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C1: Fq = G1_COEFF_A_NON_RESIDUE; + +impl SWModelParameters for Parameters { + const COEFF_A: Fq2 = crate::Parameters::TWIST_COEFF_A; + // B coefficient of MNT4-753 G2 = + // ``` + // mnt4753_twist_coeff_b = mnt4753_Fq2(mnt4753_Fq::zero(), + // mnt4753_G1::coeff_b * mnt4753_Fq2::non_residue); + // non_residue = mnt4753_Fq2::non_residue = mnt4753_Fq("13"); + // = (ZERO, G1_B_COEFF * NON_RESIDUE); + // = + // (0, 39196523001581428369576759982967177918859161321667605855515469914917622337081756705006832951954384669101573360625169461998308377011601613979275218690841934572954991361632773738259652003389826903175898479855893660378722437317212) + // ``` + #[rustfmt::skip] + const COEFF_B: Fq2 = field_new!(Fq2, + FQ_ZERO, + field_new!(Fq, BigInteger768([ + 15129916544657421551, + 11332543254671606602, + 11913830318987286849, + 13905314883394440110, + 16479690325073358448, + 14869098639251228898, + 10663986895980443550, + 10768989312009479656, + 9469728929095040349, + 4512954369775881939, + 8788997129423430122, + 459763387588954, + ])), + ); + + /// COFACTOR = + /// 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888049094905534395567574915333486969589229856772141392370549616644545554517640527237829320384324374366385444967219201 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 16436257212445032449, + 8690275530472745198, + 17315389657026393162, + 1645397558963170979, + 3544984605440726586, + 12665092767997125024, + 11083680675069097885, + 575819899841080717, + 6825179918269667443, + 13256793349531086829, + 1162650133526138285, + 497830423872529, + ]; + + /// COFACTOR^(-1) mod r = + /// 102345604409665481004734934052318066391634848395005988700111949231215905051467807945653833683883449458834877235200 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger768([ + 1879390364380281898, + 7926794171490610432, + 6437239504245874253, + 16688141022047191858, + 17059416847145768464, + 15065047661241262516, + 16537575340937777321, + 3324411942044534547, + 3878293904770657570, + 18116939243856833744, + 7557533897589069385, + 78370361203778, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(elt: &Fq2) -> Fq2 { + field_new!(Fq2, MUL_BY_A_C0 * &elt.c0, MUL_BY_A_C1 * &elt.c1,) + } +} + +const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); +const G2_GENERATOR_Y: Fq2 = field_new!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1); + +// Generator of G2 +// These are two Fq elements each because X and Y (and Z) are elements of Fq^2 +// X = 29483965110843144675703364744708836524643960105538608078862508397502447349913068434941060515343254862580437318493682762113105361632548148204806052114008731372757389645383891982211245013965175213456066452587869519098351487925167, +// 19706011319630172391076079624799753948158506771222147486237995321925443331396169656568431378974558350664383559981183980668976846806019030432389169137953988990802000581078994008283967768348275973921598166274857631001635633631000, +// Y = 39940152670760519653940320314827327941993141403708338666925204282084477074754642625849927569427860786384998614863651207257467076192649385174108085803168743803491780568503369317093191101779534035377266300185099318717465441820654, +// 17608637424964395737041291373756657139607306440193731804102457011726690702169238966996114255971643893157857311132388792357391583164125870757541009035041469463366528798593952884745987697403056488744603829437448927398468360797245, +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger768([ + 7263636080534048301, + 7643227961769035653, + 15787777614640869937, + 17661317895964274771, + 4142647779394287783, + 15064949873659932676, + 4579259080596351332, + 2207443675339702626, + 5738725620118622838, + 4338467638707299712, + 6558861849926282439, + 341078935870328 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger768([ + 13073882729051113867, + 195909455108318710, + 10527070038778509320, + 16605710222187477118, + 10442518358308209073, + 7776589986153052354, + 16034091384000651523, + 17429232381273855185, + 512853344493546034, + 7982076214836075255, + 3601416800138513610, + 399028695285184 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger768([ + 4867672648970469422, + 2453112364260322863, + 11918672197974895143, + 3923647310180624143, + 12707123323825700670, + 15781895092544451511, + 17747112377690960911, + 16511994611001933567, + 15360620366665804029, + 10252080383738480571, + 5722654046339742760, + 316853130349807 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger768([ + 17322957246732430708, + 11825815087694023697, + 7654216682602683900, + 13544637981229618042, + 17057060382219081849, + 4038731408172002692, + 6631723222530012253, + 10585926166286435412, + 16050667328028620117, + 16598483946296156500, + 11771818132648686020, + 1230430296095 +])); diff --git a/mnt4_753/src/curves/mod.rs b/mnt4_753/src/curves/mod.rs new file mode 100644 index 0000000..ba690fd --- /dev/null +++ b/mnt4_753/src/curves/mod.rs @@ -0,0 +1,90 @@ +use ark_ec::models::mnt4::{MNT4Parameters, MNT4}; +use ark_ff::{biginteger::BigInteger768, field_new, fields::FpParameters, Fp2}; + +use crate::{Fq, Fq2, Fq2Parameters, Fq4Parameters, FqParameters, Fr, FrParameters}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub use self::{ + g1::{G1Affine, G1Prepared, G1Projective}, + g2::{G2Affine, G2Prepared, G2Projective}, +}; + +pub type MNT4_753 = MNT4; + +pub struct Parameters; + +impl MNT4Parameters for Parameters { + const TWIST: Fp2 = field_new!(Fq2, FQ_ZERO, FQ_ONE); + // A coefficient of MNT4-753 G2 = + // ``` + // mnt4753_twist_coeff_a = mnt4753_Fq2(mnt4753_G1::coeff_a * non_residue, mnt6753_Fq::zero()); + // = (A_COEFF * NONRESIDUE, ZERO) + // = (26, ZERO) + // ``` + #[rustfmt::skip] + const TWIST_COEFF_A: Fp2 = field_new!(Fq2, + G1_COEFF_A_NON_RESIDUE, + FQ_ZERO, + ); + // https://github.com/o1-labs/snarky/blob/9c21ab2bb23874604640740d646a932e813432c3/snarkette/mnt4753.ml + const ATE_LOOP_COUNT: &'static [u64] = &[ + 8824542903220142080, + 7711082599397206192, + 8303354903384568230, + 5874150271971943936, + 9717849827920685054, + 95829799234282493, + ]; + const ATE_IS_LOOP_COUNT_NEG: bool = true; + const FINAL_EXPONENT_LAST_CHUNK_1: BigInteger768 = + BigInteger768([0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); + const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = true; + const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger768 = BigInteger768([ + 8824542903220142079, + 7711082599397206192, + 8303354903384568230, + 5874150271971943936, + 9717849827920685054, + 95829799234282493, + 0, + 0, + 0, + 0, + 0, + 0, + ]); + type Fp = Fq; + type Fr = Fr; + type Fp2Params = Fq2Parameters; + type Fp4Params = Fq4Parameters; + type G1Parameters = self::g1::Parameters; + type G2Parameters = self::g2::Parameters; +} + +// 26 +pub const G1_COEFF_A_NON_RESIDUE: Fq = field_new!( + Fq, + BigInteger768([ + 16948538951764659373, + 10775354577659735631, + 12766795894854242596, + 8684022258823474090, + 973489465296612807, + 3883945490221946200, + 16178634811223492029, + 16155746945640075033, + 17642042187059426365, + 10295720303844380352, + 13265853240981244259, + 39422991244875, + ]) +); +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FR_ZERO: Fr = field_new!(Fr, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); +pub const FR_ONE: Fr = field_new!(Fr, FrParameters::R); diff --git a/mnt4_753/src/curves/tests.rs b/mnt4_753/src/curves/tests.rs new file mode 100644 index 0000000..0dc11e8 --- /dev/null +++ b/mnt4_753/src/curves/tests.rs @@ -0,0 +1,90 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField, UniformRand}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = MNT4_753::pairing(sa, b); + let ans2 = MNT4_753::pairing(a, sb); + let ans3 = MNT4_753::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq4::one()); + assert_ne!(ans2, Fq4::one()); + assert_ne!(ans3, Fq4::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq4::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq4::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq4::one()); +} + +#[test] +fn test_product_of_pairings() { + let rng = &mut test_rng(); + + let a = G1Projective::rand(rng).into_affine(); + let b = G2Projective::rand(rng).into_affine(); + let c = G1Projective::rand(rng).into_affine(); + let d = G2Projective::rand(rng).into_affine(); + let ans1 = MNT4_753::pairing(a, b) * &MNT4_753::pairing(c, d); + let ans2 = MNT4_753::product_of_pairings(&[(a.into(), b.into()), (c.into(), d.into())]); + assert_eq!(ans1, ans2); +} diff --git a/mnt4_753/src/fields/fq.rs b/mnt4_753/src/fields/fq.rs new file mode 100644 index 0000000..8b7d3f5 --- /dev/null +++ b/mnt4_753/src/fields/fq.rs @@ -0,0 +1,170 @@ +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, +}; + +pub type Fq = Fp768; + +pub struct FqParameters; + +impl Fp768Parameters for FqParameters {} +impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 15; + + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x3b079c7556ac378, + 0x2c8c74d04a3f00d4, + 0xd3b001061b90d4cf, + 0x946e77514891b0e6, + 0x79caec8ad6dc9ea1, + 0xbefd780edc81435d, + 0xe093d4dca630b154, + 0x43a0f673199f1c12, + 0x92276c78436253ff, + 0xe249d1cf014fcd24, + 0x96f36471fb7c3ec5, + 0x1080b8906b7c4, + ]); + + const SMALL_SUBGROUP_BASE: Option = Some(5); + const SMALL_SUBGROUP_BASE_ADICITY: Option = Some(2); + /// LARGE_SUBGROUP_ROOT_OF_UNITY = + /// 12249458902762217747626832919710926618510011455364963726393752854649914979954138109976331601455448780251166045203053508523342111624583986869301658366625356826888785691823710598470775453742133593634524619429629803955083254436531 + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = Some(BigInteger([ + 8926681816978929800, + 10873079436792120119, + 6519893728366769435, + 7899277225737766970, + 8416573500933450083, + 12951641800297678468, + 7093775028595490583, + 14327009285082556021, + 18228411097456927576, + 2823658094446565457, + 1708328092507553067, + 109589007594791, + ])); +} +impl FpParameters for FqParameters { + /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601 + const MODULUS: BigInteger = BigInteger([ + 0x5e9063de245e8001, + 0xe39d54522cdd119f, + 0x638810719ac425f0, + 0x685acce9767254a4, + 0xb80f0da5cb537e38, + 0xb117e776f218059d, + 0x99d124d9a15af79d, + 0x7fdb925e8a0ed8d, + 0x5eb7e8f96c97d873, + 0xb7f997505b8fafed, + 0x10229022eee2cdad, + 0x1c4c62d92c411, + ]); + + const MODULUS_BITS: u32 = 753; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 15; + + const R: BigInteger = BigInteger([ + 0x98a8ecabd9dc6f42, + 0x91cd31c65a034686, + 0x97c3e4a0cd14572e, + 0x79589819c788b601, + 0xed269c942108976f, + 0x1e0f4d8acf031d68, + 0x320c3bb713338559, + 0x598b4302d2f00a62, + 0x4074c9cbfd8ca621, + 0xfa47edb3865e88c, + 0x95455fb31ff9a195, + 0x7b479ec8e242, + ]); + + const R2: BigInteger = BigInteger([ + 0x84717088cfd190c8, + 0xc7d9ff8e7df03c0a, + 0xa24bea56242b3507, + 0xa896a656a0714c7d, + 0x80a46659ff6f3ddf, + 0x2f47839ef88d7ce8, + 0xa8c86d4604a3b597, + 0xe03c79cac4f7ef07, + 0x2505daf1f4a81245, + 0x8e4605754c381723, + 0xb081f15bcbfdacaf, + 0x2a33e89cb485, + ]); + + const INV: u64 = 0xf2044cfbe45e7fff; + + const GENERATOR: BigInteger = BigInteger([ + 0xa8f627f0e629635e, + 0x202afce346c36872, + 0x85e1ece733493254, + 0x6d76e610664ac389, + 0xdf542f3f04441585, + 0x3aa4885bf6d4dd80, + 0xeb8b63c1c0fffc74, + 0xd2488e985f6cfa4e, + 0xcce1c2a623f7a66a, + 0x2a060f4d5085b19a, + 0xa9111a596408842f, + 0x11ca8d50bf627, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xaf4831ef122f4000, + 0x71ceaa29166e88cf, + 0x31c40838cd6212f8, + 0x342d6674bb392a52, + 0xdc0786d2e5a9bf1c, + 0xd88bf3bb790c02ce, + 0xcce8926cd0ad7bce, + 0x83fedc92f45076c6, + 0xaf5bf47cb64bec39, + 0xdbfccba82dc7d7f6, + 0x88114811777166d6, + 0xe26316c96208, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + /// T = (MODULUS - 1) / 2^S = + /// 1278640471433073529124274133033466709233725278318907137200424283478556909563327233064541435662546964154604216671394463687571830033251476599169665701965732619291119517454523942352538645255842982596454713491581459512424155325 + const T: BigInteger = BigInteger([ + 0x233ebd20c7bc48bd, + 0x4be1c73aa8a459ba, + 0xa948c71020e33588, + 0xfc70d0b599d2ece4, + 0xb3b701e1b4b96a6, + 0xef3b622fceede430, + 0xdb1b33a249b342b5, + 0xb0e60ffb724bd141, + 0x5fdabd6fd1f2d92f, + 0x9b5b6ff32ea0b71f, + 0x882220452045ddc5, + 0x3898c5b25, + ]); + + /// (T - 1) / 2 = + /// 639320235716536764562137066516733354616862639159453568600212141739278454781663616532270717831273482077302108335697231843785915016625738299584832850982866309645559758727261971176269322627921491298227356745790729756212077662 + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x119f5e9063de245e, + 0x25f0e39d54522cdd, + 0x54a4638810719ac4, + 0x7e38685acce97672, + 0x59db80f0da5cb53, + 0xf79db117e776f218, + 0xed8d99d124d9a15a, + 0xd87307fdb925e8a0, + 0xafed5eb7e8f96c97, + 0xcdadb7f997505b8f, + 0xc41110229022eee2, + 0x1c4c62d92, + ]); +} diff --git a/mnt4_753/src/fields/fq2.rs b/mnt4_753/src/fields/fq2.rs new file mode 100644 index 0000000..e0514d6 --- /dev/null +++ b/mnt4_753/src/fields/fq2.rs @@ -0,0 +1,77 @@ +use crate::{Fq, FQ_ONE}; +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp2::{Fp2, Fp2Parameters}, +}; + +pub type Fq2 = Fp2; + +pub struct Fq2Parameters; + +impl Fp2Parameters for Fq2Parameters { + type Fp = Fq; + + // non_residue = 13 + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 11881297496860141143, + 13588356353764843511, + 9969398190777826186, + 17325157081734070311, + 16341533986183788031, + 8322434028726676858, + 13631157743146294957, + 8365783422740577875, + 3010239015809771096, + 11776256826687733591, + 7214251687253691272, + 268626707558702 + ])); + + // qnr = (8, 1) + const QUADRATIC_NONRESIDUE: (Self::Fp, Self::Fp) = ( + field_new!( + Fq, + BigInteger([ + 587330122779359758, + 14352661462510473462, + 17802452401246596498, + 18018663494943049411, + 17948754733747257098, + 10253180574146027531, + 6683223122694781837, + 13573468617269213174, + 5059368039312883748, + 950479668716233863, + 9936591501985804621, + 88719447132658 + ]) + ), + FQ_ONE, + ); + + // Coefficients: + // [1, 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689600] + // see https://github.com/o1-labs/snarky/blob/2cf5ef3a14989e57c17518832b3c52590068fc48/src/camlsnark_c/libsnark-caml/depends/libff/libff/algebra/curves/mnt753/mnt4753/mnt4753_init.cpp + const FROBENIUS_COEFF_FP2_C1: &'static [Self::Fp] = &[ + FQ_ONE, + field_new!( + Fq, + BigInteger([ + 14260497802974073023, + 5895249896161266456, + 14682908860938702530, + 17222385991615618722, + 14621060510943733448, + 10594887362868996148, + 7477357615964975684, + 12570239403004322603, + 2180620924574446161, + 12129628062772479841, + 8853285699251153944, + 362282887012814 + ]) + ), + ]; +} diff --git a/mnt4_753/src/fields/fq4.rs b/mnt4_753/src/fields/fq4.rs new file mode 100644 index 0000000..21855b1 --- /dev/null +++ b/mnt4_753/src/fields/fq4.rs @@ -0,0 +1,68 @@ +use crate::{Fq, Fq2, Fq2Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp4::{Fp4, Fp4Parameters}, +}; + +pub type Fq4 = Fp4; + +pub struct Fq4Parameters; + +impl Fp4Parameters for Fq4Parameters { + type Fp2Params = Fq2Parameters; + + const NONRESIDUE: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ONE); + + // Coefficients for the Frobenius automorphism. + // c1[0] = 1, + // c1[1] = 18691656569803771296244054523431852464958959799019013859007259692542121208304602539555350517075508287829753932558576476751900235650227380562700444433662761577027341858128610410779088384480737679672900770810745291515010467307990 + // c1[2] = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689600 + // c1[3] = 23206834398115182106100160267808784663211750120934935212776243228483231604266504233503543246714830633588317039329677309362453490879357004638891167538350364891904062489821230132228897943262725174047727280881395973788104254381611 + #[rustfmt::skip] + const FROBENIUS_COEFF_FP4_C1: &'static [Fq] = &[ + FQ_ONE, + field_new!(Fq, BigInteger([ + 2732208433323581659, + 2172983777736624684, + 14351170316343013496, + 6345300643186282385, + 3197292113538174065, + 1887663496013421009, + 16627860175048929982, + 1842296636815120666, + 13463717484107308085, + 721000253033730237, + 1214767992212094798, + 163570781165682, + ])), + field_new!(Fq, BigInteger([ + 14260497802974073023, + 5895249896161266456, + 14682908860938702530, + 17222385991615618722, + 14621060510943733448, + 10594887362868996148, + 7477357615964975684, + 12570239403004322603, + 2180620924574446161, + 12129628062772479841, + 8853285699251153944, + 362282887012814, + ])), + field_new!(Fq, BigInteger([ + 4081847608632041254, + 14228374352133326707, + 11267574244067947896, + 1174247187748832530, + 10065542319823237575, + 10873259071217986508, + 12902564573729719519, + 17180267336735511666, + 11808206507871910973, + 12535793096497356591, + 18394626215023595103, + 334259642706846, + ])), + ]; +} diff --git a/mnt4_753/src/fields/fr.rs b/mnt4_753/src/fields/fr.rs new file mode 100644 index 0000000..5e4d773 --- /dev/null +++ b/mnt4_753/src/fields/fr.rs @@ -0,0 +1,151 @@ +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + fields::{FftParameters, Fp768, Fp768Parameters, FpParameters}, +}; + +pub type Fr = Fp768; + +pub struct FrParameters; + +impl Fp768Parameters for FrParameters {} +impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 30; + + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0x307f66b297671883, + 0xd72a7f2b1e645f4e, + 0x67079daa9a902283, + 0xf33f7620a86c668b, + 0x8878570d66464c12, + 0xa557af5b524f522b, + 0x5fafa3f6ef19319d, + 0x1eb9e04110a65629, + 0x3f96feb3c639a0b0, + 0x4d4fe37df3ffd732, + 0xadc831bd55bcf3e9, + 0x1b9f32a8bd6ab, + ]); +} +impl FpParameters for FrParameters { + /// MODULUS = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001 + const MODULUS: BigInteger = BigInteger([ + 0xd90776e240000001, + 0x4ea099170fa13a4f, + 0xd6c381bc3f005797, + 0xb9dff97634993aa4, + 0x3eebca9429212636, + 0xb26c5c28c859a99b, + 0x99d124d9a15af79d, + 0x7fdb925e8a0ed8d, + 0x5eb7e8f96c97d873, + 0xb7f997505b8fafed, + 0x10229022eee2cdad, + 0x1c4c62d92c411, + ]); + + const MODULUS_BITS: u32 = 753; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 15; + + const R: BigInteger = BigInteger([ + 0xb99680147fff6f42, + 0x4eb16817b589cea8, + 0xa1ebd2d90c79e179, + 0xf725caec549c0da, + 0xab0c4ee6d3e6dad4, + 0x9fbca908de0ccb62, + 0x320c3bb713338498, + 0x598b4302d2f00a62, + 0x4074c9cbfd8ca621, + 0xfa47edb3865e88c, + 0x95455fb31ff9a195, + 0x7b479ec8e242, + ]); + + const R2: BigInteger = BigInteger([ + 0x3f9c69c7b7f4c8d1, + 0x70a50fa9ee48d127, + 0xcdbe6702009569cb, + 0x6bd8c6c6c49edc38, + 0x7955876cc35ee94e, + 0xc7285529be54a3f4, + 0xded52121ecec77cf, + 0x99be80f2ee12ee8e, + 0xc8a0ff01493bdcef, + 0xacc27988f3d9a316, + 0xd9e817a8fb44b3c9, + 0x5b58037e0e4, + ]); + + const INV: u64 = 0xc90776e23fffffff; + + const GENERATOR: BigInteger = BigInteger([ + 0xeee0a5d37ff6635e, + 0xff458536cfa1cff4, + 0x659af978d8169ab0, + 0x1f1841c24780e3f1, + 0x602213036dcfef3a, + 0xd1d5c8f39d72db20, + 0xeb8b63c1c0ffefab, + 0xd2488e985f6cfa4e, + 0xcce1c2a623f7a66a, + 0x2a060f4d5085b19a, + 0xa9111a596408842f, + 0x11ca8d50bf627, + ]); + + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xec83bb7120000000, + 0xa7504c8b87d09d27, + 0x6b61c0de1f802bcb, + 0x5ceffcbb1a4c9d52, + 0x9f75e54a1490931b, + 0xd9362e14642cd4cd, + 0xcce8926cd0ad7bce, + 0x83fedc92f45076c6, + 0xaf5bf47cb64bec39, + 0xdbfccba82dc7d7f6, + 0x88114811777166d6, + 0xe26316c96208, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + + /// T = (MODULUS - 1) / 2^S = + /// 39021010480745652133919498688765463538626870065884617224134041854204007249857398469987226430131438115069708760723898631821547688442835449306011425196003537779414482717728302293895201885929702287178426719326440397855625 + const T: BigInteger = BigInteger([ + 0x3e84e93f641ddb89, + 0xfc015e5d3a82645c, + 0xd264ea935b0e06f0, + 0xa48498dae77fe5d8, + 0x2166a66cfbaf2a50, + 0x856bde76c9b170a3, + 0xa283b63667449366, + 0xb25f61cc1ff6e497, + 0x6e3ebfb57adfa3e5, + 0xbb8b36b6dfe65d41, + 0xb64b1044408a408b, + 0x71318, + ]); + + /// (T - 1) / 2 = + /// 19510505240372826066959749344382731769313435032942308612067020927102003624928699234993613215065719057534854380361949315910773844221417724653005712598001768889707241358864151146947600942964851143589213359663220198927812 + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x1f42749fb20eedc4, + 0x7e00af2e9d41322e, + 0x69327549ad870378, + 0x52424c6d73bff2ec, + 0x90b353367dd79528, + 0x42b5ef3b64d8b851, + 0xd141db1b33a249b3, + 0xd92fb0e60ffb724b, + 0xb71f5fdabd6fd1f2, + 0xddc59b5b6ff32ea0, + 0x5b25882220452045, + 0x3898c, + ]); +} diff --git a/mnt4_753/src/fields/mod.rs b/mnt4_753/src/fields/mod.rs new file mode 100644 index 0000000..719e03b --- /dev/null +++ b/mnt4_753/src/fields/mod.rs @@ -0,0 +1,22 @@ +#[cfg(feature = "scalar_field")] +pub mod fr; +#[cfg(feature = "scalar_field")] +pub use self::fr::*; + +#[cfg(feature = "base_field")] +pub mod fq; +#[cfg(feature = "base_field")] +pub use self::fq::*; + +#[cfg(feature = "curve")] +pub mod fq2; +#[cfg(feature = "curve")] +pub use self::fq2::*; + +#[cfg(feature = "curve")] +pub mod fq4; +#[cfg(feature = "curve")] +pub use self::fq4::*; + +#[cfg(all(feature = "curve", test))] +mod tests; diff --git a/mnt4_753/src/fields/tests.rs b/mnt4_753/src/fields/tests.rs new file mode 100644 index 0000000..9891d3a --- /dev/null +++ b/mnt4_753/src/fields/tests.rs @@ -0,0 +1,45 @@ +use ark_ff::{test_rng, Field}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq2() { + let mut rng = test_rng(); + let a: Fq2 = rng.gen(); + let b: Fq2 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); +} + +#[test] +fn test_fq4() { + let mut rng = test_rng(); + let a: Fq4 = rng.gen(); + let b: Fq4 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/mnt4_753/src/lib.rs b/mnt4_753/src/lib.rs new file mode 100644 index 0000000..75cfffc --- /dev/null +++ b/mnt4_753/src/lib.rs @@ -0,0 +1,38 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the MNT4_753 curve generated in +//! [[BCTV14]](https://eprint.iacr.org/2014/595). The name denotes that it is a +//! Miyaji--Nakabayashi--Takano curve of embedding degree 4, defined over a 753-bit (prime) field. +//! The main feature of this curve is that its scalar field and base field respectively equal the +//! base field and scalar field of MNT6_753. +//! +//! Curve information: +//! * Base field: q = 0x01C4C62D92C41110229022EEE2CDADB7F997505B8FAFED5EB7E8F96C97D87307FDB925E8A0ED8D99D124D9A15AF79DB117E776F218059DB80F0DA5CB537E38685ACCE9767254A4638810719AC425F0E39D54522CDD119F5E9063DE245E8001 +//! * Scalar field: r = 0x01C4C62D92C41110229022EEE2CDADB7F997505B8FAFED5EB7E8F96C97D87307FDB925E8A0ED8D99D124D9A15AF79DB26C5C28C859A99B3EEBCA9429212636B9DFF97634993AA4D6C381BC3F0057974EA099170FA13A4FD90776E240000001 +//! * valuation(q - 1, 2) = 15 +//! * valuation(r - 1, 2) = 30 +//! * G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 2 +//! * b = 0x01373684A8C9DCAE7A016AC5D7748D3313CD8E39051C596560835DF0C9E50A5B59B882A92C78DC537E51A16703EC9855C77FC3D8BB21C8D68BB8CFB9DB4B8C8FBA773111C36C8B1B4E8F1ECE940EF9EAAD265458E06372009C9A0491678EF4 +//! * G2 curve equation: y^2 = x^3 + Ax + B, where +//! * A = Fq2 = (a * NON_RESIDUE, 0) +//! * B = Fq2(0, b * NON_RESIDUE) +//! * NON_RESIDUE = 13 is the quadratic non-residue used to construct the extension field Fq2 + +#[cfg(feature = "curve")] +mod curves; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +mod fields; + +#[cfg(feature = "curve")] +pub use curves::*; +#[cfg(any(feature = "scalar_field", feature = "base_field"))] +pub use fields::*; diff --git a/mnt6_298/Cargo.toml b/mnt6_298/Cargo.toml new file mode 100644 index 0000000..7d3af93 --- /dev/null +++ b/mnt6_298/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-mnt6-298" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The MNT6-298 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-mnt6-298/" +keywords = ["cryptography", "finite fields" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-mnt4-298 = { path = "../mnt4_298", default-features = false, features = [ "scalar_field", "base_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] diff --git a/mnt6_298/src/curves/g1.rs b/mnt6_298/src/curves/g1.rs new file mode 100644 index 0000000..32561fc --- /dev/null +++ b/mnt6_298/src/curves/g1.rs @@ -0,0 +1,79 @@ +use ark_ec::{ + mnt6, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger320, field_new}; + +use crate::{Fq, Fr}; + +pub type G1Affine = mnt6::G1Affine; +pub type G1Projective = mnt6::G1Projective; +pub type G1Prepared = mnt6::G1Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger320([ + 0xb9b2411bfd0eafef, + 0xc61a10fadd9fecbd, + 0x89f128e59811f3fb, + 0x980c0f780adadabb, + 0x9ba1f11320, + ])); + + /// COEFF_B = + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger320([ + 0xa94cb16ed8e733b, + 0xe1ed15e8119bae6, + 0xae927592157c8121, + 0x990dbcbc6661cf95, + 0xecff0892ef, + ])); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[1]; + + /// COFACTOR^(-1) mod r = + /// 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger320([ + 1784298994435064924, + 16852041090100268533, + 14258261760832875328, + 2961187778261111191, + 1929014752195, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); +} + +/// G1_GENERATOR_X = +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger320([ + 0x1a663562f74e1d24, + 0xc1d1d583fccd1b79, + 0xda077538a9763df2, + 0x70c4a4ea36aa01d9, + 0x86537578a8, +])); + +/// G1_GENERATOR_Y = +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger320([ + 0x7ad5bfd16dcfffb2, + 0x88dd739252215070, + 0x43f137a8b517b339, + 0x9a7fac709a8c463c, + 0x3140fbc3593, +])); diff --git a/mnt6_298/src/curves/g2.rs b/mnt6_298/src/curves/g2.rs new file mode 100644 index 0000000..c44031d --- /dev/null +++ b/mnt6_298/src/curves/g2.rs @@ -0,0 +1,159 @@ +use ark_ec::{ + mnt6, + mnt6::MNT6Parameters, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger320, field_new}; + +use crate::{g1, Fq, Fq3, Fr}; + +pub type G2Affine = mnt6::G2Affine; +pub type G2Projective = mnt6::G2Projective; +pub type G2Prepared = mnt6::G2Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq3; + type ScalarField = Fr; +} + +/// MUL_BY_A_C0 = NONRESIDUE * COEFF_A + #[rustfmt::skip] +pub const MUL_BY_A_C0: Fq = field_new!(Fq, BigInteger320([ + 0xa07b458bf1496fab, + 0xde8254e6541f9fb4, + 0xb1b5cc7bf859c3ea, + 0xf83c4d58364645a9, + 0x30a29b55fa2, +])); + +/// MUL_BY_A_C1 = NONRESIDUE * COEFF_A + #[rustfmt::skip] +pub const MUL_BY_A_C1: Fq = field_new!(Fq, BigInteger320([ + 0xa07b458bf1496fab, + 0xde8254e6541f9fb4, + 0xb1b5cc7bf859c3ea, + 0xf83c4d58364645a9, + 0x30a29b55fa2, +])); + +/// MUL_BY_A_C2 = COEFF_A +pub const MUL_BY_A_C2: Fq = g1::Parameters::COEFF_A; + +impl SWModelParameters for Parameters { + const COEFF_A: Fq3 = crate::Parameters::TWIST_COEFF_A; + #[rustfmt::skip] + const COEFF_B: Fq3 = field_new!(Fq3, + field_new!(Fq, BigInteger320([ + 0x79a4c2cea3c84026, + 0x4b50cad0f3233baa, + 0x9ded82770e7a4410, + 0x5ade8b105838b95d, + 0xe4036e0a3a, + ])), + field_new!(Fq, BigInteger320([0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger320([0, 0, 0, 0, 0])), + ); + + /// COFACTOR = + /// 226502022472576270196498690498308461791828762732602586162207535351960270082712694977333372361549082214519252261735048131889018501404377856786623430385820659037970876666767495659520 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 15308190245346869248, + 10669098443577192943, + 4561413759929581409, + 3680089780298582849, + 17336300687782721465, + 10745756320947240891, + 17479264233688728128, + 16828697388537672097, + 4184034152442024798, + 915787, + ]; + + /// COFACTOR^(-1) mod r = + /// 79320381028210220958891541608841408590854146655427655872973753568875979721417185067925504 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger320([ + 5837598184463018016, + 7845868194417674836, + 12170332588914158076, + 6950611683754678431, + 102280178745, + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(elt: &Fq3) -> Fq3 { + field_new!( + Fq3, + MUL_BY_A_C0 * &elt.c1, + MUL_BY_A_C1 * &elt.c2, + MUL_BY_A_C2 * &elt.c0, + ) + } +} + +const G2_GENERATOR_X: Fq3 = + field_new!(Fq3, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1, G2_GENERATOR_X_C2); +const G2_GENERATOR_Y: Fq3 = + field_new!(Fq3, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1, G2_GENERATOR_Y_C2); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger320([ + 0x15ca12fc5d551ea7, + 0x9e0b2b2b2bb8b979, + 0xe6e66283ad5a786a, + 0x46ba0aedcc383c07, + 0x243853463ed, +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger320([ + 0x2c0e3dd7be176130, + 0x27a15d879495904b, + 0x6f1f0d2dd1502a82, + 0x9782ee3c70834da, + 0x2c28bb71862, +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C2: Fq = field_new!(Fq, BigInteger320([ + 0xf3e5f4eb9631e1f1, + 0x657801e80c50778, + 0x2d2abb128fee90f3, + 0x72e58e4c3aa3598c, + 0x100b8026b9d, +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger320([ + 0xb1cddd6c64a67c5f, + 0xa01e90d89aa5d2ba, + 0x39e9a733be49ed1, + 0x9438f46f63d3264f, + 0x12cc928ef10, +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger320([ + 0xa1529b7265ad4be7, + 0x21c5e827cf309306, + 0x9b3d647bd8c70b22, + 0x42835bf373e4b213, + 0xd3c77c9ff9, +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C2: Fq = field_new!(Fq, BigInteger320([ + 0x610557ec4b58b8df, + 0x51a23865b52045f1, + 0x9dcfd915a09da608, + 0x6d65c95f69adb700, + 0x2d3c3d195a1, +])); diff --git a/mnt6_298/src/curves/mod.rs b/mnt6_298/src/curves/mod.rs new file mode 100644 index 0000000..2d2dc19 --- /dev/null +++ b/mnt6_298/src/curves/mod.rs @@ -0,0 +1,51 @@ +use ark_ff::{biginteger::BigInteger320, field_new, fields::FpParameters, Fp3}; + +use ark_ec::models::mnt6::{MNT6Parameters, MNT6}; + +use crate::{Fq, Fq3, Fq3Parameters, Fq6Parameters, FqParameters, Fr}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub use self::{ + g1::{G1Affine, G1Prepared, G1Projective}, + g2::{G2Affine, G2Prepared, G2Projective}, +}; + +pub type MNT6_298 = MNT6; + +pub struct Parameters; + +impl MNT6Parameters for Parameters { + const TWIST: Fp3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + #[rustfmt::skip] + const TWIST_COEFF_A: Fp3 = field_new!(Fq3, + FQ_ZERO, + FQ_ZERO, + field_new!(Fq, BigInteger320([ + 0xb9b2411bfd0eafef, + 0xc61a10fadd9fecbd, + 0x89f128e59811f3fb, + 0x980c0f780adadabb, + 0x9ba1f11320, + ])), + ); + const ATE_LOOP_COUNT: &'static [u64] = &[0xdc9a1b671660000, 0x46609756bec2a33f, 0x1eef55]; + const ATE_IS_LOOP_COUNT_NEG: bool = true; + const FINAL_EXPONENT_LAST_CHUNK_1: BigInteger320 = BigInteger320([0x1, 0x0, 0x0, 0x0, 0x0]); + const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = true; + const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger320 = + BigInteger320([0xdc9a1b671660000, 0x46609756bec2a33f, 0x1eef55, 0x0, 0x0]); + type Fp = Fq; + type Fr = Fr; + type Fp3Params = Fq3Parameters; + type Fp6Params = Fq6Parameters; + type G1Parameters = self::g1::Parameters; + type G2Parameters = self::g2::Parameters; +} + +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger320([0, 0, 0, 0, 0])); +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); diff --git a/mnt6_298/src/curves/tests.rs b/mnt6_298/src/curves/tests.rs new file mode 100644 index 0000000..03f7229 --- /dev/null +++ b/mnt6_298/src/curves/tests.rs @@ -0,0 +1,90 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField, UniformRand}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = MNT6_298::pairing(sa, b); + let ans2 = MNT6_298::pairing(a, sb); + let ans3 = MNT6_298::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq6::one()); + assert_ne!(ans2, Fq6::one()); + assert_ne!(ans3, Fq6::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq6::one()); +} + +#[test] +fn test_product_of_pairings() { + let rng = &mut test_rng(); + + let a = G1Projective::rand(rng).into_affine(); + let b = G2Projective::rand(rng).into_affine(); + let c = G1Projective::rand(rng).into_affine(); + let d = G2Projective::rand(rng).into_affine(); + let ans1 = MNT6_298::pairing(a, b) * &MNT6_298::pairing(c, d); + let ans2 = MNT6_298::product_of_pairings(&[(a.into(), b.into()), (c.into(), d.into())]); + assert_eq!(ans1, ans2); +} diff --git a/mnt6_298/src/fields/fq.rs b/mnt6_298/src/fields/fq.rs new file mode 100644 index 0000000..f587b1a --- /dev/null +++ b/mnt6_298/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_mnt4_298::{Fr as Fq, FrParameters as FqParameters}; diff --git a/mnt6_298/src/fields/fq3.rs b/mnt6_298/src/fields/fq3.rs new file mode 100644 index 0000000..f414c1e --- /dev/null +++ b/mnt6_298/src/fields/fq3.rs @@ -0,0 +1,106 @@ +use crate::fq::Fq; +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + field_new, + fields::fp3::{Fp3, Fp3Parameters}, +}; + +pub type Fq3 = Fp3; + +pub struct Fq3Parameters; + +impl Fp3Parameters for Fq3Parameters { + type Fp = Fq; + + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 0x58eefd67fea995ca, + 0x12f14affbb33a004, + 0x4780323da44ac69b, + 0x88acf9bea707eed9, + 0x14bbbb859e8, + ])); + + const TWO_ADICITY: u32 = 34; + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + 0x69232b75663933bd, + 0xca650efcfc00ee0, + 0x77ca3963fe36f720, + 0xe4cb46632f9bcf7e, + 0xef510453f08f9f30, + 0x9dd5b8fc72f02d83, + 0x7f8d017ed86608ab, + 0xeb2219b3697c97a4, + 0xc8663846ab96996f, + 0x833cd532053eac7d, + 0x1d5b73dfb20bd3cc, + 0x6f5f6da606b59873, + 0x62e990f43dfc42d6, + 0x6878f58, + ]; + + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 0x44a4178610a3a4e6, + 0x49321e4d00f35073, + 0xbbc01b9c400c07a1, + 0xd0127c4589095738, + 0x3730de2a45d, + ])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0])), + ); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0xc3177aefffbb845c, + 0x9b80c702f9961788, + 0xc5df8dcdac70a85a, + 0x29184098647b5197, + 0x1c1223d33c3, + ])), + field_new!(Fq, BigInteger([ + 0x1c17bb7477085b6a, + 0x2621629c22e83dbb, + 0x21c062106d949dd8, + 0x9d5b981062164ba, + 0x84ad703207, + ])), + field_new!(Fq, BigInteger([ + 0xdc13fe3f893c203b, + 0x39a7226875df158f, + 0xe34ed98542eefb62, + 0x6f782a843d139e3c, + 0x177280f6ea9, + ])), + ]; + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C2: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0xc3177aefffbb845c, + 0x9b80c702f9961788, + 0xc5df8dcdac70a85a, + 0x29184098647b5197, + 0x1c1223d33c3, + ])), + field_new!(Fq, BigInteger([ + 0xdc13fe3f893c203b, + 0x39a7226875df158f, + 0xe34ed98542eefb62, + 0x6f782a843d139e3c, + 0x177280f6ea9, + ])), + field_new!(Fq, BigInteger([ + 0x1c17bb7477085b6a, + 0x2621629c22e83dbb, + 0x21c062106d949dd8, + 0x9d5b981062164ba, + 0x84ad703207, + ])), + ]; +} diff --git a/mnt6_298/src/fields/fq6.rs b/mnt6_298/src/fields/fq6.rs new file mode 100644 index 0000000..e6dded9 --- /dev/null +++ b/mnt6_298/src/fields/fq6.rs @@ -0,0 +1,63 @@ +use crate::{Fq, Fq3, Fq3Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger320 as BigInteger, + field_new, + fields::fp6_2over3::{Fp6, Fp6Parameters}, +}; + +pub type Fq6 = Fp6; + +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp3Params = Fq3Parameters; + + #[rustfmt::skip] + const NONRESIDUE: Fq3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq] = &[ + field_new!(Fq, BigInteger([ + 0xc3177aefffbb845c, + 0x9b80c702f9961788, + 0xc5df8dcdac70a85a, + 0x29184098647b5197, + 0x1c1223d33c3, + ])), + field_new!(Fq, BigInteger([ + 0xdf2f366476c3dfc6, + 0xc1a2299f1c7e5543, + 0xe79fefde1a054632, + 0x32edfa196a9cb651, + 0x245cfad65ca, + ])), + field_new!(Fq, BigInteger([ + 0x1c17bb7477085b6a, + 0x2621629c22e83dbb, + 0x21c062106d949dd8, + 0x9d5b981062164ba, + 0x84ad703207, + ])), + field_new!(Fq, BigInteger([ + 0xf82bb9b400447ba5, + 0x5fc8850498c7534a, + 0x50f3b95b083993a, + 0x794de405433502f7, + 0x1fbd57fa0b0, + ])), + field_new!(Fq, BigInteger([ + 0xdc13fe3f893c203b, + 0x39a7226875df158f, + 0xe34ed98542eefb62, + 0x6f782a843d139e3c, + 0x177280f6ea9, + ])), + field_new!(Fq, BigInteger([ + 0x9f2b792f88f7a497, + 0xd527e96b6f752d18, + 0xa92e6752ef5fa3bc, + 0x98906b1ca18eefd4, + 0x3384a4ca26c, + ])), + ]; +} diff --git a/mnt6_298/src/fields/fr.rs b/mnt6_298/src/fields/fr.rs new file mode 100644 index 0000000..274bfe3 --- /dev/null +++ b/mnt6_298/src/fields/fr.rs @@ -0,0 +1 @@ +pub use ark_mnt4_298::{Fq as Fr, FqParameters as FrParameters}; diff --git a/mnt6_298/src/fields/mod.rs b/mnt6_298/src/fields/mod.rs new file mode 100644 index 0000000..bf9cff7 --- /dev/null +++ b/mnt6_298/src/fields/mod.rs @@ -0,0 +1,14 @@ +pub mod fr; +pub use self::fr::*; + +pub mod fq; +pub use self::fq::*; + +pub mod fq3; +pub use self::fq3::*; + +pub mod fq6; +pub use self::fq6::*; + +#[cfg(all(feature = "mnt6_298", test))] +mod tests; diff --git a/mnt6_298/src/fields/tests.rs b/mnt6_298/src/fields/tests.rs new file mode 100644 index 0000000..fa001cc --- /dev/null +++ b/mnt6_298/src/fields/tests.rs @@ -0,0 +1,52 @@ +use ark_ff::{ + fields::{models::fp6_2over3::*, quadratic_extension::QuadExtParameters}, + test_rng, Field, +}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq3() { + let mut rng = test_rng(); + let a: Fq3 = rng.gen(); + let b: Fq3 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); + assert_eq!( + a * Fq6Parameters::NONRESIDUE, + >::mul_base_field_by_nonresidue(&a) + ); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + let a: Fq6 = rng.gen(); + let b: Fq6 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/mnt6_298/src/lib.rs b/mnt6_298/src/lib.rs new file mode 100644 index 0000000..8c5c53e --- /dev/null +++ b/mnt6_298/src/lib.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the MNT6_298 curve generated in +//! [[BCTV14]](https://eprint.iacr.org/2014/595). The name denotes that it is a +//! Miyaji--Nakabayashi--Takano curve of embedding degree 6, defined over a 298-bit (prime) field. +//! The main feature of this curve is that its scalar field and base field respectively equal the +//! base field and scalar field of MNT4_298. +//! +//! +//! Curve information: +//! * Scalar field: q = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +//! * Base field: r = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 +//! * valuation(q - 1, 2) = 34 +//! * valuation(r - 1, 2) = 17 +//! * G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 11 +//! * b = 106700080510851735677967319632585352256454251201367587890185989362936000262606668469523074 +//! * G2 curve equation: y^2 = x^3 + Ax + B, where +//! * A = Fq2 = (0, 0, a) +//! * B = Fq2(b * NON_RESIDUE, 0, 0) +//! * NON_RESIDUE = 5 is the cubic non-residue used to construct the field extension Fq3 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/mnt6_753/Cargo.toml b/mnt6_753/Cargo.toml new file mode 100644 index 0000000..6b7d02e --- /dev/null +++ b/mnt6_753/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ark-mnt6-753" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "The MNT6-753 pairing-friendly elliptic curve" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-mnt6-753/" +keywords = ["cryptography", "finite fields" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } +ark-mnt4-753 = { path = "../mnt4_753", default-features = false, features = [ "scalar_field", "base_field" ] } + +[dev-dependencies] +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false } +ark-curve-tests = { path = "../curve-tests", default-features = false } +rand = { version = "0.7", default-features = false } +rand_xorshift = "0.2" + +[features] +default = [] +std = [ "ark-std/std", "ark-ff/std", "ark-ec/std" ] diff --git a/mnt6_753/src/curves/g1.rs b/mnt6_753/src/curves/g1.rs new file mode 100644 index 0000000..a1ac6eb --- /dev/null +++ b/mnt6_753/src/curves/g1.rs @@ -0,0 +1,104 @@ +use ark_ec::{ + mnt6, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger768, field_new}; + +use crate::{Fq, Fr, FR_ONE}; + +pub type G1Affine = mnt6::G1Affine; +pub type G1Projective = mnt6::G1Projective; +pub type G1Prepared = mnt6::G1Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl SWModelParameters for Parameters { + /// COEFF_A = 11 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, BigInteger768([ + 5145524327033718740, + 14149824967095184544, + 5159730833497260295, + 3902941467692815387, + 15830098551216085679, + 8665641533746801158, + 17502192300007146323, + 14483698255198590748, + 546300946688995976, + 4331975528992054828, + 5311428878520309260, + 495362057711802, + ])); + + /// COEFF_B = 0x7DA285E70863C79D56446237CE2E1468D14AE9BB64B2BB01B10E60A5D5DFE0A25714B7985993F62F03B22A9A3C737A1A1E0FCF2C43D7BF847957C34CCA1E3585F9A80A95F401867C4E80F4747FDE5ABA7505BA6FCF2485540B13DFC8468A + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, BigInteger768([ + 8828711393625909642, + 12722539140758597443, + 2303826860244282256, + 8063890988281098391, + 6269149169423748670, + 3425772737529456013, + 1457017085322601211, + 5177155908178255133, + 18057960053344868113, + 10481469207136524576, + 17888199912367160320, + 290288558853910, + ])); + + /// COFACTOR = 1 + const COFACTOR: &'static [u64] = &[1]; + + /// COFACTOR^(-1) mod r = + /// 1 + #[rustfmt::skip] + const COFACTOR_INV: Fr = FR_ONE; + + /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G1_GENERATOR_X, G1_GENERATOR_Y); +} + +// Generator of G1 +// X = 3458420969484235708806261200128850544017070333833944116801482064540723268149235477762870414664917360605949659630933184751526227993647030875167687492714052872195770088225183259051403087906158701786758441889742618916006546636728, +// Y = 27460508402331965149626600224382137254502975979168371111640924721589127725376473514838234361114855175488242007431439074223827742813911899817930728112297763448010814764117701403540298764970469500339646563344680868495474127850569, +/// G1_GENERATOR_X = +#[rustfmt::skip] +pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ + 16404456614462158210, + 16873534995404346316, + 29580875041164893, + 12740551787746921884, + 16087583716780115490, + 15096170813200936110, + 930080103225705610, + 660122182606823185, + 5211213138865083410, + 15466479635231681544, + 11783401481713071326, + 20214808394592 +])); + +/// G1_GENERATOR_Y = +#[rustfmt::skip] +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ + 11636140615878154554, + 15149343852908177063, + 14426639389651280896, + 12711360703798958610, + 3787948290527586979, + 7628180411662927078, + 17195203689728925717, + 6800476327444280291, + 2228796880865780105, + 15627033749683396124, + 13783535191786892346, + 61400438920476 +])); diff --git a/mnt6_753/src/curves/g2.rs b/mnt6_753/src/curves/g2.rs new file mode 100644 index 0000000..eee092d --- /dev/null +++ b/mnt6_753/src/curves/g2.rs @@ -0,0 +1,262 @@ +use ark_ec::{ + mnt6, + mnt6::MNT6Parameters, + models::{ModelParameters, SWModelParameters}, +}; +use ark_ff::{biginteger::BigInteger768, field_new}; + +use crate::{g1, Fq, Fq3, Fr, FQ_ZERO}; + +pub type G2Affine = mnt6::G2Affine; +pub type G2Projective = mnt6::G2Projective; +pub type G2Prepared = mnt6::G2Prepared; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct Parameters; + +impl ModelParameters for Parameters { + type BaseField = Fq3; + type ScalarField = Fr; +} + +/// MUL_BY_A_C0 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C0: Fq = field_new!(Fq, BigInteger768([ + 10895242587870565906, + 6757387713923212228, + 12683949709867392876, + 1229095484098138811, + 18111217745394181988, + 3648021353977015866, + 7900332254549424237, + 5988529219097278134, + 11544487525720487778, + 7317517692149492894, + 9905728181042915773, + 470678396104534 +])); + +/// MUL_BY_A_C1 = NONRESIDUE * COEFF_A +#[rustfmt::skip] +pub const MUL_BY_A_C1: Fq = field_new!(Fq, BigInteger768([ + 10895242587870565906, + 6757387713923212228, + 12683949709867392876, + 1229095484098138811, + 18111217745394181988, + 3648021353977015866, + 7900332254549424237, + 5988529219097278134, + 11544487525720487778, + 7317517692149492894, + 9905728181042915773, + 470678396104534 +])); + +/// MUL_BY_A_C2 = COEFF_A +pub const MUL_BY_A_C2: Fq = g1::Parameters::COEFF_A; + +impl SWModelParameters for Parameters { + const COEFF_A: Fq3 = crate::Parameters::TWIST_COEFF_A; + // B coefficient of MNT6-753 G2 = + // ``` + // mnt6753_twist_coeff_b = mnt6753_Fq3(mnt6753_G1::coeff_b * mnt6753_Fq3::non_residue, + // mnt6753_Fq::zero(), mnt6753_Fq::zero()); + // non_residue = mnt6753_Fq3::non_residue = mnt6753_Fq("11"); + // = (G1_B_COEFF * NON_RESIDUE, ZERO, ZERO); + // = + // (2189526091197672465268098090392210500740714959757583916377481826443393499947557697773546040576162515434508768057245887856591913752342600919117433675080691499697020523783784738694360040853591723916201150207746019687604267190251, + // 0, 0) + // ``` + #[rustfmt::skip] + const COEFF_B: Fq3 = field_new!( + Fq3, + field_new!(Fq, BigInteger768([ + 3284231658830416104, + 13720030246451177991, + 6276939417009443243, + 8340612253649729185, + 4863511590806861670, + 15883218135158530927, + 4865336109262680856, + 16600307443495218926, + 10112528487499131659, + 17308657107605697754, + 5326857497786417651, + 206191604157846 + ])), + FQ_ZERO, + FQ_ZERO, + ); + + /// COFACTOR = + /// 1755483545388786116744270475466687259186947712032004459714210070280389500116987496124098574823389466285978151140155508638765729019174599527183600372094760023144398285325863550664578643924584541949466179502227232245309952839189635010671372908411609248348904807785904229403747495114436660255866932060472369629692502198423138429922875792635236729929780298333055698257230963645509826963717287902205842627121011526048163097042046361575549171961352924692480000 + #[rustfmt::skip] + const COFACTOR: &'static [u64] = &[ + 17839255819456086016, + 500623104730997740, + 2110252009236161768, + 1500878543414750896, + 12839751506594314239, + 8978537329634833065, + 13830010955957826199, + 7626514311663165506, + 14876243211944528805, + 2316601947950921451, + 2601177562497904269, + 18300670698693155036, + 17321427554953155530, + 12586270719596716948, + 807965545138267130, + 13086323046094411844, + 16597411233431396880, + 5578519820383338987, + 16478065054289650824, + 12110148809888520863, + 5901144846689643164, + 3407195776166256068, + 14663852814447346059, + 13435169368, + ]; + + /// COFACTOR^(-1) mod r = + /// 6983081827986492233724035798540106188028451653325658178630583820170892135428517795509815627298389820236345161981341515817589065927929152555581161598204976128690232061758269440757592419606754539638220064054062394397574161203200 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, BigInteger768([ + 9418103049026957703, + 3464743017686961509, + 7872172759259099794, + 17514322419398292337, + 1496353716802911167, + 16961719271566193274, + 15426671498718617736, + 9230857178223113223, + 11731938389074297274, + 16450973680014766981, + 431917267220694852, + 94637508603012 + ])); + + /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y) + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = + (G2_GENERATOR_X, G2_GENERATOR_Y); + + #[inline(always)] + fn mul_by_a(elt: &Fq3) -> Fq3 { + field_new!( + Fq3, + MUL_BY_A_C0 * &elt.c1, + MUL_BY_A_C1 * &elt.c2, + MUL_BY_A_C2 * &elt.c0, + ) + } +} + +const G2_GENERATOR_X: Fq3 = + field_new!(Fq3, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1, G2_GENERATOR_X_C2); +const G2_GENERATOR_Y: Fq3 = + field_new!(Fq3, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1, G2_GENERATOR_Y_C2); + +// Generator of G2 +// These are three Fq elements each because X and Y (and Z) are elements of Fq^3 +// X = 27250797394340459586637772414334383652934225310678303542554641987990991970766156209996739240400887081904395745019996048910447071686918567661896491214767494514394154061111870331668445455228882471000120574964265209669155206168252, +// 35762481056967998715733586393399457882827322353696313323665483142561285210083843314423554450886956650265947502285422529615273790981238406393402603210224104850580302463396274854098657541573494421834514772635884262388058080180368, +// 36955296703808958167583270646821654948157955258947892285629161090141878438357164213613114995903637211606408001037026832604054121847388692538440756596264746452765613740820430501353237866984394057660379098674983614861254438847846, +// Y = 2540920530670785421282147216459500299597350984927286541981768941513322907384197363939300669100157141915897390694710534916701460991329498878429407641200901974650893207493883271892985923686300670742888673128384350189165542294615, +// 7768974215205248225654340523113146529854477025417883273460270519532499370133542215655437897583245920162220909271982265882784840026754554720358946490360213245668334549692889019612343620295335698052097726325099648573158597797497, +// 21014872727619291834131369222699267167761185012487859171850226473555446863681002782100371394603357586906967186931035615146288030444598977758226767063525819170917389755555854704165900869058188909090444447822088242504281789869689, +#[rustfmt::skip] +pub const G2_GENERATOR_X_C0: Fq = field_new!(Fq, BigInteger768([ + 12772807549130126376, + 2873211972983293592, + 15999100872160401842, + 5277158980096688998, + 12258756012310206056, + 11885883517271414939, + 6373672746025419911, + 13662747456330091710, + 11960680427306056040, + 15150766304321120168, + 9480712498131729809, + 413066879180657 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C1: Fq = field_new!(Fq, BigInteger768([ + 10478274013728260378, + 15392361149861123784, + 17610084573134912261, + 14474130264887792371, + 16754378329454263996, + 3186303078832273968, + 7143189323629797683, + 897486443141339765, + 3675579496642106405, + 4429391539758461550, + 18414257413872084180, + 331209511183940 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_X_C2: Fq = field_new!(Fq, BigInteger768([ + 5133712986240959624, + 10763134357204872827, + 8672341403101541980, + 18084133226637702602, + 4689040548070804594, + 7352115990101270007, + 14358820512747653623, + 10167201669589504005, + 3117673189936726036, + 9407838052466059644, + 7246385421116647671, + 464288782946273 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, BigInteger768([ + 710862246533630948, + 9314168172257972041, + 4722111556929662508, + 4408676313209842703, + 10491088158750500898, + 13211840969745661306, + 13985341743807087374, + 7111198859398088665, + 158194789363472891, + 7682183069894584797, + 9510326135325230913, + 338826428359581 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, BigInteger768([ + 10889422482835557076, + 6073207585023077555, + 16059368148547235058, + 14871121891082823821, + 15156344465408677175, + 12695157488434086405, + 7840105431702704631, + 4763759818130023465, + 12295696339556388640, + 352741974984397506, + 10581333776569094279, + 204002329498100 +])); + +#[rustfmt::skip] +pub const G2_GENERATOR_Y_C2: Fq = field_new!(Fq, BigInteger768([ + 11263496889641203707, + 16306762242042931049, + 8275973312257833978, + 12034012818098316014, + 5392903691498465561, + 4572635011530974247, + 696221667645211601, + 11098678912660456319, + 5477755854538915619, + 11442390115310629698, + 10262065045802790037, + 17901561410539 +])); diff --git a/mnt6_753/src/curves/mod.rs b/mnt6_753/src/curves/mod.rs new file mode 100644 index 0000000..bf233ed --- /dev/null +++ b/mnt6_753/src/curves/mod.rs @@ -0,0 +1,77 @@ +use ark_ff::{biginteger::BigInteger768, field_new, fields::FpParameters, Fp3}; + +use ark_ec::models::{ + mnt6::{MNT6Parameters, MNT6}, + SWModelParameters, +}; + +use crate::{Fq, Fq3, Fq3Parameters, Fq6Parameters, FqParameters, Fr, FrParameters}; + +pub mod g1; +pub mod g2; + +#[cfg(test)] +mod tests; + +pub use self::{ + g1::{G1Affine, G1Prepared, G1Projective}, + g2::{G2Affine, G2Prepared, G2Projective}, +}; + +pub type MNT6_753 = MNT6; + +pub struct Parameters; + +impl MNT6Parameters for Parameters { + const TWIST: Fp3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + // A coefficient of MNT6-753 G2 = + // ``` + // mnt6753_twist_coeff_a = mnt6753_Fq3(mnt6753_Fq::zero(), mnt6753_Fq::zero(), + // mnt6753_G1::coeff_a); + // = (ZERO, ZERO, A_COEFF); + // ``` + #[rustfmt::skip] + const TWIST_COEFF_A: Fp3 = field_new!(Fq3, + FQ_ZERO, + FQ_ZERO, + g1::Parameters::COEFF_A, + ); + // https://github.com/o1-labs/snarky/blob/9c21ab2bb23874604640740d646a932e813432c3/snarkette/mnt6753.ml + const ATE_LOOP_COUNT: &'static [u64] = &[ + 8824542903220142080, + 7711082599397206192, + 8303354903384568230, + 5874150271971943936, + 9717849827920685054, + 95829799234282493, + ]; + const ATE_IS_LOOP_COUNT_NEG: bool = false; + const FINAL_EXPONENT_LAST_CHUNK_1: BigInteger768 = + BigInteger768([0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]); + const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool = false; + const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: BigInteger768 = BigInteger768([ + 8824542903220142080, + 7711082599397206192, + 8303354903384568230, + 5874150271971943936, + 9717849827920685054, + 95829799234282493, + 0, + 0, + 0, + 0, + 0, + 0, + ]); + type Fp = Fq; + type Fr = Fr; + type Fp3Params = Fq3Parameters; + type Fp6Params = Fq6Parameters; + type G1Parameters = self::g1::Parameters; + type G2Parameters = self::g2::Parameters; +} + +pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); +pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); +pub const FR_ZERO: Fr = field_new!(Fr, BigInteger768([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); +pub const FR_ONE: Fr = field_new!(Fr, FrParameters::R); diff --git a/mnt6_753/src/curves/tests.rs b/mnt6_753/src/curves/tests.rs new file mode 100644 index 0000000..5a03d3f --- /dev/null +++ b/mnt6_753/src/curves/tests.rs @@ -0,0 +1,90 @@ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{test_rng, Field, One, PrimeField, UniformRand}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::{curves::*, groups::*}; + +#[test] +fn test_g1_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g1_projective_group() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G1Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g1_generator() { + let generator = G1Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_g2_projective_curve() { + curve_tests::(); + + sw_tests::(); +} + +#[test] +fn test_g2_projective_group() { + let mut rng = test_rng(); + let a: G2Projective = rng.gen(); + let b: G2Projective = rng.gen(); + group_test(a, b); +} + +#[test] +fn test_g2_generator() { + let generator = G2Affine::prime_subgroup_generator(); + assert!(generator.is_on_curve()); + assert!(generator.is_in_correct_subgroup_assuming_on_curve()); +} + +#[test] +fn test_bilinearity() { + let mut rng = test_rng(); + let a: G1Projective = rng.gen(); + let b: G2Projective = rng.gen(); + let s: Fr = rng.gen(); + + let sa = a.mul(s); + let sb = b.mul(s); + + let ans1 = MNT6_753::pairing(sa, b); + let ans2 = MNT6_753::pairing(a, sb); + let ans3 = MNT6_753::pairing(a, b).pow(s.into_repr()); + + assert_eq!(ans1, ans2); + assert_eq!(ans2, ans3); + + assert_ne!(ans1, Fq6::one()); + assert_ne!(ans2, Fq6::one()); + assert_ne!(ans3, Fq6::one()); + + assert_eq!(ans1.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans2.pow(Fr::characteristic()), Fq6::one()); + assert_eq!(ans3.pow(Fr::characteristic()), Fq6::one()); +} + +#[test] +fn test_product_of_pairings() { + let rng = &mut test_rng(); + + let a = G1Projective::rand(rng).into_affine(); + let b = G2Projective::rand(rng).into_affine(); + let c = G1Projective::rand(rng).into_affine(); + let d = G2Projective::rand(rng).into_affine(); + let ans1 = MNT6_753::pairing(a, b) * &MNT6_753::pairing(c, d); + let ans2 = MNT6_753::product_of_pairings(&[(a.into(), b.into()), (c.into(), d.into())]); + assert_eq!(ans1, ans2); +} diff --git a/mnt6_753/src/fields/fq.rs b/mnt6_753/src/fields/fq.rs new file mode 100644 index 0000000..33f3df1 --- /dev/null +++ b/mnt6_753/src/fields/fq.rs @@ -0,0 +1 @@ +pub use ark_mnt4_753::{Fr as Fq, FrParameters as FqParameters}; diff --git a/mnt6_753/src/fields/fq3.rs b/mnt6_753/src/fields/fq3.rs new file mode 100644 index 0000000..91e150a --- /dev/null +++ b/mnt6_753/src/fields/fq3.rs @@ -0,0 +1,137 @@ +use crate::{fq::Fq, FQ_ONE}; +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp3::{Fp3, Fp3Parameters}, +}; + +pub type Fq3 = Fp3; + +pub struct Fq3Parameters; + +impl Fp3Parameters for Fq3Parameters { + type Fp = Fq; + + #[rustfmt::skip] + const NONRESIDUE: Fq = field_new!(Fq, BigInteger([ + 5145524327033718740, + 14149824967095184544, + 5159730833497260295, + 3902941467692815387, + 15830098551216085679, + 8665641533746801158, + 17502192300007146323, + 14483698255198590748, + 546300946688995976, + 4331975528992054828, + 5311428878520309260, + 495362057711802, + ])); + + const TWO_ADICITY: u32 = 30; + + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: &'static [u64] = &[ + 15439605736802142541, + 18190868848461853149, + 6220121510046940818, + 10310485528612680366, + 5032137869959796540, + 3943048799800510054, + 1971151279016362045, + 6096644900171872841, + 12908407994230849218, + 4163225373804228290, + 10382959950522770522, + 9008828410264446883, + 18411821899404157689, + 12386199240837247984, + 13370099281150720481, + 11909278545073807560, + 5964354403900302648, + 15347506722065009035, + 7045354120681109597, + 14294096902719509929, + 6180325033003959541, + 14381489272445870003, + 18159920240207503954, + 17487026929061632528, + 12314108197538755669, + 12116872703077811769, + 3401400733784294722, + 13905351619889935522, + 10972472942574358218, + 6104159581753028261, + 4690139121547787552, + 4880965491878697414, + 1926648890365125214, + 13532564555356297305, + 3114545746551080, + 0, + ]; + + #[rustfmt::skip] + const QUADRATIC_NONRESIDUE_TO_T: (Fq, Fq, Fq) = ( + field_new!(Fq, BigInteger([ + 2456656400918202012, + 7503386575313625620, + 1014314685003569848, + 10473903647598823719, + 15893393002146336511, + 8418203974290622500, + 9017296731996077946, + 2923126592994124774, + 9368756030960215800, + 17344552888362241070, + 10938255746876359306, + 107029542386399, + ])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])), + ); + + // Coefficients for the Frobenius automorphism. + // c1[0] = 1, + // c1[1] = 24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132 + // c1[2] = 17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868, + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C1: &'static [Fq] = &[ + FQ_ONE, + field_new!(Fq, BigInteger([ + 7739145380395648640, + 1403348385939055902, + 11220424057264707228, + 4567962295300549271, + 5929583493640677751, + 17618207486530478833, + 16600462137977359741, + 16551719371247820635, + 12057922785354578416, + 13022559182829558162, + 13308285686168533250, + 313705269181021, + ])), + field_new!(Fq, BigInteger([ + 12973180669431253567, + 17038664486452692616, + 11034024317238370177, + 7712681843988565810, + 4725787734130647531, + 2175028350442404679, + 9323639551697167751, + 14465264105466053583, + 8569442212929419360, + 17553812953652473294, + 13991744086792172309, + 48577617831792, + ])), + ]; + + // c2 = {c1[0], c1[2], c1[1]} + #[rustfmt::skip] + const FROBENIUS_COEFF_FP3_C2: &'static [Fq] = &[ + FQ_ONE, + Self::FROBENIUS_COEFF_FP3_C1[2], + Self::FROBENIUS_COEFF_FP3_C1[1], + ]; +} diff --git a/mnt6_753/src/fields/fq6.rs b/mnt6_753/src/fields/fq6.rs new file mode 100644 index 0000000..8c1a011 --- /dev/null +++ b/mnt6_753/src/fields/fq6.rs @@ -0,0 +1,99 @@ +use crate::{Fq, Fq3, Fq3Parameters, FQ_ONE, FQ_ZERO}; +use ark_ff::{ + biginteger::BigInteger768 as BigInteger, + field_new, + fields::fp6_2over3::{Fp6, Fp6Parameters}, +}; + +pub type Fq6 = Fp6; + +pub struct Fq6Parameters; + +impl Fp6Parameters for Fq6Parameters { + type Fp3Params = Fq3Parameters; + + #[rustfmt::skip] + const NONRESIDUE: Fq3 = field_new!(Fq3, FQ_ZERO, FQ_ONE, FQ_ZERO); + + // Coefficients for the Frobenius automorphism. + // c1[0] = 1, + // c1[1] = 24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052133 + // c1[2] = 24129022407817241407134263419936114379815707076943508280977368156625538709102831814843582780138963119807143081677569721953561801075623741378629346409604471234573396989178424163772589090105392407118197799904755622897541183052132 + // c1[3] = 41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160000 + // c1[4] = 17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107868 + // c1[5] = 17769468560101711995209951371304522748355002843010440790806134764399814103468274958215310983651375801610927890210888755369611256415970113691066895445191924931148019336171640277697829047741006062493737919155152541323243293107869 + #[rustfmt::skip] + const FROBENIUS_COEFF_FP6_C1: &'static [Fq] = &[ + FQ_ONE, + field_new!(Fq, BigInteger([ + 2665418275744511426, + 7073776242814464967, + 4441331072847607829, + 5681016258918493042, + 18254896527151449163, + 10681724016023285331, + 1760041123371930134, + 4557299868084578750, + 16702481779049799698, + 14149724469588165150, + 5617650120443517591, + 449252806040736, + ])), + field_new!(Fq, BigInteger([ + 7739145380395648640, + 1403348385939055902, + 11220424057264707228, + 4567962295300549271, + 5929583493640677751, + 17618207486530478833, + 16600462137977359741, + 16551719371247820635, + 12057922785354578416, + 13022559182829558162, + 13308285686168533250, + 313705269181021, + ])), + field_new!(Fq, BigInteger([ + 2265581976117350591, + 18442012872391748519, + 3807704300793525789, + 12280644139289115082, + 10655371227771325282, + 1346491763263331896, + 7477357615964975877, + 12570239403004322603, + 2180620924574446161, + 12129628062772479841, + 8853285699251153944, + 362282887012814, + ])), + field_new!(Fq, BigInteger([ + 12973180669431253567, + 17038664486452692616, + 11034024317238370177, + 7712681843988565810, + 4725787734130647531, + 2175028350442404679, + 9323639551697167751, + 14465264105466053583, + 8569442212929419360, + 17553812953652473294, + 13991744086792172309, + 48577617831792, + ])), + field_new!(Fq, BigInteger([ + 7899453564780116353, + 4262348269618550065, + 4254931332821270779, + 8825735807606509581, + 17051100767641418943, + 13685288953644762793, + 12929962610801289759, + 2470844602302811697, + 13214001206624640642, + 234234166701528666, + 6301108521067156651, + 184125154691507, + ])), + ]; +} diff --git a/mnt6_753/src/fields/fr.rs b/mnt6_753/src/fields/fr.rs new file mode 100644 index 0000000..5f91ca2 --- /dev/null +++ b/mnt6_753/src/fields/fr.rs @@ -0,0 +1 @@ +pub use ark_mnt4_753::{Fq as Fr, FqParameters as FrParameters}; diff --git a/mnt6_753/src/fields/mod.rs b/mnt6_753/src/fields/mod.rs new file mode 100644 index 0000000..f394204 --- /dev/null +++ b/mnt6_753/src/fields/mod.rs @@ -0,0 +1,14 @@ +pub mod fr; +pub use self::fr::*; + +pub mod fq; +pub use self::fq::*; + +pub mod fq3; +pub use self::fq3::*; + +pub mod fq6; +pub use self::fq6::*; + +#[cfg(all(feature = "mnt6_753", test))] +mod tests; diff --git a/mnt6_753/src/fields/tests.rs b/mnt6_753/src/fields/tests.rs new file mode 100644 index 0000000..fa001cc --- /dev/null +++ b/mnt6_753/src/fields/tests.rs @@ -0,0 +1,52 @@ +use ark_ff::{ + fields::{models::fp6_2over3::*, quadratic_extension::QuadExtParameters}, + test_rng, Field, +}; +use rand::Rng; + +use crate::*; + +use ark_curve_tests::fields::*; + +#[test] +fn test_fr() { + let mut rng = test_rng(); + let a: Fr = rng.gen(); + let b: Fr = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq() { + let mut rng = test_rng(); + let a: Fq = rng.gen(); + let b: Fq = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + primefield_test::(); +} + +#[test] +fn test_fq3() { + let mut rng = test_rng(); + let a: Fq3 = rng.gen(); + let b: Fq3 = rng.gen(); + field_test(a, b); + sqrt_field_test(a); + frobenius_test::(Fq::characteristic(), 13); + assert_eq!( + a * Fq6Parameters::NONRESIDUE, + >::mul_base_field_by_nonresidue(&a) + ); +} + +#[test] +fn test_fq6() { + let mut rng = test_rng(); + let a: Fq6 = rng.gen(); + let b: Fq6 = rng.gen(); + field_test(a, b); + frobenius_test::(Fq::characteristic(), 13); +} diff --git a/mnt6_753/src/lib.rs b/mnt6_753/src/lib.rs new file mode 100644 index 0000000..9eb1609 --- /dev/null +++ b/mnt6_753/src/lib.rs @@ -0,0 +1,34 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] + +//! This library implements the MNT6_753 curve generated in +//! [[BCTV14]](https://eprint.iacr.org/2014/595). The name denotes that it is a +//! Miyaji--Nakabayashi--Takano curve of embedding degree 6, defined over a 753-bit (prime) field. +//! The main feature of this curve is that its scalar field and base field respectively equal the +//! base field and scalar field of MNT4_753. +//! +//! Curve information: +//! * Base field: q = 0x01C4C62D92C41110229022EEE2CDADB7F997505B8FAFED5EB7E8F96C97D87307FDB925E8A0ED8D99D124D9A15AF79DB26C5C28C859A99B3EEBCA9429212636B9DFF97634993AA4D6C381BC3F0057974EA099170FA13A4FD90776E240000001 +//! * Scalar field: r = 0x01C4C62D92C41110229022EEE2CDADB7F997505B8FAFED5EB7E8F96C97D87307FDB925E8A0ED8D99D124D9A15AF79DB117E776F218059DB80F0DA5CB537E38685ACCE9767254A4638810719AC425F0E39D54522CDD119F5E9063DE245E8001 +//! * valuation(q - 1, 2) = 30 +//! * valuation(r - 1, 2) = 15 +//! * G1 curve equation: y^2 = x^3 + ax + b, where +//! * a = 11 +//! * b = 0x7DA285E70863C79D56446237CE2E1468D14AE9BB64B2BB01B10E60A5D5DFE0A25714B7985993F62F03B22A9A3C737A1A1E0FCF2C43D7BF847957C34CCA1E3585F9A80A95F401867C4E80F4747FDE5ABA7505BA6FCF2485540B13DFC8468A +//! * G2 curve equation: y^2 = x^3 + Ax + B, where +//! * A = Fq3(0, 0, a) +//! * B = Fq3(b * NON_RESIDUE, 0, 0) +//! * NON_RESIDUE = 11 is the cubic non-residue used to construct the extension field Fq3 + +mod curves; +mod fields; + +pub use curves::*; +pub use fields::*; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7171213 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,9 @@ +reorder_imports = true +wrap_comments = true +normalize_comments = true +use_try_shorthand = true +match_block_trailing_comma = true +use_field_init_shorthand = true +edition = "2018" +condense_wildcard_suffixes = true +merge_imports = true diff --git a/scripts/install-hook.sh b/scripts/install-hook.sh new file mode 100755 index 0000000..eafcf81 --- /dev/null +++ b/scripts/install-hook.sh @@ -0,0 +1,9 @@ +#!/bin/env bash +# This script will install the provided directory ../.hooks as the hook +# directory for the present repo. See there for hooks, including a pre-commit +# hook that runs rustfmt on files before a commit. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +HOOKS_DIR="${DIR}/../.hooks" + +git config core.hooksPath "$HOOKS_DIR"