pairing_plus/bls12_381/ec/
g1.rs

1use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
2use super::g2::G2Affine;
3use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
4use std::fmt;
5use {CurveAffine, CurveProjective, EncodedPoint, Engine, GroupDecodingError, SubgroupCheck};
6curve_impl!(
7    "G1",
8    G1,
9    G1Affine,
10    G1Prepared,
11    Fq,
12    Fr,
13    G1Uncompressed,
14    G1Compressed,
15    G2Affine
16);
17
18#[derive(Copy, Clone)]
19pub struct G1Uncompressed([u8; 96]);
20
21impl AsRef<[u8]> for G1Uncompressed {
22    fn as_ref(&self) -> &[u8] {
23        &self.0
24    }
25}
26
27impl AsMut<[u8]> for G1Uncompressed {
28    fn as_mut(&mut self) -> &mut [u8] {
29        &mut self.0
30    }
31}
32
33impl fmt::Debug for G1Uncompressed {
34    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
35        self.0[..].fmt(formatter)
36    }
37}
38
39impl EncodedPoint for G1Uncompressed {
40    type Affine = G1Affine;
41
42    fn empty() -> Self {
43        G1Uncompressed([0; 96])
44    }
45    fn size() -> usize {
46        96
47    }
48    fn into_affine(&self) -> Result<G1Affine, GroupDecodingError> {
49        let affine = self.into_affine_unchecked()?;
50
51        if !affine.is_on_curve() {
52            Err(GroupDecodingError::NotOnCurve)
53        } else if !affine.in_subgroup() {
54            Err(GroupDecodingError::NotInSubgroup)
55        } else {
56            Ok(affine)
57        }
58    }
59    fn into_affine_unchecked(&self) -> Result<G1Affine, GroupDecodingError> {
60        // Create a copy of this representation.
61        let mut copy = self.0;
62
63        if copy[0] & (1 << 7) != 0 {
64            // Distinguisher bit is set, but this should be uncompressed!
65            return Err(GroupDecodingError::UnexpectedCompressionMode);
66        }
67
68        if copy[0] & (1 << 6) != 0 {
69            // This is the point at infinity, which means that if we mask away
70            // the first two bits, the entire representation should consist
71            // of zeroes.
72            copy[0] &= 0x3f;
73
74            if copy.iter().all(|b| *b == 0) {
75                Ok(G1Affine::zero())
76            } else {
77                Err(GroupDecodingError::UnexpectedInformation)
78            }
79        } else {
80            if copy[0] & (1 << 5) != 0 {
81                // The bit indicating the y-coordinate should be lexicographically
82                // largest is set, but this is an uncompressed element.
83                return Err(GroupDecodingError::UnexpectedInformation);
84            }
85
86            // Unset the three most significant bits.
87            copy[0] &= 0x1f;
88
89            let mut x = FqRepr([0; 6]);
90            let mut y = FqRepr([0; 6]);
91
92            {
93                let mut reader = &copy[..];
94
95                x.read_be(&mut reader).unwrap();
96                y.read_be(&mut reader).unwrap();
97            }
98
99            Ok(G1Affine {
100                x: Fq::from_repr(x)
101                    .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?,
102                y: Fq::from_repr(y)
103                    .map_err(|e| GroupDecodingError::CoordinateDecodingError("y coordinate", e))?,
104                infinity: false,
105            })
106        }
107    }
108    fn from_affine(affine: G1Affine) -> Self {
109        let mut res = Self::empty();
110
111        if affine.is_zero() {
112            // Set the second-most significant bit to indicate this point
113            // is at infinity.
114            res.0[0] |= 1 << 6;
115        } else {
116            let mut writer = &mut res.0[..];
117
118            affine.x.into_repr().write_be(&mut writer).unwrap();
119            affine.y.into_repr().write_be(&mut writer).unwrap();
120        }
121
122        res
123    }
124}
125
126#[derive(Copy, Clone)]
127pub struct G1Compressed([u8; 48]);
128
129impl AsRef<[u8]> for G1Compressed {
130    fn as_ref(&self) -> &[u8] {
131        &self.0
132    }
133}
134
135impl AsMut<[u8]> for G1Compressed {
136    fn as_mut(&mut self) -> &mut [u8] {
137        &mut self.0
138    }
139}
140
141impl fmt::Debug for G1Compressed {
142    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
143        self.0[..].fmt(formatter)
144    }
145}
146
147impl EncodedPoint for G1Compressed {
148    type Affine = G1Affine;
149
150    fn empty() -> Self {
151        G1Compressed([0; 48])
152    }
153    fn size() -> usize {
154        48
155    }
156    fn into_affine(&self) -> Result<G1Affine, GroupDecodingError> {
157        let affine = self.into_affine_unchecked()?;
158
159        // NB: Decompression guarantees that it is on the curve already.
160
161        if !affine.in_subgroup() {
162            Err(GroupDecodingError::NotInSubgroup)
163        } else {
164            Ok(affine)
165        }
166    }
167    fn into_affine_unchecked(&self) -> Result<G1Affine, GroupDecodingError> {
168        // Create a copy of this representation.
169        let mut copy = self.0;
170
171        if copy[0] & (1 << 7) == 0 {
172            // Distinguisher bit isn't set.
173            return Err(GroupDecodingError::UnexpectedCompressionMode);
174        }
175
176        if copy[0] & (1 << 6) != 0 {
177            // This is the point at infinity, which means that if we mask away
178            // the first two bits, the entire representation should consist
179            // of zeroes.
180            copy[0] &= 0x3f;
181
182            if copy.iter().all(|b| *b == 0) {
183                Ok(G1Affine::zero())
184            } else {
185                Err(GroupDecodingError::UnexpectedInformation)
186            }
187        } else {
188            // Determine if the intended y coordinate must be greater
189            // lexicographically.
190            let greatest = copy[0] & (1 << 5) != 0;
191
192            // Unset the three most significant bits.
193            copy[0] &= 0x1f;
194
195            let mut x = FqRepr([0; 6]);
196
197            {
198                let mut reader = &copy[..];
199
200                x.read_be(&mut reader).unwrap();
201            }
202
203            // Interpret as Fq element.
204            let x = Fq::from_repr(x)
205                .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?;
206
207            G1Affine::get_point_from_x(x, greatest).ok_or(GroupDecodingError::NotOnCurve)
208        }
209    }
210    fn from_affine(affine: G1Affine) -> Self {
211        let mut res = Self::empty();
212
213        if affine.is_zero() {
214            // Set the second-most significant bit to indicate this point
215            // is at infinity.
216            res.0[0] |= 1 << 6;
217        } else {
218            {
219                let mut writer = &mut res.0[..];
220
221                affine.x.into_repr().write_be(&mut writer).unwrap();
222            }
223
224            let mut negy = affine.y;
225            negy.negate();
226
227            // Set the third most significant bit if the correct y-coordinate
228            // is lexicographically largest.
229            if affine.y > negy {
230                res.0[0] |= 1 << 5;
231            }
232        }
233
234        // Set highest bit to distinguish this as a compressed element.
235        res.0[0] |= 1 << 7;
236
237        res
238    }
239}
240
241impl G1Affine {
242    fn scale_by_cofactor(&self) -> G1 {
243        // G1 cofactor = (x - 1)^2 / 3  = 76329603384216526031706109802092473003
244        let cofactor = BitIterator::new([0x8c00aaab0000aaab, 0x396c8c005555e156]);
245        self.mul_bits(cofactor)
246    }
247
248    fn get_generator() -> Self {
249        G1Affine {
250            x: super::super::fq::G1_GENERATOR_X,
251            y: super::super::fq::G1_GENERATOR_Y,
252            infinity: false,
253        }
254    }
255
256    fn get_coeff_b() -> Fq {
257        super::super::fq::B_COEFF
258    }
259
260    fn perform_pairing(&self, other: &G2Affine) -> Fq12 {
261        super::super::Bls12::pairing(*self, *other)
262    }
263}
264
265impl G1 {
266    fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize {
267        let num_bits = scalar.num_bits() as usize;
268
269        if num_bits >= 130 {
270            4
271        } else if num_bits >= 34 {
272            3
273        } else {
274            2
275        }
276    }
277
278    fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
279        const RECOMMENDATIONS: [usize; 12] =
280            [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
281
282        let mut ret = 4;
283        for r in &RECOMMENDATIONS {
284            if num_scalars > *r {
285                ret += 1;
286            } else {
287                break;
288            }
289        }
290
291        ret
292    }
293}
294
295#[derive(Clone, Debug)]
296pub struct G1Prepared(pub(crate) G1Affine);
297
298impl G1Prepared {
299    pub fn is_zero(&self) -> bool {
300        self.0.is_zero()
301    }
302
303    pub fn from_affine(p: G1Affine) -> Self {
304        G1Prepared(p)
305    }
306}
307
308mod subgroup_check {
309
310    use super::G1Affine;
311    #[cfg(test)]
312    use super::G1;
313    #[cfg(test)]
314    use rand_core::SeedableRng;
315    use SubgroupCheck;
316    #[cfg(test)]
317    use {CurveAffine, CurveProjective};
318
319    impl SubgroupCheck for G1Affine {
320        fn in_subgroup(&self) -> bool {
321            self.is_on_curve() && self.is_in_correct_subgroup_assuming_on_curve()
322        }
323    }
324
325    #[test]
326    fn test_g1_subgroup_check() {
327        use bls12_381::ClearH;
328        let mut rng = rand_xorshift::XorShiftRng::from_seed([
329            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
330            0xbc, 0xe5,
331        ]);
332
333        for _ in 0..32 {
334            let p = G1::random(&mut rng).into_affine();
335            assert_eq!(
336                p.in_subgroup(),
337                p.is_in_correct_subgroup_assuming_on_curve()
338            );
339
340            let mut pp = p.into_projective();
341            pp.clear_h();
342            let p = pp.into_affine();
343            assert!(p.in_subgroup() && p.is_in_correct_subgroup_assuming_on_curve());
344        }
345    }
346}
347
348#[test]
349fn g1_generator() {
350    use SqrtField;
351
352    let mut x = Fq::zero();
353    let mut i = 0;
354    loop {
355        // y^2 = x^3 + b
356        let mut rhs = x;
357        rhs.square();
358        rhs.mul_assign(&x);
359        rhs.add_assign(&G1Affine::get_coeff_b());
360
361        if let Some(y) = rhs.sqrt() {
362            let yrepr = y.into_repr();
363            let mut negy = y;
364            negy.negate();
365            let negyrepr = negy.into_repr();
366
367            let p = G1Affine {
368                x,
369                y: if yrepr < negyrepr { y } else { negy },
370                infinity: false,
371            };
372            assert!(!p.in_subgroup());
373
374            let g1 = p.scale_by_cofactor();
375            if !g1.is_zero() {
376                assert_eq!(i, 4);
377                let g1 = G1Affine::from(g1);
378
379                assert!(g1.in_subgroup());
380
381                assert_eq!(g1, G1Affine::one());
382                break;
383            }
384        }
385
386        i += 1;
387        x.add_assign(&Fq::one());
388    }
389}
390
391#[test]
392fn g1_test_is_valid() {
393    // Reject point on isomorphic twist (b = 24)
394    {
395        let p = G1Affine {
396            x: Fq::from_repr(FqRepr([
397                0xc58d887b66c035dc,
398                0x10cbfd301d553822,
399                0xaf23e064f1131ee5,
400                0x9fe83b1b4a5d648d,
401                0xf583cc5a508f6a40,
402                0xc3ad2aefde0bb13,
403            ]))
404            .unwrap(),
405            y: Fq::from_repr(FqRepr([
406                0x60aa6f9552f03aae,
407                0xecd01d5181300d35,
408                0x8af1cdb8aa8ce167,
409                0xe760f57922998c9d,
410                0x953703f5795a39e5,
411                0xfe3ae0922df702c,
412            ]))
413            .unwrap(),
414            infinity: false,
415        };
416        assert!(!p.is_on_curve());
417    }
418
419    // Reject point on a twist (b = 3)
420    {
421        let p = G1Affine {
422            x: Fq::from_repr(FqRepr([
423                0xee6adf83511e15f5,
424                0x92ddd328f27a4ba6,
425                0xe305bd1ac65adba7,
426                0xea034ee2928b30a8,
427                0xbd8833dc7c79a7f7,
428                0xe45c9f0c0438675,
429            ]))
430            .unwrap(),
431            y: Fq::from_repr(FqRepr([
432                0x3b450eb1ab7b5dad,
433                0xa65cb81e975e8675,
434                0xaa548682b21726e5,
435                0x753ddf21a2601d20,
436                0x532d0b640bd3ff8b,
437                0x118d2c543f031102,
438            ]))
439            .unwrap(),
440            infinity: false,
441        };
442        assert!(!p.is_on_curve());
443        assert!(!p.in_subgroup());
444    }
445
446    // Reject point in an invalid subgroup
447    // There is only one r-order subgroup, as r does not divide the cofactor.
448    {
449        let p = G1Affine {
450            x: Fq::from_repr(FqRepr([
451                0x76e1c971c6db8fe8,
452                0xe37e1a610eff2f79,
453                0x88ae9c499f46f0c0,
454                0xf35de9ce0d6b4e84,
455                0x265bddd23d1dec54,
456                0x12a8778088458308,
457            ]))
458            .unwrap(),
459            y: Fq::from_repr(FqRepr([
460                0x8a22defa0d526256,
461                0xc57ca55456fcb9ae,
462                0x1ba194e89bab2610,
463                0x921beef89d4f29df,
464                0x5b6fda44ad85fa78,
465                0xed74ab9f302cbe0,
466            ]))
467            .unwrap(),
468            infinity: false,
469        };
470        assert!(p.is_on_curve());
471        assert!(!p.in_subgroup());
472    }
473}
474
475#[test]
476fn test_g1_addition_correctness() {
477    let mut p = G1 {
478        x: Fq::from_repr(FqRepr([
479            0x47fd1f891d6e8bbf,
480            0x79a3b0448f31a2aa,
481            0x81f3339e5f9968f,
482            0x485e77d50a5df10d,
483            0x4c6fcac4b55fd479,
484            0x86ed4d9906fb064,
485        ]))
486        .unwrap(),
487        y: Fq::from_repr(FqRepr([
488            0xd25ee6461538c65,
489            0x9f3bbb2ecd3719b9,
490            0xa06fd3f1e540910d,
491            0xcefca68333c35288,
492            0x570c8005f8573fa6,
493            0x152ca696fe034442,
494        ]))
495        .unwrap(),
496        z: Fq::one(),
497    };
498
499    p.add_assign(&G1 {
500        x: Fq::from_repr(FqRepr([
501            0xeec78f3096213cbf,
502            0xa12beb1fea1056e6,
503            0xc286c0211c40dd54,
504            0x5f44314ec5e3fb03,
505            0x24e8538737c6e675,
506            0x8abd623a594fba8,
507        ]))
508        .unwrap(),
509        y: Fq::from_repr(FqRepr([
510            0x6b0528f088bb7044,
511            0x2fdeb5c82917ff9e,
512            0x9a5181f2fac226ad,
513            0xd65104c6f95a872a,
514            0x1f2998a5a9c61253,
515            0xe74846154a9e44,
516        ]))
517        .unwrap(),
518        z: Fq::one(),
519    });
520
521    let p = G1Affine::from(p);
522
523    assert_eq!(
524        p,
525        G1Affine {
526            x: Fq::from_repr(FqRepr([
527                0x6dd3098f22235df,
528                0xe865d221c8090260,
529                0xeb96bb99fa50779f,
530                0xc4f9a52a428e23bb,
531                0xd178b28dd4f407ef,
532                0x17fb8905e9183c69
533            ]))
534            .unwrap(),
535            y: Fq::from_repr(FqRepr([
536                0xd0de9d65292b7710,
537                0xf6a05f2bcf1d9ca7,
538                0x1040e27012f20b64,
539                0xeec8d1a5b7466c58,
540                0x4bc362649dce6376,
541                0x430cbdc5455b00a
542            ]))
543            .unwrap(),
544            infinity: false,
545        }
546    );
547}
548
549#[test]
550fn test_g1_doubling_correctness() {
551    let mut p = G1 {
552        x: Fq::from_repr(FqRepr([
553            0x47fd1f891d6e8bbf,
554            0x79a3b0448f31a2aa,
555            0x81f3339e5f9968f,
556            0x485e77d50a5df10d,
557            0x4c6fcac4b55fd479,
558            0x86ed4d9906fb064,
559        ]))
560        .unwrap(),
561        y: Fq::from_repr(FqRepr([
562            0xd25ee6461538c65,
563            0x9f3bbb2ecd3719b9,
564            0xa06fd3f1e540910d,
565            0xcefca68333c35288,
566            0x570c8005f8573fa6,
567            0x152ca696fe034442,
568        ]))
569        .unwrap(),
570        z: Fq::one(),
571    };
572
573    p.double();
574
575    let p = G1Affine::from(p);
576
577    assert_eq!(
578        p,
579        G1Affine {
580            x: Fq::from_repr(FqRepr([
581                0xf939ddfe0ead7018,
582                0x3b03942e732aecb,
583                0xce0e9c38fdb11851,
584                0x4b914c16687dcde0,
585                0x66c8baf177d20533,
586                0xaf960cff3d83833
587            ]))
588            .unwrap(),
589            y: Fq::from_repr(FqRepr([
590                0x3f0675695f5177a8,
591                0x2b6d82ae178a1ba0,
592                0x9096380dd8e51b11,
593                0x1771a65b60572f4e,
594                0x8b547c1313b27555,
595                0x135075589a687b1e
596            ]))
597            .unwrap(),
598            infinity: false,
599        }
600    );
601}
602
603#[test]
604fn test_g1_same_y() {
605    // Test the addition of two points with different x coordinates
606    // but the same y coordinate.
607
608    // x1 = 128100205326445210408953809171070606737678357140298133325128175840781723996595026100005714405541449960643523234125
609    // x2 = 3821408151224848222394078037104966877485040835569514006839342061575586899845797797516352881516922679872117658572470
610    // y = 2291134451313223670499022936083127939567618746216464377735567679979105510603740918204953301371880765657042046687078
611
612    let a = G1Affine {
613        x: Fq::from_repr(FqRepr([
614            0xea431f2cc38fc94d,
615            0x3ad2354a07f5472b,
616            0xfe669f133f16c26a,
617            0x71ffa8021531705,
618            0x7418d484386d267,
619            0xd5108d8ff1fbd6,
620        ]))
621        .unwrap(),
622        y: Fq::from_repr(FqRepr([
623            0xa776ccbfe9981766,
624            0x255632964ff40f4a,
625            0xc09744e650b00499,
626            0x520f74773e74c8c3,
627            0x484c8fc982008f0,
628            0xee2c3d922008cc6,
629        ]))
630        .unwrap(),
631        infinity: false,
632    };
633
634    let b = G1Affine {
635        x: Fq::from_repr(FqRepr([
636            0xe06cdb156b6356b6,
637            0xd9040b2d75448ad9,
638            0xe702f14bb0e2aca5,
639            0xc6e05201e5f83991,
640            0xf7c75910816f207c,
641            0x18d4043e78103106,
642        ]))
643        .unwrap(),
644        y: Fq::from_repr(FqRepr([
645            0xa776ccbfe9981766,
646            0x255632964ff40f4a,
647            0xc09744e650b00499,
648            0x520f74773e74c8c3,
649            0x484c8fc982008f0,
650            0xee2c3d922008cc6,
651        ]))
652        .unwrap(),
653        infinity: false,
654    };
655
656    // Expected
657    // x = 52901198670373960614757979459866672334163627229195745167587898707663026648445040826329033206551534205133090753192
658    // y = 1711275103908443722918766889652776216989264073722543507596490456144926139887096946237734327757134898380852225872709
659    let c = G1Affine {
660        x: Fq::from_repr(FqRepr([
661            0xef4f05bdd10c8aa8,
662            0xad5bf87341a2df9,
663            0x81c7424206b78714,
664            0x9676ff02ec39c227,
665            0x4c12c15d7e55b9f3,
666            0x57fd1e317db9bd,
667        ]))
668        .unwrap(),
669        y: Fq::from_repr(FqRepr([
670            0x1288334016679345,
671            0xf955cd68615ff0b5,
672            0xa6998dbaa600f18a,
673            0x1267d70db51049fb,
674            0x4696deb9ab2ba3e7,
675            0xb1e4e11177f59d4,
676        ]))
677        .unwrap(),
678        infinity: false,
679    };
680
681    assert!(a.is_on_curve() && a.in_subgroup());
682    assert!(b.is_on_curve() && b.in_subgroup());
683    assert!(c.is_on_curve() && c.in_subgroup());
684
685    let mut tmp1 = a.into_projective();
686    tmp1.add_assign(&b.into_projective());
687    assert_eq!(tmp1.into_affine(), c);
688    assert_eq!(tmp1, c.into_projective());
689
690    let mut tmp2 = a.into_projective();
691    tmp2.add_assign_mixed(&b);
692    assert_eq!(tmp2.into_affine(), c);
693    assert_eq!(tmp2, c.into_projective());
694}
695
696#[test]
697fn g1_curve_tests() {
698    ::tests::curve::curve_tests::<G1>();
699}