├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── api.rs ├── examples ├── dh.rs └── joux.rs ├── shootout ├── README.md ├── main.rs └── test.cpp └── src ├── arith.rs ├── fields ├── fp.rs ├── fq12.rs ├── fq2.rs ├── fq6.rs ├── mod.rs └── tests.rs ├── groups ├── mod.rs └── tests.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | script: 4 | - cargo test --release 5 | - cargo test --release --no-default-features 6 | - cargo check --no-default-features 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "substrate-bn" 3 | version = "0.6.0" 4 | authors = ["Sean Bowe ", "Parity Technologies "] 5 | description = "Pairing cryptography with the Barreto-Naehrig curve" 6 | keywords = ["pairing","crypto","cryptography"] 7 | readme = "README.md" 8 | homepage = "https://github.com/paritytech/bn" 9 | repository = "https://github.com/paritytech/bn" 10 | license = "MIT OR Apache-2.0" 11 | edition = "2018" 12 | 13 | [features] 14 | default = [] 15 | 16 | [[bench]] 17 | name = "api" 18 | 19 | [dependencies] 20 | rand = { version = "0.8.3", default-features = false } 21 | byteorder = { version = "1.0", features = ["i128"], default-features = false } 22 | crunchy = "0.2.1" 23 | lazy_static = { version = "1.4.0", features = ["spin_no_std"] } 24 | rustc-hex = { version = "2", default-features = false } 25 | 26 | [dev-dependencies] 27 | rand = { version = "0.8.3", features = ["std_rng"] } 28 | 29 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Zcash Electric Coin Company 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "{}" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright {yyyy} {name of copyright owner} 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | 205 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Zcash Electric Coin Company 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bn [![Crates.io](https://img.shields.io/crates/v/bn.svg)](https://crates.io/crates/bn) [![Build status](https://api.travis-ci.org/zcash/bn.svg)](https://travis-ci.org/zcash/bn) 2 | 3 | This is a [pairing cryptography](https://en.wikipedia.org/wiki/Pairing-based_cryptography) library written in pure Rust. It makes use of the Barreto-Naehrig (BN) curve construction from [[BCTV2015]](https://eprint.iacr.org/2013/879.pdf) to provide two cyclic groups **G1** and **G2**, with an efficient bilinear pairing: 4 | 5 | *e: G1 × G2 → GT* 6 | 7 | ## Security warnings 8 | 9 | This library, like other pairing cryptography libraries implementing this construction, is not resistant to side-channel attacks. 10 | 11 | ## Usage 12 | 13 | Add the `bn` crate to your dependencies in `Cargo.toml`... 14 | 15 | ```toml 16 | [dependencies] 17 | bn = "0.4.2" 18 | ``` 19 | 20 | ...and add an `extern crate` declaration to your crate root: 21 | 22 | ```rust 23 | extern crate bn; 24 | ``` 25 | 26 | ## API 27 | 28 | * `Fr` is an element of Fr 29 | * `G1` is a point on the BN curve E/Fq : y^2 = x^3 + b 30 | * `G2` is a point on the twisted BN curve E'/Fq2 : y^2 = x^3 + b/xi 31 | * `Gt` is a group element (written multiplicatively) obtained with the `pairing` function over `G1` and `G2`. 32 | 33 | ### Examples 34 | 35 | #### Joux's key agreement protocol 36 | 37 | In a typical Diffie-Hellman key exchange, relying on ECDLP, a three-party key exchange requires two rounds. A single round protocol is possible through the use of a bilinear pairing: given Alice's public key *a*P1 and Bob's public key *b*P2, Carol can compute the shared secret with her private key *c* by *e*(*a*P1, *b*P2)c. 38 | 39 | (See `examples/joux.rs` for the full example.) 40 | 41 | ```rust 42 | // Generate private keys 43 | let alice_sk = Fr::random(rng); 44 | let bob_sk = Fr::random(rng); 45 | let carol_sk = Fr::random(rng); 46 | 47 | // Generate public keys in G1 and G2 48 | let (alice_pk1, alice_pk2) = (G1::one() * alice_sk, G2::one() * alice_sk); 49 | let (bob_pk1, bob_pk2) = (G1::one() * bob_sk, G2::one() * bob_sk); 50 | let (carol_pk1, carol_pk2) = (G1::one() * carol_sk, G2::one() * carol_sk); 51 | 52 | // Each party computes the shared secret 53 | let alice_ss = pairing(bob_pk1, carol_pk2).pow(alice_sk); 54 | let bob_ss = pairing(carol_pk1, alice_pk2).pow(bob_sk); 55 | let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk); 56 | 57 | assert!(alice_ss == bob_ss && bob_ss == carol_ss); 58 | ``` 59 | 60 | ## License 61 | 62 | Licensed under either of 63 | 64 | * MIT license, ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 65 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 66 | 67 | at your option. 68 | 69 | Copyright 2016 [Zcash Electric Coin Company](https://z.cash/). The Zcash Company promises to maintain the "bn" crate on crates.io under this MIT/Apache-2.0 dual license. 70 | 71 | ### Authors 72 | 73 | * [Sean Bowe](https://github.com/ebfull) 74 | 75 | ### Contribution 76 | 77 | Unless you explicitly state otherwise, any contribution intentionally 78 | submitted for inclusion in the work by you, as defined in the Apache-2.0 79 | license, shall be dual licensed as above, without any additional terms or 80 | conditions. 81 | -------------------------------------------------------------------------------- /benches/api.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | use substrate_bn::*; 4 | 5 | const SAMPLES: usize = 30; 6 | 7 | macro_rules! benchmark( 8 | ($name:ident, $input:ident($rng:ident) = $pre:expr; $post:expr) => ( 9 | #[bench] 10 | fn $name(b: &mut test::Bencher) { 11 | let $rng = &mut rand::thread_rng(); 12 | let $input: Vec<_> = (0..SAMPLES).map(|_| $pre).collect(); 13 | 14 | let mut c = 0; 15 | 16 | b.iter(|| { 17 | c += 1; 18 | 19 | let $input = &$input[c % SAMPLES]; 20 | 21 | $post 22 | }); 23 | } 24 | ) 25 | ); 26 | 27 | benchmark!(fr_addition, 28 | input(rng) = (Fr::random(rng), Fr::random(rng)); 29 | 30 | input.0 + input.1 31 | ); 32 | 33 | benchmark!(fr_subtraction, 34 | input(rng) = (Fr::random(rng), Fr::random(rng)); 35 | 36 | input.0 - input.1 37 | ); 38 | 39 | benchmark!(fr_multiplication, 40 | input(rng) = (Fr::random(rng), Fr::random(rng)); 41 | 42 | input.0 * input.1 43 | ); 44 | 45 | benchmark!(fr_inverses, 46 | input(rng) = Fr::random(rng); 47 | 48 | input.inverse() 49 | ); 50 | 51 | benchmark!(g1_addition, 52 | input(rng) = (G1::random(rng), G1::random(rng)); 53 | 54 | input.0 + input.1 55 | ); 56 | 57 | benchmark!(g1_subtraction, 58 | input(rng) = (G1::random(rng), G1::random(rng)); 59 | 60 | input.0 - input.1 61 | ); 62 | 63 | benchmark!(g1_scalar_multiplication, 64 | input(rng) = (G1::random(rng), Fr::random(rng)); 65 | 66 | input.0 * input.1 67 | ); 68 | 69 | benchmark!(g2_addition, 70 | input(rng) = (G2::random(rng), G2::random(rng)); 71 | 72 | input.0 + input.1 73 | ); 74 | 75 | benchmark!(g2_subtraction, 76 | input(rng) = (G2::random(rng), G2::random(rng)); 77 | 78 | input.0 - input.1 79 | ); 80 | 81 | benchmark!(g2_scalar_multiplication, 82 | input(rng) = (G2::random(rng), Fr::random(rng)); 83 | 84 | input.0 * input.1 85 | ); 86 | 87 | benchmark!(fq12_scalar_multiplication, 88 | input(rng) = { 89 | let g1_1 = G1::random(rng); 90 | let g2_1 = G2::random(rng); 91 | 92 | let g1_2 = G1::random(rng); 93 | let g2_2 = G2::random(rng); 94 | 95 | (pairing(g1_1, g2_1), pairing(g1_2, g2_2)) 96 | }; 97 | 98 | input.0 * input.1 99 | ); 100 | 101 | benchmark!(fq12_exponentiation, 102 | input(rng) = ({ 103 | let g1 = G1::random(rng); 104 | let g2 = G2::random(rng); 105 | 106 | pairing(g1, g2) 107 | }, Fr::random(rng)); 108 | 109 | input.0.pow(input.1) 110 | ); 111 | 112 | benchmark!(perform_pairing, 113 | input(rng) = (G1::random(rng), G2::random(rng)); 114 | 115 | pairing(input.0, input.1) 116 | ); 117 | -------------------------------------------------------------------------------- /examples/dh.rs: -------------------------------------------------------------------------------- 1 | // This is an example of three-party Diffie-Hellman key exchange 2 | // Requires two rounds 3 | 4 | use substrate_bn::*; 5 | 6 | fn main() { 7 | let rng = &mut rand::thread_rng(); 8 | 9 | // Construct private keys 10 | let alice_sk = Fr::random(rng); 11 | let bob_sk = Fr::random(rng); 12 | let carol_sk = Fr::random(rng); 13 | 14 | // Construct public keys 15 | let alice_pk = G1::one() * alice_sk; 16 | let bob_pk = G1::one() * bob_sk; 17 | let carol_pk = G1::one() * carol_sk; 18 | 19 | // Round one: 20 | let alice_dh_1 = bob_pk * carol_sk; 21 | let bob_dh_1 = carol_pk * alice_sk; 22 | let carol_dh_1 = alice_pk * bob_sk; 23 | 24 | // Round two: 25 | let alice_dh_2 = alice_dh_1 * alice_sk; 26 | let bob_dh_2 = bob_dh_1 * bob_sk; 27 | let carol_dh_2 = carol_dh_1 * carol_sk; 28 | 29 | // All parties should arrive to the same shared secret 30 | assert!(alice_dh_2 == bob_dh_2 && bob_dh_2 == carol_dh_2); 31 | } 32 | -------------------------------------------------------------------------------- /examples/joux.rs: -------------------------------------------------------------------------------- 1 | use substrate_bn::{Group, Fr, G1, G2, pairing}; 2 | 3 | fn main() { 4 | let rng = &mut rand::thread_rng(); 5 | 6 | // Generate private keys 7 | let alice_sk = Fr::random(rng); 8 | let bob_sk = Fr::random(rng); 9 | let carol_sk = Fr::random(rng); 10 | 11 | // Generate public keys in G1 and G2 12 | let (alice_pk1, alice_pk2) = (G1::one() * alice_sk, G2::one() * alice_sk); 13 | let (bob_pk1, bob_pk2) = (G1::one() * bob_sk, G2::one() * bob_sk); 14 | let (carol_pk1, carol_pk2) = (G1::one() * carol_sk, G2::one() * carol_sk); 15 | 16 | // Each party computes the shared secret 17 | let alice_ss = pairing(bob_pk1, carol_pk2).pow(alice_sk); 18 | let bob_ss = pairing(carol_pk1, alice_pk2).pow(bob_sk); 19 | let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk); 20 | 21 | assert!(alice_ss == bob_ss && bob_ss == carol_ss); 22 | } 23 | -------------------------------------------------------------------------------- /shootout/README.md: -------------------------------------------------------------------------------- 1 | bn crate performing 20000 pairing operations 2 | 3 | real 3m28.831s 4 | user 3m28.797s 5 | sys 0m0.020s 6 | 7 | libsnark (ALT_BN128 with USE_ASM disabled) performing 20000 pairing operations 8 | 9 | real 2m3.656s 10 | user 2m3.543s 11 | sys 0m0.007s 12 | -------------------------------------------------------------------------------- /shootout/main.rs: -------------------------------------------------------------------------------- 1 | extern crate bn; 2 | 3 | use bn::*; 4 | 5 | fn main() { 6 | let mut a = G1::one(); 7 | let mut b = G2::one(); 8 | let c = Fr::from_str("1901").unwrap().inverse().unwrap(); 9 | let d = Fr::from_str("2344").unwrap().inverse().unwrap(); 10 | 11 | let mut acc1 = Gt::one(); 12 | for i in 0..10000 { 13 | acc1 = acc1 * pairing(a, b); 14 | a = a * c; 15 | b = b * d; 16 | } 17 | 18 | a = G1::one(); 19 | b = G2::one(); 20 | 21 | let mut acc2 = Gt::one(); 22 | for i in 0..10000 { 23 | acc2 = acc2 * pairing(a, b); 24 | a = a * d; 25 | b = b * c; 26 | } 27 | 28 | assert!(acc1 == acc2); 29 | } 30 | -------------------------------------------------------------------------------- /shootout/test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/default_types/r1cs_ppzksnark_pp.hpp" 2 | #include "common/profiling.hpp" 3 | 4 | // CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" make lib CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT 5 | // g++ -std=c++11 -O3 test.cpp -o test -Isrc/ -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC -L. -lsnark -lgmp -lsodium 6 | 7 | typedef libsnark::default_r1cs_ppzksnark_pp curve_pp; 8 | typedef libsnark::default_r1cs_ppzksnark_pp::G1_type curve_G1; 9 | typedef libsnark::default_r1cs_ppzksnark_pp::G2_type curve_G2; 10 | typedef libsnark::default_r1cs_ppzksnark_pp::GT_type curve_GT; 11 | typedef libsnark::default_r1cs_ppzksnark_pp::Fp_type curve_Fr; 12 | 13 | int main() { 14 | curve_pp::init_public_params(); 15 | libsnark::inhibit_profiling_info = true; 16 | libsnark::inhibit_profiling_counters = true; 17 | 18 | curve_G1 a = curve_G1::one(); 19 | curve_G2 b = curve_G2::one(); 20 | 21 | curve_Fr c = curve_Fr("1901").inverse(); 22 | curve_Fr d = curve_Fr("2344").inverse(); 23 | 24 | curve_GT acc1 = curve_GT::one(); 25 | 26 | for (size_t i = 0; i < 10000; i++) { 27 | acc1 = acc1 * curve_pp::reduced_pairing(a, b); 28 | a = c * a; 29 | b = d * b; 30 | } 31 | 32 | a = curve_G1::one(); 33 | b = curve_G2::one(); 34 | 35 | curve_GT acc2 = curve_GT::one(); 36 | 37 | for (size_t i = 0; i < 10000; i++) { 38 | acc2 = acc2 * curve_pp::reduced_pairing(a, b); 39 | a = d * a; 40 | b = c * b; 41 | } 42 | 43 | assert(acc1 == acc2); 44 | } 45 | -------------------------------------------------------------------------------- /src/arith.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::Ordering; 2 | use rand::Rng; 3 | use crunchy::unroll; 4 | 5 | use byteorder::{BigEndian, ByteOrder}; 6 | 7 | /// 256-bit, stack allocated biginteger for use in prime field 8 | /// arithmetic. 9 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 10 | #[repr(C)] 11 | pub struct U256(pub [u128; 2]); 12 | 13 | impl From<[u64; 4]> for U256 { 14 | fn from(d: [u64; 4]) -> Self { 15 | let mut a = [0u128; 2]; 16 | a[0] = (d[1] as u128) << 64 | d[0] as u128; 17 | a[1] = (d[3] as u128) << 64 | d[2] as u128; 18 | U256(a) 19 | } 20 | } 21 | 22 | impl From for U256 { 23 | fn from(d: u64) -> Self { 24 | U256::from([d, 0, 0, 0]) 25 | } 26 | } 27 | 28 | /// 512-bit, stack allocated biginteger for use in extension 29 | /// field serialization and scalar interpretation. 30 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 31 | #[repr(C)] 32 | pub struct U512(pub [u128; 4]); 33 | 34 | impl From<[u64; 8]> for U512 { 35 | fn from(d: [u64; 8]) -> Self { 36 | let mut a = [0u128; 4]; 37 | a[0] = (d[1] as u128) << 64 | d[0] as u128; 38 | a[1] = (d[3] as u128) << 64 | d[2] as u128; 39 | a[2] = (d[5] as u128) << 64 | d[4] as u128; 40 | a[3] = (d[7] as u128) << 64 | d[6] as u128; 41 | U512(a) 42 | } 43 | } 44 | 45 | impl U512 { 46 | /// Multiplies c1 by modulo, adds c0. 47 | pub fn new(c1: &U256, c0: &U256, modulo: &U256) -> U512 { 48 | let mut res = [0; 4]; 49 | 50 | debug_assert_eq!(c1.0.len(), 2); 51 | unroll! { 52 | for i in 0..2 { 53 | mac_digit(i, &mut res, &modulo.0, c1.0[i]); 54 | } 55 | } 56 | 57 | let mut carry = 0; 58 | 59 | debug_assert_eq!(res.len(), 4); 60 | unroll! { 61 | for i in 0..2 { 62 | res[i] = adc(res[i], c0.0[i], &mut carry); 63 | } 64 | } 65 | 66 | unroll! { 67 | for i in 0..2 { 68 | let (a1, a0) = split_u128(res[i + 2]); 69 | let (c, r0) = split_u128(a0 + carry); 70 | let (c, r1) = split_u128(a1 + c); 71 | carry = c; 72 | 73 | res[i + 2] = combine_u128(r1, r0); 74 | } 75 | } 76 | 77 | debug_assert!(0 == carry); 78 | 79 | U512(res) 80 | } 81 | 82 | pub fn from_slice(s: &[u8]) -> Result { 83 | if s.len() != 64 { 84 | return Err(Error::InvalidLength { 85 | expected: 32, 86 | actual: s.len(), 87 | }); 88 | } 89 | 90 | let mut n = [0; 4]; 91 | for (l, i) in (0..4).rev().zip((0..4).map(|i| i * 16)) { 92 | n[l] = BigEndian::read_u128(&s[i..]); 93 | } 94 | 95 | Ok(U512(n)) 96 | } 97 | 98 | /// Get a random U512 99 | pub fn random(rng: &mut R) -> U512 { 100 | U512(rng.gen()) 101 | } 102 | 103 | pub fn get_bit(&self, n: usize) -> Option { 104 | if n >= 512 { 105 | None 106 | } else { 107 | let part = n / 128; 108 | let bit = n - (128 * part); 109 | 110 | Some(self.0[part] & (1 << bit) > 0) 111 | } 112 | } 113 | 114 | /// Divides self by modulo, returning remainder and, if 115 | /// possible, a quotient smaller than the modulus. 116 | pub fn divrem(&self, modulo: &U256) -> (Option, U256) { 117 | let mut q = Some(U256::zero()); 118 | let mut r = U256::zero(); 119 | 120 | for i in (0..512).rev() { 121 | // NB: modulo's first two bits are always unset 122 | // so this will never destroy information 123 | mul2(&mut r.0); 124 | assert!(r.set_bit(0, self.get_bit(i).unwrap())); 125 | if &r >= modulo { 126 | sub_noborrow(&mut r.0, &modulo.0); 127 | if q.is_some() && !q.as_mut().unwrap().set_bit(i, true) { 128 | q = None 129 | } 130 | } 131 | } 132 | 133 | if q.is_some() && (q.as_ref().unwrap() >= modulo) { 134 | (None, r) 135 | } else { 136 | (q, r) 137 | } 138 | } 139 | 140 | pub fn interpret(buf: &[u8; 64]) -> U512 { 141 | let mut n = [0; 4]; 142 | for (l, i) in (0..4).rev().zip((0..4).map(|i| i * 16)) { 143 | n[l] = BigEndian::read_u128(&buf[i..]); 144 | } 145 | 146 | U512(n) 147 | } 148 | } 149 | 150 | impl Ord for U512 { 151 | #[inline] 152 | fn cmp(&self, other: &U512) -> Ordering { 153 | for (a, b) in self.0.iter().zip(other.0.iter()).rev() { 154 | if *a < *b { 155 | return Ordering::Less; 156 | } else if *a > *b { 157 | return Ordering::Greater; 158 | } 159 | } 160 | 161 | return Ordering::Equal; 162 | } 163 | } 164 | 165 | impl PartialOrd for U512 { 166 | #[inline] 167 | fn partial_cmp(&self, other: &U512) -> Option { 168 | Some(self.cmp(other)) 169 | } 170 | } 171 | 172 | impl Ord for U256 { 173 | #[inline] 174 | fn cmp(&self, other: &U256) -> Ordering { 175 | for (a, b) in self.0.iter().zip(other.0.iter()).rev() { 176 | if *a < *b { 177 | return Ordering::Less; 178 | } else if *a > *b { 179 | return Ordering::Greater; 180 | } 181 | } 182 | 183 | return Ordering::Equal; 184 | } 185 | } 186 | 187 | impl PartialOrd for U256 { 188 | #[inline] 189 | fn partial_cmp(&self, other: &U256) -> Option { 190 | Some(self.cmp(other)) 191 | } 192 | } 193 | 194 | /// U256/U512 errors 195 | #[derive(Debug)] 196 | pub enum Error { 197 | InvalidLength { expected: usize, actual: usize }, 198 | } 199 | 200 | impl U256 { 201 | /// Initialize U256 from slice of bytes (big endian) 202 | pub fn from_slice(s: &[u8]) -> Result { 203 | if s.len() != 32 { 204 | return Err(Error::InvalidLength { 205 | expected: 32, 206 | actual: s.len(), 207 | }); 208 | } 209 | 210 | let mut n = [0; 2]; 211 | for (l, i) in (0..2).rev().zip((0..2).map(|i| i * 16)) { 212 | n[l] = BigEndian::read_u128(&s[i..]); 213 | } 214 | 215 | Ok(U256(n)) 216 | } 217 | 218 | pub fn to_big_endian(&self, s: &mut [u8]) -> Result<(), Error> { 219 | if s.len() != 32 { 220 | return Err(Error::InvalidLength { 221 | expected: 32, 222 | actual: s.len(), 223 | }); 224 | } 225 | 226 | for (l, i) in (0..2).rev().zip((0..2).map(|i| i * 16)) { 227 | BigEndian::write_u128(&mut s[i..], self.0[l]); 228 | } 229 | 230 | Ok(()) 231 | } 232 | 233 | #[inline] 234 | pub fn zero() -> U256 { 235 | U256([0, 0]) 236 | } 237 | 238 | #[inline] 239 | pub fn one() -> U256 { 240 | U256([1, 0]) 241 | } 242 | 243 | /// Produce a random number (mod `modulo`) 244 | pub fn random(rng: &mut R, modulo: &U256) -> U256 { 245 | U512::random(rng).divrem(modulo).1 246 | } 247 | 248 | pub fn is_zero(&self) -> bool { 249 | self.0[0] == 0 && self.0[1] == 0 250 | } 251 | 252 | pub fn set_bit(&mut self, n: usize, to: bool) -> bool { 253 | if n >= 256 { 254 | false 255 | } else { 256 | let part = n / 128; 257 | let bit = n - (128 * part); 258 | 259 | if to { 260 | self.0[part] |= 1 << bit; 261 | } else { 262 | self.0[part] &= !(1 << bit); 263 | } 264 | 265 | true 266 | } 267 | } 268 | 269 | pub fn get_bit(&self, n: usize) -> Option { 270 | if n >= 256 { 271 | None 272 | } else { 273 | let part = n / 128; 274 | let bit = n - (128 * part); 275 | 276 | Some(self.0[part] & (1 << bit) > 0) 277 | } 278 | } 279 | 280 | /// Add `other` to `self` (mod `modulo`) 281 | pub fn add(&mut self, other: &U256, modulo: &U256) { 282 | add_nocarry(&mut self.0, &other.0); 283 | 284 | if *self >= *modulo { 285 | sub_noborrow(&mut self.0, &modulo.0); 286 | } 287 | } 288 | 289 | /// Subtract `other` from `self` (mod `modulo`) 290 | pub fn sub(&mut self, other: &U256, modulo: &U256) { 291 | if *self < *other { 292 | add_nocarry(&mut self.0, &modulo.0); 293 | } 294 | 295 | sub_noborrow(&mut self.0, &other.0); 296 | } 297 | 298 | /// Multiply `self` by `other` (mod `modulo`) via the Montgomery 299 | /// multiplication method. 300 | pub fn mul(&mut self, other: &U256, modulo: &U256, inv: u128) { 301 | mul_reduce(&mut self.0, &other.0, &modulo.0, inv); 302 | 303 | if *self >= *modulo { 304 | sub_noborrow(&mut self.0, &modulo.0); 305 | } 306 | } 307 | 308 | /// Turn `self` into its additive inverse (mod `modulo`) 309 | pub fn neg(&mut self, modulo: &U256) { 310 | if *self > Self::zero() { 311 | let mut tmp = modulo.0; 312 | sub_noborrow(&mut tmp, &self.0); 313 | 314 | self.0 = tmp; 315 | } 316 | } 317 | 318 | #[inline] 319 | pub fn is_even(&self) -> bool { 320 | self.0[0] & 1 == 0 321 | } 322 | 323 | /// Turn `self` into its multiplicative inverse (mod `modulo`) 324 | pub fn invert(&mut self, modulo: &U256) { 325 | // Guajardo Kumar Paar Pelzl 326 | // Efficient Software-Implementation of Finite Fields with Applications to Cryptography 327 | // Algorithm 16 (BEA for Inversion in Fp) 328 | 329 | let mut u = *self; 330 | let mut v = *modulo; 331 | let mut b = U256::one(); 332 | let mut c = U256::zero(); 333 | 334 | while u != U256::one() && v != U256::one() { 335 | while u.is_even() { 336 | div2(&mut u.0); 337 | 338 | if b.is_even() { 339 | div2(&mut b.0); 340 | } else { 341 | add_nocarry(&mut b.0, &modulo.0); 342 | div2(&mut b.0); 343 | } 344 | } 345 | while v.is_even() { 346 | div2(&mut v.0); 347 | 348 | if c.is_even() { 349 | div2(&mut c.0); 350 | } else { 351 | add_nocarry(&mut c.0, &modulo.0); 352 | div2(&mut c.0); 353 | } 354 | } 355 | 356 | if u >= v { 357 | sub_noborrow(&mut u.0, &v.0); 358 | b.sub(&c, modulo); 359 | } else { 360 | sub_noborrow(&mut v.0, &u.0); 361 | c.sub(&b, modulo); 362 | } 363 | } 364 | 365 | if u == U256::one() { 366 | self.0 = b.0; 367 | } else { 368 | self.0 = c.0; 369 | } 370 | } 371 | 372 | /// Return an Iterator over all bits from 373 | /// MSB to LSB. 374 | pub fn bits(&self) -> BitIterator { 375 | BitIterator { int: &self, n: 256 } 376 | } 377 | } 378 | 379 | pub struct BitIterator<'a> { 380 | int: &'a U256, 381 | n: usize, 382 | } 383 | 384 | impl<'a> Iterator for BitIterator<'a> { 385 | type Item = bool; 386 | 387 | fn next(&mut self) -> Option { 388 | if self.n == 0 { 389 | None 390 | } else { 391 | self.n -= 1; 392 | 393 | self.int.get_bit(self.n) 394 | } 395 | } 396 | } 397 | 398 | /// Divide by two 399 | #[inline] 400 | fn div2(a: &mut [u128; 2]) { 401 | let tmp = a[1] << 127; 402 | a[1] >>= 1; 403 | a[0] >>= 1; 404 | a[0] |= tmp; 405 | } 406 | 407 | /// Multiply by two 408 | #[inline] 409 | fn mul2(a: &mut [u128; 2]) { 410 | let tmp = a[0] >> 127; 411 | a[0] <<= 1; 412 | a[1] <<= 1; 413 | a[1] |= tmp; 414 | } 415 | 416 | #[inline(always)] 417 | fn split_u128(i: u128) -> (u128, u128) { 418 | (i >> 64, i & 0xFFFFFFFFFFFFFFFF) 419 | } 420 | 421 | #[inline(always)] 422 | fn combine_u128(hi: u128, lo: u128) -> u128 { 423 | (hi << 64) | lo 424 | } 425 | 426 | #[inline] 427 | fn adc(a: u128, b: u128, carry: &mut u128) -> u128 { 428 | let (a1, a0) = split_u128(a); 429 | let (b1, b0) = split_u128(b); 430 | let (c, r0) = split_u128(a0 + b0 + *carry); 431 | let (c, r1) = split_u128(a1 + b1 + c); 432 | *carry = c; 433 | 434 | combine_u128(r1, r0) 435 | } 436 | 437 | #[inline] 438 | fn add_nocarry(a: &mut [u128; 2], b: &[u128; 2]) { 439 | let mut carry = 0; 440 | 441 | for (a, b) in a.into_iter().zip(b.iter()) { 442 | *a = adc(*a, *b, &mut carry); 443 | } 444 | 445 | debug_assert!(0 == carry); 446 | } 447 | 448 | #[inline] 449 | fn sub_noborrow(a: &mut [u128; 2], b: &[u128; 2]) { 450 | #[inline] 451 | fn sbb(a: u128, b: u128, borrow: &mut u128) -> u128 { 452 | let (a1, a0) = split_u128(a); 453 | let (b1, b0) = split_u128(b); 454 | let (b, r0) = split_u128((1 << 64) + a0 - b0 - *borrow); 455 | let (b, r1) = split_u128((1 << 64) + a1 - b1 - ((b == 0) as u128)); 456 | 457 | *borrow = (b == 0) as u128; 458 | 459 | combine_u128(r1, r0) 460 | } 461 | 462 | let mut borrow = 0; 463 | 464 | for (a, b) in a.into_iter().zip(b.iter()) { 465 | *a = sbb(*a, *b, &mut borrow); 466 | } 467 | 468 | debug_assert!(0 == borrow); 469 | } 470 | 471 | // TODO: Make `from_index` a const param 472 | #[inline(always)] 473 | fn mac_digit(from_index: usize, acc: &mut [u128; 4], b: &[u128; 2], c: u128) { 474 | #[inline] 475 | fn mac_with_carry(a: u128, b: u128, c: u128, carry: &mut u128) -> u128 { 476 | let (b_hi, b_lo) = split_u128(b); 477 | let (c_hi, c_lo) = split_u128(c); 478 | 479 | let (a_hi, a_lo) = split_u128(a); 480 | let (carry_hi, carry_lo) = split_u128(*carry); 481 | let (x_hi, x_lo) = split_u128(b_lo * c_lo + a_lo + carry_lo); 482 | let (y_hi, y_lo) = split_u128(b_lo * c_hi); 483 | let (z_hi, z_lo) = split_u128(b_hi * c_lo); 484 | // Brackets to allow better ILP 485 | let (r_hi, r_lo) = split_u128((x_hi + y_lo) + (z_lo + a_hi) + carry_hi); 486 | 487 | *carry = (b_hi * c_hi) + r_hi + y_hi + z_hi; 488 | 489 | combine_u128(r_lo, x_lo) 490 | } 491 | 492 | if c == 0 { 493 | return; 494 | } 495 | 496 | let mut carry = 0; 497 | 498 | debug_assert_eq!(acc.len(), 4); 499 | unroll! { 500 | for i in 0..2 { 501 | let a_index = i + from_index; 502 | acc[a_index] = mac_with_carry(acc[a_index], b[i], c, &mut carry); 503 | } 504 | } 505 | unroll! { 506 | for i in 0..2 { 507 | let a_index = i + from_index + 2; 508 | if a_index < 4 { 509 | let (a_hi, a_lo) = split_u128(acc[a_index]); 510 | let (carry_hi, carry_lo) = split_u128(carry); 511 | let (x_hi, x_lo) = split_u128(a_lo + carry_lo); 512 | let (r_hi, r_lo) = split_u128(x_hi + a_hi + carry_hi); 513 | 514 | carry = r_hi; 515 | 516 | acc[a_index] = combine_u128(r_lo, x_lo); 517 | } 518 | } 519 | } 520 | 521 | debug_assert!(carry == 0); 522 | } 523 | 524 | #[inline] 525 | fn mul_reduce(this: &mut [u128; 2], by: &[u128; 2], modulus: &[u128; 2], inv: u128) { 526 | // The Montgomery reduction here is based on Algorithm 14.32 in 527 | // Handbook of Applied Cryptography 528 | // . 529 | 530 | let mut res = [0; 2 * 2]; 531 | unroll! { 532 | for i in 0..2 { 533 | mac_digit(i, &mut res, by, this[i]); 534 | } 535 | } 536 | 537 | unroll! { 538 | for i in 0..2 { 539 | let k = inv.wrapping_mul(res[i]); 540 | mac_digit(i, &mut res, modulus, k); 541 | } 542 | } 543 | 544 | this.copy_from_slice(&res[2..]); 545 | } 546 | 547 | #[test] 548 | fn setting_bits() { 549 | let rng = &mut ::rand::thread_rng(); 550 | let modulo = U256::from([0xffffffffffffffff; 4]); 551 | 552 | let a = U256::random(rng, &modulo); 553 | let mut e = U256::zero(); 554 | for (i, b) in a.bits().enumerate() { 555 | assert!(e.set_bit(255 - i, b)); 556 | } 557 | 558 | assert_eq!(a, e); 559 | } 560 | 561 | #[test] 562 | fn from_slice() { 563 | let tst = U256::one(); 564 | let mut s = [0u8; 32]; 565 | s[31] = 1; 566 | 567 | let num = 568 | U256::from_slice(&s).expect("U256 should initialize ok from slice in `from_slice` test"); 569 | assert_eq!(num, tst); 570 | } 571 | 572 | #[test] 573 | fn to_big_endian() { 574 | let num = U256::one(); 575 | let mut s = [0u8; 32]; 576 | 577 | num.to_big_endian(&mut s) 578 | .expect("U256 should convert to bytes ok in `to_big_endian` test"); 579 | assert_eq!( 580 | s, 581 | [ 582 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 583 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 584 | ] 585 | ); 586 | } 587 | 588 | #[test] 589 | fn testing_divrem() { 590 | let rng = &mut ::rand::thread_rng(); 591 | 592 | let modulo = U256::from([ 593 | 0x3c208c16d87cfd47, 594 | 0x97816a916871ca8d, 595 | 0xb85045b68181585d, 596 | 0x30644e72e131a029, 597 | ]); 598 | 599 | for _ in 0..100 { 600 | let c0 = U256::random(rng, &modulo); 601 | let c1 = U256::random(rng, &modulo); 602 | 603 | let c1q_plus_c0 = U512::new(&c1, &c0, &modulo); 604 | 605 | let (new_c1, new_c0) = c1q_plus_c0.divrem(&modulo); 606 | 607 | assert!(c1 == new_c1.unwrap()); 608 | assert!(c0 == new_c0); 609 | } 610 | 611 | { 612 | // Modulus should become 1*q + 0 613 | let a = U512::from([ 614 | 0x3c208c16d87cfd47, 615 | 0x97816a916871ca8d, 616 | 0xb85045b68181585d, 617 | 0x30644e72e131a029, 618 | 0, 619 | 0, 620 | 0, 621 | 0, 622 | ]); 623 | 624 | let (c1, c0) = a.divrem(&modulo); 625 | assert_eq!(c1.unwrap(), U256::one()); 626 | assert_eq!(c0, U256::zero()); 627 | } 628 | 629 | { 630 | // Modulus squared minus 1 should be (q-1) q + q-1 631 | let a = U512::from([ 632 | 0x3b5458a2275d69b0, 633 | 0xa602072d09eac101, 634 | 0x4a50189c6d96cadc, 635 | 0x04689e957a1242c8, 636 | 0x26edfa5c34c6b38d, 637 | 0xb00b855116375606, 638 | 0x599a6f7c0348d21c, 639 | 0x0925c4b8763cbf9c, 640 | ]); 641 | 642 | let (c1, c0) = a.divrem(&modulo); 643 | assert_eq!( 644 | c1.unwrap(), 645 | U256::from([ 646 | 0x3c208c16d87cfd46, 647 | 0x97816a916871ca8d, 648 | 0xb85045b68181585d, 649 | 0x30644e72e131a029 650 | ]) 651 | ); 652 | assert_eq!( 653 | c0, 654 | U256::from([ 655 | 0x3c208c16d87cfd46, 656 | 0x97816a916871ca8d, 657 | 0xb85045b68181585d, 658 | 0x30644e72e131a029 659 | ]) 660 | ); 661 | } 662 | 663 | { 664 | // Modulus squared minus 2 should be (q-1) q + q-2 665 | let a = U512::from([ 666 | 0x3b5458a2275d69af, 667 | 0xa602072d09eac101, 668 | 0x4a50189c6d96cadc, 669 | 0x04689e957a1242c8, 670 | 0x26edfa5c34c6b38d, 671 | 0xb00b855116375606, 672 | 0x599a6f7c0348d21c, 673 | 0x0925c4b8763cbf9c, 674 | ]); 675 | 676 | let (c1, c0) = a.divrem(&modulo); 677 | 678 | assert_eq!( 679 | c1.unwrap(), 680 | U256::from([ 681 | 0x3c208c16d87cfd46, 682 | 0x97816a916871ca8d, 683 | 0xb85045b68181585d, 684 | 0x30644e72e131a029 685 | ]) 686 | ); 687 | assert_eq!( 688 | c0, 689 | U256::from([ 690 | 0x3c208c16d87cfd45, 691 | 0x97816a916871ca8d, 692 | 0xb85045b68181585d, 693 | 0x30644e72e131a029 694 | ]) 695 | ); 696 | } 697 | 698 | { 699 | // Ridiculously large number should fail 700 | let a = U512::from([ 701 | 0xffffffffffffffff, 702 | 0xffffffffffffffff, 703 | 0xffffffffffffffff, 704 | 0xffffffffffffffff, 705 | 0xffffffffffffffff, 706 | 0xffffffffffffffff, 707 | 0xffffffffffffffff, 708 | 0xffffffffffffffff, 709 | ]); 710 | 711 | let (c1, c0) = a.divrem(&modulo); 712 | assert!(c1.is_none()); 713 | assert_eq!( 714 | c0, 715 | U256::from([ 716 | 0xf32cfc5b538afa88, 717 | 0xb5e71911d44501fb, 718 | 0x47ab1eff0a417ff6, 719 | 0x06d89f71cab8351f 720 | ]) 721 | ); 722 | } 723 | 724 | { 725 | // Modulus squared should fail 726 | let a = U512::from([ 727 | 0x3b5458a2275d69b1, 728 | 0xa602072d09eac101, 729 | 0x4a50189c6d96cadc, 730 | 0x04689e957a1242c8, 731 | 0x26edfa5c34c6b38d, 732 | 0xb00b855116375606, 733 | 0x599a6f7c0348d21c, 734 | 0x0925c4b8763cbf9c, 735 | ]); 736 | 737 | let (c1, c0) = a.divrem(&modulo); 738 | assert!(c1.is_none()); 739 | assert_eq!(c0, U256::zero()); 740 | } 741 | 742 | { 743 | // Modulus squared plus one should fail 744 | let a = U512::from([ 745 | 0x3b5458a2275d69b2, 746 | 0xa602072d09eac101, 747 | 0x4a50189c6d96cadc, 748 | 0x04689e957a1242c8, 749 | 0x26edfa5c34c6b38d, 750 | 0xb00b855116375606, 751 | 0x599a6f7c0348d21c, 752 | 0x0925c4b8763cbf9c, 753 | ]); 754 | 755 | let (c1, c0) = a.divrem(&modulo); 756 | assert!(c1.is_none()); 757 | assert_eq!(c0, U256::one()); 758 | } 759 | 760 | { 761 | let modulo = U256::from([ 762 | 0x43e1f593f0000001, 763 | 0x2833e84879b97091, 764 | 0xb85045b68181585d, 765 | 0x30644e72e131a029, 766 | ]); 767 | 768 | // Fr modulus masked off is valid 769 | let a = U512::from([ 770 | 0xffffffffffffffff, 771 | 0xffffffffffffffff, 772 | 0xffffffffffffffff, 773 | 0xffffffffffffffff, 774 | 0xffffffffffffffff, 775 | 0xffffffffffffffff, 776 | 0xffffffffffffffff, 777 | 0x07ffffffffffffff, 778 | ]); 779 | 780 | let (c1, c0) = a.divrem(&modulo); 781 | 782 | assert!(c1.unwrap() < modulo); 783 | assert!(c0 < modulo); 784 | } 785 | } 786 | -------------------------------------------------------------------------------- /src/fields/fp.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use core::ops::{Add, Mul, Neg, Sub}; 3 | use rand::Rng; 4 | use crate::fields::FieldElement; 5 | use crate::arith::{U256, U512}; 6 | 7 | macro_rules! field_impl { 8 | ($name:ident, $modulus:expr, $rsquared:expr, $rcubed:expr, $one:expr, $inv:expr) => { 9 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 10 | #[repr(C)] 11 | pub struct $name(U256); 12 | 13 | impl From<$name> for U256 { 14 | #[inline] 15 | fn from(mut a: $name) -> Self { 16 | a.0.mul(&U256::one(), &U256::from($modulus), $inv); 17 | 18 | a.0 19 | } 20 | } 21 | 22 | impl $name { 23 | pub fn from_str(s: &str) -> Option { 24 | let ints: Vec<_> = { 25 | let mut acc = Self::zero(); 26 | (0..11).map(|_| {let tmp = acc; acc = acc + Self::one(); tmp}).collect() 27 | }; 28 | 29 | let mut res = Self::zero(); 30 | for c in s.chars() { 31 | match c.to_digit(10) { 32 | Some(d) => { 33 | res = res * ints[10]; 34 | res = res + ints[d as usize]; 35 | }, 36 | None => { 37 | return None; 38 | } 39 | } 40 | } 41 | 42 | Some(res) 43 | } 44 | 45 | /// Converts a U256 to an Fp so long as it's below the modulus. 46 | pub fn new(mut a: U256) -> Option { 47 | if a < U256::from($modulus) { 48 | a.mul(&U256::from($rsquared), &U256::from($modulus), $inv); 49 | 50 | Some($name(a)) 51 | } else { 52 | None 53 | } 54 | } 55 | 56 | /// Converts a U256 to an Fr regardless of modulus. 57 | pub fn new_mul_factor(mut a: U256) -> Self { 58 | a.mul(&U256::from($rsquared), &U256::from($modulus), $inv); 59 | $name(a) 60 | } 61 | 62 | pub fn interpret(buf: &[u8; 64]) -> Self { 63 | $name::new(U512::interpret(buf).divrem(&U256::from($modulus)).1).unwrap() 64 | } 65 | 66 | /// Returns the modulus 67 | #[inline] 68 | #[allow(dead_code)] 69 | pub fn modulus() -> U256 { 70 | U256::from($modulus) 71 | } 72 | 73 | #[inline] 74 | #[allow(dead_code)] 75 | pub fn inv(&self) -> u128 { 76 | $inv 77 | } 78 | 79 | pub fn raw(&self) -> &U256 { 80 | &self.0 81 | } 82 | 83 | pub fn set_bit(&mut self, bit: usize, to: bool) { 84 | self.0.set_bit(bit, to); 85 | } 86 | } 87 | 88 | impl FieldElement for $name { 89 | #[inline] 90 | fn zero() -> Self { 91 | $name(U256::from([0, 0, 0, 0])) 92 | } 93 | 94 | #[inline] 95 | fn one() -> Self { 96 | $name(U256::from($one)) 97 | } 98 | 99 | fn random(rng: &mut R) -> Self { 100 | $name(U256::random(rng, &U256::from($modulus))) 101 | } 102 | 103 | #[inline] 104 | fn is_zero(&self) -> bool { 105 | self.0.is_zero() 106 | } 107 | 108 | fn inverse(mut self) -> Option { 109 | if self.is_zero() { 110 | None 111 | } else { 112 | self.0.invert(&U256::from($modulus)); 113 | self.0.mul(&U256::from($rcubed), &U256::from($modulus), $inv); 114 | 115 | Some(self) 116 | } 117 | } 118 | } 119 | 120 | impl Add for $name { 121 | type Output = $name; 122 | 123 | #[inline] 124 | fn add(mut self, other: $name) -> $name { 125 | self.0.add(&other.0, &U256::from($modulus)); 126 | 127 | self 128 | } 129 | } 130 | 131 | impl Sub for $name { 132 | type Output = $name; 133 | 134 | #[inline] 135 | fn sub(mut self, other: $name) -> $name { 136 | self.0.sub(&other.0, &U256::from($modulus)); 137 | 138 | self 139 | } 140 | } 141 | 142 | impl Mul for $name { 143 | type Output = $name; 144 | 145 | #[inline] 146 | fn mul(mut self, other: $name) -> $name { 147 | self.0.mul(&other.0, &U256::from($modulus), $inv); 148 | 149 | self 150 | } 151 | } 152 | 153 | impl Neg for $name { 154 | type Output = $name; 155 | 156 | #[inline] 157 | fn neg(mut self) -> $name { 158 | self.0.neg(&U256::from($modulus)); 159 | 160 | self 161 | } 162 | } 163 | } 164 | } 165 | 166 | field_impl!( 167 | Fr, 168 | [ 169 | 0x43e1f593f0000001, 170 | 0x2833e84879b97091, 171 | 0xb85045b68181585d, 172 | 0x30644e72e131a029 173 | ], 174 | [ 175 | 0x1bb8e645ae216da7, 176 | 0x53fe3ab1e35c59e3, 177 | 0x8c49833d53bb8085, 178 | 0x0216d0b17f4e44a5 179 | ], 180 | [ 181 | 0x5e94d8e1b4bf0040, 182 | 0x2a489cbe1cfbb6b8, 183 | 0x893cc664a19fcfed, 184 | 0x0cf8594b7fcc657c 185 | ], 186 | [ 187 | 0xac96341c4ffffffb, 188 | 0x36fc76959f60cd29, 189 | 0x666ea36f7879462e, 190 | 0xe0a77c19a07df2f 191 | ], 192 | 0x6586864b4c6911b3c2e1f593efffffff 193 | ); 194 | 195 | field_impl!( 196 | Fq, 197 | [ 198 | 0x3c208c16d87cfd47, 199 | 0x97816a916871ca8d, 200 | 0xb85045b68181585d, 201 | 0x30644e72e131a029 202 | ], 203 | [ 204 | 0xf32cfc5b538afa89, 205 | 0xb5e71911d44501fb, 206 | 0x47ab1eff0a417ff6, 207 | 0x06d89f71cab8351f 208 | ], 209 | [ 210 | 0xb1cd6dafda1530df, 211 | 0x62f210e6a7283db6, 212 | 0xef7f0b0c0ada0afb, 213 | 0x20fd6e902d592544 214 | ], 215 | [ 216 | 0xd35d438dc58f0d9d, 217 | 0xa78eb28f5c70b3d, 218 | 0x666ea36f7879462c, 219 | 0xe0a77c19a07df2f 220 | ], 221 | 0x9ede7d651eca6ac987d20782e4866389 222 | ); 223 | 224 | lazy_static::lazy_static! { 225 | 226 | static ref FQ: U256 = U256::from([ 227 | 0x3c208c16d87cfd47, 228 | 0x97816a916871ca8d, 229 | 0xb85045b68181585d, 230 | 0x30644e72e131a029 231 | ]); 232 | 233 | pub static ref FQ_MINUS3_DIV4: Fq = 234 | Fq::new(3.into()).expect("3 is a valid field element and static; qed").neg() * 235 | Fq::new(4.into()).expect("4 is a valid field element and static; qed").inverse() 236 | .expect("4 has inverse in Fq and is static; qed"); 237 | 238 | static ref FQ_MINUS1_DIV2: Fq = 239 | Fq::new(1.into()).expect("1 is a valid field element and static; qed").neg() * 240 | Fq::new(2.into()).expect("2 is a valid field element and static; qed").inverse() 241 | .expect("2 has inverse in Fq and is static; qed"); 242 | 243 | } 244 | 245 | impl Fq { 246 | pub fn sqrt(&self) -> Option { 247 | let a1 = self.pow(*FQ_MINUS3_DIV4); 248 | let a1a = a1 * *self; 249 | let a0 = a1 * (a1a); 250 | 251 | let mut am1 = *FQ; 252 | am1.sub(&1.into(), &*FQ); 253 | 254 | if a0 == Fq::new(am1).unwrap() { 255 | None 256 | } else { 257 | Some(a1a) 258 | } 259 | } 260 | } 261 | 262 | #[inline] 263 | pub fn const_fq(i: [u64; 4]) -> Fq { 264 | Fq(U256::from(i)) 265 | } 266 | 267 | #[test] 268 | fn test_rsquared() { 269 | let rng = &mut ::rand::thread_rng(); 270 | 271 | for _ in 0..1000 { 272 | let a = Fr::random(rng); 273 | let b: U256 = a.into(); 274 | let c = Fr::new(b).unwrap(); 275 | 276 | assert_eq!(a, c); 277 | } 278 | 279 | for _ in 0..1000 { 280 | let a = Fq::random(rng); 281 | let b: U256 = a.into(); 282 | let c = Fq::new(b).unwrap(); 283 | 284 | assert_eq!(a, c); 285 | } 286 | } 287 | 288 | 289 | #[test] 290 | fn sqrt_fq() { 291 | // from zcash test_proof.cpp 292 | let fq1 = Fq::from_str("5204065062716160319596273903996315000119019512886596366359652578430118331601").unwrap(); 293 | let fq2 = Fq::from_str("348579348568").unwrap(); 294 | 295 | assert_eq!(fq1, fq2.sqrt().expect("348579348568 is quadratic residue")); 296 | } 297 | -------------------------------------------------------------------------------- /src/fields/fq12.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Add, Mul, Neg, Sub}; 2 | use rand::Rng; 3 | use crate::fields::{const_fq, FieldElement, Fq, Fq2, Fq6}; 4 | use crate::arith::U256; 5 | 6 | fn frobenius_coeffs_c1(power: usize) -> Fq2 { 7 | match power % 12 { 8 | 0 => Fq2::one(), 9 | 1 => Fq2::new( 10 | const_fq([ 11 | 12653890742059813127, 12 | 14585784200204367754, 13 | 1278438861261381767, 14 | 212598772761311868, 15 | ]), 16 | const_fq([ 17 | 11683091849979440498, 18 | 14992204589386555739, 19 | 15866167890766973222, 20 | 1200023580730561873, 21 | ]), 22 | ), 23 | 2 => Fq2::new( 24 | const_fq([ 25 | 14595462726357228530, 26 | 17349508522658994025, 27 | 1017833795229664280, 28 | 299787779797702374, 29 | ]), 30 | Fq::zero(), 31 | ), 32 | 3 => Fq2::new( 33 | const_fq([ 34 | 3914496794763385213, 35 | 790120733010914719, 36 | 7322192392869644725, 37 | 581366264293887267, 38 | ]), 39 | const_fq([ 40 | 12817045492518885689, 41 | 4440270538777280383, 42 | 11178533038884588256, 43 | 2767537931541304486, 44 | ]), 45 | ), 46 | _ => unimplemented!(), 47 | } 48 | } 49 | 50 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 51 | #[repr(C)] 52 | pub struct Fq12 { 53 | c0: Fq6, 54 | c1: Fq6, 55 | } 56 | 57 | impl Fq12 { 58 | pub fn new(c0: Fq6, c1: Fq6) -> Self { 59 | Fq12 { c0: c0, c1: c1 } 60 | } 61 | 62 | fn final_exponentiation_first_chunk(&self) -> Option { 63 | match self.inverse() { 64 | Some(b) => { 65 | let a = self.unitary_inverse(); 66 | let c = a * b; 67 | let d = c.frobenius_map(2); 68 | 69 | Some(d * c) 70 | } 71 | None => None, 72 | } 73 | } 74 | 75 | fn final_exponentiation_last_chunk(&self) -> Fq12 { 76 | let a = self.exp_by_neg_z(); 77 | let b = a.cyclotomic_squared(); 78 | let c = b.cyclotomic_squared(); 79 | let d = c * b; 80 | 81 | let e = d.exp_by_neg_z(); 82 | let f = e.cyclotomic_squared(); 83 | let g = f.exp_by_neg_z(); 84 | let h = d.unitary_inverse(); 85 | let i = g.unitary_inverse(); 86 | 87 | let j = i * e; 88 | let k = j * h; 89 | let l = k * b; 90 | let m = k * e; 91 | let n = *self * m; 92 | 93 | let o = l.frobenius_map(1); 94 | let p = o * n; 95 | 96 | let q = k.frobenius_map(2); 97 | let r = q * p; 98 | 99 | let s = self.unitary_inverse(); 100 | let t = s * l; 101 | let u = t.frobenius_map(3); 102 | let v = u * r; 103 | 104 | v 105 | } 106 | 107 | pub fn final_exponentiation(&self) -> Option { 108 | self.final_exponentiation_first_chunk() 109 | .map(|a| a.final_exponentiation_last_chunk()) 110 | } 111 | 112 | pub fn frobenius_map(&self, power: usize) -> Self { 113 | Fq12 { 114 | c0: self.c0.frobenius_map(power), 115 | c1: self.c1 116 | .frobenius_map(power) 117 | .scale(frobenius_coeffs_c1(power)), 118 | } 119 | } 120 | 121 | pub fn exp_by_neg_z(&self) -> Fq12 { 122 | self.cyclotomic_pow(U256::from([4965661367192848881, 0, 0, 0])) 123 | .unitary_inverse() 124 | } 125 | 126 | pub fn unitary_inverse(&self) -> Fq12 { 127 | Fq12::new(self.c0, -self.c1) 128 | } 129 | 130 | pub fn mul_by_024(&self, ell_0: Fq2, ell_vw: Fq2, ell_vv: Fq2) -> Fq12 { 131 | let z0 = self.c0.c0; 132 | let z1 = self.c0.c1; 133 | let z2 = self.c0.c2; 134 | let z3 = self.c1.c0; 135 | let z4 = self.c1.c1; 136 | let z5 = self.c1.c2; 137 | 138 | let x0 = ell_0; 139 | let x2 = ell_vv; 140 | let x4 = ell_vw; 141 | 142 | let d0 = z0 * x0; 143 | let d2 = z2 * x2; 144 | let d4 = z4 * x4; 145 | let t2 = z0 + z4; 146 | let t1 = z0 + z2; 147 | let s0 = z1 + z3 + z5; 148 | 149 | let s1 = z1 * x2; 150 | let t3 = s1 + d4; 151 | let t4 = t3.mul_by_nonresidue() + d0; 152 | let z0 = t4; 153 | 154 | let t3 = z5 * x4; 155 | let s1 = s1 + t3; 156 | let t3 = t3 + d2; 157 | let t4 = t3.mul_by_nonresidue(); 158 | let t3 = z1 * x0; 159 | let s1 = s1 + t3; 160 | let t4 = t4 + t3; 161 | let z1 = t4; 162 | 163 | let t0 = x0 + x2; 164 | let t3 = t1 * t0 - d0 - d2; 165 | let t4 = z3 * x4; 166 | let s1 = s1 + t4; 167 | let t3 = t3 + t4; 168 | 169 | let t0 = z2 + z4; 170 | let z2 = t3; 171 | 172 | let t1 = x2 + x4; 173 | let t3 = t0 * t1 - d2 - d4; 174 | let t4 = t3.mul_by_nonresidue(); 175 | let t3 = z3 * x0; 176 | let s1 = s1 + t3; 177 | let t4 = t4 + t3; 178 | let z3 = t4; 179 | 180 | let t3 = z5 * x2; 181 | let s1 = s1 + t3; 182 | let t4 = t3.mul_by_nonresidue(); 183 | let t0 = x0 + x4; 184 | let t3 = t2 * t0 - d0 - d4; 185 | let t4 = t4 + t3; 186 | let z4 = t4; 187 | 188 | let t0 = x0 + x2 + x4; 189 | let t3 = s0 * t0 - s1; 190 | let z5 = t3; 191 | 192 | Fq12 { 193 | c0: Fq6::new(z0, z1, z2), 194 | c1: Fq6::new(z3, z4, z5), 195 | } 196 | } 197 | 198 | pub fn cyclotomic_squared(&self) -> Self { 199 | let z0 = self.c0.c0; 200 | let z4 = self.c0.c1; 201 | let z3 = self.c0.c2; 202 | let z2 = self.c1.c0; 203 | let z1 = self.c1.c1; 204 | let z5 = self.c1.c2; 205 | 206 | let tmp = z0 * z1; 207 | let t0 = (z0 + z1) * (z1.mul_by_nonresidue() + z0) - tmp - tmp.mul_by_nonresidue(); 208 | let t1 = tmp + tmp; 209 | 210 | let tmp = z2 * z3; 211 | let t2 = (z2 + z3) * (z3.mul_by_nonresidue() + z2) - tmp - tmp.mul_by_nonresidue(); 212 | let t3 = tmp + tmp; 213 | 214 | let tmp = z4 * z5; 215 | let t4 = (z4 + z5) * (z5.mul_by_nonresidue() + z4) - tmp - tmp.mul_by_nonresidue(); 216 | let t5 = tmp + tmp; 217 | 218 | let z0 = t0 - z0; 219 | let z0 = z0 + z0; 220 | let z0 = z0 + t0; 221 | 222 | let z1 = t1 + z1; 223 | let z1 = z1 + z1; 224 | let z1 = z1 + t1; 225 | 226 | let tmp = t5.mul_by_nonresidue(); 227 | let z2 = tmp + z2; 228 | let z2 = z2 + z2; 229 | let z2 = z2 + tmp; 230 | 231 | let z3 = t4 - z3; 232 | let z3 = z3 + z3; 233 | let z3 = z3 + t4; 234 | 235 | let z4 = t2 - z4; 236 | let z4 = z4 + z4; 237 | let z4 = z4 + t2; 238 | 239 | let z5 = t3 + z5; 240 | let z5 = z5 + z5; 241 | let z5 = z5 + t3; 242 | 243 | Fq12 { 244 | c0: Fq6::new(z0, z4, z3), 245 | c1: Fq6::new(z2, z1, z5), 246 | } 247 | } 248 | 249 | pub fn cyclotomic_pow>(&self, by: I) -> Self { 250 | let mut res = Self::one(); 251 | 252 | let mut found_one = false; 253 | 254 | for i in by.into().bits() { 255 | if found_one { 256 | res = res.cyclotomic_squared(); 257 | } 258 | 259 | if i { 260 | found_one = true; 261 | res = *self * res; 262 | } 263 | } 264 | 265 | res 266 | } 267 | } 268 | 269 | impl FieldElement for Fq12 { 270 | fn zero() -> Self { 271 | Fq12 { 272 | c0: Fq6::zero(), 273 | c1: Fq6::zero(), 274 | } 275 | } 276 | 277 | fn one() -> Self { 278 | Fq12 { 279 | c0: Fq6::one(), 280 | c1: Fq6::zero(), 281 | } 282 | } 283 | 284 | fn random(rng: &mut R) -> Self { 285 | Fq12 { 286 | c0: Fq6::random(rng), 287 | c1: Fq6::random(rng), 288 | } 289 | } 290 | 291 | fn is_zero(&self) -> bool { 292 | self.c0.is_zero() && self.c1.is_zero() 293 | } 294 | 295 | fn squared(&self) -> Self { 296 | let ab = self.c0 * self.c1; 297 | 298 | Fq12 { 299 | c0: (self.c1.mul_by_nonresidue() + self.c0) * (self.c0 + self.c1) - ab 300 | - ab.mul_by_nonresidue(), 301 | c1: ab + ab, 302 | } 303 | } 304 | 305 | fn inverse(self) -> Option { 306 | match (self.c0.squared() - (self.c1.squared().mul_by_nonresidue())).inverse() { 307 | Some(t) => Some(Fq12 { 308 | c0: self.c0 * t, 309 | c1: -(self.c1 * t), 310 | }), 311 | None => None, 312 | } 313 | } 314 | } 315 | 316 | impl Mul for Fq12 { 317 | type Output = Fq12; 318 | 319 | fn mul(self, other: Fq12) -> Fq12 { 320 | let aa = self.c0 * other.c0; 321 | let bb = self.c1 * other.c1; 322 | 323 | Fq12 { 324 | c0: bb.mul_by_nonresidue() + aa, 325 | c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb, 326 | } 327 | } 328 | } 329 | 330 | impl Sub for Fq12 { 331 | type Output = Fq12; 332 | 333 | fn sub(self, other: Fq12) -> Fq12 { 334 | Fq12 { 335 | c0: self.c0 - other.c0, 336 | c1: self.c1 - other.c1, 337 | } 338 | } 339 | } 340 | 341 | impl Add for Fq12 { 342 | type Output = Fq12; 343 | 344 | fn add(self, other: Fq12) -> Fq12 { 345 | Fq12 { 346 | c0: self.c0 + other.c0, 347 | c1: self.c1 + other.c1, 348 | } 349 | } 350 | } 351 | 352 | impl Neg for Fq12 { 353 | type Output = Fq12; 354 | 355 | fn neg(self) -> Fq12 { 356 | Fq12 { 357 | c0: -self.c0, 358 | c1: -self.c1, 359 | } 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/fields/fq2.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Add, Mul, Neg, Sub}; 2 | use rand::Rng; 3 | use crate::fields::{const_fq, FieldElement, Fq}; 4 | use crate::arith::{U256, U512}; 5 | 6 | #[inline] 7 | fn fq_non_residue() -> Fq { 8 | // (q - 1) is a quadratic nonresidue in Fq 9 | // 21888242871839275222246405745257275088696311157297823662689037894645226208582 10 | const_fq([ 11 | 0x68c3488912edefaa, 12 | 0x8d087f6872aabf4f, 13 | 0x51e1a24709081231, 14 | 0x2259d6b14729c0fa, 15 | ]) 16 | } 17 | 18 | #[inline] 19 | pub fn fq2_nonresidue() -> Fq2 { 20 | Fq2::new( 21 | const_fq([ 22 | 0xf60647ce410d7ff7, 23 | 0x2f3d6f4dd31bd011, 24 | 0x2943337e3940c6d1, 25 | 0x1d9598e8a7e39857, 26 | ]), 27 | const_fq([ 28 | 0xd35d438dc58f0d9d, 29 | 0x0a78eb28f5c70b3d, 30 | 0x666ea36f7879462c, 31 | 0x0e0a77c19a07df2f, 32 | ]), 33 | ) 34 | } 35 | 36 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 37 | #[repr(C)] 38 | pub struct Fq2 { 39 | c0: Fq, 40 | c1: Fq, 41 | } 42 | 43 | impl Fq2 { 44 | pub fn new(c0: Fq, c1: Fq) -> Self { 45 | Fq2 { c0: c0, c1: c1 } 46 | } 47 | 48 | pub fn scale(&self, by: Fq) -> Self { 49 | Fq2 { 50 | c0: self.c0 * by, 51 | c1: self.c1 * by, 52 | } 53 | } 54 | 55 | pub fn mul_by_nonresidue(&self) -> Self { 56 | *self * fq2_nonresidue() 57 | } 58 | 59 | pub fn frobenius_map(&self, power: usize) -> Self { 60 | if power % 2 == 0 { 61 | *self 62 | } else { 63 | Fq2 { 64 | c0: self.c0, 65 | c1: self.c1 * fq_non_residue(), 66 | } 67 | } 68 | } 69 | 70 | pub fn real(&self) -> &Fq { 71 | &self.c0 72 | } 73 | 74 | pub fn imaginary(&self) -> &Fq { 75 | &self.c1 76 | } 77 | } 78 | 79 | impl FieldElement for Fq2 { 80 | fn zero() -> Self { 81 | Fq2 { 82 | c0: Fq::zero(), 83 | c1: Fq::zero(), 84 | } 85 | } 86 | 87 | fn one() -> Self { 88 | Fq2 { 89 | c0: Fq::one(), 90 | c1: Fq::zero(), 91 | } 92 | } 93 | 94 | fn random(rng: &mut R) -> Self { 95 | Fq2 { 96 | c0: Fq::random(rng), 97 | c1: Fq::random(rng), 98 | } 99 | } 100 | 101 | fn is_zero(&self) -> bool { 102 | self.c0.is_zero() && self.c1.is_zero() 103 | } 104 | 105 | fn squared(&self) -> Self { 106 | // Devegili OhEig Scott Dahab 107 | // Multiplication and Squaring on Pairing-Friendly Fields.pdf 108 | // Section 3 (Complex squaring) 109 | 110 | let ab = self.c0 * self.c1; 111 | 112 | Fq2 { 113 | c0: (self.c1 * fq_non_residue() + self.c0) * (self.c0 + self.c1) - ab 114 | - ab * fq_non_residue(), 115 | c1: ab + ab, 116 | } 117 | } 118 | 119 | fn inverse(self) -> Option { 120 | // "High-Speed Software Implementation of the Optimal Ate Pairing 121 | // over Barreto–Naehrig Curves"; Algorithm 8 122 | 123 | match (self.c0.squared() - (self.c1.squared() * fq_non_residue())).inverse() { 124 | Some(t) => Some(Fq2 { 125 | c0: self.c0 * t, 126 | c1: -(self.c1 * t), 127 | }), 128 | None => None, 129 | } 130 | } 131 | } 132 | 133 | impl Mul for Fq2 { 134 | type Output = Fq2; 135 | 136 | fn mul(self, other: Fq2) -> Fq2 { 137 | // Devegili OhEig Scott Dahab 138 | // Multiplication and Squaring on Pairing-Friendly Fields.pdf 139 | // Section 3 (Karatsuba) 140 | 141 | let aa = self.c0 * other.c0; 142 | let bb = self.c1 * other.c1; 143 | 144 | Fq2 { 145 | c0: bb * fq_non_residue() + aa, 146 | c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb, 147 | } 148 | } 149 | } 150 | 151 | impl Sub for Fq2 { 152 | type Output = Fq2; 153 | 154 | fn sub(self, other: Fq2) -> Fq2 { 155 | Fq2 { 156 | c0: self.c0 - other.c0, 157 | c1: self.c1 - other.c1, 158 | } 159 | } 160 | } 161 | 162 | impl Add for Fq2 { 163 | type Output = Fq2; 164 | 165 | fn add(self, other: Fq2) -> Fq2 { 166 | Fq2 { 167 | c0: self.c0 + other.c0, 168 | c1: self.c1 + other.c1, 169 | } 170 | } 171 | } 172 | 173 | impl Neg for Fq2 { 174 | type Output = Fq2; 175 | 176 | fn neg(self) -> Fq2 { 177 | Fq2 { 178 | c0: -self.c0, 179 | c1: -self.c1, 180 | } 181 | } 182 | } 183 | 184 | lazy_static::lazy_static! { 185 | static ref FQ: U256 = U256::from([ 186 | 0x3c208c16d87cfd47, 187 | 0x97816a916871ca8d, 188 | 0xb85045b68181585d, 189 | 0x30644e72e131a029 190 | ]); 191 | 192 | static ref FQ_MINUS3_DIV4: Fq = 193 | Fq::new(3.into()).expect("3 is a valid field element and static; qed").neg() * 194 | Fq::new(4.into()).expect("4 is a valid field element and static; qed").inverse() 195 | .expect("4 has inverse in Fq and is static; qed"); 196 | 197 | static ref FQ_MINUS1_DIV2: Fq = 198 | Fq::new(1.into()).expect("1 is a valid field element and static; qed").neg() * 199 | Fq::new(2.into()).expect("2 is a valid field element and static; qed").inverse() 200 | .expect("2 has inverse in Fq and is static; qed"); 201 | } 202 | 203 | impl Fq2 { 204 | pub fn i() -> Fq2 { 205 | Fq2::new(Fq::zero(), Fq::one()) 206 | } 207 | 208 | pub fn sqrt(&self) -> Option { 209 | let a1 = self.pow::((*FQ_MINUS3_DIV4).into()); 210 | let a1a = a1 * *self; 211 | let alpha = a1 * a1a; 212 | let a0 = alpha.pow(*FQ) * alpha; 213 | 214 | if a0 == Fq2::one().neg() { 215 | return None; 216 | } 217 | 218 | if alpha == Fq2::one().neg() { 219 | Some(Self::i() * a1a) 220 | } else { 221 | let b = (alpha + Fq2::one()).pow::((*FQ_MINUS1_DIV2).into()); 222 | Some(b * a1a) 223 | } 224 | } 225 | 226 | pub fn to_u512(&self) -> U512 { 227 | let c0: U256 = (*self.real()).into(); 228 | let c1: U256 = (*self.imaginary()).into(); 229 | 230 | U512::new(&c1, &c0, &FQ) 231 | } 232 | } 233 | 234 | 235 | #[test] 236 | fn sqrt_fq2() { 237 | // from zcash test_proof.cpp 238 | let x1 = Fq2::new( 239 | Fq::from_str("12844195307879678418043983815760255909500142247603239203345049921980497041944").unwrap(), 240 | Fq::from_str("7476417578426924565731404322659619974551724117137577781074613937423560117731").unwrap(), 241 | ); 242 | 243 | let x2 = Fq2::new( 244 | Fq::from_str("3345897230485723946872934576923485762803457692345760237495682347502347589474").unwrap(), 245 | Fq::from_str("1234912378405347958234756902345768290345762348957605678245967234857634857676").unwrap(), 246 | ); 247 | 248 | assert_eq!(x2.sqrt().unwrap(), x1); 249 | 250 | // i is sqrt(-1) 251 | assert_eq!( 252 | Fq2::one().neg().sqrt().unwrap(), 253 | Fq2::i(), 254 | ); 255 | 256 | // no sqrt for (1 + 2i) 257 | assert!( 258 | Fq2::new(Fq::from_str("1").unwrap(), Fq::from_str("2").unwrap()).sqrt().is_none() 259 | ); 260 | } 261 | -------------------------------------------------------------------------------- /src/fields/fq6.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::{const_fq, FieldElement, Fq, Fq2}; 2 | use core::ops::{Add, Mul, Neg, Sub}; 3 | use rand::Rng; 4 | 5 | fn frobenius_coeffs_c1(n: usize) -> Fq2 { 6 | match n % 6 { 7 | 0 => Fq2::one(), 8 | 1 => Fq2::new( 9 | const_fq([ 10 | 13075984984163199792, 11 | 3782902503040509012, 12 | 8791150885551868305, 13 | 1825854335138010348, 14 | ]), 15 | const_fq([ 16 | 7963664994991228759, 17 | 12257807996192067905, 18 | 13179524609921305146, 19 | 2767831111890561987, 20 | ]), 21 | ), 22 | 2 => Fq2::new( 23 | const_fq([ 24 | 3697675806616062876, 25 | 9065277094688085689, 26 | 6918009208039626314, 27 | 2775033306905974752, 28 | ]), 29 | Fq::zero(), 30 | ), 31 | 3 => Fq2::new( 32 | const_fq([ 33 | 14532872967180610477, 34 | 12903226530429559474, 35 | 1868623743233345524, 36 | 2316889217940299650, 37 | ]), 38 | const_fq([ 39 | 12447993766991532972, 40 | 4121872836076202828, 41 | 7630813605053367399, 42 | 740282956577754197, 43 | ]), 44 | ), 45 | _ => unimplemented!(), 46 | } 47 | } 48 | fn frobenius_coeffs_c2(n: usize) -> Fq2 { 49 | match n % 6 { 50 | 0 => Fq2::one(), 51 | 1 => Fq2::new( 52 | const_fq([ 53 | 8314163329781907090, 54 | 11942187022798819835, 55 | 11282677263046157209, 56 | 1576150870752482284, 57 | ]), 58 | const_fq([ 59 | 6763840483288992073, 60 | 7118829427391486816, 61 | 4016233444936635065, 62 | 2630958277570195709, 63 | ]), 64 | ), 65 | 2 => Fq2::new( 66 | const_fq([ 67 | 8183898218631979349, 68 | 12014359695528440611, 69 | 12263358156045030468, 70 | 3187210487005268291, 71 | ]), 72 | Fq::zero(), 73 | ), 74 | 3 => Fq2::new( 75 | const_fq([ 76 | 4938922280314430175, 77 | 13823286637238282975, 78 | 15589480384090068090, 79 | 481952561930628184, 80 | ]), 81 | const_fq([ 82 | 3105754162722846417, 83 | 11647802298615474591, 84 | 13057042392041828081, 85 | 1660844386505564338, 86 | ]), 87 | ), 88 | _ => unimplemented!(), 89 | } 90 | } 91 | 92 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 93 | #[repr(C)] 94 | pub struct Fq6 { 95 | pub c0: Fq2, 96 | pub c1: Fq2, 97 | pub c2: Fq2, 98 | } 99 | 100 | impl Fq6 { 101 | pub fn new(c0: Fq2, c1: Fq2, c2: Fq2) -> Self { 102 | Fq6 { 103 | c0: c0, 104 | c1: c1, 105 | c2: c2, 106 | } 107 | } 108 | 109 | pub fn mul_by_nonresidue(&self) -> Self { 110 | Fq6 { 111 | c0: self.c2.mul_by_nonresidue(), 112 | c1: self.c0, 113 | c2: self.c1, 114 | } 115 | } 116 | 117 | pub fn scale(&self, by: Fq2) -> Self { 118 | Fq6 { 119 | c0: self.c0 * by, 120 | c1: self.c1 * by, 121 | c2: self.c2 * by, 122 | } 123 | } 124 | 125 | pub fn frobenius_map(&self, power: usize) -> Self { 126 | Fq6 { 127 | c0: self.c0.frobenius_map(power), 128 | c1: self.c1.frobenius_map(power) * frobenius_coeffs_c1(power), 129 | c2: self.c2.frobenius_map(power) * frobenius_coeffs_c2(power), 130 | } 131 | } 132 | } 133 | 134 | impl FieldElement for Fq6 { 135 | fn zero() -> Self { 136 | Fq6 { 137 | c0: Fq2::zero(), 138 | c1: Fq2::zero(), 139 | c2: Fq2::zero(), 140 | } 141 | } 142 | 143 | fn one() -> Self { 144 | Fq6 { 145 | c0: Fq2::one(), 146 | c1: Fq2::zero(), 147 | c2: Fq2::zero(), 148 | } 149 | } 150 | 151 | fn random(rng: &mut R) -> Self { 152 | Fq6 { 153 | c0: Fq2::random(rng), 154 | c1: Fq2::random(rng), 155 | c2: Fq2::random(rng), 156 | } 157 | } 158 | 159 | fn is_zero(&self) -> bool { 160 | self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero() 161 | } 162 | 163 | fn squared(&self) -> Self { 164 | let s0 = self.c0.squared(); 165 | let ab = self.c0 * self.c1; 166 | let s1 = ab + ab; 167 | let s2 = (self.c0 - self.c1 + self.c2).squared(); 168 | let bc = self.c1 * self.c2; 169 | let s3 = bc + bc; 170 | let s4 = self.c2.squared(); 171 | 172 | Fq6 { 173 | c0: s0 + s3.mul_by_nonresidue(), 174 | c1: s1 + s4.mul_by_nonresidue(), 175 | c2: s1 + s2 + s3 - s0 - s4, 176 | } 177 | } 178 | 179 | fn inverse(self) -> Option { 180 | let c0 = self.c0.squared() - self.c1 * self.c2.mul_by_nonresidue(); 181 | let c1 = self.c2.squared().mul_by_nonresidue() - self.c0 * self.c1; 182 | let c2 = self.c1.squared() - self.c0 * self.c2; 183 | match ((self.c2 * c1 + self.c1 * c2).mul_by_nonresidue() + self.c0 * c0).inverse() { 184 | Some(t) => Some(Fq6 { 185 | c0: t * c0, 186 | c1: t * c1, 187 | c2: t * c2, 188 | }), 189 | None => None, 190 | } 191 | } 192 | } 193 | 194 | impl Mul for Fq6 { 195 | type Output = Fq6; 196 | 197 | fn mul(self, other: Fq6) -> Fq6 { 198 | let a_a = self.c0 * other.c0; 199 | let b_b = self.c1 * other.c1; 200 | let c_c = self.c2 * other.c2; 201 | 202 | Fq6 { 203 | c0: ((self.c1 + self.c2) * (other.c1 + other.c2) - b_b - c_c).mul_by_nonresidue() + a_a, 204 | c1: (self.c0 + self.c1) * (other.c0 + other.c1) - a_a - b_b + c_c.mul_by_nonresidue(), 205 | c2: (self.c0 + self.c2) * (other.c0 + other.c2) - a_a + b_b - c_c, 206 | } 207 | } 208 | } 209 | 210 | impl Sub for Fq6 { 211 | type Output = Fq6; 212 | 213 | fn sub(self, other: Fq6) -> Fq6 { 214 | Fq6 { 215 | c0: self.c0 - other.c0, 216 | c1: self.c1 - other.c1, 217 | c2: self.c2 - other.c2, 218 | } 219 | } 220 | } 221 | 222 | impl Add for Fq6 { 223 | type Output = Fq6; 224 | 225 | fn add(self, other: Fq6) -> Fq6 { 226 | Fq6 { 227 | c0: self.c0 + other.c0, 228 | c1: self.c1 + other.c1, 229 | c2: self.c2 + other.c2, 230 | } 231 | } 232 | } 233 | 234 | impl Neg for Fq6 { 235 | type Output = Fq6; 236 | 237 | fn neg(self) -> Fq6 { 238 | Fq6 { 239 | c0: -self.c0, 240 | c1: -self.c1, 241 | c2: -self.c2, 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/fields/mod.rs: -------------------------------------------------------------------------------- 1 | mod fp; 2 | mod fq2; 3 | mod fq6; 4 | mod fq12; 5 | 6 | use crate::arith::U256; 7 | use rand::Rng; 8 | use core::ops::{Add, Mul, Neg, Sub}; 9 | use alloc::fmt::Debug; 10 | 11 | pub use self::fp::{const_fq, Fq, Fr}; 12 | pub use self::fq2::{Fq2, fq2_nonresidue}; 13 | pub use self::fq6::Fq6; 14 | pub use self::fq12::Fq12; 15 | 16 | pub trait FieldElement 17 | : Sized 18 | + Copy 19 | + Clone 20 | + Add 21 | + Sub 22 | + Mul 23 | + Neg 24 | + PartialEq 25 | + Eq 26 | + Debug { 27 | fn zero() -> Self; 28 | fn one() -> Self; 29 | fn random(_: &mut R) -> Self; 30 | fn is_zero(&self) -> bool; 31 | fn squared(&self) -> Self { 32 | (*self) * (*self) 33 | } 34 | fn inverse(self) -> Option; 35 | fn pow>(&self, by: I) -> Self { 36 | let mut res = Self::one(); 37 | 38 | for i in by.into().bits() { 39 | res = res.squared(); 40 | if i { 41 | res = *self * res; 42 | } 43 | } 44 | 45 | res 46 | } 47 | } 48 | 49 | #[cfg(test)] 50 | mod tests; 51 | 52 | #[test] 53 | fn test_fr() { 54 | tests::field_trials::(); 55 | } 56 | 57 | #[test] 58 | fn test_fq() { 59 | tests::field_trials::(); 60 | } 61 | 62 | #[test] 63 | fn test_fq2() { 64 | tests::field_trials::(); 65 | } 66 | 67 | #[test] 68 | fn test_str() { 69 | assert_eq!( 70 | -Fr::one(), 71 | Fr::from_str( 72 | "21888242871839275222246405745257275088548364400416034343698204186575808495616" 73 | ).unwrap() 74 | ); 75 | assert_eq!( 76 | -Fq::one(), 77 | Fq::from_str( 78 | "21888242871839275222246405745257275088696311157297823662689037894645226208582" 79 | ).unwrap() 80 | ); 81 | } 82 | 83 | #[test] 84 | fn test_fq6() { 85 | tests::field_trials::(); 86 | } 87 | 88 | #[test] 89 | fn test_fq12() { 90 | tests::field_trials::(); 91 | } 92 | 93 | #[test] 94 | fn fq12_test_vector() { 95 | let start = Fq12::new( 96 | Fq6::new( 97 | Fq2::new( 98 | Fq::from_str( 99 | "19797905000333868150253315089095386158892526856493194078073564469188852136946", 100 | ).unwrap(), 101 | Fq::from_str( 102 | "10509658143212501778222314067134547632307419253211327938344904628569123178733", 103 | ).unwrap(), 104 | ), 105 | Fq2::new( 106 | Fq::from_str( 107 | "208316612133170645758860571704540129781090973693601051684061348604461399206", 108 | ).unwrap(), 109 | Fq::from_str( 110 | "12617661120538088237397060591907161689901553895660355849494983891299803248390", 111 | ).unwrap(), 112 | ), 113 | Fq2::new( 114 | Fq::from_str( 115 | "2897490589776053688661991433341220818937967872052418196321943489809183508515", 116 | ).unwrap(), 117 | Fq::from_str( 118 | "2730506433347642574983433139433778984782882168213690554721050571242082865799", 119 | ).unwrap(), 120 | ), 121 | ), 122 | Fq6::new( 123 | Fq2::new( 124 | Fq::from_str( 125 | "17870056122431653936196746815433147921488990391314067765563891966783088591110", 126 | ).unwrap(), 127 | Fq::from_str( 128 | "14314041658607615069703576372547568077123863812415914883625850585470406221594", 129 | ).unwrap(), 130 | ), 131 | Fq2::new( 132 | Fq::from_str( 133 | "10123533891707846623287020000407963680629966110211808794181173248765209982878", 134 | ).unwrap(), 135 | Fq::from_str( 136 | "5062091880848845693514855272640141851746424235009114332841857306926659567101", 137 | ).unwrap(), 138 | ), 139 | Fq2::new( 140 | Fq::from_str( 141 | "9839781502639936537333620974973645053542086898304697594692219798017709586567", 142 | ).unwrap(), 143 | Fq::from_str( 144 | "1583892292110602864638265389721494775152090720173641072176370350017825640703", 145 | ).unwrap(), 146 | ), 147 | ), 148 | ); 149 | 150 | // Do a bunch of arbitrary stuff to the element 151 | 152 | let mut next = start.clone(); 153 | for _ in 0..100 { 154 | next = next * start; 155 | } 156 | 157 | let cpy = next.clone(); 158 | 159 | for _ in 0..10 { 160 | next = next.squared(); 161 | } 162 | 163 | for _ in 0..10 { 164 | next = next + start; 165 | next = next - cpy; 166 | next = -next; 167 | } 168 | 169 | next = next.squared(); 170 | 171 | let finally = Fq12::new( 172 | Fq6::new( 173 | Fq2::new( 174 | Fq::from_str( 175 | "18388750939593263065521177085001223024106699964957029146547831509155008229833", 176 | ).unwrap(), 177 | Fq::from_str( 178 | "18370529854582635460997127698388761779167953912610241447912705473964014492243", 179 | ).unwrap(), 180 | ), 181 | Fq2::new( 182 | Fq::from_str( 183 | "3691824277096717481466579496401243638295254271265821828017111951446539785268", 184 | ).unwrap(), 185 | Fq::from_str( 186 | "20513494218085713799072115076991457239411567892860153903443302793553884247235", 187 | ).unwrap(), 188 | ), 189 | Fq2::new( 190 | Fq::from_str( 191 | "12214155472433286415803224222551966441740960297013786627326456052558698216399", 192 | ).unwrap(), 193 | Fq::from_str( 194 | "10987494248070743195602580056085773610850106455323751205990078881956262496575", 195 | ).unwrap(), 196 | ), 197 | ), 198 | Fq6::new( 199 | Fq2::new( 200 | Fq::from_str( 201 | "5134522153456102954632718911439874984161223687865160221119284322136466794876", 202 | ).unwrap(), 203 | Fq::from_str( 204 | "20119236909927036376726859192821071338930785378711977469360149362002019539920", 205 | ).unwrap(), 206 | ), 207 | Fq2::new( 208 | Fq::from_str( 209 | "8839766648621210419302228913265679710586991805716981851373026244791934012854", 210 | ).unwrap(), 211 | Fq::from_str( 212 | "9103032146464138788288547957401673544458789595252696070370942789051858719203", 213 | ).unwrap(), 214 | ), 215 | Fq2::new( 216 | Fq::from_str( 217 | "10378379548636866240502412547812481928323945124508039853766409196375806029865", 218 | ).unwrap(), 219 | Fq::from_str( 220 | "9021627154807648093720460686924074684389554332435186899318369174351765754041", 221 | ).unwrap(), 222 | ), 223 | ), 224 | ); 225 | 226 | assert_eq!(finally, next); 227 | } 228 | 229 | #[test] 230 | fn test_cyclotomic_exp() { 231 | let orig = Fq12::new( 232 | Fq6::new( 233 | Fq2::new( 234 | Fq::from_str( 235 | "2259924035228092997691937637688451143058635253053054071159756458902878894295", 236 | ).unwrap(), 237 | Fq::from_str( 238 | "13145690032701362144460254305183927872683620413225364127064863863535255135244", 239 | ).unwrap(), 240 | ), 241 | Fq2::new( 242 | Fq::from_str( 243 | "9910063591662383599552477067956819406417086889312288278252482503717089428441", 244 | ).unwrap(), 245 | Fq::from_str( 246 | "537414042055419261990282459138081732565514913399498746664966841152381183961", 247 | ).unwrap(), 248 | ), 249 | Fq2::new( 250 | Fq::from_str( 251 | "15311812409497308894370893420777496684951030254049554818293571309705780605004", 252 | ).unwrap(), 253 | Fq::from_str( 254 | "13657107176064455789881282546557276003626320193974643644160350907227082365810", 255 | ).unwrap(), 256 | ), 257 | ), 258 | Fq6::new( 259 | Fq2::new( 260 | Fq::from_str( 261 | "4913017949003742946864670837361832856526234260447029873580022776602534856819", 262 | ).unwrap(), 263 | Fq::from_str( 264 | "7834351480852267338070670220119081676575418514182895774094743209915633114041", 265 | ).unwrap(), 266 | ), 267 | Fq2::new( 268 | Fq::from_str( 269 | "12837298223308203788092748646758194441270207338661891973231184407371206766993", 270 | ).unwrap(), 271 | Fq::from_str( 272 | "12756474445699147370503225379431475413909971718057034061593007812727141391799", 273 | ).unwrap(), 274 | ), 275 | Fq2::new( 276 | Fq::from_str( 277 | "9473802207170192255373153510655867502408045964296373712891954747252332944018", 278 | ).unwrap(), 279 | Fq::from_str( 280 | "4583089109360519374075173304035813179013579459429335467869926761027310749713", 281 | ).unwrap(), 282 | ), 283 | ), 284 | ); 285 | 286 | let expected = Fq12::new( 287 | Fq6::new( 288 | Fq2::new( 289 | Fq::from_str( 290 | "14722956046055152398903846391223329501345567382234608299399030576415080188350", 291 | ).unwrap(), 292 | Fq::from_str( 293 | "14280703280777926697010730619606819467080027543707671882210769811674790473417", 294 | ).unwrap(), 295 | ), 296 | Fq2::new( 297 | Fq::from_str( 298 | "19969875076083990244184003223190771301761436396530543002586073549972410735411", 299 | ).unwrap(), 300 | Fq::from_str( 301 | "10717335566913889643303549252432531178405520196706173198634734518494041323243", 302 | ).unwrap(), 303 | ), 304 | Fq2::new( 305 | Fq::from_str( 306 | "6063612626166484870786832843320782567259894784043383626084549455432890717937", 307 | ).unwrap(), 308 | Fq::from_str( 309 | "17089783040131779205038789608891431427943860868115199598200376195935079808729", 310 | ).unwrap(), 311 | ), 312 | ), 313 | Fq6::new( 314 | Fq2::new( 315 | Fq::from_str( 316 | "10029863438921507421569931792104023129735006154272482043027653425575205672906", 317 | ).unwrap(), 318 | Fq::from_str( 319 | "6406252222753462799887280578845937185621081001436094637606245493619821542775", 320 | ).unwrap(), 321 | ), 322 | Fq2::new( 323 | Fq::from_str( 324 | "1048245462913506652602966692378792381004227332967846949234978073448561848050", 325 | ).unwrap(), 326 | Fq::from_str( 327 | "1444281375189053827455518242624554285012408033699861764136810522738182087554", 328 | ).unwrap(), 329 | ), 330 | Fq2::new( 331 | Fq::from_str( 332 | "8839610992666735109106629514135300820412539620261852250193684883379364789120", 333 | ).unwrap(), 334 | Fq::from_str( 335 | "11347360242067273846784836674906058940820632082713814508736182487171407730718", 336 | ).unwrap(), 337 | ), 338 | ), 339 | ); 340 | 341 | let e = orig.exp_by_neg_z(); 342 | 343 | assert_eq!(e, expected); 344 | } 345 | -------------------------------------------------------------------------------- /src/fields/tests.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rng, SeedableRng, rngs::StdRng}; 2 | use super::FieldElement; 3 | 4 | fn can_invert() { 5 | let mut a = F::one(); 6 | 7 | for _ in 0..10000 { 8 | assert_eq!(a * a.inverse().unwrap(), F::one()); 9 | 10 | a = a + F::one(); 11 | } 12 | 13 | a = -F::one(); 14 | for _ in 0..10000 { 15 | assert_eq!(a * a.inverse().unwrap(), F::one()); 16 | 17 | a = a - F::one(); 18 | } 19 | 20 | assert_eq!(F::zero().inverse(), None); 21 | } 22 | 23 | fn rand_element_eval(rng: &mut R) { 24 | for _ in 0..100 { 25 | let a = F::random(rng); 26 | let b = F::random(rng); 27 | let c = F::random(rng); 28 | let d = F::random(rng); 29 | 30 | assert_eq!((a + b) * (c + d), (a * c) + (b * c) + (a * d) + (b * d)); 31 | } 32 | } 33 | 34 | fn rand_element_squaring(rng: &mut R) { 35 | for _ in 0..100 { 36 | let a = F::random(rng); 37 | 38 | assert!(a * a == a.squared()); 39 | } 40 | 41 | let mut cur = F::zero(); 42 | for _ in 0..100 { 43 | assert_eq!(cur.squared(), cur * cur); 44 | 45 | cur = cur + F::one(); 46 | } 47 | } 48 | 49 | fn rand_element_addition_and_negation(rng: &mut R) { 50 | for _ in 0..100 { 51 | let a = F::random(rng); 52 | 53 | assert_eq!(a + (-a), F::zero()); 54 | } 55 | 56 | for _ in 0..100 { 57 | let mut a = F::random(rng); 58 | let r = F::random(rng); 59 | let mut b = a + r; 60 | 61 | for _ in 0..10 { 62 | let r = F::random(rng); 63 | a = a + r; 64 | b = b + r; 65 | 66 | let r = F::random(rng); 67 | a = a - r; 68 | b = b - r; 69 | 70 | let r = F::random(rng); 71 | a = a + (-(-r)); 72 | b = b + (-(-r)); 73 | 74 | let r = F::random(rng); 75 | a = a - r; 76 | b = b + (-r); 77 | 78 | let r = F::random(rng); 79 | a = a + (-r); 80 | b = b - r; 81 | } 82 | 83 | b = b - r; 84 | assert_eq!(a, b); 85 | } 86 | } 87 | 88 | fn rand_element_inverse(rng: &mut R) { 89 | for _ in 0..10000 { 90 | let a = F::random(rng); 91 | assert!(a.inverse().unwrap() * a == F::one()); 92 | let b = F::random(rng); 93 | assert_eq!((a * b) * (a.inverse().unwrap()), b); 94 | } 95 | } 96 | 97 | fn rand_element_multiplication(rng: &mut R) { 98 | // If field is not associative under multiplication, 1/8 of all triplets a, b, c 99 | // will fail the test (a*b)*c = a*(b*c). 100 | 101 | for _ in 0..250 { 102 | let a = F::random(rng); 103 | let b = F::random(rng); 104 | let c = F::random(rng); 105 | 106 | assert_eq!((a * b) * c, a * (b * c)); 107 | } 108 | } 109 | 110 | pub fn field_trials() { 111 | can_invert::(); 112 | 113 | assert_eq!(-F::zero(), F::zero()); 114 | assert_eq!(-F::one() + F::one(), F::zero()); 115 | assert_eq!(F::zero() - F::zero(), F::zero()); 116 | 117 | let seed = [ 118 | 0, 0, 0, 0, 0, 0, 64, 13, // 103245 119 | 0, 0, 0, 0, 0, 0, 176, 2, // 191922 120 | 0, 0, 0, 0, 0, 0, 0, 13, // 1293 121 | 0, 0, 0, 0, 0, 0, 96, 7u8, // 192103 122 | ]; 123 | let mut rng = StdRng::from_seed(seed); 124 | 125 | rand_element_squaring::(&mut rng); 126 | rand_element_addition_and_negation::(&mut rng); 127 | rand_element_multiplication::(&mut rng); 128 | rand_element_inverse::(&mut rng); 129 | rand_element_eval::(&mut rng); 130 | } 131 | -------------------------------------------------------------------------------- /src/groups/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::fields::{const_fq, FieldElement, Fq, Fq12, Fq2, Fr, fq2_nonresidue}; 2 | use crate::arith::U256; 3 | use core::{fmt, ops::{Add, Mul, Neg, Sub}}; 4 | use rand::Rng; 5 | use alloc::vec::Vec; 6 | #[cfg(test)] 7 | use alloc::vec; 8 | 9 | // This is the NAF version of ate_loop_count. Entries are all mod 4, so 3 = -1 10 | // n.b. ate_loop_count = 0x19d797039be763ba8 11 | // = 11001110101111001011100000011100110111110011101100011101110101000 12 | // (naf version) = 11010003030003010300300000100301003000030100030300100030030101000 13 | // We skip the first element (1) as we would need to skip over it in the main loop 14 | const ATE_LOOP_COUNT_NAF : [u8; 64] = [1,0,1,0,0,0,3,0,3,0,0,0,3,0,1,0,3,0,0,3,0,0,0,0,0,1,0,0,3,0,1,0,0,3,0,0,0,0,3,0,1,0,0,0,3,0,3,0,0,1,0,0,0,3,0,0,3,0,1,0,1,0,0,0]; 15 | 16 | pub trait GroupElement 17 | : Sized 18 | + Copy 19 | + Clone 20 | + PartialEq 21 | + Eq 22 | + fmt::Debug 23 | + Add 24 | + Sub 25 | + Neg 26 | + Mul { 27 | fn zero() -> Self; 28 | fn one() -> Self; 29 | fn random(rng: &mut R) -> Self; 30 | fn is_zero(&self) -> bool; 31 | fn double(&self) -> Self; 32 | } 33 | 34 | pub trait GroupParams: Sized + fmt::Debug { 35 | type Base: FieldElement; 36 | 37 | fn name() -> &'static str; 38 | fn one() -> G; 39 | fn coeff_b() -> Self::Base; 40 | fn check_order() -> bool { 41 | false 42 | } 43 | } 44 | 45 | #[repr(C)] 46 | pub struct G { 47 | x: P::Base, 48 | y: P::Base, 49 | z: P::Base, 50 | } 51 | 52 | impl G

{ 53 | pub fn new(x: P::Base, y: P::Base, z: P::Base) -> Self { 54 | G { x: x, y: y, z: z } 55 | } 56 | 57 | pub fn x(&self) -> &P::Base { 58 | &self.x 59 | } 60 | 61 | pub fn x_mut(&mut self) -> &mut P::Base { 62 | &mut self.x 63 | } 64 | 65 | pub fn y(&self) -> &P::Base { 66 | &self.y 67 | } 68 | 69 | pub fn y_mut(&mut self) -> &mut P::Base { 70 | &mut self.y 71 | } 72 | 73 | pub fn z(&self) -> &P::Base { 74 | &self.z 75 | } 76 | 77 | pub fn z_mut(&mut self) -> &mut P::Base { 78 | &mut self.z 79 | } 80 | } 81 | 82 | #[derive(Debug)] 83 | pub struct AffineG { 84 | x: P::Base, 85 | y: P::Base, 86 | } 87 | 88 | #[derive(Debug)] 89 | pub enum Error { 90 | NotOnCurve, 91 | NotInSubgroup, 92 | } 93 | 94 | impl AffineG

{ 95 | pub fn new(x: P::Base, y: P::Base) -> Result { 96 | if y.squared() == (x.squared() * x) + P::coeff_b() { 97 | if P::check_order() { 98 | let p: G

= G { 99 | x: x, 100 | y: y, 101 | z: P::Base::one(), 102 | }; 103 | 104 | if (p * (-Fr::one())) + p != G::zero() { 105 | return Err(Error::NotInSubgroup); 106 | } 107 | } 108 | 109 | Ok(AffineG { x: x, y: y }) 110 | } else { 111 | Err(Error::NotOnCurve) 112 | } 113 | } 114 | 115 | pub fn x(&self) -> &P::Base { 116 | &self.x 117 | } 118 | 119 | pub fn x_mut(&mut self) -> &mut P::Base { 120 | &mut self.x 121 | } 122 | 123 | pub fn y(&self) -> &P::Base { 124 | &self.y 125 | } 126 | 127 | pub fn y_mut(&mut self) -> &mut P::Base { 128 | &mut self.y 129 | } 130 | } 131 | 132 | impl PartialEq for AffineG

{ 133 | fn eq(&self, other: &Self) -> bool { 134 | self.x == other.x && self.y == other.y 135 | } 136 | } 137 | 138 | impl Eq for AffineG

{} 139 | 140 | impl fmt::Debug for G

{ 141 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 142 | write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z) 143 | } 144 | } 145 | 146 | impl Clone for G

{ 147 | fn clone(&self) -> Self { 148 | G { 149 | x: self.x, 150 | y: self.y, 151 | z: self.z, 152 | } 153 | } 154 | } 155 | 156 | impl Copy for G

{} 157 | 158 | impl Clone for AffineG

{ 159 | fn clone(&self) -> Self { 160 | AffineG { 161 | x: self.x, 162 | y: self.y, 163 | } 164 | } 165 | } 166 | 167 | impl Copy for AffineG

{} 168 | 169 | impl PartialEq for G

{ 170 | fn eq(&self, other: &Self) -> bool { 171 | if self.is_zero() { 172 | return other.is_zero(); 173 | } 174 | 175 | if other.is_zero() { 176 | return false; 177 | } 178 | 179 | let z1_squared = self.z.squared(); 180 | let z2_squared = other.z.squared(); 181 | 182 | if self.x * z2_squared != other.x * z1_squared { 183 | return false; 184 | } 185 | 186 | let z1_cubed = self.z * z1_squared; 187 | let z2_cubed = other.z * z2_squared; 188 | 189 | if self.y * z2_cubed != other.y * z1_cubed { 190 | return false; 191 | } 192 | 193 | return true; 194 | } 195 | } 196 | impl Eq for G

{} 197 | 198 | impl G

{ 199 | pub fn to_affine(&self) -> Option> { 200 | if self.z.is_zero() { 201 | None 202 | } else if self.z == P::Base::one() { 203 | Some(AffineG { 204 | x: self.x, 205 | y: self.y, 206 | }) 207 | } else { 208 | let zinv = self.z.inverse().unwrap(); 209 | let zinv_squared = zinv.squared(); 210 | 211 | Some(AffineG { 212 | x: self.x * zinv_squared, 213 | y: self.y * (zinv_squared * zinv), 214 | }) 215 | } 216 | } 217 | } 218 | 219 | impl AffineG

{ 220 | pub fn to_jacobian(&self) -> G

{ 221 | G { 222 | x: self.x, 223 | y: self.y, 224 | z: P::Base::one(), 225 | } 226 | } 227 | } 228 | 229 | impl GroupElement for G

{ 230 | fn zero() -> Self { 231 | G { 232 | x: P::Base::zero(), 233 | y: P::Base::one(), 234 | z: P::Base::zero(), 235 | } 236 | } 237 | 238 | fn one() -> Self { 239 | P::one() 240 | } 241 | 242 | fn random(rng: &mut R) -> Self { 243 | P::one() * Fr::random(rng) 244 | } 245 | 246 | fn is_zero(&self) -> bool { 247 | self.z.is_zero() 248 | } 249 | 250 | fn double(&self) -> Self { 251 | let a = self.x.squared(); 252 | let b = self.y.squared(); 253 | let c = b.squared(); 254 | let mut d = (self.x + b).squared() - a - c; 255 | d = d + d; 256 | let e = a + a + a; 257 | let f = e.squared(); 258 | let x3 = f - (d + d); 259 | let mut eight_c = c + c; 260 | eight_c = eight_c + eight_c; 261 | eight_c = eight_c + eight_c; 262 | let y1z1 = self.y * self.z; 263 | 264 | G { 265 | x: x3, 266 | y: e * (d - x3) - eight_c, 267 | z: y1z1 + y1z1, 268 | } 269 | } 270 | } 271 | 272 | impl Mul for G

{ 273 | type Output = G

; 274 | 275 | fn mul(self, other: Fr) -> G

{ 276 | let mut res = G::zero(); 277 | let mut found_one = false; 278 | 279 | for i in U256::from(other).bits() { 280 | if found_one { 281 | res = res.double(); 282 | } 283 | 284 | if i { 285 | found_one = true; 286 | res = res + self; 287 | } 288 | } 289 | 290 | res 291 | } 292 | } 293 | 294 | impl Add> for G

{ 295 | type Output = G

; 296 | 297 | fn add(self, other: G

) -> G

{ 298 | if self.is_zero() { 299 | return other; 300 | } 301 | 302 | if other.is_zero() { 303 | return self; 304 | } 305 | 306 | let z1_squared = self.z.squared(); 307 | let z2_squared = other.z.squared(); 308 | let u1 = self.x * z2_squared; 309 | let u2 = other.x * z1_squared; 310 | let z1_cubed = self.z * z1_squared; 311 | let z2_cubed = other.z * z2_squared; 312 | let s1 = self.y * z2_cubed; 313 | let s2 = other.y * z1_cubed; 314 | 315 | if u1 == u2 && s1 == s2 { 316 | self.double() 317 | } else { 318 | let h = u2 - u1; 319 | let s2_minus_s1 = s2 - s1; 320 | let i = (h + h).squared(); 321 | let j = h * i; 322 | let r = s2_minus_s1 + s2_minus_s1; 323 | let v = u1 * i; 324 | let s1_j = s1 * j; 325 | let x3 = r.squared() - j - (v + v); 326 | 327 | G { 328 | x: x3, 329 | y: r * (v - x3) - (s1_j + s1_j), 330 | z: ((self.z + other.z).squared() - z1_squared - z2_squared) * h, 331 | } 332 | } 333 | } 334 | } 335 | 336 | impl Neg for G

{ 337 | type Output = G

; 338 | 339 | fn neg(self) -> G

{ 340 | if self.is_zero() { 341 | self 342 | } else { 343 | G { 344 | x: self.x, 345 | y: -self.y, 346 | z: self.z, 347 | } 348 | } 349 | } 350 | } 351 | 352 | impl Neg for AffineG

{ 353 | type Output = AffineG

; 354 | 355 | fn neg(self) -> AffineG

{ 356 | AffineG { 357 | x: self.x, 358 | y: -self.y, 359 | } 360 | } 361 | } 362 | 363 | impl Sub> for G

{ 364 | type Output = G

; 365 | 366 | fn sub(self, other: G

) -> G

{ 367 | self + (-other) 368 | } 369 | } 370 | 371 | #[derive(Debug)] 372 | pub struct G1Params; 373 | 374 | impl GroupParams for G1Params { 375 | type Base = Fq; 376 | 377 | fn name() -> &'static str { 378 | "G1" 379 | } 380 | 381 | fn one() -> G { 382 | G { 383 | x: Fq::one(), 384 | y: const_fq([ 385 | 0xa6ba871b8b1e1b3a, 386 | 0x14f1d651eb8e167b, 387 | 0xccdd46def0f28c58, 388 | 0x1c14ef83340fbe5e, 389 | ]), 390 | z: Fq::one(), 391 | } 392 | } 393 | 394 | fn coeff_b() -> Fq { 395 | const_fq([ 396 | 0x7a17caa950ad28d7, 397 | 0x1f6ac17ae15521b9, 398 | 0x334bea4e696bd284, 399 | 0x2a1f6744ce179d8e, 400 | ]) 401 | } 402 | } 403 | 404 | pub type G1 = G; 405 | 406 | pub type AffineG1 = AffineG; 407 | 408 | #[derive(Debug)] 409 | pub struct G2Params; 410 | 411 | impl GroupParams for G2Params { 412 | type Base = Fq2; 413 | 414 | fn name() -> &'static str { 415 | "G2" 416 | } 417 | 418 | fn one() -> G { 419 | G { 420 | x: Fq2::new( 421 | const_fq([ 422 | 0x8e83b5d102bc2026, 423 | 0xdceb1935497b0172, 424 | 0xfbb8264797811adf, 425 | 0x19573841af96503b, 426 | ]), 427 | const_fq([ 428 | 0xafb4737da84c6140, 429 | 0x6043dd5a5802d8c4, 430 | 0x09e950fc52a02f86, 431 | 0x14fef0833aea7b6b, 432 | ]), 433 | ), 434 | y: Fq2::new( 435 | const_fq([ 436 | 0x619dfa9d886be9f6, 437 | 0xfe7fd297f59e9b78, 438 | 0xff9e1a62231b7dfe, 439 | 0x28fd7eebae9e4206, 440 | ]), 441 | const_fq([ 442 | 0x64095b56c71856ee, 443 | 0xdc57f922327d3cbb, 444 | 0x55f935be33351076, 445 | 0x0da4a0e693fd6482, 446 | ]), 447 | ), 448 | z: Fq2::one(), 449 | } 450 | } 451 | 452 | fn coeff_b() -> Fq2 { 453 | Fq2::new( 454 | const_fq([ 455 | 0x3bf938e377b802a8, 456 | 0x020b1b273633535d, 457 | 0x26b7edf049755260, 458 | 0x2514c6324384a86d, 459 | ]), 460 | const_fq([ 461 | 0x38e7ecccd1dcff67, 462 | 0x65f0b37d93ce0d3e, 463 | 0xd749d0dd22ac00aa, 464 | 0x0141b9ce4a688d4d, 465 | ]), 466 | ) 467 | } 468 | 469 | fn check_order() -> bool { 470 | true 471 | } 472 | } 473 | 474 | pub type G2 = G; 475 | 476 | pub type AffineG2 = AffineG; 477 | 478 | #[cfg(test)] 479 | mod tests; 480 | 481 | #[test] 482 | fn test_g1() { 483 | tests::group_trials::(); 484 | } 485 | 486 | #[test] 487 | fn test_g2() { 488 | tests::group_trials::(); 489 | } 490 | 491 | #[test] 492 | fn test_affine_jacobian_conversion() { 493 | let rng = &mut ::rand::thread_rng(); 494 | 495 | assert!(G1::zero().to_affine().is_none()); 496 | assert!(G2::zero().to_affine().is_none()); 497 | 498 | for _ in 0..1000 { 499 | let a = G1::one() * Fr::random(rng); 500 | let b = a.to_affine().unwrap(); 501 | let c = b.to_jacobian(); 502 | 503 | assert_eq!(a, c); 504 | } 505 | 506 | for _ in 0..1000 { 507 | let a = G2::one() * Fr::random(rng); 508 | let b = a.to_affine().unwrap(); 509 | let c = b.to_jacobian(); 510 | 511 | assert_eq!(a, c); 512 | } 513 | } 514 | 515 | #[inline] 516 | fn twist() -> Fq2 { 517 | fq2_nonresidue() 518 | } 519 | 520 | #[inline] 521 | fn two_inv() -> Fq { 522 | const_fq([ 523 | 9781510331150239090, 524 | 15059239858463337189, 525 | 10331104244869713732, 526 | 2249375503248834476, 527 | ]) 528 | } 529 | 530 | #[inline] 531 | fn twist_mul_by_q_x() -> Fq2 { 532 | Fq2::new( 533 | const_fq([ 534 | 13075984984163199792, 535 | 3782902503040509012, 536 | 8791150885551868305, 537 | 1825854335138010348, 538 | ]), 539 | const_fq([ 540 | 7963664994991228759, 541 | 12257807996192067905, 542 | 13179524609921305146, 543 | 2767831111890561987, 544 | ]), 545 | ) 546 | } 547 | 548 | #[inline] 549 | fn twist_mul_by_q_y() -> Fq2 { 550 | Fq2::new( 551 | const_fq([ 552 | 16482010305593259561, 553 | 13488546290961988299, 554 | 3578621962720924518, 555 | 2681173117283399901, 556 | ]), 557 | const_fq([ 558 | 11661927080404088775, 559 | 553939530661941723, 560 | 7860678177968807019, 561 | 3208568454732775116, 562 | ]), 563 | ) 564 | } 565 | 566 | #[derive(PartialEq, Eq)] 567 | pub struct EllCoeffs { 568 | pub ell_0: Fq2, 569 | pub ell_vw: Fq2, 570 | pub ell_vv: Fq2, 571 | } 572 | 573 | #[derive(PartialEq, Eq)] 574 | pub struct G2Precomp { 575 | pub q: AffineG, 576 | pub coeffs: Vec, 577 | } 578 | 579 | impl G2Precomp { 580 | pub fn miller_loop(&self, g1: &AffineG) -> Fq12 { 581 | let mut f = Fq12::one(); 582 | 583 | let mut idx = 0; 584 | 585 | for i in ATE_LOOP_COUNT_NAF.iter() { 586 | let c = &self.coeffs[idx]; 587 | idx += 1; 588 | f = f.squared() 589 | .mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 590 | 591 | if *i != 0 { 592 | let c = &self.coeffs[idx]; 593 | idx += 1; 594 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 595 | } 596 | } 597 | 598 | let c = &self.coeffs[idx]; 599 | idx += 1; 600 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 601 | 602 | let c = &self.coeffs[idx]; 603 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 604 | 605 | f 606 | } 607 | } 608 | 609 | pub fn miller_loop_batch(g2_precomputes: &Vec, g1_vec: &Vec>) -> Fq12 { 610 | let mut f = Fq12::one(); 611 | 612 | let mut idx = 0; 613 | 614 | for i in ATE_LOOP_COUNT_NAF.iter() { 615 | f = f.squared(); 616 | for (g2_precompute, g1) in g2_precomputes.iter().zip(g1_vec.iter()) { 617 | let c = &g2_precompute.coeffs[idx]; 618 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 619 | } 620 | idx += 1; 621 | if *i != 0 { 622 | for (g2_precompute, g1) in g2_precomputes.iter().zip(g1_vec.iter()) { 623 | let c = &g2_precompute.coeffs[idx]; 624 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 625 | } 626 | idx += 1; 627 | } 628 | } 629 | 630 | for (g2_precompute, g1) in g2_precomputes.iter().zip(g1_vec.iter()) { 631 | let c = &g2_precompute.coeffs[idx]; 632 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 633 | } 634 | idx += 1; 635 | for (g2_precompute, g1) in g2_precomputes.iter().zip(g1_vec.iter()) { 636 | let c = &g2_precompute.coeffs[idx]; 637 | f = f.mul_by_024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x)); 638 | } 639 | f 640 | } 641 | 642 | #[test] 643 | fn test_miller_loop() { 644 | use crate::fields::Fq6; 645 | 646 | let g1 = G1::one() 647 | * Fr::from_str( 648 | "18097487326282793650237947474982649264364522469319914492172746413872781676", 649 | ).unwrap(); 650 | let g2 = G2::one() 651 | * Fr::from_str( 652 | "20390255904278144451778773028944684152769293537511418234311120800877067946", 653 | ).unwrap(); 654 | 655 | let g1_pre = g1.to_affine().unwrap(); 656 | let g2_pre = g2.to_affine().unwrap().precompute(); 657 | 658 | let gt = g2_pre.miller_loop(&g1_pre); 659 | 660 | let expected: Fq12 = Fq12::new( 661 | Fq6::new( 662 | Fq2::new( 663 | Fq::new(U256([51910954035973319022896381997847359481, 49070349125448662928383548013678560320])).unwrap(), 664 | Fq::new(U256([150594250655925940766158230906714822921, 45067780486977162411874315270532662559])).unwrap(), 665 | ), 666 | Fq2::new( 667 | Fq::new(U256([293313211826787380313097274184299135668, 28033688961864567415258173424862015279])).unwrap(), 668 | Fq::new(U256([167463228417728651969785007140185669229, 7077084888790581611350259269763958251])).unwrap(), 669 | ), 670 | Fq2::new( 671 | Fq::new(U256([166574695108782631900870170909221310910, 36301755601680728879208628452507017454])).unwrap(), 672 | Fq::new(U256([61790765844042689836493058059938629070, 8459680572251855304146082351314233167])).unwrap(), 673 | ) 674 | ), 675 | Fq6::new( 676 | Fq2::new( 677 | Fq::new(U256([274725556782132290265566702453516000786, 47645385003117491559484060631887523335])).unwrap(), 678 | Fq::new(U256([218741759704184655717004970623859820160, 5768209145436844234600983552836237590])).unwrap(), 679 | ), 680 | Fq2::new( 681 | Fq::new(U256([166365676746880051357185694330614395245, 44422629177536239628987108174157680084])).unwrap(), 682 | Fq::new(U256([188797990739833756731082975171894736944, 643465180603364587407484249282263717])).unwrap(), 683 | ), 684 | Fq2::new( 685 | Fq::new(U256([271144479861903489720584548513988144824, 10463758518630442972881156820224659715])).unwrap(), 686 | Fq::new(U256([214759070354702766397810519515686065785, 63150584453541665372008601383729030318])).unwrap(), 687 | ) 688 | ) 689 | ); 690 | assert_eq!(gt, expected); 691 | } 692 | 693 | impl AffineG { 694 | fn mul_by_q(&self) -> Self { 695 | AffineG { 696 | x: twist_mul_by_q_x() * self.x.frobenius_map(1), 697 | y: twist_mul_by_q_y() * self.y.frobenius_map(1), 698 | } 699 | } 700 | 701 | pub fn precompute(&self) -> G2Precomp { 702 | let mut r = self.to_jacobian(); 703 | 704 | let mut coeffs = Vec::with_capacity(102); 705 | 706 | let q_neg = self.neg(); 707 | for i in ATE_LOOP_COUNT_NAF.iter() { 708 | coeffs.push(r.doubling_step_for_flipped_miller_loop()); 709 | 710 | if *i == 1 { 711 | coeffs.push(r.mixed_addition_step_for_flipped_miller_loop(self)); 712 | } 713 | if *i == 3 { 714 | coeffs.push(r.mixed_addition_step_for_flipped_miller_loop(&q_neg)); 715 | } 716 | } 717 | let q1 = self.mul_by_q(); 718 | let q2 = -(q1.mul_by_q()); 719 | 720 | coeffs.push(r.mixed_addition_step_for_flipped_miller_loop(&q1)); 721 | coeffs.push(r.mixed_addition_step_for_flipped_miller_loop(&q2)); 722 | 723 | G2Precomp { 724 | q: *self, 725 | coeffs: coeffs, 726 | } 727 | } 728 | } 729 | 730 | impl G2 { 731 | fn mixed_addition_step_for_flipped_miller_loop( 732 | &mut self, 733 | base: &AffineG, 734 | ) -> EllCoeffs { 735 | let d = self.x - self.z * base.x; 736 | let e = self.y - self.z * base.y; 737 | let f = d.squared(); 738 | let g = e.squared(); 739 | let h = d * f; 740 | let i = self.x * f; 741 | let j = self.z * g + h - (i + i); 742 | 743 | self.x = d * j; 744 | self.y = e * (i - j) - h * self.y; 745 | self.z = self.z * h; 746 | 747 | EllCoeffs { 748 | ell_0: twist() * (e * base.x - d * base.y), 749 | ell_vv: e.neg(), 750 | ell_vw: d, 751 | } 752 | } 753 | 754 | fn doubling_step_for_flipped_miller_loop(&mut self) -> EllCoeffs { 755 | let a = (self.x * self.y).scale(two_inv()); 756 | let b = self.y.squared(); 757 | let c = self.z.squared(); 758 | let d = c + c + c; 759 | let e = G2Params::coeff_b() * d; 760 | let f = e + e + e; 761 | let g = (b + f).scale(two_inv()); 762 | let h = (self.y + self.z).squared() - (b + c); 763 | let i = e - b; 764 | let j = self.x.squared(); 765 | let e_sq = e.squared(); 766 | 767 | self.x = a * (b - f); 768 | self.y = g.squared() - (e_sq + e_sq + e_sq); 769 | self.z = b * h; 770 | 771 | EllCoeffs { 772 | ell_0: twist() * i, 773 | ell_vw: h.neg(), 774 | ell_vv: j + j + j, 775 | } 776 | } 777 | } 778 | 779 | #[test] 780 | fn test_prepared_g2() { 781 | let g2 = G2::one() 782 | * Fr::from_str( 783 | "20390255904278144451778773028944684152769293537511418234311120800877067946", 784 | ).unwrap(); 785 | 786 | let g2_p = g2.to_affine().unwrap().precompute(); 787 | 788 | let expected_g2_p = G2Precomp { 789 | q: AffineG { 790 | x: Fq2::new( 791 | Fq::new(U256([286108132425575157823044300810193365120, 40955922372263072279965766273066553545])).unwrap(), 792 | Fq::new(U256([51787456028377068413742525949644831103, 18727496177066613612143648473641354138])).unwrap() 793 | ), 794 | y: Fq2::new( 795 | Fq::new(U256([105235307093009526756443741536710213857, 56697136982397507595538316605420403515])).unwrap(), 796 | Fq::new(U256([329285813328264858787093963282305459902, 40620233227497131789363095249389429612])).unwrap() 797 | ) 798 | }, 799 | coeffs: vec![ 800 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([145915152615018094207274265949237364577, 7720188347992263845704223037750674843])).unwrap(), Fq::new(U256([1642602221754736777334297091439332137, 43455737427254701713230610624368790806])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([192300176042178641247789718482757908684, 15253255261571338892647481759611271748])).unwrap(), Fq::new(U256([84481530492606440649863882423335628050, 47407062771372090504997924471673219553])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([232941999867492381013751617901190279960, 33161335727531633874118709394498248694])).unwrap(), Fq::new(U256([205159091107726234051689046255658875895, 18784742195738106358087607099254122817])).unwrap()) }, 801 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([44903717410722925336080339155272113598, 2432148164440313442445265360131108750])).unwrap(), Fq::new(U256([115058944839679151514931430187558137193, 19913547532675326995005163334665928687])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([162225342243516818284353803749727397649, 2902812998987289816105769597190405892])).unwrap(), Fq::new(U256([280882305470180330735174149091034017688, 45000755139204939118391532933575113126])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([81439170073299243743458979294198176188, 8269567577349210062003854855333109246])).unwrap(), Fq::new(U256([229588642195598894684486216729209468602, 50120631775179825949138513731773141671])).unwrap()) }, 802 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([62571086408084349816772432183764211635, 50233214695378430835319156584725532968])).unwrap(), Fq::new(U256([187531012616569709709565459550531626708, 25399966597901061874032352675540749982])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([125202410210363842487043120679844927964, 32132029049461004568346717732357115368])).unwrap(), Fq::new(U256([40047990517661970904320150752358301419, 29547330482153702904408059941549019061])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([72725441636162608820485881978479394755, 4335829118654814821890758647864621059])).unwrap(), Fq::new(U256([3808530996119731737716737121624391430, 14840119309897919310042357130477699760])).unwrap()) }, 803 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([230923838046707456761202857863657685779, 30663581424308030115949734185266015957])).unwrap(), Fq::new(U256([75804784823545649980980649059385057066, 40783805432413650791639865054248573254])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([220403174695454806701510356109644664970, 61694366506643321007589345694791625235])).unwrap(), Fq::new(U256([111050616308506297168851165107648527276, 29953858315513175963460036136567176100])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([339360714692284035291265180647668192278, 51066683198194726198561068977822786062])).unwrap(), Fq::new(U256([20532264324124291215869821260466642056, 53772344434441015474139364759811842825])).unwrap()) }, 804 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([53390632401876602131528763251836289052, 7039696239984002955384050250007606842])).unwrap(), Fq::new(U256([120756148133186395786471763371515340851, 62560956052144901655506280432592733452])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([308576049186755490218939550330371718607, 60158766280438165965298754059752443327])).unwrap(), Fq::new(U256([36519660971413271753359371158311247925, 33166369001790145692925310192829466902])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([178902296336418821251231963767960641976, 54039139529656231144797458475123200306])).unwrap(), Fq::new(U256([327709063289359470903820254941214044104, 29921523827667065809753199129798632038])).unwrap()) }, 805 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([293947345738284310028696202770439717312, 23629199470233866978708839571836323911])).unwrap(), Fq::new(U256([270255405451020462647135094276398320650, 10214498461032217021941670870340839535])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([159737597162744224577379609113239040296, 42414292048147664393527940182644080820])).unwrap(), Fq::new(U256([319166235401593060755720596880844332847, 23942967675619615172318074973192451617])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([322582854267025287594765649802803266076, 43815838906866149475744535388480851056])).unwrap(), Fq::new(U256([194731262617323725381582694441938082298, 6318043913263416116808511289860376787])).unwrap()) }, 806 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([340258202167813930211448229264749672038, 49309561646299510355653200516855272117])).unwrap(), Fq::new(U256([314009511129121341897071879080163927420, 46733418159091100849346822998375177924])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([296127326349185873181435771941022502705, 27092339993712929447599322475752229815])).unwrap(), Fq::new(U256([14090774041595571810302865485069892149, 9416959189726308679959984066033622764])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([331192186309261416893996962356905314610, 6133490180262551399580874298514378708])).unwrap(), Fq::new(U256([52146008553438513232574426823996261862, 51692389190081578424424830745703412620])).unwrap()) }, 807 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([304886724958645105936240400377782311329, 24452949520921718326419149662293231897])).unwrap(), Fq::new(U256([191644523888771552477578834463319391872, 21762407072532056308389337796258587948])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([131875657381595539531276734057336373872, 46145756403556903236477737806904884925])).unwrap(), Fq::new(U256([15513558811446045405402043661936649706, 6164660913794769127674854991137805768])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([37628908878688989915703006228108158588, 32333568458099455743134394992114761192])).unwrap(), Fq::new(U256([310028653933656868572053471966984499925, 50927285178735796712220443510555951806])).unwrap()) }, 808 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([323579290279633699483736616036574636320, 26462458255852549637810201830373030787])).unwrap(), Fq::new(U256([212356178148004645362110693008071812466, 7147771462841335914859391157142419270])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([33793486114682505251748396905247663179, 12971208030293312519168903516345112146])).unwrap(), Fq::new(U256([105470215179403498779276452125929471612, 13243999928262666388833873861601164323])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([336774965397927402479055329499391144750, 14092422716202439890370586466555281245])).unwrap(), Fq::new(U256([128524990965480598411024491536330888971, 16339349487558512101009117692791080358])).unwrap()) }, 809 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([308807709363499650659552856561459119304, 20549512613498060437905021698882254003])).unwrap(), Fq::new(U256([296831825878801592442122280385770051837, 12999356604250035352468537408632919011])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([6416952549311962005690662486801715420, 6562024922514861810686738146979657369])).unwrap(), Fq::new(U256([208034701293282569885312328681897330015, 32565296199581814532888690261728578093])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([158821090683358871468006667057662171383, 43639936137708212270934870661514052516])).unwrap(), Fq::new(U256([273462267971100585683746592136866263017, 33686004986452254374790215788772597950])).unwrap()) }, 810 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([239050458738191424179259026508283200850, 59033062634877072212375745660456082761])).unwrap(), Fq::new(U256([42735232027681689333255156554135804585, 3645324355274008091830665999900460711])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([108736755942765297679539162065532976047, 53005795603772553534072950762621113576])).unwrap(), Fq::new(U256([161143215360647768117453097687908448132, 47995551574176504820342605188594172079])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([6657347986892301669776633258074701543, 11902481233202623619409687758723915636])).unwrap(), Fq::new(U256([222956595276083444090603007056080975801, 36382879863546362219365726153085767156])).unwrap()) }, 811 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([313682093040115002688525404999246872446, 42956501626298358982264420981703353471])).unwrap(), Fq::new(U256([16910327688907897736932577003378075753, 1359671211117678708781834746493106650])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([6643221945930263241861939865579251413, 53936065521860576156419486432192485437])).unwrap(), Fq::new(U256([309056291241266457640134736864478816427, 37247957207987268075661977484645707642])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([222157301260856896664619946160442713805, 49516872999212369072183141842522894943])).unwrap(), Fq::new(U256([205513791444704603844975928062124661076, 57468270224470125473802906477068197830])).unwrap()) }, 812 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([8285963000933560101573593109316673578, 14786122523410515396563958444109027710])).unwrap(), Fq::new(U256([122158657553570962061566147876423950513, 52139940048286310424786112221915773798])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([334881138980927901869290199603379387015, 25426740963889929124688873103192284934])).unwrap(), Fq::new(U256([15041987314727689102877759056668987416, 53279076961030137249765180937167164331])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([219851721339103004718273461131600868626, 36871882814964809764289908414024625695])).unwrap(), Fq::new(U256([131269942067631553063094618567097759738, 53556533347945713183394135477679452243])).unwrap()) }, 813 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([303322002694907044040904386256578801369, 47818402373691165133570276489205539247])).unwrap(), Fq::new(U256([23840328058016663665484464556433078317, 57137757685631244994429644684135564308])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([313347268925459844355339673983448992252, 63059125438530014597733264556246943889])).unwrap(), Fq::new(U256([332951624867081114956044501931839262097, 21446965953220512177611603903918604526])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([43308962429154740283739513584277671586, 36726788540078024416606994278261486896])).unwrap(), Fq::new(U256([201462004284693135670392448782496773481, 37361169637624833127302583281977615660])).unwrap()) }, 814 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([23765318454509223469921591210222962901, 44990033695398054388153021046567582164])).unwrap(), Fq::new(U256([31305053791054889490552967007711680166, 27103171064041391806294729422128985527])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([276126480562835962332188871122724756846, 16736136826306680287985573076016202896])).unwrap(), Fq::new(U256([4414319697794720805306194236550991584, 62019193108561650400059767099940339027])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([264396677944255651896935058261233808058, 56759185289081036894005736531633938393])).unwrap(), Fq::new(U256([203628704629834831927134686796555271069, 48471469187143841926703236705753907861])).unwrap()) }, 815 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([239115594351165984647685996782641428320, 44545149465284571473177119694335581490])).unwrap(), Fq::new(U256([213078788930221853484251159402089402698, 16763897914971151155224113448725254022])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([114008097138551618719252989046711208100, 59881147407771812558336453348641148192])).unwrap(), Fq::new(U256([73126778233281675579715222201222232223, 38826300453213723195010574430400377747])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([241042448915505783580706972981273226980, 56417003146210087305012985177072964806])).unwrap(), Fq::new(U256([169177487653248888684114813249577243086, 32380354283087538368804702239086564787])).unwrap()) }, 816 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([158019800920508883600584012748066500495, 26898142140797843980908437809386681141])).unwrap(), Fq::new(U256([306502797874464726523541130582372927512, 24906313146242057911294566839234262300])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([285760763932996537001129740504018931266, 61805280449958461312688755177468072593])).unwrap(), Fq::new(U256([135545131264687967800977791145788692523, 58139772512775079850670752006123037712])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([70329035009259499088740735594160571447, 39714506367478198523957872987679138518])).unwrap(), Fq::new(U256([140879819390078281356249388675648473246, 43854973736398482797037510623636581696])).unwrap()) }, 817 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([38618198701391964654224360704900902096, 38909748519501972274789640400408937483])).unwrap(), Fq::new(U256([180923031305898977193921630254659948144, 27460338595509200370239569387614912648])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([70057505024221161194312385639309591716, 18962666975131076741596858262806841593])).unwrap(), Fq::new(U256([214987899942827030987983709303642547609, 7354730872853772995022889424236171557])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([915509610432328048899540473086774484, 34629556430715177067961193484853677166])).unwrap(), Fq::new(U256([210548802885276746342162088554780886285, 59946451357630926783981469963615555141])).unwrap()) }, 818 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([192587880731165909190755427373555634019, 10976459312692912490911357520717353871])).unwrap(), Fq::new(U256([167196051583193420579377374296283755878, 49401460467894024879692901111127305932])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([280565789968090605174946518022513606221, 37294483328987043033011583201807512274])).unwrap(), Fq::new(U256([43162969061744994465193287354736460751, 22121767444104992380234797550707180209])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([253802905125777094707425424576407998829, 61686094369188045360896737944218403088])).unwrap(), Fq::new(U256([182974256593102716284343824242596548794, 7848028085342627691056691434137748535])).unwrap()) }, 819 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([84344031984214336466355469526466525167, 27093607600401090432285884248864703045])).unwrap(), Fq::new(U256([149328956099164822232925589118520984554, 2238105695079930209978670615986667957])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([164524345257317963111443719298495629688, 60976929030698527695079882388987310770])).unwrap(), Fq::new(U256([306918226890341242065585311833805224781, 55722896155980110701397483880645840750])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([93128913154066328529254602049518310767, 33148637643432199376041913783211199036])).unwrap(), Fq::new(U256([232426184416524951250597496934702636450, 43720696322889678655980069182616949616])).unwrap()) }, 820 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([102654491688396809766739755399745558766, 38605113922396003219627575078289843591])).unwrap(), Fq::new(U256([19593962899181063954599229676070513364, 60350965404501231355169027639339453296])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([159636507003615123705820979675398042179, 54313579941440479276773225578829814974])).unwrap(), Fq::new(U256([119356164563490256235392395335237959869, 39953340372362730589797197026608570557])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([63485981942258213001157530320762394972, 31200716913018312733656963741875248687])).unwrap(), Fq::new(U256([12902614517986449375080893856817237357, 18985985729109591831690040180758616083])).unwrap()) }, 821 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([42308655177239821867892255001741444297, 48752963962065714616191625548108808])).unwrap(), Fq::new(U256([128521931437576558829282023068349026555, 41085812991756679343188097975462933419])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([10035402786640614748259945360125292132, 38557266307605033249489727552659930268])).unwrap(), Fq::new(U256([261287166540169381393014929830322479654, 42514049292646924562828996896910004962])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([56319885731071444245573249522306017699, 53577564523791470572591472840806985932])).unwrap(), Fq::new(U256([124520094647080351085028512262335797477, 34908241061842840630524194497782012074])).unwrap()) }, 822 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([126634618253919797596379978688751079772, 52145187142657016821034369446677208400])).unwrap(), Fq::new(U256([331622287147942589908508350657315302543, 33514242158733995981408830992771427380])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([120940515437555419164907643421042686361, 17509271053436215565086784812667241751])).unwrap(), Fq::new(U256([115780741523467210253488502554959480585, 32352495928341192491861819481034439523])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([3619315753849520875056567968398971518, 24276420029996570458336249792816120452])).unwrap(), Fq::new(U256([211494135803191326215038551543926917828, 43184746342435212339590913052197238451])).unwrap()) }, 823 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([299074873552726234274845052736068685064, 17100980781941753342716208137755315141])).unwrap(), Fq::new(U256([132717845842422445158092928854959930670, 44970515850781790514922204901459656647])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([216867730679061124743178802618784487478, 57695717306148677588162001948381364803])).unwrap(), Fq::new(U256([270218131380365097755408360718075538527, 57477676726794026534017337223493668494])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([165279544895097377741304748618110436848, 20425223618131822879513743747480509436])).unwrap(), Fq::new(U256([74939006713979852471760437945055491248, 13009460391442509409368588074771283312])).unwrap()) }, 824 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([66759827770349370888034213457290956508, 9005955800938032302448930728853089346])).unwrap(), Fq::new(U256([132741330683696165661450722498530220360, 7366906791443646993778243377846220425])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([253540438895289112523278690834655986794, 6116090159416232554407405788526490758])).unwrap(), Fq::new(U256([30829083910163512740218467627901622426, 55620601051021580444864016142195538972])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([250454368142865329167214266233567636554, 62357304312342518984982585510065736692])).unwrap(), Fq::new(U256([188759902529624961292182168219378957599, 46090313440960353890072197786322881372])).unwrap()) }, 825 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([273524456438634570870477083331972978477, 9134704483036112456254510849911524401])).unwrap(), Fq::new(U256([67478468272116511526567438494812739067, 25741563822514337717816912706935692500])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([116593352960394465976476340555861894686, 41112534697095493718894382902662572752])).unwrap(), Fq::new(U256([120743240887113383410964567068981375379, 38598788085595749947162720656886407615])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([312187803926537773957821532171857044863, 19370576499152094014450666672812249236])).unwrap(), Fq::new(U256([240827398452930199439299722869808431504, 49509218268486878713361004562421178491])).unwrap()) }, 826 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([290888165778751654611450374067314903262, 37392757737237359968235356696866333927])).unwrap(), Fq::new(U256([252204440608865557722718990121112495320, 55975286037277175922442767802285953079])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([270039432299546232993592658461203399951, 60656209400809596126720306545905143183])).unwrap(), Fq::new(U256([285724268091089729569589544862374658568, 31963711474983717334851248248346512047])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([3884505529011790540935411500477268151, 13223063167340752683657032423528371760])).unwrap(), Fq::new(U256([159305752483642939978115090933392332739, 7151624608160356980135319367119889070])).unwrap()) }, 827 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([272676514700352082082833454466828720931, 25063412692149354657238579769317314943])).unwrap(), Fq::new(U256([293621566718932528694833049559922653569, 45585304922174719737960365050252747127])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([54835393883782456964222308618682542993, 37980634195943561261187934261099825702])).unwrap(), Fq::new(U256([59974402342646963556531661011524247325, 35696051147487701670582425632191066303])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([259456005420154607862207518414346338959, 26130920677564288823895676956971235383])).unwrap(), Fq::new(U256([116130095060524137327607346021153250193, 10807286360635090367088053443993301396])).unwrap()) }, 828 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([49392952615759746255132704409838115781, 47072336582571607445080612120532993304])).unwrap(), Fq::new(U256([176567394438796320529775330793638953568, 28322815468520297894419530294472748019])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([80922979608932498062547214350892680237, 39454405473363814575369344229244849847])).unwrap(), Fq::new(U256([91401220192762005776280059066692026476, 15657465297119889794043496656394015039])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([66039352326985904039959490473173702089, 53019684969492620390541557616482571566])).unwrap(), Fq::new(U256([241714503488139707849386627025007386925, 26075944201145781355709956722513636060])).unwrap()) }, 829 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([282595284318374809009793390206732488298, 45748314157085313197379566607025256839])).unwrap(), Fq::new(U256([270827203295353120306891953779231995484, 2061164657869992110070755346638481586])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([122772591180024083766405253289036218458, 22573428243213343555967649475581629995])).unwrap(), Fq::new(U256([335389040951271989935196787085438096490, 19801736168278388699669751501679386348])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([339013185026928567100232707644090060309, 19772463825247091662201186215246641510])).unwrap(), Fq::new(U256([4804384610649622501550615795150497154, 23912076036945346828195974346279787457])).unwrap()) }, 830 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([214353258010296277687883233632193811097, 5219474783704014986415232032947372339])).unwrap(), Fq::new(U256([79624479932762034850342328421303227111, 56787485322265889115274972394242117773])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([184200025840089548499823017798379240877, 48381517011877532244879858559402925202])).unwrap(), Fq::new(U256([107565933978602112957892502247036378430, 45988606090744912079186414974711188065])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([110593764674444376346243358175616189408, 35712801833060284055338218769830573236])).unwrap(), Fq::new(U256([151909254176585476474604484796159407774, 47158276852552318249500199498589330637])).unwrap()) }, 831 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([322742519015404082194067614300530448854, 59892171075434557254836830922854923608])).unwrap(), Fq::new(U256([32065386578298932256366582168915019527, 26752577181504287044232901657950904669])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([174803672897784440584915958306641383601, 41091446500573741637560530719439634516])).unwrap(), Fq::new(U256([209867082646016733058415245870200692364, 62329211607238784395268250532556435532])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([306258598889945544178464082933019504953, 54721033386841216374878966418312958051])).unwrap(), Fq::new(U256([60603024880089835430212078876452798438, 46149383487322374768616169869877411190])).unwrap()) }, 832 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([217026022228859342220342856144348485905, 57413523264998851221438276699831981764])).unwrap(), Fq::new(U256([124187198815039194427087238512103681551, 5443344443330946400667796667492661757])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([329826946228202959132718054863501702187, 48520872455619090037740041830322500851])).unwrap(), Fq::new(U256([84830400552123989859098307569998867522, 48734171266537512281517863759978814030])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([223121539165880683751973996773385673012, 25883364325220384256766392563193579368])).unwrap(), Fq::new(U256([299825902106679285294937343573961127742, 60789713632874624396137039249203910802])).unwrap()) }, 833 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([256516074149138488025765885988857744378, 14065986710590565469822003697004376208])).unwrap(), Fq::new(U256([234079806620020815932181140203001517322, 23367862088314049165195572485764983176])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([196437028129330799836797952742061629213, 48672430434915053819319219832418834574])).unwrap(), Fq::new(U256([325437437809364731749456582922626432887, 48166506837989600793252437510600468487])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([159308630334191903727834955555702331135, 62436879262294424125843661083177310796])).unwrap(), Fq::new(U256([36766573815532717355926225449599862176, 45422312033048180700369981630678147962])).unwrap()) }, 834 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([242582781609674647644149440448686667005, 38749506523024653240132899426202698768])).unwrap(), Fq::new(U256([175781266358339061379292613713370680613, 18670420110220807116103915283744134837])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([330308428247032904787707230285980997411, 57858504610626027326513601505745660271])).unwrap(), Fq::new(U256([137930876960001856905683673437505764610, 51655613850377410017968900339454298922])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([313120701922067853802383887994976410392, 45975781155280265622735990880466050470])).unwrap(), Fq::new(U256([335042362116388769047290965043326509112, 60559196975175152299532260702584038813])).unwrap()) }, 835 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([168129439507943874458360855948848921748, 49297302702020077848733359456178701712])).unwrap(), Fq::new(U256([269089028431861389215030548077466532939, 39860705713699087717989916919780377864])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([13752419440807207645064267622022228455, 58622973202646179187733854793315255353])).unwrap(), Fq::new(U256([214305013520593573583121266790878302778, 38633624705329558986475404541639527124])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([149534517263071862076005511513725705381, 33923419970735724678578488530397069094])).unwrap(), Fq::new(U256([52240222008682291290000393139971676649, 13553337484321113195355299279586301175])).unwrap()) }, 836 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([272900340425393991345320871434898164480, 38006376657960211098766747755417992280])).unwrap(), Fq::new(U256([261987172512287267237176115671442326513, 8128050373266945066047548013741537435])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([262663552198367871113333688806502970707, 16999213382693802141971886256404278345])).unwrap(), Fq::new(U256([82246501115823748400993076962512494264, 9513280785331020628797944368204762745])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([68225301292307439157467124956340428751, 23984526331358356113154550150873972672])).unwrap(), Fq::new(U256([322267803776402446716363035932937663522, 7643551605057856674267205902314118400])).unwrap()) }, 837 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([226851502497426762485425012577563658166, 33899046058167810318161894461593654070])).unwrap(), Fq::new(U256([106137231667287271021611800141669940221, 38201180579053106362613109983520968531])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([75276265667487657641526123222570637963, 18790008468742777802887427569490235644])).unwrap(), Fq::new(U256([236348579709234796216705203173042603149, 51488118889105930334369568118204095717])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([70847827090593073015786004614483673839, 3475230874891506896203634678143642692])).unwrap(), Fq::new(U256([8314731801106602343291488634630259831, 3521008420700564106163167660007668706])).unwrap()) }, 838 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([92354268952660546820822603858288251059, 19778715140389467112147527814081030657])).unwrap(), Fq::new(U256([329385425284714431570594794971018721246, 60587846563454266929636649850787073194])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([288633840471857542459144118014949000217, 51605528849039220650036727626483827846])).unwrap(), Fq::new(U256([251176740648089198193669671101929833609, 48200613470991338988108533743364275499])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([329193234492690486040808567065220826749, 21378867659438236011740749197423248550])).unwrap(), Fq::new(U256([285725508694128806244839238836446595834, 16111887615812423492270406970991867951])).unwrap()) }, 839 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([152431519506548878061194990588057484057, 49184327280433466363535994383523121304])).unwrap(), Fq::new(U256([176897083100713735838942116510311567986, 37010995217032206230292299420436992452])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([130722401240365261778198584122678322362, 19293082368638790806988358431355209633])).unwrap(), Fq::new(U256([336032502313799023638100083369289206306, 31063427179065887680551186789065013379])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([313119215174514058940660103265063450959, 25103967051083955792570154250792420707])).unwrap(), Fq::new(U256([31520718700780462452153016807890400365, 3961179668062303572693429066523266858])).unwrap()) }, 840 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([36667789591031625960240713279402427923, 5637784774941607531109129433890086293])).unwrap(), Fq::new(U256([286537786902526732905389646221547183400, 56733382321156059969864849624810202662])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([318803650206508773198520172514605937449, 26727846312556415159035648438885744059])).unwrap(), Fq::new(U256([296466727057750056890238712141155450998, 27938872020780344351123790536034462604])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([324800882000687209140271724886698306645, 44039571306759586933457684739133508444])).unwrap(), Fq::new(U256([47608245752536926992583482090528259005, 47831283599118732387313994410846427415])).unwrap()) }, 841 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([234409386597337888556308771844488457344, 12956567414802650084616113864217789370])).unwrap(), Fq::new(U256([54897214305565100948138138335662741789, 15577398627840234231085370089137424292])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([133034516621699526624516176710921958663, 21900941110792896857560826682314104825])).unwrap(), Fq::new(U256([91786723574963827227124861422083359642, 15631994703072556950984703411138300334])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([61994842824519647915165015802348883298, 3606506510538278544457628965895793792])).unwrap(), Fq::new(U256([176676927874382884508332121131239871282, 40115823781693004388411447312641595826])).unwrap()) }, 842 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([16486756791893393092802670694010735350, 51213785425023838862657045286249924761])).unwrap(), Fq::new(U256([127374475998848055784786954745585192546, 61927128032062116041960763307324749312])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([57390628646817442883586335851238696952, 1896752620999083872406878608493454725])).unwrap(), Fq::new(U256([221112496886805666932828220912733522283, 2796002105546343313342619098780470642])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([126113866998638086000522716026151108800, 58788515162206661637618804912085907736])).unwrap(), Fq::new(U256([19079621171649876430748555077055696995, 46826087543975014201271501761421031441])).unwrap()) }, 843 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([287527947651847089840085422221128698763, 3282429064220775329203352366444259855])).unwrap(), Fq::new(U256([307065141447870398567299540185758941637, 48193280250277647112409463651594786821])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([39874018308944266937776827490734641649, 37791912819895325896728519088674532352])).unwrap(), Fq::new(U256([11619188332176047954604673895207823813, 12983193006960451462302777892755566431])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([76045219079383487030610001932731241273, 16472513195230803643409094386807276517])).unwrap(), Fq::new(U256([244195048886093761135684126358283143738, 19479715688038787901591036330200598003])).unwrap()) }, 844 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([10563934263428977131610186732868968998, 14179527485555674710937849675581267906])).unwrap(), Fq::new(U256([257836314204976892854269567329818300595, 50763620022812667001295845381267741649])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([160125271831790681583846356333205971645, 38979573670559551140762745448476278558])).unwrap(), Fq::new(U256([258822435332825467396267733276444939733, 19361127335094998017975714923507638644])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([5086484109635987997951722709219418410, 11993539151823720275736182499510363133])).unwrap(), Fq::new(U256([171423009691627362399764794909459189507, 20404136165000279368092981943358482669])).unwrap()) }, 845 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([249500614137833023351305910264605008487, 42310425481082032237299673828774704531])).unwrap(), Fq::new(U256([253496613223900195266106558972296162241, 19046240361322320039639197826388768369])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([72263736846331351747703353269055941107, 19969702258117494907412570199791763548])).unwrap(), Fq::new(U256([126173921786290239044307538655562024455, 18006158804314393556918633600879748967])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([16201000244836956196708576962189993382, 32135871927111623648702296852432295139])).unwrap(), Fq::new(U256([186963801770492707056456887595022261993, 2392014174637078162701730926122882282])).unwrap()) }, 846 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([8922998024015454766590940715881630670, 55567280047347356367358986337109964651])).unwrap(), Fq::new(U256([313173491437683437471834863194199707492, 3438176908844635046641649505356812159])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([276513541262028309851175912267910407247, 11212571122829858982221117734299851084])).unwrap(), Fq::new(U256([259509606552160006313745402323745013955, 43114059504717558659877851383190095613])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([28098698558455079499553496395853067214, 2999821831816440733771768849050005165])).unwrap(), Fq::new(U256([334260605709723946550826958885726232933, 11843826148467149350077605819950881153])).unwrap()) }, 847 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([283455530950531157108702282345810919101, 52521643621580203161269969006017546759])).unwrap(), Fq::new(U256([118200123115287742628646618978307449884, 14795263733303838767894982171654042612])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([132641709504834974317245159550618583253, 28570895840581787308435502085893978558])).unwrap(), Fq::new(U256([229949535634549796967397304164923056337, 42352202734287711800564772982472784839])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([128199924683494278990710814519750517837, 58638050185358930355922065483565476451])).unwrap(), Fq::new(U256([4192016302378839786647752861109219112, 61114929591783829703998838288847230811])).unwrap()) }, 848 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([113754079486581376183180167710451964178, 25998717875687967363117010408717972365])).unwrap(), Fq::new(U256([133697001740616163002906224555636440440, 23546896556625148713807775573505304385])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([227150749988479615370826356819617461792, 41368715815045829029754124051658999245])).unwrap(), Fq::new(U256([222514455614853854819390285868145864687, 27579121989432504016710179821357885225])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([128433415390196263739951350076595027296, 55636438757722652255615208065796848545])).unwrap(), Fq::new(U256([94671524825895380554049635623924644741, 9791488862788864605119131922310440121])).unwrap()) }, 849 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([153881172058568095361353223261899310845, 17156484263879687903526208855029043640])).unwrap(), Fq::new(U256([192077265925835218260989605323461142787, 32318605747689071742310867751273886645])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([317408271159096505221916390262196469787, 49717575675851229633286204770028665263])).unwrap(), Fq::new(U256([230095008714744652782426759714312292445, 34768179553549400629211217553610554586])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([259609023305192462223688164733847327699, 55498873698881710203435569648274404478])).unwrap(), Fq::new(U256([256325550082466559964506871761831536884, 46357653853657184428683736043713888406])).unwrap()) }, 850 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([174577378801081039438668831531067795857, 53157547858752109585449689851969780390])).unwrap(), Fq::new(U256([82151408345597494862089436182070514285, 16466308473185906030465208465158400278])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([245839213042247079917412337301921026922, 22457019238909031929740892448482221879])).unwrap(), Fq::new(U256([109513130235370254599453293800543710331, 47936140417415756744920707247895308699])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([10776161146456696103487000724300150234, 21638563281306406703950273508675616623])).unwrap(), Fq::new(U256([207085916216710302318982426148546767798, 7534717897684081051796825732586695012])).unwrap()) }, 851 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([155690435801319682239901337205468120840, 57696234800836220244083348626584391674])).unwrap(), Fq::new(U256([126757665472044690642504190674454727065, 27689844381974512633117281405461511493])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([111371524430469273469505773333501881358, 41915381107432591576214180621073813739])).unwrap(), Fq::new(U256([8591307386286176660318558848651389629, 19322060932256059989553597776338707006])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([34843642275668259465089406915935512474, 25199006933559492770352887141455099490])).unwrap(), Fq::new(U256([10645844381812821922686446509476566858, 35688555865712593739042131731320400759])).unwrap()) }, 852 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([189947043026848705532544415056376972054, 16798314122488336019972329871173393651])).unwrap(), Fq::new(U256([308591971026665862143792543801958855960, 31580607213628921122716343407923691193])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([163093806147198705684115256712150030567, 61044717475711501197927838344963107641])).unwrap(), Fq::new(U256([307478741843426518207523544103444625011, 32813498165003357356133773951397928550])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([95291548361985054080716711033104720817, 32740343556226865497613504752972186774])).unwrap(), Fq::new(U256([99656074525833092595857684423204299816, 52556239373424263650635019541397500598])).unwrap()) }, 853 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([131443621763425639580622258813874957855, 17694455882904396881053896673232601550])).unwrap(), Fq::new(U256([57787363176533727883752817750279248594, 1322856562657561354884935596241784834])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([41788280636884607828680584839495219344, 51762903848994175839707598487572362464])).unwrap(), Fq::new(U256([327908654890111464339978492292915303796, 47344360741808824501224988176645616993])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([263873593879772810642440946076120656306, 60210233792451977377881584251511840173])).unwrap(), Fq::new(U256([77405826008973124400288647208797749719, 53019697808811506999139211676029205579])).unwrap()) }, 854 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([254578463202394703187741702356839561011, 21096342408485278014732435848864790919])).unwrap(), Fq::new(U256([230473548197181635567135409745417796610, 22147822186055995413422331229074559071])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([336878015160301245042116518989872047941, 3472301140759760061593082376347546380])).unwrap(), Fq::new(U256([16684778019642037346902548590480489922, 63174559216409847644418505532384053845])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([7942031074055265340884029455787976403, 46511448608441944387405531466341650044])).unwrap(), Fq::new(U256([201615416576767918339868727158350994412, 64255187168173681561527383354144167567])).unwrap()) }, 855 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([243308496406996226443557446925779452296, 45849597498959240205941430238383669623])).unwrap(), Fq::new(U256([48147614977633577164856356428453305437, 24480032415168951986931189038013914221])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([74830884455458736654394458059429787198, 19093844097308332947749289150298249126])).unwrap(), Fq::new(U256([33643899737753431509498018706471379301, 1054576208141392093174173023229894557])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([25010096200987042473393926604632958161, 36666296164531908118513449509789076579])).unwrap(), Fq::new(U256([33471717379111372311065514803349918045, 39155528164590001712332400960607038189])).unwrap()) }, 856 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([130247467451091212947023092388792369109, 5581090585326037371051920053369586280])).unwrap(), Fq::new(U256([322360327312842929444256001314179239601, 39584478520709259399389327249557202594])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([109138162516199992788447200019766811785, 47525457821584643247627414608651841972])).unwrap(), Fq::new(U256([76309968110600274074720854748516338453, 54739068402347163521228676077893779893])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([42180409310074737345249452446852603163, 4374831491626595184699821621506201010])).unwrap(), Fq::new(U256([130057601620482713644106051600317093239, 12010679381934251249551375242240386988])).unwrap()) }, 857 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([203271863519350650976092478448210829293, 52275506975977654460248547356331731574])).unwrap(), Fq::new(U256([87019891938199989232789187109647269328, 44030460834732836505939430240249354505])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([110171920943726136564495503552694726540, 18110786866783187141705660513534498930])).unwrap(), Fq::new(U256([86561692963802460817471572747090778194, 16449770553500671507593674575394564582])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([221876651023252602014468911202182579931, 20555077542463658872780769250687782117])).unwrap(), Fq::new(U256([121263539082468326970413896423548540112, 61907715120666399953423277772754945448])).unwrap()) }, 858 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([290357192776207049084050762947655748975, 57738753410091871200747406135207764151])).unwrap(), Fq::new(U256([135358190114239175182066780052123869069, 56081507988571629614406051210751609147])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([195622544431419990666685034787625747326, 54874770374981417815900652767969731611])).unwrap(), Fq::new(U256([6243075893789260529022348241785972764, 56521196313521047823704039910006760241])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([243495103440406073534289072917982313090, 57589106164518822864160786869003317813])).unwrap(), Fq::new(U256([235848100009165241948327269818774314127, 37511141642844469126769577281189903937])).unwrap()) }, 859 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([78592775623001882471215007061407141105, 34941191764695857355641077076235001298])).unwrap(), Fq::new(U256([267356444067983260493350102628306009780, 28391440678450825886400816194304466425])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([315751120363918319477358949808863604966, 2531298718421943078485957285990819438])).unwrap(), Fq::new(U256([242692025957487623878146464744369629015, 52949313651228011397330521709355671746])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([223701370913329345484604486557612973051, 34658421329859066183602046886271845301])).unwrap(), Fq::new(U256([239281725801587867757289553693045231533, 14055606950515704853984812857124180593])).unwrap()) }, 860 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([321292144065398009067550865125623060600, 18828918489183113618746569726487918435])).unwrap(), Fq::new(U256([44953266506250560322305758112518632685, 12818035770624926325618902943072758802])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([198712001500603483304766131655796332238, 37755493054877351200992330081944773222])).unwrap(), Fq::new(U256([203494901390506520787336076745404879355, 9719695048988798612029815523720059188])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([324082713664478232334150476671698670935, 57968755532718074766231332303127747698])).unwrap(), Fq::new(U256([172967914786650717580471091827836918517, 39836011047291872323399953583350854813])).unwrap()) }, 861 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([104693003047177326696685168159983773290, 21362453846755563999603040010467525220])).unwrap(), Fq::new(U256([56374029098225126238873495696162227687, 61374137561202742141169238350854689065])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([158941255788517659316631775720407312680, 2477940982651390357755438379586767771])).unwrap(), Fq::new(U256([212374631437158170731256215648153937637, 51786402687200191668238627015343248084])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([67431426417348416607065438525684723676, 59371917376780773574999923335758781547])).unwrap(), Fq::new(U256([329921395426288970367695061271959172005, 18586382421107856878975478269722973139])).unwrap()) }, 862 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([207312856868420470351121539398556490708, 6749469271717320482346458817170377645])).unwrap(), Fq::new(U256([297463942398989836675066926378547228117, 42180709737629195771943741993025816145])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([294946811578231549301710677543341218799, 20992621396953319301177509266206083412])).unwrap(), Fq::new(U256([334489506001987366917405458471890123881, 5644882162624043756459843063788196004])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([339439573540481749394421794993912483199, 45246606008318294125455064627263238236])).unwrap(), Fq::new(U256([270454941633781906426514756020454116063, 13672349860189847846584888881208438638])).unwrap()) }, 863 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([184109810967303467375292693011959132443, 22047527326459095654736206729881706277])).unwrap(), Fq::new(U256([306855976122543936818762044270256507301, 13817693020515802987708208420701920996])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([18944943876649574380290951381571111173, 54681599103691370082120691137707858843])).unwrap(), Fq::new(U256([274481158071926596330090943889570839876, 27656594457831811691825162550052997369])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([72068179718393541085353916977402777797, 23085120169523399820600846468009840798])).unwrap(), Fq::new(U256([39623239893391127442673085065505018616, 49714238177847283522861975755429582165])).unwrap()) }, 864 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([326109292257788796875387755492793672492, 38017828106840559651298055936334805586])).unwrap(), Fq::new(U256([300970874956733001966255469483871058465, 61693366793354972449623979259561628170])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([247117608403708963869106314083852845952, 6270392892469923670893298889464309224])).unwrap(), Fq::new(U256([85229127169148541816114014402805254942, 23692121466582475015916841187427174063])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([322377160078698123442118813943355848949, 44790955831224275605828973863316334451])).unwrap(), Fq::new(U256([246121457999548771204074791900055840778, 36237050391238930724599650306620108395])).unwrap()) }, 865 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([6479203335512729615298164829455402801, 18899857059703106109444283718983930606])).unwrap(), Fq::new(U256([307909459343553081188134777979054198524, 23104930848877581327335450138633822165])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([117408687141894236273811591312978416850, 27064268635283187986411799061361560149])).unwrap(), Fq::new(U256([89156958054425667145216654832344296184, 28498155840544447742658664925302722255])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([264148561516468171084137463578412456470, 56169366101528802291286278394614323282])).unwrap(), Fq::new(U256([80748178838045963455037482306103002135, 31627837956246452962075717178352705444])).unwrap()) }, 866 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([228462396223758741175275124462032775241, 541217865154375519097785562072294622])).unwrap(), Fq::new(U256([147690209661782719555035340726175029695, 47332569057322758675859735205860987883])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([332785070356059610611838282826287767824, 28411804506527712891888004500289036321])).unwrap(), Fq::new(U256([80347503246503526995863756906237840538, 40694963808412110626720215103350226072])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([73246772632733278293170183313248743910, 51739954405360462951359314934075204478])).unwrap(), Fq::new(U256([323288654986485051471927026636004277374, 55328786519754064217639655113348868700])).unwrap()) }, 867 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([107183915141555030394480811055835932411, 28743337205734819613101267731330261274])).unwrap(), Fq::new(U256([265627562010734120334801493421007962860, 21113833505065027987742094370311235794])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([145390576010968264278778301175950417032, 25603093564950634850451680305056487937])).unwrap(), Fq::new(U256([171224041010792018070371064846900704811, 50628689539088695975060303147297926726])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([181636860313080877557100227907605412643, 19106550849436726002022081116470620327])).unwrap(), Fq::new(U256([97037887458346176230370696042525047476, 38315199704917257726469887714210863756])).unwrap()) }, 868 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([165755565692898412861884552154775259871, 23293168176203049828541858307098176114])).unwrap(), Fq::new(U256([111579679857180892572143097811395790681, 21526844626039124934190021704344618627])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([335258764315672309726009417334449368453, 103404408330729181499563204707141002])).unwrap(), Fq::new(U256([191071126894978514432059671553769626880, 5078535341242500657674641815850178322])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([72579254643315478022492189073789591450, 44167090301255006150406576419615402343])).unwrap(), Fq::new(U256([183377394594390630206602640102963629039, 23990882412966103396841140729654425350])).unwrap()) }, 869 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([66679892701097417538832992488778691458, 58183623071000462877229489086029090922])).unwrap(), Fq::new(U256([294287188350011499287443971281382798030, 18151493196929461249661140690411179165])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([74805142807574287323605988196524192535, 18100483139591925759594156937304667397])).unwrap(), Fq::new(U256([139120256621259665435015294709846943744, 33412960622211929574259219789625651855])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([220224993980394484792559335583346867939, 59970476024877867633551960552156066815])).unwrap(), Fq::new(U256([165016476912320413641798011850430383400, 40087637389842239140931509158661317913])).unwrap()) }, 870 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([26669149284356063486638395246213038984, 48932308059862148467989673144064276455])).unwrap(), Fq::new(U256([112017260916309235481572722060511554523, 1292432061742789600481111238179731344])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([162967204317649679020730851544536806310, 32746563765578881184210706548921981702])).unwrap(), Fq::new(U256([337655071624981772776297963145482993016, 33145701869840355692613219913227327224])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([116821007696021810040981824168902376385, 46826353416371587869648603174437608629])).unwrap(), Fq::new(U256([286148963257224477643539266261574758187, 20903220425259595580283778435979469601])).unwrap()) }, 871 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([265822762895337622674318289864003560145, 62593533822281897460585212079268870737])).unwrap(), Fq::new(U256([180099245396770402139578639916315358651, 5289891249371566111607452004558281256])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([215101732208902323596827687492609836402, 60151379040875297433910120987825047988])).unwrap(), Fq::new(U256([200376206977547885622799626268846642009, 36107786828287031009478318323095814795])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([228632312969356396843036040954049410317, 29609317291386275502321244693464627541])).unwrap(), Fq::new(U256([250663071554126685512943663183005740350, 26707628083885320745488595167117920892])).unwrap()) }, 872 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([167686658731994607869572641962208584698, 32951815034866853047881968952398296677])).unwrap(), Fq::new(U256([59732843077777643290110085014121270991, 19690792480201713304572701985281652804])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([231501326469976058677041937508913323742, 58052555179693233540250119022219467367])).unwrap(), Fq::new(U256([268839178939407644460103390562050250791, 51244123519915889574699519125947948433])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([15335721378364717505397406493265760457, 50543654003772338617069451450467156120])).unwrap(), Fq::new(U256([147668560194510325215853847922114742688, 63436405408432434981818242494869996954])).unwrap()) }, 873 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([324251215335356818847634371978327094047, 53597895382917031159515977918983297046])).unwrap(), Fq::new(U256([336456284126450597413571076848285070208, 9834107003348358663468869495065030828])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([4893147365574829346121011245181836636, 48500338802265501645481354399443896938])).unwrap(), Fq::new(U256([242843203647079174857073639694991742532, 39587639177217829196831837775949647839])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([260649755517395052354543412976006056345, 41595453161552128661866319661777368912])).unwrap(), Fq::new(U256([186473459113497941493205881377276393540, 10232971634855792150439771169030969984])).unwrap()) }, 874 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([153156583597535672033657311231041916285, 12870713391441384499488044032601826356])).unwrap(), Fq::new(U256([160011046903032247780660416127755862604, 59740658966179967701258870119449151446])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([53781592683706300755113958689829175735, 5160246898475719650527746461036900035])).unwrap(), Fq::new(U256([127406077100448076503048857464807666048, 5027357614298608514576108334690214373])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([123323183388079598137911866134337668968, 30831375761327507469744048674597209517])).unwrap(), Fq::new(U256([282757148554018853521114389661374143994, 41725892078174834143829265912887863334])).unwrap()) }, 875 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([231142251602796484920728141361531696801, 43369687276260799996121293373394088506])).unwrap(), Fq::new(U256([193386979673076292922455602081629373614, 13517077812823754339540367661413555482])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([32945933209167472962271089890685376310, 23645956766949617286909797728539496219])).unwrap(), Fq::new(U256([128873344219688070096765758438736759675, 54069131826062143440208582926638727688])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([307107650784744827303698892877513591771, 60627460508970098579939906160617347629])).unwrap(), Fq::new(U256([12937320851881845879608263929438137281, 2854427512588805421842219517935335360])).unwrap()) }, 876 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([262645642925640470181426114122199935672, 23413555848620303130105885294683582394])).unwrap(), Fq::new(U256([23944562046020585348174388998952320194, 45084472027505841447432550475379032518])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([270949855981998457946423634423510659239, 52707980377915683827433393510154134085])).unwrap(), Fq::new(U256([171166926104504281831828631675145047352, 56745888676097625411354427758332611365])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([185108543406354812098225836322332681649, 38838551534016041901193249287881822376])).unwrap(), Fq::new(U256([220861944829798693206584739921489268335, 13318922669002030127185287983351463417])).unwrap()) }, 877 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([262922874647306006405720155830997014046, 60319938491997842161822791958118330349])).unwrap(), Fq::new(U256([267514688756785010198929321975858316586, 13431251784763107399729556927577885114])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([305051645126359797430782278231595423685, 47480212315012773203275805598650271426])).unwrap(), Fq::new(U256([61134576323692903306240935503639110628, 44357224521089864059608299955085658945])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([288996190497897556231840221598596395445, 7566958477031738465971309099100507442])).unwrap(), Fq::new(U256([133814060971580680876860604680251720534, 59538638355154696335532006425868258220])).unwrap()) }, 878 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([255893828824714285725760712618255298338, 62054226651551009305279711173141456137])).unwrap(), Fq::new(U256([278488875745654026562827558863613836490, 21008509582420141439141693540430274581])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([275369357162135051507223962619748317962, 42306683939383379782070254815636483252])).unwrap(), Fq::new(U256([33692084190064829046021773249716169044, 16341905693988596015816579527114077079])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([50744916563901235043837175537752247974, 10172930551818555335663216915059687204])).unwrap(), Fq::new(U256([130434124352272975884189586048532260990, 23515228462564504103971218058319726320])).unwrap()) }, 879 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([315580665939248091007437797584737352150, 29708290546079112870849940807626622733])).unwrap(), Fq::new(U256([74442409874403535705044740324158268395, 1505199293980260993350511103843027993])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([250928935731107472086814134230515792409, 5910959187805062997477270179924851551])).unwrap(), Fq::new(U256([280398933657384735588696583124789483429, 54783439113329460653893087793006061735])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([251724005393716093632013371894721049773, 58848512269437108583523559065211202801])).unwrap(), Fq::new(U256([31822195116686689031909059702809975955, 24789755710735999475756589726034740758])).unwrap()) }, 880 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([311444467767445140793669110935330311306, 49680899512402416135008064018078765713])).unwrap(), Fq::new(U256([260075513883026034919987130520464438138, 71886459212490540714376620236740887])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([218811104197169142519581806122315915406, 2003975639040616906277810278389252752])).unwrap(), Fq::new(U256([162449781759514417953768678035934414521, 20826616094394726852079185751274539294])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([50122791277121629311774878848574398797, 41715208027917549489096484827508261925])).unwrap(), Fq::new(U256([61219715357759165032395798940008313361, 55168729445645977375765036089053114792])).unwrap()) }, 881 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([79415664581913745231517567945561341244, 19961313692291707660858657690356279927])).unwrap(), Fq::new(U256([169697929611525566517558862344260578764, 32844991405556424161021671060175948696])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([97951068758528710273694591785781637499, 18749313896215455583118043227454839626])).unwrap(), Fq::new(U256([86416223342992670848217929911878122430, 45508713650090104780284816480988042321])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([205166366708889542887913296220698256110, 64283667930878381361054417761490454821])).unwrap(), Fq::new(U256([127337780289640176933683040648197123026, 45189848010560984741741084451460237213])).unwrap()) }, 882 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([339284773562100413239152438122508204497, 50631498218339719105248005011418978450])).unwrap(), Fq::new(U256([33417073692493560040015373020490319634, 35461627756915585142929292352046627148])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([65706590332479893819786959846945487398, 49780412881756049082474794087182699607])).unwrap(), Fq::new(U256([52838637386752308153448355705238086197, 25418435995504719731730063829115376943])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([272342513391057040499052435082268704444, 40734611488359738470851428580967866388])).unwrap(), Fq::new(U256([195464905670800875597868841505577455579, 4567343913211817054294335942572391310])).unwrap()) }, 883 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([116585277318795490267488822790585572050, 60535270002127930300661104257194060095])).unwrap(), Fq::new(U256([60938698090087736292473391678184666708, 13034546647626058553077909902189865751])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([173096860849358760769153772521753734944, 46051492674049147015395144791836438516])).unwrap(), Fq::new(U256([217847244022302146556080020387033222160, 3714600728561149832835084325311638745])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([86749998713441153819371623717671780463, 22072421598347798931100735874660737662])).unwrap(), Fq::new(U256([318879363093875678699747171034610586590, 20824335590094416898946169150944599166])).unwrap()) }, 884 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([64488889092438538888826783837043953900, 37184887689753051095864638902885179863])).unwrap(), Fq::new(U256([30545663928156310707528798028105042841, 35594636889744346303301050561815356233])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([25983064025798529721395241242693795182, 8818840193887973907465639723423785685])).unwrap(), Fq::new(U256([258083038864362618956338229292791076964, 59924965332411444209484507096908691451])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([220038260912754873591576914680586914279, 13066051346629987308799710602199271472])).unwrap(), Fq::new(U256([145490690982645862542497983334649610263, 61905193484912278316593689230425266660])).unwrap()) }, 885 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([91140715068468329987534450751429662322, 19286363177619277557153390898202185703])).unwrap(), Fq::new(U256([93820352751188715792914230189639637744, 34108640942617057347076989500332659863])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([64028159517497609933876978072339213461, 15242545675596643010631683990284567829])).unwrap(), Fq::new(U256([196818140250582584748747602707707107768, 19674391967426090834762688793787807910])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([240272916169613868056785616677104041776, 43506134861603450917738367078393340621])).unwrap(), Fq::new(U256([4195648020339163006604321850508278540, 4672904647050343041579830671683109182])).unwrap()) }, 886 | EllCoeffs { ell_0: Fq2::new(Fq::new(U256([76224289879065773445423898190273853011, 29552147447995384759425668183293749353])).unwrap(), Fq::new(U256([131775855227043960655312514543203001277, 11525949759137095338012468817574456927])).unwrap()), ell_vw: Fq2::new(Fq::new(U256([24164999216876611682317527533876599098, 1468136824339634997687523096410027135])).unwrap(), Fq::new(U256([287955683679784091578386069448645460818, 42392463637589581183769087503942163916])).unwrap()), ell_vv: Fq2::new(Fq::new(U256([277415168387483520146499744266583303231, 43682907322954483721445867111493680565])).unwrap(), Fq::new(U256([231497467135626786731515493713118585761, 56904388641135605566397108514408579757])).unwrap()) } 887 | ] 888 | }; 889 | 890 | assert!(expected_g2_p == g2_p); 891 | assert!(expected_g2_p.coeffs.len() == 87); 892 | } 893 | 894 | pub fn pairing(p: &G1, q: &G2) -> Fq12 { 895 | match (p.to_affine(), q.to_affine()) { 896 | (None, _) | (_, None) => Fq12::one(), 897 | (Some(p), Some(q)) => q.precompute() 898 | .miller_loop(&p) 899 | .final_exponentiation() 900 | .expect("miller loop cannot produce zero"), 901 | } 902 | } 903 | 904 | pub fn pairing_batch(ps: &[G1], qs: &[G2]) -> Fq12 { 905 | let mut p_affines: Vec> = Vec::new(); 906 | let mut q_precomputes: Vec = Vec::new(); 907 | for (p, q) in ps.into_iter().zip(qs.into_iter()) { 908 | 909 | let p_affine = p.to_affine(); 910 | let q_affine = q.to_affine(); 911 | let exists = match(p_affine, q_affine) 912 | { 913 | (None, _) | (_, None) => false, 914 | (Some(_p_affine), Some(_q_affine)) => true, 915 | }; 916 | 917 | if exists { 918 | p_affines.push(p.to_affine().unwrap()); 919 | q_precomputes.push(q.to_affine().unwrap().precompute()); 920 | } 921 | } 922 | if q_precomputes.len() == 0 { 923 | return Fq12::one(); 924 | } 925 | miller_loop_batch(&q_precomputes, &p_affines).final_exponentiation().expect("miller loop cannot produce zero") 926 | } 927 | 928 | #[test] 929 | fn test_reduced_pairing() { 930 | use crate::fields::Fq6; 931 | 932 | let g1 = G1::one() 933 | * Fr::from_str( 934 | "18097487326282793650237947474982649264364522469319914492172746413872781676", 935 | ).unwrap(); 936 | let g2 = G2::one() 937 | * Fr::from_str( 938 | "20390255904278144451778773028944684152769293537511418234311120800877067946", 939 | ).unwrap(); 940 | 941 | let gt = pairing(&g1, &g2); 942 | 943 | let expected = Fq12::new( 944 | Fq6::new( 945 | Fq2::new( 946 | Fq::from_str( 947 | "7520311483001723614143802378045727372643587653754534704390832890681688842501", 948 | ).unwrap(), 949 | Fq::from_str( 950 | "20265650864814324826731498061022229653175757397078253377158157137251452249882", 951 | ).unwrap(), 952 | ), 953 | Fq2::new( 954 | Fq::from_str( 955 | "11942254371042183455193243679791334797733902728447312943687767053513298221130", 956 | ).unwrap(), 957 | Fq::from_str( 958 | "759657045325139626991751731924144629256296901790485373000297868065176843620", 959 | ).unwrap(), 960 | ), 961 | Fq2::new( 962 | Fq::from_str( 963 | "16045761475400271697821392803010234478356356448940805056528536884493606035236", 964 | ).unwrap(), 965 | Fq::from_str( 966 | "4715626119252431692316067698189337228571577552724976915822652894333558784086", 967 | ).unwrap(), 968 | ), 969 | ), 970 | Fq6::new( 971 | Fq2::new( 972 | Fq::from_str( 973 | "14901948363362882981706797068611719724999331551064314004234728272909570402962", 974 | ).unwrap(), 975 | Fq::from_str( 976 | "11093203747077241090565767003969726435272313921345853819385060670210834379103", 977 | ).unwrap(), 978 | ), 979 | Fq2::new( 980 | Fq::from_str( 981 | "17897835398184801202802503586172351707502775171934235751219763553166796820753", 982 | ).unwrap(), 983 | Fq::from_str( 984 | "1344517825169318161285758374052722008806261739116142912817807653057880346554", 985 | ).unwrap(), 986 | ), 987 | Fq2::new( 988 | Fq::from_str( 989 | "11123896897251094532909582772961906225000817992624500900708432321664085800838", 990 | ).unwrap(), 991 | Fq::from_str( 992 | "17453370448280081813275586256976217762629631160552329276585874071364454854650", 993 | ).unwrap(), 994 | ), 995 | ), 996 | ); 997 | 998 | assert_eq!(expected, gt); 999 | } 1000 | 1001 | #[test] 1002 | fn predefined_pair() { 1003 | let g1 = AffineG1::new( 1004 | Fq::from_str("1").expect("Fq(1) should exist"), 1005 | Fq::from_str("2").expect("Fq(2) should exist"), 1006 | ).expect("Point (1,2) should exist in G1") 1007 | .to_jacobian(); 1008 | 1009 | let g2 = AffineG2::new( 1010 | Fq2::new( 1011 | Fq::from_str("10857046999023057135944570762232829481370756359578518086990519993285655852781") 1012 | .expect("a-coeff of g2 x generator is of the right order"), 1013 | Fq::from_str("11559732032986387107991004021392285783925812861821192530917403151452391805634") 1014 | .expect("b-coeff of g2 x generator is of the right order"), 1015 | ), 1016 | Fq2::new( 1017 | Fq::from_str("8495653923123431417604973247489272438418190587263600148770280649306958101930") 1018 | .expect("a-coeff of g2 y generator is of the right order"), 1019 | Fq::from_str("4082367875863433681332203403145435568316851327593401208105741076214120093531") 1020 | .expect("b-coeff of g2 y generator is of the right order"), 1021 | ), 1022 | ).expect("Point(11559732032986387107991004021392285783925812861821192530917403151452391805634 * i + 10857046999023057135944570762232829481370756359578518086990519993285655852781, 4082367875863433681332203403145435568316851327593401208105741076214120093531 * i + 8495653923123431417604973247489272438418190587263600148770280649306958101930) is a valid generator for G2") 1023 | .to_jacobian(); 1024 | 1025 | let p = pairing(&g1, &g2); 1026 | 1027 | let g1_vec : Vec = vec![g1, g1]; 1028 | let g2_vec : Vec = vec![g2, g2]; 1029 | let p2 = pairing_batch(&g1_vec, &g2_vec); 1030 | assert!(!p2.is_zero()); 1031 | assert!(!p.is_zero()); 1032 | } 1033 | 1034 | #[test] 1035 | fn test_batch_bilinearity_empty() { 1036 | let p_vec : Vec = Vec::new(); 1037 | let q_vec : Vec = Vec::new(); 1038 | let r = pairing_batch(&p_vec, &q_vec); 1039 | assert_eq!(r, Fq12::one()); 1040 | } 1041 | 1042 | #[test] 1043 | fn test_batch_bilinearity_one() { 1044 | use rand::{SeedableRng, rngs::StdRng}; 1045 | let seed = [ 1046 | 0, 0, 0, 0, 0, 0, 64, 13, // 103245 1047 | 0, 0, 0, 0, 0, 0, 176, 2, // 191922 1048 | 0, 0, 0, 0, 0, 0, 0, 13, // 1293 1049 | 0, 0, 0, 0, 0, 0, 96, 7u8, // 192103 1050 | ]; 1051 | let mut rng = StdRng::from_seed(seed); 1052 | let p_vec : Vec = vec![G1::random(&mut rng)]; 1053 | let q_vec : Vec = vec![G2::random(&mut rng)]; 1054 | let s = Fr::random(&mut rng); 1055 | let sp_vec : Vec = vec![p_vec[0] * s]; 1056 | let sq_vec : Vec = vec![q_vec[0] * s]; 1057 | let b = pairing_batch(&sp_vec, &q_vec); 1058 | let c = pairing_batch(&p_vec, &sq_vec); 1059 | assert_eq!(b, c); 1060 | } 1061 | 1062 | #[test] 1063 | fn test_batch_bilinearity_fifty() { 1064 | use rand::{SeedableRng, rngs::StdRng}; 1065 | let seed = [ 1066 | 0, 0, 0, 0, 0, 0, 64, 13, // 103245 1067 | 0, 0, 0, 0, 0, 0, 176, 2, // 191922 1068 | 0, 0, 0, 0, 0, 0, 0, 13, // 1293 1069 | 0, 0, 0, 0, 0, 0, 96, 7u8, // 192103 1070 | ]; 1071 | let mut rng = StdRng::from_seed(seed); 1072 | 1073 | let mut p_vec : Vec = Vec::new(); 1074 | let mut q_vec : Vec = Vec::new(); 1075 | let mut sp_vec : Vec = Vec::new(); 1076 | let mut sq_vec : Vec = Vec::new(); 1077 | 1078 | for _ in 0..50 { 1079 | let p = G1::random(&mut rng); 1080 | let q = G2::random(&mut rng); 1081 | let s = Fr::random(&mut rng); 1082 | let sp = p * s; 1083 | let sq = q * s; 1084 | sp_vec.push(sp); 1085 | q_vec.push(q); 1086 | sq_vec.push(sq); 1087 | p_vec.push(p); 1088 | } 1089 | let b_batch = pairing_batch(&sp_vec, &q_vec); 1090 | let c_batch = pairing_batch(&p_vec, &sq_vec); 1091 | assert_eq!(b_batch, c_batch); 1092 | } 1093 | 1094 | #[test] 1095 | fn test_bilinearity() { 1096 | use rand::{SeedableRng, rngs::StdRng}; 1097 | let seed = [ 1098 | 0, 0, 0, 0, 0, 0, 64, 13, // 103245 1099 | 0, 0, 0, 0, 0, 0, 176, 2, // 191922 1100 | 0, 0, 0, 0, 0, 0, 0, 13, // 1293 1101 | 0, 0, 0, 0, 0, 0, 96, 7u8, // 192103 1102 | ]; 1103 | let mut rng = StdRng::from_seed(seed); 1104 | 1105 | for _ in 0..50 { 1106 | let p = G1::random(&mut rng); 1107 | let q = G2::random(&mut rng); 1108 | let s = Fr::random(&mut rng); 1109 | let sp = p * s; 1110 | let sq = q * s; 1111 | 1112 | let a = pairing(&p, &q).pow(s); 1113 | let b = pairing(&sp, &q); 1114 | let c = pairing(&p, &sq); 1115 | 1116 | assert_eq!(a, b); 1117 | assert_eq!(b, c); 1118 | 1119 | let t = -Fr::one(); 1120 | 1121 | assert!(a != Fq12::one()); 1122 | assert_eq!((a.pow(t)) * a, Fq12::one()); 1123 | } 1124 | } 1125 | 1126 | #[test] 1127 | fn internals() { 1128 | let test_p = G1::one(); 1129 | 1130 | let val = G1::new(test_p.x().clone(), test_p.y().clone(), test_p.z().clone()); 1131 | 1132 | let affine = val.to_affine() 1133 | .expect("There should be affine coords for (0, 0)"); 1134 | 1135 | assert_eq!(affine.x(), &Fq::one()); 1136 | } 1137 | 1138 | #[test] 1139 | fn affine_fail() { 1140 | let res = AffineG1::new(Fq::one(), Fq::one()); 1141 | assert!( 1142 | res.is_err(), 1143 | "Affine initialization should fail because the point is not on curve" 1144 | ); 1145 | } 1146 | 1147 | #[test] 1148 | fn affine_ok() { 1149 | let res = AffineG1::new(Fq::one(), G1Params::coeff_b()); 1150 | assert!( 1151 | res.is_err(), 1152 | "Affine initialization should be ok because the point is on the curve" 1153 | ); 1154 | } 1155 | 1156 | #[test] 1157 | fn test_y_at_point_at_infinity() { 1158 | assert!(G1::zero().y == Fq::one()); 1159 | assert!((-G1::zero()).y == Fq::one()); 1160 | 1161 | assert!(G2::zero().y == Fq2::one()); 1162 | assert!((-G2::zero()).y == Fq2::one()); 1163 | } 1164 | -------------------------------------------------------------------------------- /src/groups/tests.rs: -------------------------------------------------------------------------------- 1 | use super::GroupElement; 2 | use crate::fields::{FieldElement, Fr}; 3 | use rand::Rng; 4 | 5 | fn random_test_addition(rng: &mut R) { 6 | for _ in 0..50 { 7 | let r1 = G::random(rng); 8 | let r2 = G::random(rng); 9 | let r3 = G::random(rng); 10 | 11 | assert_eq!((r1 + r2) + r3, r1 + (r2 + r3)); 12 | assert!(((r1 + r2 + r3) - r2 - r3 - r1).is_zero()); 13 | } 14 | } 15 | 16 | fn random_test_doubling(rng: &mut R) { 17 | for _ in 0..50 { 18 | let r1 = G::random(rng); 19 | let r2 = G::random(rng); 20 | let ti = Fr::from_str("2").unwrap().inverse().unwrap(); 21 | 22 | assert_eq!((r1 + r2) + r1, r1.double() + r2); 23 | assert_eq!(r1, r1.double() * ti); 24 | } 25 | } 26 | 27 | fn random_test_dh(rng: &mut R) { 28 | for _ in 0..50 { 29 | let alice_sk = Fr::random(rng); 30 | let bob_sk = Fr::random(rng); 31 | 32 | let alice_pk = G::one() * alice_sk; 33 | let bob_pk = G::one() * bob_sk; 34 | 35 | let alice_shared = bob_pk * alice_sk; 36 | let bob_shared = alice_pk * bob_sk; 37 | 38 | assert_eq!(alice_shared, bob_shared); 39 | } 40 | } 41 | 42 | fn random_test_equality(rng: &mut R) { 43 | for _ in 0..50 { 44 | let begin = G::random(rng); 45 | 46 | let mut acc = begin; 47 | 48 | // Do a bunch of random things. 49 | 50 | let a = Fr::random(rng); 51 | let b = G::random(rng); 52 | let c = Fr::random(rng); 53 | let d = G::random(rng); 54 | 55 | for _ in 0..10 { 56 | acc = acc * a; 57 | acc = -acc; 58 | acc = acc + b; 59 | acc = acc * c; 60 | acc = -acc; 61 | acc = acc - d; 62 | acc = acc.double(); 63 | } 64 | 65 | // Then reverse the operations 66 | 67 | let ai = a.inverse().unwrap(); 68 | let ci = c.inverse().unwrap(); 69 | let ti = Fr::from_str("2").unwrap().inverse().unwrap(); 70 | 71 | for _ in 0..10 { 72 | acc = acc * ti; 73 | acc = acc + d; 74 | acc = -acc; 75 | acc = acc * ci; 76 | acc = acc - b; 77 | acc = -acc; 78 | acc = acc * ai; 79 | } 80 | 81 | assert_eq!(acc, begin); 82 | } 83 | } 84 | 85 | pub fn group_trials() { 86 | assert!(G::zero().is_zero()); 87 | assert!((G::one() - G::one()).is_zero()); 88 | assert_eq!(G::one() + G::one(), G::one() * Fr::from_str("2").unwrap()); 89 | assert!(G::zero().double().is_zero()); 90 | 91 | assert!((G::one() * (-Fr::one()) + G::one()).is_zero()); 92 | 93 | use rand::{SeedableRng, rngs::StdRng}; 94 | let seed = [ 95 | 0, 0, 0, 0, 0, 0, 64, 13, // 103245 96 | 0, 0, 0, 0, 0, 0, 176, 2, // 191922 97 | 0, 0, 0, 0, 0, 0, 0, 13, // 1293 98 | 0, 0, 0, 0, 0, 0, 96, 7u8, // 192103 99 | ]; 100 | let mut rng = StdRng::from_seed(seed); 101 | 102 | random_test_addition::(&mut rng); 103 | random_test_doubling::(&mut rng); 104 | random_test_dh::(&mut rng); 105 | random_test_equality::(&mut rng); 106 | } 107 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | pub mod arith; 6 | mod fields; 7 | mod groups; 8 | 9 | use crate::fields::FieldElement; 10 | use crate::groups::{GroupElement, G1Params, G2Params, GroupParams}; 11 | 12 | use alloc::vec::Vec; 13 | use core::ops::{Add, Mul, Neg, Sub}; 14 | use rand::Rng; 15 | 16 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 17 | #[repr(C)] 18 | pub struct Fr(fields::Fr); 19 | 20 | impl Fr { 21 | pub fn zero() -> Self { 22 | Fr(fields::Fr::zero()) 23 | } 24 | pub fn one() -> Self { 25 | Fr(fields::Fr::one()) 26 | } 27 | pub fn random(rng: &mut R) -> Self { 28 | Fr(fields::Fr::random(rng)) 29 | } 30 | pub fn pow(&self, exp: Fr) -> Self { 31 | Fr(self.0.pow(exp.0)) 32 | } 33 | pub fn from_str(s: &str) -> Option { 34 | fields::Fr::from_str(s).map(|e| Fr(e)) 35 | } 36 | pub fn inverse(&self) -> Option { 37 | self.0.inverse().map(|e| Fr(e)) 38 | } 39 | pub fn is_zero(&self) -> bool { 40 | self.0.is_zero() 41 | } 42 | pub fn interpret(buf: &[u8; 64]) -> Fr { 43 | Fr(fields::Fr::interpret(buf)) 44 | } 45 | pub fn from_slice(slice: &[u8]) -> Result { 46 | arith::U256::from_slice(slice) 47 | .map_err(|_| FieldError::InvalidSliceLength) // todo: maybe more sensful error handling 48 | .map(|x| Fr::new_mul_factor(x)) 49 | } 50 | pub fn to_big_endian(&self, slice: &mut [u8]) -> Result<(), FieldError> { 51 | self.0 52 | .raw() 53 | .to_big_endian(slice) 54 | .map_err(|_| FieldError::InvalidSliceLength) 55 | } 56 | pub fn new(val: arith::U256) -> Option { 57 | fields::Fr::new(val).map(|x| Fr(x)) 58 | } 59 | pub fn new_mul_factor(val: arith::U256) -> Self { 60 | Fr(fields::Fr::new_mul_factor(val)) 61 | } 62 | pub fn into_u256(self) -> arith::U256 { 63 | (self.0).into() 64 | } 65 | pub fn set_bit(&mut self, bit: usize, to: bool) { 66 | self.0.set_bit(bit, to); 67 | } 68 | } 69 | 70 | impl Add for Fr { 71 | type Output = Fr; 72 | 73 | fn add(self, other: Fr) -> Fr { 74 | Fr(self.0 + other.0) 75 | } 76 | } 77 | 78 | impl Sub for Fr { 79 | type Output = Fr; 80 | 81 | fn sub(self, other: Fr) -> Fr { 82 | Fr(self.0 - other.0) 83 | } 84 | } 85 | 86 | impl Neg for Fr { 87 | type Output = Fr; 88 | 89 | fn neg(self) -> Fr { 90 | Fr(-self.0) 91 | } 92 | } 93 | 94 | impl Mul for Fr { 95 | type Output = Fr; 96 | 97 | fn mul(self, other: Fr) -> Fr { 98 | Fr(self.0 * other.0) 99 | } 100 | } 101 | 102 | #[derive(Debug)] 103 | pub enum FieldError { 104 | InvalidSliceLength, 105 | InvalidU512Encoding, 106 | NotMember, 107 | } 108 | 109 | #[derive(Debug)] 110 | pub enum CurveError { 111 | InvalidEncoding, 112 | NotMember, 113 | Field(FieldError), 114 | ToAffineConversion, 115 | } 116 | 117 | impl From for CurveError { 118 | fn from(fe: FieldError) -> Self { 119 | CurveError::Field(fe) 120 | } 121 | } 122 | 123 | pub use crate::groups::Error as GroupError; 124 | 125 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 126 | #[repr(C)] 127 | pub struct Fq(fields::Fq); 128 | 129 | impl Fq { 130 | pub fn zero() -> Self { 131 | Fq(fields::Fq::zero()) 132 | } 133 | pub fn one() -> Self { 134 | Fq(fields::Fq::one()) 135 | } 136 | pub fn random(rng: &mut R) -> Self { 137 | Fq(fields::Fq::random(rng)) 138 | } 139 | pub fn pow(&self, exp: Fq) -> Self { 140 | Fq(self.0.pow(exp.0)) 141 | } 142 | pub fn from_str(s: &str) -> Option { 143 | fields::Fq::from_str(s).map(|e| Fq(e)) 144 | } 145 | pub fn inverse(&self) -> Option { 146 | self.0.inverse().map(|e| Fq(e)) 147 | } 148 | pub fn is_zero(&self) -> bool { 149 | self.0.is_zero() 150 | } 151 | pub fn interpret(buf: &[u8; 64]) -> Fq { 152 | Fq(fields::Fq::interpret(buf)) 153 | } 154 | pub fn from_slice(slice: &[u8]) -> Result { 155 | arith::U256::from_slice(slice) 156 | .map_err(|_| FieldError::InvalidSliceLength) // todo: maybe more sensful error handling 157 | .and_then(|x| fields::Fq::new(x).ok_or(FieldError::NotMember)) 158 | .map(|x| Fq(x)) 159 | } 160 | pub fn to_big_endian(&self, slice: &mut [u8]) -> Result<(), FieldError> { 161 | let mut a: arith::U256 = self.0.into(); 162 | // convert from Montgomery representation 163 | a.mul( 164 | &fields::Fq::one().raw(), 165 | &fields::Fq::modulus(), 166 | self.0.inv(), 167 | ); 168 | a.to_big_endian(slice) 169 | .map_err(|_| FieldError::InvalidSliceLength) 170 | } 171 | pub fn from_u256(u256: arith::U256) -> Result { 172 | Ok(Fq(fields::Fq::new(u256).ok_or(FieldError::NotMember)?)) 173 | } 174 | pub fn into_u256(self) -> arith::U256 { 175 | (self.0).into() 176 | } 177 | pub fn modulus() -> arith::U256 { 178 | fields::Fq::modulus() 179 | } 180 | 181 | pub fn sqrt(&self) -> Option { 182 | self.0.sqrt().map(Fq) 183 | } 184 | } 185 | 186 | impl Add for Fq { 187 | type Output = Fq; 188 | 189 | fn add(self, other: Fq) -> Fq { 190 | Fq(self.0 + other.0) 191 | } 192 | } 193 | 194 | impl Sub for Fq { 195 | type Output = Fq; 196 | 197 | fn sub(self, other: Fq) -> Fq { 198 | Fq(self.0 - other.0) 199 | } 200 | } 201 | 202 | impl Neg for Fq { 203 | type Output = Fq; 204 | 205 | fn neg(self) -> Fq { 206 | Fq(-self.0) 207 | } 208 | } 209 | 210 | impl Mul for Fq { 211 | type Output = Fq; 212 | 213 | fn mul(self, other: Fq) -> Fq { 214 | Fq(self.0 * other.0) 215 | } 216 | } 217 | 218 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 219 | #[repr(C)] 220 | pub struct Fq2(fields::Fq2); 221 | 222 | impl Fq2 { 223 | pub fn one() -> Fq2 { 224 | Fq2(fields::Fq2::one()) 225 | } 226 | 227 | pub fn i() -> Fq2 { 228 | Fq2(fields::Fq2::i()) 229 | } 230 | 231 | pub fn zero() -> Fq2 { 232 | Fq2(fields::Fq2::zero()) 233 | } 234 | 235 | /// Initalizes new F_q2(a + bi, a is real coeff, b is imaginary) 236 | pub fn new(a: Fq, b: Fq) -> Fq2 { 237 | Fq2(fields::Fq2::new(a.0, b.0)) 238 | } 239 | 240 | pub fn is_zero(&self) -> bool { 241 | self.0.is_zero() 242 | } 243 | 244 | pub fn pow(&self, exp: arith::U256) -> Self { 245 | Fq2(self.0.pow(exp)) 246 | } 247 | 248 | pub fn real(&self) -> Fq { 249 | Fq(*self.0.real()) 250 | } 251 | 252 | pub fn imaginary(&self) -> Fq { 253 | Fq(*self.0.imaginary()) 254 | } 255 | 256 | pub fn sqrt(&self) -> Option { 257 | self.0.sqrt().map(Fq2) 258 | } 259 | 260 | pub fn from_slice(bytes: &[u8]) -> Result { 261 | let u512 = arith::U512::from_slice(bytes).map_err(|_| FieldError::InvalidU512Encoding)?; 262 | let (res, c0) = u512.divrem(&Fq::modulus()); 263 | Ok(Fq2::new( 264 | Fq::from_u256(c0).map_err(|_| FieldError::NotMember)?, 265 | Fq::from_u256(res.ok_or(FieldError::NotMember)?).map_err(|_| FieldError::NotMember)?, 266 | )) 267 | } 268 | } 269 | 270 | 271 | impl Add for Fq2 { 272 | type Output = Self; 273 | 274 | fn add(self, other: Self) -> Self { 275 | Fq2(self.0 + other.0) 276 | } 277 | } 278 | 279 | impl Sub for Fq2 { 280 | type Output = Self; 281 | 282 | fn sub(self, other: Self) -> Self { 283 | Fq2(self.0 - other.0) 284 | } 285 | } 286 | 287 | impl Neg for Fq2 { 288 | type Output = Self; 289 | 290 | fn neg(self) -> Self { 291 | Fq2(-self.0) 292 | } 293 | } 294 | 295 | impl Mul for Fq2 { 296 | type Output = Self; 297 | 298 | fn mul(self, other: Self) -> Self { 299 | Fq2(self.0 * other.0) 300 | } 301 | } 302 | 303 | pub trait Group 304 | : Send 305 | + Sync 306 | + Copy 307 | + Clone 308 | + PartialEq 309 | + Eq 310 | + Sized 311 | + Add 312 | + Sub 313 | + Neg 314 | + Mul { 315 | fn zero() -> Self; 316 | fn one() -> Self; 317 | fn random(rng: &mut R) -> Self; 318 | fn is_zero(&self) -> bool; 319 | fn normalize(&mut self); 320 | } 321 | 322 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 323 | #[repr(C)] 324 | pub struct G1(groups::G1); 325 | 326 | impl G1 { 327 | pub fn new(x: Fq, y: Fq, z: Fq) -> Self { 328 | G1(groups::G1::new(x.0, y.0, z.0)) 329 | } 330 | 331 | pub fn x(&self) -> Fq { 332 | Fq(self.0.x().clone()) 333 | } 334 | 335 | pub fn set_x(&mut self, x: Fq) { 336 | *self.0.x_mut() = x.0 337 | } 338 | 339 | pub fn y(&self) -> Fq { 340 | Fq(self.0.y().clone()) 341 | } 342 | 343 | pub fn set_y(&mut self, y: Fq) { 344 | *self.0.y_mut() = y.0 345 | } 346 | 347 | pub fn z(&self) -> Fq { 348 | Fq(self.0.z().clone()) 349 | } 350 | 351 | pub fn set_z(&mut self, z: Fq) { 352 | *self.0.z_mut() = z.0 353 | } 354 | 355 | pub fn b() -> Fq { 356 | Fq(G1Params::coeff_b()) 357 | } 358 | 359 | pub fn from_compressed(bytes: &[u8]) -> Result { 360 | if bytes.len() != 33 { return Err(CurveError::InvalidEncoding); } 361 | 362 | let sign = bytes[0]; 363 | let fq = Fq::from_slice(&bytes[1..])?; 364 | let x = fq; 365 | let y_squared = (fq * fq * fq) + Self::b(); 366 | 367 | let mut y = y_squared.sqrt().ok_or(CurveError::NotMember)?; 368 | 369 | if sign == 2 && y.into_u256().get_bit(0).expect("bit 0 always exist; qed") { y = y.neg(); } 370 | else if sign == 3 && !y.into_u256().get_bit(0).expect("bit 0 always exist; qed") { y = y.neg(); } 371 | else if sign != 3 && sign != 2 { 372 | return Err(CurveError::InvalidEncoding); 373 | } 374 | AffineG1::new(x, y).map_err(|_| CurveError::NotMember).map(Into::into) 375 | } 376 | } 377 | 378 | impl Group for G1 { 379 | fn zero() -> Self { 380 | G1(groups::G1::zero()) 381 | } 382 | fn one() -> Self { 383 | G1(groups::G1::one()) 384 | } 385 | fn random(rng: &mut R) -> Self { 386 | G1(groups::G1::random(rng)) 387 | } 388 | fn is_zero(&self) -> bool { 389 | self.0.is_zero() 390 | } 391 | fn normalize(&mut self) { 392 | let new = match self.0.to_affine() { 393 | Some(a) => a, 394 | None => return, 395 | }; 396 | 397 | self.0 = new.to_jacobian(); 398 | } 399 | } 400 | 401 | impl Add for G1 { 402 | type Output = G1; 403 | 404 | fn add(self, other: G1) -> G1 { 405 | G1(self.0 + other.0) 406 | } 407 | } 408 | 409 | impl Sub for G1 { 410 | type Output = G1; 411 | 412 | fn sub(self, other: G1) -> G1 { 413 | G1(self.0 - other.0) 414 | } 415 | } 416 | 417 | impl Neg for G1 { 418 | type Output = G1; 419 | 420 | fn neg(self) -> G1 { 421 | G1(-self.0) 422 | } 423 | } 424 | 425 | impl Mul for G1 { 426 | type Output = G1; 427 | 428 | fn mul(self, other: Fr) -> G1 { 429 | G1(self.0 * other.0) 430 | } 431 | } 432 | 433 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 434 | #[repr(C)] 435 | pub struct AffineG1(groups::AffineG1); 436 | 437 | impl AffineG1 { 438 | pub fn new(x: Fq, y: Fq) -> Result { 439 | Ok(AffineG1(groups::AffineG1::new(x.0, y.0)?)) 440 | } 441 | 442 | pub fn x(&self) -> Fq { 443 | Fq(self.0.x().clone()) 444 | } 445 | 446 | pub fn set_x(&mut self, x: Fq) { 447 | *self.0.x_mut() = x.0 448 | } 449 | 450 | pub fn y(&self) -> Fq { 451 | Fq(self.0.y().clone()) 452 | } 453 | 454 | pub fn set_y(&mut self, y: Fq) { 455 | *self.0.y_mut() = y.0 456 | } 457 | 458 | pub fn from_jacobian(g1: G1) -> Option { 459 | g1.0.to_affine().map(|x| AffineG1(x)) 460 | } 461 | } 462 | 463 | impl From for G1 { 464 | fn from(affine: AffineG1) -> Self { 465 | G1(affine.0.to_jacobian()) 466 | } 467 | } 468 | 469 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 470 | #[repr(C)] 471 | pub struct G2(groups::G2); 472 | 473 | impl G2 { 474 | pub fn new(x: Fq2, y: Fq2, z: Fq2) -> Self { 475 | G2(groups::G2::new(x.0, y.0, z.0)) 476 | } 477 | 478 | pub fn x(&self) -> Fq2 { 479 | Fq2(self.0.x().clone()) 480 | } 481 | 482 | pub fn set_x(&mut self, x: Fq2) { 483 | *self.0.x_mut() = x.0 484 | } 485 | 486 | pub fn y(&self) -> Fq2 { 487 | Fq2(self.0.y().clone()) 488 | } 489 | 490 | pub fn set_y(&mut self, y: Fq2) { 491 | *self.0.y_mut() = y.0 492 | } 493 | 494 | pub fn z(&self) -> Fq2 { 495 | Fq2(self.0.z().clone()) 496 | } 497 | 498 | pub fn set_z(&mut self, z: Fq2) { 499 | *self.0.z_mut() = z.0 500 | } 501 | 502 | pub fn b() -> Fq2 { 503 | Fq2(G2Params::coeff_b()) 504 | } 505 | 506 | pub fn from_compressed(bytes: &[u8]) -> Result { 507 | 508 | if bytes.len() != 65 { return Err(CurveError::InvalidEncoding); } 509 | 510 | let sign = bytes[0]; 511 | let x = Fq2::from_slice(&bytes[1..])?; 512 | 513 | let y_squared = (x * x * x) + G2::b(); 514 | let y = y_squared.sqrt().ok_or(CurveError::NotMember)?; 515 | let y_neg = -y; 516 | 517 | let y_gt = y.0.to_u512() > y_neg.0.to_u512(); 518 | 519 | let e_y = if sign == 10 { if y_gt { y_neg } else { y } } 520 | else if sign == 11 { if y_gt { y } else { y_neg } } 521 | else { 522 | return Err(CurveError::InvalidEncoding); 523 | }; 524 | 525 | AffineG2::new(x, e_y).map_err(|_| CurveError::NotMember).map(Into::into) 526 | } 527 | } 528 | 529 | impl Group for G2 { 530 | fn zero() -> Self { 531 | G2(groups::G2::zero()) 532 | } 533 | fn one() -> Self { 534 | G2(groups::G2::one()) 535 | } 536 | fn random(rng: &mut R) -> Self { 537 | G2(groups::G2::random(rng)) 538 | } 539 | fn is_zero(&self) -> bool { 540 | self.0.is_zero() 541 | } 542 | fn normalize(&mut self) { 543 | let new = match self.0.to_affine() { 544 | Some(a) => a, 545 | None => return, 546 | }; 547 | 548 | self.0 = new.to_jacobian(); 549 | } 550 | } 551 | 552 | impl Add for G2 { 553 | type Output = G2; 554 | 555 | fn add(self, other: G2) -> G2 { 556 | G2(self.0 + other.0) 557 | } 558 | } 559 | 560 | impl Sub for G2 { 561 | type Output = G2; 562 | 563 | fn sub(self, other: G2) -> G2 { 564 | G2(self.0 - other.0) 565 | } 566 | } 567 | 568 | impl Neg for G2 { 569 | type Output = G2; 570 | 571 | fn neg(self) -> G2 { 572 | G2(-self.0) 573 | } 574 | } 575 | 576 | impl Mul for G2 { 577 | type Output = G2; 578 | 579 | fn mul(self, other: Fr) -> G2 { 580 | G2(self.0 * other.0) 581 | } 582 | } 583 | 584 | #[derive(Copy, Clone, PartialEq, Eq)] 585 | #[repr(C)] 586 | pub struct Gt(fields::Fq12); 587 | 588 | impl Gt { 589 | pub fn one() -> Self { 590 | Gt(fields::Fq12::one()) 591 | } 592 | pub fn pow(&self, exp: Fr) -> Self { 593 | Gt(self.0.pow(exp.0)) 594 | } 595 | pub fn inverse(&self) -> Option { 596 | self.0.inverse().map(Gt) 597 | } 598 | pub fn final_exponentiation(&self) -> Option { 599 | self.0.final_exponentiation().map(Gt) 600 | } 601 | } 602 | 603 | impl Mul for Gt { 604 | type Output = Gt; 605 | 606 | fn mul(self, other: Gt) -> Gt { 607 | Gt(self.0 * other.0) 608 | } 609 | } 610 | 611 | pub fn pairing(p: G1, q: G2) -> Gt { 612 | Gt(groups::pairing(&p.0, &q.0)) 613 | } 614 | 615 | pub fn pairing_batch(pairs: &[(G1, G2)]) -> Gt { 616 | let mut ps : Vec = Vec::new(); 617 | let mut qs : Vec = Vec::new(); 618 | for (p, q) in pairs { 619 | ps.push(p.0); 620 | qs.push(q.0); 621 | } 622 | Gt(groups::pairing_batch(&ps, &qs)) 623 | } 624 | 625 | pub fn miller_loop_batch(pairs: &[(G2, G1)]) -> Result { 626 | let mut ps : Vec = Vec::new(); 627 | let mut qs : Vec> = Vec::new(); 628 | for (p, q) in pairs { 629 | ps.push(p.0.to_affine().ok_or(CurveError::ToAffineConversion)?.precompute()); 630 | qs.push(q.0.to_affine().ok_or(CurveError::ToAffineConversion)?); 631 | } 632 | Ok(Gt(groups::miller_loop_batch(&ps, &qs))) 633 | } 634 | 635 | #[derive(Copy, Clone, PartialEq, Eq)] 636 | #[repr(C)] 637 | pub struct AffineG2(groups::AffineG2); 638 | 639 | impl AffineG2 { 640 | pub fn new(x: Fq2, y: Fq2) -> Result { 641 | Ok(AffineG2(groups::AffineG2::new(x.0, y.0)?)) 642 | } 643 | 644 | pub fn x(&self) -> Fq2 { 645 | Fq2(self.0.x().clone()) 646 | } 647 | 648 | pub fn set_x(&mut self, x: Fq2) { 649 | *self.0.x_mut() = x.0 650 | } 651 | 652 | pub fn y(&self) -> Fq2 { 653 | Fq2(self.0.y().clone()) 654 | } 655 | 656 | pub fn set_y(&mut self, y: Fq2) { 657 | *self.0.y_mut() = y.0 658 | } 659 | 660 | pub fn from_jacobian(g2: G2) -> Option { 661 | g2.0.to_affine().map(|x| AffineG2(x)) 662 | } 663 | } 664 | 665 | impl From for G2 { 666 | fn from(affine: AffineG2) -> Self { 667 | G2(affine.0.to_jacobian()) 668 | } 669 | } 670 | 671 | #[cfg(test)] 672 | mod tests { 673 | use alloc::vec::Vec; 674 | use super::{G1, Fq, G2, Fq2}; 675 | 676 | fn hex(s: &'static str) -> Vec { 677 | use rustc_hex::FromHex; 678 | s.from_hex().unwrap() 679 | } 680 | 681 | #[test] 682 | fn g1_from_compressed() { 683 | let g1 = G1::from_compressed(&hex("0230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46")) 684 | .expect("Invalid g1 decompress result"); 685 | assert_eq!(g1.x(), Fq::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208582").unwrap()); 686 | assert_eq!(g1.y(), Fq::from_str("3969792565221544645472939191694882283483352126195956956354061729942568608776").unwrap()); 687 | assert_eq!(g1.z(), Fq::one()); 688 | } 689 | 690 | 691 | #[test] 692 | fn g2_from_compressed() { 693 | let g2 = G2::from_compressed( 694 | &hex("0a023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a") 695 | ).expect("Valid g2 point hex encoding"); 696 | 697 | assert_eq!(g2.x(), 698 | Fq2::new( 699 | Fq::from_str("5923585509243758863255447226263146374209884951848029582715967108651637186684").unwrap(), 700 | Fq::from_str("5336385337059958111259504403491065820971993066694750945459110579338490853570").unwrap(), 701 | ) 702 | ); 703 | 704 | assert_eq!(g2.y(), 705 | Fq2::new( 706 | Fq::from_str("10374495865873200088116930399159835104695426846400310764827677226300185211748").unwrap(), 707 | Fq::from_str("5256529835065685814318509161957442385362539991735248614869838648137856366932").unwrap(), 708 | ) 709 | ); 710 | 711 | // 0b prefix is point reflection on the curve 712 | let g2 = -G2::from_compressed( 713 | &hex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a") 714 | ).expect("Valid g2 point hex encoding"); 715 | 716 | assert_eq!(g2.x(), 717 | Fq2::new( 718 | Fq::from_str("5923585509243758863255447226263146374209884951848029582715967108651637186684").unwrap(), 719 | Fq::from_str("5336385337059958111259504403491065820971993066694750945459110579338490853570").unwrap(), 720 | ) 721 | ); 722 | 723 | assert_eq!(g2.y(), 724 | Fq2::new( 725 | Fq::from_str("10374495865873200088116930399159835104695426846400310764827677226300185211748").unwrap(), 726 | Fq::from_str("5256529835065685814318509161957442385362539991735248614869838648137856366932").unwrap(), 727 | ) 728 | ); 729 | 730 | // valid point but invalid sign prefix 731 | assert!( 732 | G2::from_compressed( 733 | &hex("0c023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a") 734 | ).is_err() 735 | ); 736 | } 737 | } 738 | --------------------------------------------------------------------------------