1#![allow(dead_code)]
2
3use core::{
4 fmt,
5 ops::{Add, AddAssign, Mul, Neg, Sub},
6};
7use hex_literal::hex;
8use rand::Rng;
9
10use crate::{
11 One, Zero,
12 fields::{FieldElement, Fq, Fq2, Fr},
13 u256::U256,
14};
15
16const SM9_P1X: [u8; 32] =
17 hex!("93DE051D 62BF718F F5ED0704 487D01D6 E1E40869 09DC3280 E8C4E481 7C66DDDD");
18const SM9_P1Y: [u8; 32] =
19 hex!("21FE8DDA 4F21E607 63106512 5C395BBC 1C1C00CB FA602435 0C464CD7 0A3EA616");
20const SM9_P2X1: [u8; 32] =
21 hex!("85AEF3D0 78640C98 597B6027 B441A01F F1DD2C19 0F5E93C4 54806C11 D8806141");
22const SM9_P2X0: [u8; 32] =
23 hex!("37227552 92130B08 D2AAB97F D34EC120 EE265948 D19C17AB F9B7213B AF82D65B");
24const SM9_P2Y1: [u8; 32] =
25 hex!("17509B09 2E845C12 66BA0D26 2CBEE6ED 0736A96F A347C8BD 856DC76B 84EBEB96");
26const SM9_P2Y0: [u8; 32] =
27 hex!("A7CF28D5 19BE3DA6 5F317015 3D278FF2 47EFBA98 A71A0811 6215BBA5 C999A7C7");
28
29pub trait GroupElement:
30 Sized
31 + Copy
32 + Clone
33 + Zero
34 + PartialEq
35 + Eq
36 + fmt::Debug
37 + Add<Output = Self>
38 + Sub<Output = Self>
39 + Neg<Output = Self>
40 + Mul<Fr, Output = Self>
41{
42 fn one() -> Self;
43 fn random<R: Rng>(rng: &mut R) -> Self;
44 fn double(&self) -> Self;
45}
46
47pub trait GroupParams: Sized + fmt::Debug {
48 type Base: FieldElement;
49
50 fn name() -> &'static str;
51 fn one() -> G<Self>;
52 fn coeff_b() -> Self::Base;
53 fn check_order() -> bool {
54 false
55 }
56}
57
58#[repr(C)]
59pub struct G<P: GroupParams> {
60 pub(crate) x: P::Base,
61 pub(crate) y: P::Base,
62 pub(crate) z: P::Base,
63}
64
65impl<P: GroupParams> G<P> {
66 pub fn new(x: P::Base, y: P::Base, z: P::Base) -> Self {
67 G { x, y, z }
68 }
69
70 pub fn x(&self) -> &P::Base {
71 &self.x
72 }
73
74 pub fn x_mut(&mut self) -> &mut P::Base {
75 &mut self.x
76 }
77
78 pub fn y(&self) -> &P::Base {
79 &self.y
80 }
81
82 pub fn y_mut(&mut self) -> &mut P::Base {
83 &mut self.y
84 }
85
86 pub fn z(&self) -> &P::Base {
87 &self.z
88 }
89
90 pub fn z_mut(&mut self) -> &mut P::Base {
91 &mut self.z
92 }
93}
94
95#[derive(Debug)]
96pub struct AffineG<P: GroupParams> {
97 x: P::Base,
98 y: P::Base,
99}
100
101#[derive(Debug)]
102pub enum Error {
103 NotOnCurve,
104 NotInSubgroup,
105}
106
107impl<P: GroupParams> AffineG<P> {
108 pub fn new(x: P::Base, y: P::Base) -> Result<Self, Error> {
109 if y.squared() == (x.squared() * x) + P::coeff_b() {
110 if P::check_order() {
111 let p: G<P> = G {
112 x,
113 y,
114 z: P::Base::one(),
115 };
116
117 if (p * (-Fr::one())) + p != G::zero() {
118 return Err(Error::NotInSubgroup);
119 }
120 }
121
122 Ok(AffineG { x, y })
123 } else {
124 Err(Error::NotOnCurve)
125 }
126 }
127
128 pub fn x(&self) -> &P::Base {
129 &self.x
130 }
131
132 pub fn x_mut(&mut self) -> &mut P::Base {
133 &mut self.x
134 }
135
136 pub fn y(&self) -> &P::Base {
137 &self.y
138 }
139
140 pub fn y_mut(&mut self) -> &mut P::Base {
141 &mut self.y
142 }
143}
144
145impl<P: GroupParams> PartialEq for AffineG<P> {
146 fn eq(&self, other: &Self) -> bool {
147 self.x == other.x && self.y == other.y
148 }
149}
150
151impl<P: GroupParams> Eq for AffineG<P> {}
152
153impl<P: GroupParams> fmt::Debug for G<P> {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z)
156 }
157}
158
159impl<P: GroupParams> Clone for G<P> {
160 fn clone(&self) -> Self {
161 *self
162 }
163}
164
165impl<P: GroupParams> Copy for G<P> {}
166
167impl<P: GroupParams> Clone for AffineG<P> {
168 fn clone(&self) -> Self {
169 *self
170 }
171}
172
173impl<P: GroupParams> Copy for AffineG<P> {}
174
175impl<P: GroupParams> PartialEq for G<P> {
176 fn eq(&self, other: &Self) -> bool {
177 if self.is_zero() {
178 return other.is_zero();
179 }
180
181 if other.is_zero() {
182 return false;
183 }
184
185 let z1_squared = self.z.squared();
186 let z2_squared = other.z.squared();
187
188 if self.x * z2_squared != other.x * z1_squared {
189 return false;
190 }
191
192 let z1_cubed = self.z * z1_squared;
193 let z2_cubed = other.z * z2_squared;
194
195 if self.y * z2_cubed != other.y * z1_cubed {
196 return false;
197 }
198
199 true
200 }
201}
202impl<P: GroupParams> Eq for G<P> {}
203
204impl<P: GroupParams> G<P> {
205 pub fn to_affine(self) -> Option<AffineG<P>> {
206 if self.z.is_zero() {
207 None
208 } else if self.z == P::Base::one() {
209 Some(AffineG {
210 x: self.x,
211 y: self.y,
212 })
213 } else {
214 let zinv = self.z.inverse()?;
215 let zinv_squared = zinv.squared();
216
217 Some(AffineG {
218 x: self.x * zinv_squared,
219 y: self.y * (zinv_squared * zinv),
220 })
221 }
222 }
223}
224
225impl<P: GroupParams> AffineG<P> {
226 pub fn to_jacobian(self) -> G<P> {
227 G {
228 x: self.x,
229 y: self.y,
230 z: P::Base::one(),
231 }
232 }
233}
234
235impl<P: GroupParams> Zero for G<P> {
236 fn zero() -> Self {
237 G {
238 x: P::Base::zero(),
239 y: P::Base::one(),
240 z: P::Base::zero(),
241 }
242 }
243
244 fn is_zero(&self) -> bool {
245 self.z.is_zero()
246 }
247}
248
249impl<P: GroupParams> GroupElement for G<P> {
250 fn one() -> Self {
251 P::one()
252 }
253
254 fn random<R: Rng>(rng: &mut R) -> Self {
255 P::one() * Fr::random(rng)
256 }
257
258 fn double(&self) -> Self {
264 let a = self.x.squared();
265 let b = self.y.squared();
266 let c = b.squared();
267 let d = ((self.x + b).squared() - a - c).double();
268 let e = a.triple();
269 let f = e.squared();
270 let x3 = f - d.double();
271 let eight_c = c.double().double().double();
272 let y1z1 = self.y * self.z;
273
274 G {
275 x: x3,
276 y: e * (d - x3) - eight_c,
277 z: y1z1.double(),
278 }
279 }
280}
281impl<P: GroupParams> Mul<Fr> for G<P> {
282 type Output = G<P>;
283 #[allow(clippy::suspicious_arithmetic_impl)]
284 fn mul(self, other: Fr) -> G<P> {
286 let mut res = G::zero();
287 for i in U256::from(other).bits_without_leading_zeros() {
288 res = res.double();
289 if i {
290 res += self;
291 }
292 }
293
294 res
295 }
296}
297impl<P: GroupParams> AddAssign<G<P>> for G<P> {
298 fn add_assign(&mut self, other: G<P>) {
299 *self = *self + other;
300 }
301}
302impl<P: GroupParams> AddAssign<&G<P>> for G<P> {
303 fn add_assign(&mut self, rhs: &G<P>) {
304 *self = *self + rhs;
305 }
306}
307impl<P: GroupParams> Add<G<P>> for G<P> {
308 type Output = G<P>;
309 fn add(self, other: G<P>) -> G<P> {
316 if self.is_zero() {
317 return other;
318 }
319 if other.is_zero() {
320 return self;
321 }
322 match (self.z == P::Base::one(), other.z == P::Base::one()) {
323 (true, true) => {
324 let h = other.x - self.x;
325 let r = other.y - self.y;
326 if r.is_zero() && h.is_zero() {
327 return self.double();
328 }
329 let hh = h.squared();
330 let hhh = h * hh;
331 let v = self.x * hh;
332 let x = r.squared() - hhh - v.double();
333 let y = r * (v - x) - self.y * hhh;
334 let z = h;
335 G { x, y, z }
336 }
337 (false, true) => {
338 let z1_squared = self.z.squared();
339 let u2 = other.x * z1_squared;
340 let z1_cubed = self.z * z1_squared;
341 let s2 = other.y * z1_cubed;
342 let h = u2 - self.x;
343 let r = s2 - self.y;
344 if r.is_zero() && h.is_zero() {
345 return self.double();
346 }
347 let hh = h.squared();
348 let hhh = h * hh;
349 let v = self.x * hh;
350 let x = r.squared() - hhh - v.double();
351 let y = r * (v - x) - self.y * hhh;
352 let z = self.z * h;
353 G { x, y, z }
354 }
355 (true, false) => other + self,
356 (false, false) => {
357 let z1_squared = self.z.squared();
358 let z2_squared = other.z.squared();
359 let u1 = self.x * z2_squared;
360 let u2 = other.x * z1_squared;
361 let z1_cubed = self.z * z1_squared;
362 let z2_cubed = other.z * z2_squared;
363 let s1 = self.y * z2_cubed;
364 let s2 = other.y * z1_cubed;
365
366 let r = s2 - s1;
367 let h = u2 - u1;
368 let t6 = s1 + s2;
369 if r.is_zero() {
370 if h.is_zero() {
371 return self.double();
372 }
373 if t6.is_zero() {
374 return Self::zero();
375 }
376 }
377 let hh = h.squared();
378 let hhh = h * hh;
379 let v = u1 * hh;
380 let x = r.squared() - hhh - v.double();
381 let y = r * (v - x) - s1 * hhh;
382 let z = self.z * other.z * h;
383 G { x, y, z }
384 }
385 }
386 }
387}
388impl<P: GroupParams> Add<&G<P>> for G<P> {
389 type Output = G<P>;
390
391 fn add(self, rhs: &G<P>) -> Self::Output {
392 self + *rhs
393 }
394}
395impl<P: GroupParams> Add<G<P>> for &G<P> {
396 type Output = G<P>;
397
398 fn add(self, rhs: G<P>) -> Self::Output {
399 *self + rhs
400 }
401}
402
403impl<P: GroupParams> Neg for G<P> {
404 type Output = G<P>;
405
406 fn neg(self) -> G<P> {
407 if self.is_zero() {
408 self
409 } else {
410 G {
411 x: self.x,
412 y: -self.y,
413 z: self.z,
414 }
415 }
416 }
417}
418
419impl<P: GroupParams> Neg for AffineG<P> {
420 type Output = AffineG<P>;
421
422 fn neg(self) -> AffineG<P> {
423 AffineG {
424 x: self.x,
425 y: -self.y,
426 }
427 }
428}
429
430impl<P: GroupParams> Sub<G<P>> for G<P> {
431 type Output = G<P>;
432
433 fn sub(self, other: G<P>) -> G<P> {
434 self + (-other)
435 }
436}
437
438#[derive(Debug)]
439pub struct G1Params;
440
441impl GroupParams for G1Params {
442 type Base = Fq;
443
444 fn name() -> &'static str {
445 "G1"
446 }
447 fn one() -> G<Self> {
449 G {
450 x: Fq::from_slice(&SM9_P1X).unwrap(),
451 y: Fq::from_slice(&SM9_P1Y).unwrap(),
452 z: Fq::one(),
453 }
454 }
455
456 fn coeff_b() -> Fq {
457 Fq::from_str("5").expect("5 is a valid field element")
458 }
459}
460
461pub type G1 = G<G1Params>;
462
463pub type AffineG1 = AffineG<G1Params>;
464
465#[derive(Debug)]
466pub struct G2Params;
467
468impl GroupParams for G2Params {
469 type Base = Fq2;
470
471 fn name() -> &'static str {
472 "G2"
473 }
474 fn one() -> G<Self> {
476 G {
477 x: Fq2::new(
478 Fq::from_slice(&SM9_P2X0).unwrap(),
479 Fq::from_slice(&SM9_P2X1).unwrap(),
480 ),
481 y: Fq2::new(
482 Fq::from_slice(&SM9_P2Y0).unwrap(),
483 Fq::from_slice(&SM9_P2Y1).unwrap(),
484 ),
485 z: Fq2::one(),
486 }
487 }
488
489 fn coeff_b() -> Fq2 {
490 Fq2::i().scale(&Fq::from_str("5").expect("5 is a valid field element"))
491 }
492
493 fn check_order() -> bool {
494 true
495 }
496}
497
498pub type G2 = G<G2Params>;
499
500pub type AffineG2 = AffineG<G2Params>;
501
502#[cfg(test)]
504mod tests {
505 use super::*;
506
507 fn random_test_addition<G: GroupElement, R: Rng>(rng: &mut R) {
508 for _ in 0..50 {
509 let r1 = G::random(rng);
510 let r2 = G::random(rng);
511 let r3 = G::random(rng);
512
513 assert_eq!((r1 + r2) + r3, r1 + (r2 + r3));
514 assert!(((r1 + r2 + r3) - r2 - r3 - r1).is_zero());
515 }
516 }
517 fn random_test_doubling<G: GroupElement, R: Rng>(rng: &mut R) {
518 for _ in 0..50 {
519 let r1 = G::random(rng);
520 let r2 = G::random(rng);
521 let ti = Fr::from_str("2").unwrap().inverse().unwrap();
522
523 assert_eq!((r1 + r2) + r1, r1.double() + r2);
524 assert_eq!(r1, r1.double() * ti);
525 }
526 }
527 pub fn group_trials<G: GroupElement>() {
528 assert!(G::zero().is_zero());
529 assert!((G::one() - G::one()).is_zero());
530 assert_eq!(G::one() + G::one(), G::one() * Fr::from_str("2").unwrap());
531 assert!(G::zero().double().is_zero());
532
533 assert!((G::one() * (-Fr::one()) + G::one()).is_zero());
534 use rand::{SeedableRng, rngs::StdRng};
535 let seed = [
536 0, 0, 0, 0, 0, 0, 64, 13, 0, 0, 0, 0, 0, 0, 176, 2, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 96, 7u8, ];
541 let mut rng = StdRng::from_seed(seed);
542
543 random_test_addition::<G, _>(&mut rng);
544 random_test_doubling::<G, _>(&mut rng);
545 }
546
547 fn test_projective_negation_and_subtraction<G: GroupElement>() {
548 let a = G::one().double();
549 assert_eq!(a + (-a), G::zero());
550 assert_eq!(a + (-a), a - a);
551 }
552
553 fn test_projective_double_and_add<G: GroupElement>() {
554 let a = G::one().double().double(); let b = G::one().double(); let c = a + b; let mut d = G::one();
559 for _ in 0..5 {
560 d = d + G::one();
561 }
562 assert_eq!(c, d);
563 }
564
565 #[test]
566 fn test_g1_negation_and_subtraction() {
567 test_projective_negation_and_subtraction::<G1>();
568 }
569 #[test]
570 fn test_g2_negation_and_subtraction() {
571 test_projective_negation_and_subtraction::<G2>();
572 }
573
574 #[test]
575 fn test_g1() {
576 group_trials::<G1>();
577 }
578
579 const P1X: [u8; 32] = hex!("917be49d159184fba140f4dfc5d653464e94f718fe195b226b3f715829e6e768");
580 const P1Y: [u8; 32] = hex!("288578d9505d462867a50acee40ee143b896e72505be10e8ce4c6b0c945b642b");
581 const P2X: [u8; 32] = hex!("593417680f252445fd0522383e23c77a54b11fe222de4a886eabc26e16bffa3c");
582 const P2Y: [u8; 32] = hex!("38e8fc9a8b60f5ba0c6c411f721c117044435a833757d8fee65828511b8b245d");
583
584 const P_DBL_X: [u8; 32] =
585 hex!("268def7968f1e8c51635e277425403df88355fb2ecf16f7920f112eb2a7e50c9");
586 const P_DBL_Y: [u8; 32] =
587 hex!("5c596b534bbaa85c1d3aecf436e61ff1bfd9f70856f0309c2a63d8248205d84e");
588 const P_ADD_X: [u8; 32] =
589 hex!("056610cb69f8d5659ea94e4a67bbf3b93fb0bd449672d7ca2525ec3b68c894d1");
590 const P_ADD_Y: [u8; 32] =
591 hex!("88f3f99ce78ed3ffe6ca1cface5242570cb5d053f16a8e0baae10414babd86a7");
592 const P_NEG_X: [u8; 32] =
593 hex!("917be49d159184fba140f4dfc5d653464e94f718fe195b226b3f715829e6e768");
594 const P_NEG_Y: [u8; 32] =
595 hex!("8dba8726b24660c96e5ea081117fe601695bac2614bcddf31723301b4ef5e152");
596 const P_SUB_X: [u8; 32] =
597 hex!("29e4a54cad98da9939b95f677784bff3b1dd9334c83d93e351e0f8f7c4ce2dc5");
598 const P_SUB_Y: [u8; 32] =
599 hex!("4473eba3b8ff990b8456c41ec0727b76cb2b0f960495b144949f70bf95643b82");
600 const P_MUL_X: [u8; 32] =
601 hex!("997fcff625adbae62566f684f9e89181713f972c5a9cd9ce6764636761ba87d1");
602 const P_MUL_Y: [u8; 32] =
603 hex!("8142a28d1bd109501452a649e2d68f012e265460e0c7d3da743fb036eb23b03b");
604
605 const HEX_IV: [u8; 32] =
606 hex!("123456789abcdef00fedcba987654321123456789abcdef00fedcba987654321");
607
608 #[test]
609 fn test_g1_dbl() {
610 let p1 = G1::new(
611 Fq::from_slice(&P1X).unwrap(),
612 Fq::from_slice(&P1Y).unwrap(),
613 Fq::one(),
614 );
615 let r = G1::new(
616 Fq::from_slice(&P_DBL_X).unwrap(),
617 Fq::from_slice(&P_DBL_Y).unwrap(),
618 Fq::one(),
619 );
620 assert_eq!(r, p1.double());
621 }
622
623 #[test]
624 fn test_g1_add() {
625 let p1 = G1::new(
626 Fq::from_slice(&P1X).unwrap(),
627 Fq::from_slice(&P1Y).unwrap(),
628 Fq::one(),
629 );
630 let p2 = G1::new(
631 Fq::from_slice(&P2X).unwrap(),
632 Fq::from_slice(&P2Y).unwrap(),
633 Fq::one(),
634 );
635 let r = G1::new(
636 Fq::from_slice(&P_ADD_X).unwrap(),
637 Fq::from_slice(&P_ADD_Y).unwrap(),
638 Fq::one(),
639 );
640 assert_eq!(r, p1 + p2);
641 test_projective_double_and_add::<G1>();
642 }
643
644 #[test]
645 fn test_g1_sub() {
646 let p1 = G1::new(
647 Fq::from_slice(&P1X).unwrap(),
648 Fq::from_slice(&P1Y).unwrap(),
649 Fq::one(),
650 );
651 let p2 = G1::new(
652 Fq::from_slice(&P2X).unwrap(),
653 Fq::from_slice(&P2Y).unwrap(),
654 Fq::one(),
655 );
656 let r = G1::new(
657 Fq::from_slice(&P_NEG_X).unwrap(),
658 Fq::from_slice(&P_NEG_Y).unwrap(),
659 Fq::one(),
660 );
661 assert_eq!(r, -p1);
662 let r = G1::new(
663 Fq::from_slice(&P_SUB_X).unwrap(),
664 Fq::from_slice(&P_SUB_Y).unwrap(),
665 Fq::one(),
666 );
667 assert_eq!(r, p1 - p2);
668 }
669
670 #[test]
671 fn test_g1_mul() {
672 let p1 = G1::new(
673 Fq::from_slice(&P1X).unwrap(),
674 Fq::from_slice(&P1Y).unwrap(),
675 Fq::one(),
676 );
677 let r = G1::new(
678 Fq::from_slice(&P_MUL_X).unwrap(),
679 Fq::from_slice(&P_MUL_Y).unwrap(),
680 Fq::one(),
681 );
682 let k = Fr::from_slice(&HEX_IV).unwrap();
683 assert_eq!(r, p1 * k);
684 }
685
686 const G2_P1XY: [u8; 32] =
687 hex!("83f6a65d85d51ec72eacf19bc38384e0369eb22a134a725a0191faa6e4f192ef");
688 const G2_P1XX: [u8; 32] =
689 hex!("9a79bfd491ef1cb32d9b57f7d0590ccff6b1cfe63dd15c0823d692fafbe96dbc");
690 const G2_P1YY: [u8; 32] =
691 hex!("9ed11c499291db0454d738555af0ce8a1df960056ee7425a6bf296eae60a5037");
692 const G2_P1YX: [u8; 32] =
693 hex!("849d4434eb7113fc9fb3809b51d54064fa2f20503423d256bc044905b1eba3fb");
694
695 const G2_P2XY: [u8; 32] =
696 hex!("a36232a9713f69157b7cdceef54aa0237b3ba0642a80dbb597af8935aea2c130");
697 const G2_P2XX: [u8; 32] =
698 hex!("624b19114e49f00281e2aee1f1b9d4f0a081a135868f8bbdb7b7a7b7da5fd6bc");
699 const G2_P2YY: [u8; 32] =
700 hex!("77966917ec1c5a294dd836c34691ab5e891f8c9f017443902c0a73ec54d449d8");
701 const G2_P2YX: [u8; 32] =
702 hex!("1be45454b6fa085a53744b22fd398238e400c3e031c8796e59e1bd6222048af0");
703
704 const G2_DBLXY: [u8; 32] =
705 hex!("73cbced58a8e76ef5235b480050a74e906e4d27185bd85d7ebdcd43ad24475fd");
706 const G2_DBLXX: [u8; 32] =
707 hex!("58400f0eb23000d814f5b5d0706749a72909795b7b04f26d6d58b2cf478ad9c9");
708 const G2_DBLYY: [u8; 32] =
709 hex!("19b460e09ac9ddbb380d6441e078a47bfcaa7d4c3d60b3a6c0d05f896472dc3c");
710 const G2_DBLYX: [u8; 32] =
711 hex!("1d69f785f47d6f25cb901b131612c37edc5e89ee9ba2dac8c401ced40e340a39");
712
713 const G2_ADDXY: [u8; 32] =
714 hex!("5f443752a19e368f404b89abae20a386d2b534c424b93ededdbfd04d4c569e6b");
715 const G2_ADDXX: [u8; 32] =
716 hex!("a411bbd84ee92a6ee53e5ca9cb81bacc192c6ba406f6fdcb2b04d0ab9c42ae44");
717 const G2_ADDYY: [u8; 32] =
718 hex!("6a3dadfcaac134e8353dd3abf37d487b206ca28dfab1e0a9376649df748f1605");
719 const G2_ADDYX: [u8; 32] =
720 hex!("4fa25e5e6100a023d4923df385dd236749c6a7f8e68db55e0bd1e2263fc04d28");
721
722 const G2_MULXY: [u8; 32] =
723 hex!("5d704de3261290dbba39dbd14e6bc416025240fd1ed65ec982efed685ae41e8b");
724 const G2_MULXX: [u8; 32] =
725 hex!("705c9ca4b5ef465c4e5db80ca4880627a6d9d6bcefd4756496baba9d5eaa3304");
726 const G2_MULYY: [u8; 32] =
727 hex!("4e96eb3543aabf1e9a65cae24177b9d13b0f7fae9472145ba7ae2b14bb447aef");
728 const G2_MULYX: [u8; 32] =
729 hex!("5d7ba50d7eac49a00b18fee2069afd3cc9719993fa78271e66b7a3efed46ac8b");
730
731 const G2_MULGXY: [u8; 32] =
732 hex!("920ef6fb3a2acff52aa0c004c18feca149dfd33d98086f8f402ea9e0de303c49");
733 const G2_MULGXX: [u8; 32] =
734 hex!("1f97dd359f2b065d63e0987f5bea2f3dc865c2cc112d7d161b46b83451716fd8");
735 const G2_MULGYY: [u8; 32] =
736 hex!("614881d4d05fef3173a4990465876c5200f58c5015e13354b23ae401c20c4aef");
737 const G2_MULGYX: [u8; 32] =
738 hex!("18a22e02b7d395a49f0646a79438e79cd37c32f163fe8923c13d56bab668e8a7");
739
740 #[test]
741 fn test_g2() {
742 group_trials::<G2>();
743 }
744
745 #[test]
746 fn test_g2_dbl() {
747 let x = Fq2::new(
748 Fq::from_slice(&G2_P1XX).unwrap(),
749 Fq::from_slice(&G2_P1XY).unwrap(),
750 );
751 let y = Fq2::new(
752 Fq::from_slice(&G2_P1YX).unwrap(),
753 Fq::from_slice(&G2_P1YY).unwrap(),
754 );
755 let p1 = G2::new(x, y, Fq2::one());
756 let x = Fq2::new(
757 Fq::from_slice(&G2_DBLXX).unwrap(),
758 Fq::from_slice(&G2_DBLXY).unwrap(),
759 );
760 let y = Fq2::new(
761 Fq::from_slice(&G2_DBLYX).unwrap(),
762 Fq::from_slice(&G2_DBLYY).unwrap(),
763 );
764 let r = G2::new(x, y, Fq2::one());
765 assert_eq!(r, p1.double());
766 }
767
768 #[test]
769 fn test_g2_add() {
770 let x = Fq2::new(
771 Fq::from_slice(&G2_P1XX).unwrap(),
772 Fq::from_slice(&G2_P1XY).unwrap(),
773 );
774 let y = Fq2::new(
775 Fq::from_slice(&G2_P1YX).unwrap(),
776 Fq::from_slice(&G2_P1YY).unwrap(),
777 );
778 let p1 = G2::new(x, y, Fq2::one());
779 let x = Fq2::new(
780 Fq::from_slice(&G2_P2XX).unwrap(),
781 Fq::from_slice(&G2_P2XY).unwrap(),
782 );
783 let y = Fq2::new(
784 Fq::from_slice(&G2_P2YX).unwrap(),
785 Fq::from_slice(&G2_P2YY).unwrap(),
786 );
787 let p2 = G2::new(x, y, Fq2::one());
788 let x = Fq2::new(
789 Fq::from_slice(&G2_ADDXX).unwrap(),
790 Fq::from_slice(&G2_ADDXY).unwrap(),
791 );
792 let y = Fq2::new(
793 Fq::from_slice(&G2_ADDYX).unwrap(),
794 Fq::from_slice(&G2_ADDYY).unwrap(),
795 );
796 let r = G2::new(x, y, Fq2::one());
797 assert_eq!(r, p1 + p2);
798 test_projective_double_and_add::<G2>();
799 }
800
801 #[test]
802 fn test_g2_mul() {
803 let x = Fq2::new(
804 Fq::from_slice(&G2_P1XX).unwrap(),
805 Fq::from_slice(&G2_P1XY).unwrap(),
806 );
807 let y = Fq2::new(
808 Fq::from_slice(&G2_P1YX).unwrap(),
809 Fq::from_slice(&G2_P1YY).unwrap(),
810 );
811 let p1 = G2::new(x, y, Fq2::one());
812 let x = Fq2::new(
813 Fq::from_slice(&G2_MULXX).unwrap(),
814 Fq::from_slice(&G2_MULXY).unwrap(),
815 );
816 let y = Fq2::new(
817 Fq::from_slice(&G2_MULYX).unwrap(),
818 Fq::from_slice(&G2_MULYY).unwrap(),
819 );
820 let r = G2::new(x, y, Fq2::one());
821 let k = Fr::from_slice(&HEX_IV).unwrap();
822 assert_eq!(r, p1 * k);
823 }
824
825 #[test]
826 fn test_g2_mulg() {
827 let x = Fq2::new(
828 Fq::from_slice(&G2_MULGXX).unwrap(),
829 Fq::from_slice(&G2_MULGXY).unwrap(),
830 );
831 let y = Fq2::new(
832 Fq::from_slice(&G2_MULGYX).unwrap(),
833 Fq::from_slice(&G2_MULGYY).unwrap(),
834 );
835 let r = G2::new(x, y, Fq2::one());
836 let k = Fr::from_slice(&HEX_IV).unwrap();
837 assert_eq!(r, G2::one() * k);
838 }
839
840 #[test]
841 fn affine_fail() {
842 let res = AffineG1::new(Fq::one(), Fq::one());
843 assert!(
844 res.is_err(),
845 "Affine initialization should fail because the point is not on curve"
846 );
847 let res = AffineG1::new(Fq::one(), G1Params::coeff_b());
848 assert!(
849 res.is_err(),
850 "Affine initialization should fail because the point is not on curve"
851 );
852 }
853
854 #[test]
855 fn affine_ok() {
856 let res = AffineG1::new(
857 Fq::from_slice(&SM9_P1X).unwrap(),
858 Fq::from_slice(&SM9_P1Y).unwrap(),
859 );
860 assert!(
861 res.is_ok(),
862 "Affine initialization should be ok because the point is on the curve"
863 );
864 }
865 #[test]
866 fn test_projective_point_equality() {
867 let a = G1::one();
868 let b = G1::zero();
869
870 assert!(a == a);
871 assert!(b == b);
872 assert!(a != b);
873 assert!(b != a);
874 }
875 #[test]
876 fn test_y_at_point_at_infinity() {
877 assert!(G1::zero().y == Fq::one());
878 assert!((-G1::zero()).y == Fq::one());
879
880 assert!(G2::zero().y == Fq2::one());
881 assert!((-G2::zero()).y == Fq2::one());
882 }
883}