1use core::{
2 cmp,
3 fmt::Debug,
4 iter::Sum,
5 ops::{Add, Mul, Neg, Sub},
6};
7use std::convert::TryInto;
8
9use rand::RngCore;
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
11
12use crate::{
13 arithmetic::{mul_512, sbb, CurveEndo, EndoParameters},
14 bn256::{Fq, Fq2, Fr},
15 endo,
16 ff::{Field, PrimeField, WithSmallOrderMulGroup},
17 group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding},
18 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
19 impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt,
20};
21
22impl crate::serde::endian::EndianRepr for Fq2 {
23 const ENDIAN: crate::serde::endian::Endian = Fq::ENDIAN;
24
25 fn to_bytes(&self) -> Vec<u8> {
26 self.to_bytes().to_vec()
27 }
28
29 fn from_bytes(bytes: &[u8]) -> subtle::CtOption<Self> {
30 Fq2::from_bytes(bytes[..Fq2::SIZE].try_into().unwrap())
31 }
32}
33
34new_curve_impl!(
35 (pub),
36 G1,
37 G1Affine,
38 Fq,
39 Fr,
40 (G1_GENERATOR_X,G1_GENERATOR_Y),
41 G1_A,
42 G1_B,
43 "bn256_g1",
44 |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, G1::default_hash_to_curve_suite()),
45 crate::serde::CompressedFlagConfig::TwoSpare,
46 standard_sign
47);
48
49new_curve_impl!(
50 (pub),
51 G2,
52 G2Affine,
53 Fq2,
54 Fr,
55 (G2_GENERATOR_X, G2_GENERATOR_Y),
56 G2_A,
57 G2_B,
58 "bn256_g2",
59 |domain_prefix| hash_to_curve_g2(domain_prefix),
60 crate::serde::CompressedFlagConfig::TwoSpare,
61 standard_sign
62);
63
64#[allow(clippy::type_complexity)]
65pub(crate) fn hash_to_curve_g2<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> G2 + 'a> {
66 let suite = G2::default_hash_to_curve_suite();
67 Box::new(move |message| {
68 let r0 = suite.hash_to_curve(domain_prefix, message);
69 r0.clear_cofactor()
70 })
71}
72
73const G1_GENERATOR_X: Fq = Fq::ONE;
74const G1_GENERATOR_Y: Fq = Fq::from_raw([2, 0, 0, 0]);
75const G1_A: Fq = Fq::ZERO;
76const G1_B: Fq = Fq::from_raw([3, 0, 0, 0]);
77
78const G2_A: Fq2 = Fq2 {
79 c0: Fq::ZERO,
80 c1: Fq::ZERO,
81};
82
83const G2_B: Fq2 = Fq2 {
84 c0: Fq::from_raw([
85 0x3267e6dc24a138e5,
86 0xb5b4c5e559dbefa3,
87 0x81be18991be06ac3,
88 0x2b149d40ceb8aaae,
89 ]),
90 c1: Fq::from_raw([
91 0xe4a2bd0685c315d2,
92 0xa74fa084e52d1852,
93 0xcd2cafadeed8fdf4,
94 0x009713b03af0fed4,
95 ]),
96};
97
98const G2_GENERATOR_X: Fq2 = Fq2 {
99 c0: Fq::from_raw([
100 0x46debd5cd992f6ed,
101 0x674322d4f75edadd,
102 0x426a00665e5c4479,
103 0x1800deef121f1e76,
104 ]),
105 c1: Fq::from_raw([
106 0x97e485b7aef312c2,
107 0xf1aa493335a9e712,
108 0x7260bfb731fb5d25,
109 0x198e9393920d483a,
110 ]),
111};
112
113const G2_GENERATOR_Y: Fq2 = Fq2 {
114 c0: Fq::from_raw([
115 0x4ce6cc0166fa7daa,
116 0xe3d1e7690c43d37b,
117 0x4aab71808dcb408f,
118 0x12c85ea5db8c6deb,
119 ]),
120
121 c1: Fq::from_raw([
122 0x55acdadcd122975b,
123 0xbc4b313370b38ef3,
124 0xec9e99ad690c3395,
125 0x090689d0585ff075,
126 ]),
127};
128
129const ENDO_PARAMS_BN: EndoParameters = EndoParameters {
134 gamma1: [0xd91d232ec7e0b3d7, 0x2, 0, 0],
136 gamma2: [0x5398fd0300ff6565, 0x4ccef014a773d2d2, 0x02, 0],
138 b1: [0x89d3256894d213e3, 0, 0, 0],
139 b2: [0x0be4e1541221250b, 0x6f4d8248eeb859fd, 0, 0],
140};
141
142endo!(G1, Fr, ENDO_PARAMS_BN);
143
144impl group::cofactor::CofactorGroup for G1 {
145 type Subgroup = G1;
146
147 fn clear_cofactor(&self) -> Self {
148 *self
149 }
150
151 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
152 CtOption::new(self, 1.into())
153 }
154
155 fn is_torsion_free(&self) -> Choice {
156 1.into()
157 }
158}
159
160fn exp_by_x(g2: &G2) -> G2 {
161 let x = super::BN_X;
162
163 (0..62).rev().fold(*g2, |mut acc, i| {
164 println!("{}", ((x >> i) & 1) == 1);
165
166 acc = acc.double();
167 (((x >> i) & 1) == 1).then(|| acc += g2);
168 acc
169 })
170}
171
172fn psi(mut g2: G2) -> G2 {
173 const U0: Fq = Fq::from_raw([
174 0x99e39557176f553d,
175 0xb78cc310c2c3330c,
176 0x4c0bec3cf559b143,
177 0x2fb347984f7911f7,
178 ]);
179
180 const U1: Fq = Fq::from_raw([
181 0x1665d51c640fcba2,
182 0x32ae2a1d0b7c9dce,
183 0x4ba4cc8bd75a0794,
184 0x16c9e55061ebae20,
185 ]);
186 let u = Fq2::new(U0, U1);
187
188 const V0: Fq = Fq::from_raw([
189 0xdc54014671a0135a,
190 0xdbaae0eda9c95998,
191 0xdc5ec698b6e2f9b9,
192 0x063cf305489af5dc,
193 ]);
194
195 const V1: Fq = Fq::from_raw([
196 0x82d37f632623b0e3,
197 0x21807dc98fa25bd2,
198 0x0704b5a7ec796f2b,
199 0x07c03cbcac41049a,
200 ]);
201 let v = Fq2::new(V0, V1);
202
203 g2.x.conjugate();
204 g2.y.conjugate();
205 g2.z.conjugate();
206
207 g2.x *= u;
208 g2.y *= v;
209
210 g2
211}
212
213impl CofactorGroup for G2 {
214 type Subgroup = G2;
215
216 fn clear_cofactor(&self) -> Self {
217 let u0 = exp_by_x(self);
218 let u1 = psi(u0.double() + u0);
219 let u2 = psi(psi(u0));
220 let u3 = psi(psi(psi(*self)));
221 u0 + u1 + u2 + u3
222 }
223
224 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
225 unimplemented!();
226 }
227
228 fn is_torsion_free(&self) -> Choice {
229 let u = exp_by_x(self);
230 let pu = psi(u);
231 let ppu = psi(pu);
232 let pppu = psi(ppu);
233 (ppu + pu + u + self - pppu.double()).is_identity()
234 }
235}
236
237impl G1 {
238 const SVDW_Z: Fq = Fq::ONE;
239
240 fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 48> {
241 crate::hash_to_curve::Suite::<G1, sha2::Sha256, 48>::new(
242 b"BN254G1_XMD:SHA-256_SVDW_RO_",
243 Self::SVDW_Z,
244 crate::hash_to_curve::Method::SVDW,
245 )
246 }
247}
248
249impl G2 {
250 const SVDW_Z: Fq2 = Fq2::ONE;
251
252 fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite<Self, sha2::Sha256, 96> {
253 crate::hash_to_curve::Suite::<G2, sha2::Sha256, 96>::new(
254 b"BN254G2_XMD:SHA-256_SVDW_RO_",
255 Self::SVDW_Z,
256 crate::hash_to_curve::Method::SVDW,
257 )
258 }
259}
260
261#[cfg(test)]
262mod test {
263 use group::UncompressedEncoding;
264 use rand_core::OsRng;
265
266 use super::*;
267 use crate::{serde::SerdeObject, tests::curve::TestH2C};
268
269 crate::curve_testing_suite!(G2, "clear_cofactor");
270 crate::curve_testing_suite!(G1, G2);
271 crate::curve_testing_suite!(G1, "endo_consistency");
272 crate::curve_testing_suite!(
273 G1,
274 "endo",
275 [
278 0x8b17ea66b99c90dd,
279 0x5bfc41088d8daaa7,
280 0xb3c4d79d41a91758,
281 0x00,
282 ]
283 );
284
285 crate::curve_testing_suite!(
286 G1,
287 "constants",
288 Fq::MODULUS,
289 G1_A,
290 G1_B,
291 G1_GENERATOR_X,
292 G1_GENERATOR_Y,
293 Fr::MODULUS
294 );
295
296 crate::curve_testing_suite!(
297 G2,
298 "constants",
299 Fq2::MODULUS,
300 G2_A,
301 G2_B,
302 G2_GENERATOR_X,
303 G2_GENERATOR_Y,
304 Fr::MODULUS
305 );
306
307 #[test]
308 fn test_hash_to_curve_g1() {
309 [
311 TestH2C::<G1Affine>::new(
312 b"",
313 crate::tests::point_from_hex(
314 "0a976ab906170db1f9638d376514dbf8c42aef256a54bbd48521f20749e59e86",
315 "02925ead66b9e68bfc309b014398640ab55f6619ab59bc1fab2210ad4c4d53d5",
316 ),
317 ),
318 TestH2C::<G1Affine>::new(
319 b"abc",
320 crate::tests::point_from_hex(
321 "23f717bee89b1003957139f193e6be7da1df5f1374b26a4643b0378b5baf53d1",
322 "04142f826b71ee574452dbc47e05bc3e1a647478403a7ba38b7b93948f4e151d",
323 ),
324 ),
325 TestH2C::<G1Affine>::new(
326 b"abcdef0123456789",
327 crate::tests::point_from_hex(
328 "187dbf1c3c89aceceef254d6548d7163fdfa43084145f92c4c91c85c21442d4a",
329 "0abd99d5b0000910b56058f9cc3b0ab0a22d47cf27615f588924fac1e5c63b4d",
330 ),
331 ),
332 TestH2C::<G1Affine>::new(
333 b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
334 crate::tests::point_from_hex(
335 "00fe2b0743575324fc452d590d217390ad48e5a16cf051bee5c40a2eba233f5c",
336 "0794211e0cc72d3cbbdf8e4e5cd6e7d7e78d101ff94862caae8acbe63e9fdc78",
337 ),
338 ),
339 TestH2C::<G1Affine>::new(
340 b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
341 crate::tests::point_from_hex(
342 "01b05dc540bd79fd0fea4fbb07de08e94fc2e7bd171fe025c479dc212a2173ce",
343 "1bf028afc00c0f843d113758968f580640541728cfc6d32ced9779aa613cd9b0",
344 ),
345 ),
346 ].iter().for_each(|test| {
347 test.run("QUUX-V01-CS02-with-");
348 });
349 }
350
351 #[test]
352 fn test_hash_to_curve_g2() {
353 pub(crate) fn point_from_hex(x0: &str, x1: &str, y0: &str, y1: &str) -> G2Affine {
354 let x0: Fq = crate::tests::hex_to_field(x0);
355 let x1: Fq = crate::tests::hex_to_field(x1);
356 let x = Fq2 { c0: x0, c1: x1 };
357 let y0: Fq = crate::tests::hex_to_field(y0);
358 let y1: Fq = crate::tests::hex_to_field(y1);
359 let y = Fq2 { c0: y0, c1: y1 };
360 G2Affine::from_xy(x, y).unwrap()
361 }
362
363 [
365 TestH2C::<G2Affine>::new(
366 b"",
367 point_from_hex(
368 "1192005a0f121921a6d5629946199e4b27ff8ee4d6dd4f9581dc550ade851300",
369 "1747d950a6f23c16156e2171bce95d1189b04148ad12628869ed21c96a8c9335",
370 "0498f6bb5ac309a07d9a8b88e6ff4b8de0d5f27a075830e1eb0e68ea318201d8",
371 "2c9755350ca363ef2cf541005437221c5740086c2e909b71d075152484e845f4",
372 ),
373 ),
374 TestH2C::<G2Affine>::new(
375 b"abc",
376 point_from_hex(
377 "16c88b54eec9af86a41569608cd0f60aab43464e52ce7e6e298bf584b94fccd2",
378 "0b5db3ca7e8ef5edf3a33dfc3242357fbccead98099c3eb564b3d9d13cba4efd",
379 "1c42ba524cb74db8e2c680449746c028f7bea923f245e69f89256af2d6c5f3ac",
380 "22d02d2da7f288545ff8789e789902245ab08c6b1d253561eec789ec2c1bd630",
381 ),
382 ),
383 TestH2C::<G2Affine>::new(
384 b"abcdef0123456789",
385 point_from_hex(
386 "1435fd84aa43c699230e371f6fea3545ce7e053cbbb06a320296a2b81efddc70",
387 "2a8a360585b6b05996ef69c3c09b2c6fb17afe2b1e944f07559c53178eabf171",
388 "2820188dcdc13ffdca31694942418afa1d6dfaaf259d012fab4da52b0f592e38",
389 "142f08e2441ec431defc24621b73cfe0252d19b243cb55b84bdeb85de039207a",
390 ),
391 ),
392 TestH2C::<G2Affine>::new(
393 b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
394 point_from_hex(
395 "2cffc213fb63d00d923cb22cda5a2904837bb93a2fe6e875c532c51744388341",
396 "2718ef38d1bc4347f0266c774c8ef4ee5fa7056cc27a4bd7ecf7a888efb95b26",
397 "232553f728341afa64ce66d00535764557a052e38657594e10074ad28728c584",
398 "2206ec0a9288f31ed78531c37295df3b56c42a1284443ee9893adb1521779001",
399 ),
400 ),
401 TestH2C::<G2Affine>::new(
402 b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
403 point_from_hex(
404 "242a0a159f36f87065e7c5170426012087023165ce47a486e53d6e2845ca625a",
405 "17f9f6292998cf18ccc155903c1fe6b6465d40c794a3e1ed644a4182ad639f4a",
406 "2dc5b7b65c9c79e6ef4afab8fbe3083c66d4ce31c78f6621ece17ecc892cf4b3",
407 "18ef4886c818f01fdf309bc9a46dd904273917f85e74ecd0de62460a68122037",
408 ),
409 ),
410 ].iter().for_each(|test| {
411 test.run("QUUX-V01-CS02-with-");
412 });
413 }
414}