snarkvm_curves/bls12_377/
g2.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use snarkvm_fields::{Field, PrimeField, Zero, field};
17use snarkvm_utilities::{
18    BigInteger,
19    BitIteratorBE,
20    biginteger::{BigInteger256, BigInteger384},
21};
22
23use crate::{
24    AffineCurve,
25    ProjectiveCurve,
26    bls12_377::{Fq, Fq2, Fr, g1::Bls12_377G1Parameters},
27    traits::{ModelParameters, ShortWeierstrassParameters},
28};
29
30use std::ops::Neg;
31
32#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
33pub struct Bls12_377G2Parameters;
34
35impl ModelParameters for Bls12_377G2Parameters {
36    type BaseField = Fq2;
37    type ScalarField = Fr;
38}
39
40impl ShortWeierstrassParameters for Bls12_377G2Parameters {
41    /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y)
42    const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (G2_GENERATOR_X, G2_GENERATOR_Y);
43    /// B1 = x^2 - 1
44    const B1: Fr = field!(
45        Fr,
46        BigInteger256([12574070832645531618, 10005695704657941814, 1564543351912391449, 657300228442948690])
47    );
48    /// B2 = x^2
49    const B2: Fr = field!(
50        Fr,
51        BigInteger256([2417046298041509844, 11783911742408086824, 14689097366802547462, 270119112518072728])
52    );
53    /// COFACTOR =
54    /// 7923214915284317143930293550643874566881017850177945424769256759165301436616933228209277966774092486467289478618404761412630691835764674559376407658497
55    const COFACTOR: &'static [u64] = &[
56        0x0000000000000001,
57        0x452217cc90000000,
58        0xa0f3622fba094800,
59        0xd693e8c36676bd09,
60        0x8c505634fae2e189,
61        0xfbb36b00e1dcc40c,
62        0xddd88d99a6f6a829,
63        0x26ba558ae9562a,
64    ];
65    /// COFACTOR_INV = COFACTOR^{-1} mod r
66    ///              = 6764900296503390671038341982857278410319949526107311149686707033187604810669
67    const COFACTOR_INV: Fr = field!(
68        Fr,
69        BigInteger256([15499857013495546999, 4613531467548868169, 14546778081091178013, 549402535258503313,])
70    );
71    const PHI: Fq2 = field!(
72        Fq2,
73        field!(Fq, BigInteger384([0, 0, 0, 0, 0, 0])),
74        field!(
75            Fq,
76            BigInteger384([
77                0x2c766f925a7b8727,
78                0x03d7f6b0253d58b5,
79                0x838ec0deec122131,
80                0xbd5eb3e9f658bb10,
81                0x6942bd126ed3e52e,
82                0x01673786dd04ed6a,
83            ])
84        ),
85    );
86    /// R128 = 2^128 - 1
87    const R128: Fr = field!(
88        Fr,
89        BigInteger256([13717662654766427599, 14709524173037165000, 15342848074630952979, 736762107895475646])
90    );
91    /// WEIERSTRASS_A = [0, 0]
92    const WEIERSTRASS_A: Fq2 = field!(Fq2, Bls12_377G1Parameters::WEIERSTRASS_A, Bls12_377G1Parameters::WEIERSTRASS_A,);
93    // As per https://eprint.iacr.org/2012/072.pdf,
94    // this curve has b' = b/i, where b is the COEFF_B of G1, and x^6 -i is
95    // the irreducible poly used to extend from Fp2 to Fp12.
96    // In our case, i = u (App A.3, T_6).
97    /// WEIERSTRASS_B = [0,
98    /// 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906]
99    const WEIERSTRASS_B: Fq2 = field!(
100        Fq2,
101        field!(Fq, BigInteger384([0, 0, 0, 0, 0, 0])),
102        field!(
103            Fq,
104            BigInteger384([
105                9255502405446297221,
106                10229180150694123945,
107                9215585410771530959,
108                13357015519562362907,
109                5437107869987383107,
110                16259554076827459,
111            ])
112        ),
113    );
114
115    #[inline(always)]
116    fn mul_by_a(_: &Self::BaseField) -> Self::BaseField {
117        Self::BaseField::zero()
118    }
119
120    fn is_in_correct_subgroup_assuming_on_curve(
121        p: &crate::templates::short_weierstrass_jacobian::Affine<Self>,
122    ) -> bool {
123        p.mul_bits(BitIteratorBE::new(Self::ScalarField::characteristic())).is_zero()
124    }
125
126    fn glv_endomorphism(
127        mut p: crate::templates::short_weierstrass_jacobian::Affine<Self>,
128    ) -> crate::templates::short_weierstrass_jacobian::Affine<Self> {
129        p.x.mul_by_fp(&Self::PHI.c1);
130        p
131    }
132
133    fn mul_projective(
134        p: crate::templates::short_weierstrass_jacobian::Projective<Self>,
135        by: Self::ScalarField,
136    ) -> crate::templates::short_weierstrass_jacobian::Projective<Self> {
137        type ScalarBigInt = <Fr as PrimeField>::BigInteger;
138
139        /// The scalar multiplication window size.
140        const GLV_WINDOW_SIZE: usize = 4;
141
142        /// The table size, used for w-ary NAF recoding.
143        const TABLE_SIZE: i64 = 1 << (GLV_WINDOW_SIZE + 1);
144        const HALF_TABLE_SIZE: i64 = 1 << (GLV_WINDOW_SIZE);
145        const MASK_FOR_MOD_TABLE_SIZE: u64 = (TABLE_SIZE as u64) - 1;
146        /// The GLV table length.
147        const L: usize = 1 << (GLV_WINDOW_SIZE - 1);
148
149        let decomposition = by.decompose(&Self::Q1, &Self::Q2, Self::B1, Self::B2, Self::R128, &Self::HALF_R);
150
151        // Prepare tables.
152        let mut t_1 = Vec::with_capacity(L);
153        let double = crate::templates::short_weierstrass_jacobian::Affine::<Self>::from(p.double());
154        t_1.push(p);
155        for i in 1..L {
156            t_1.push(t_1[i - 1].add_mixed(&double));
157        }
158        let t_1 =
159            crate::templates::short_weierstrass_jacobian::Projective::<Self>::batch_normalization_into_affine(t_1);
160
161        let t_2 = t_1.iter().copied().map(Self::glv_endomorphism).collect::<Vec<_>>();
162
163        let mod_signed = |d| {
164            let d_mod_window_size = i64::try_from(d & MASK_FOR_MOD_TABLE_SIZE).unwrap();
165            if d_mod_window_size >= HALF_TABLE_SIZE { d_mod_window_size - TABLE_SIZE } else { d_mod_window_size }
166        };
167        let to_wnaf = |e: Self::ScalarField| -> Vec<i32> {
168            let mut naf = vec![];
169            let mut e = e.to_bigint();
170            while !e.is_zero() {
171                let next = if e.is_odd() {
172                    let naf_sign = mod_signed(e.as_ref()[0]);
173                    if naf_sign < 0 {
174                        e.add_nocarry(&ScalarBigInt::from(-naf_sign as u64));
175                    } else {
176                        e.sub_noborrow(&ScalarBigInt::from(naf_sign as u64));
177                    }
178                    naf_sign.try_into().unwrap()
179                } else {
180                    0
181                };
182                naf.push(next);
183                e.div2();
184            }
185
186            naf
187        };
188
189        let wnaf = |k1: Self::ScalarField, k2: Self::ScalarField, s1: bool, s2: bool| -> (Vec<i32>, Vec<i32>) {
190            let mut wnaf_1 = to_wnaf(k1);
191            let mut wnaf_2 = to_wnaf(k2);
192
193            if s1 {
194                wnaf_1.iter_mut().for_each(|e| *e = -*e);
195            }
196            if !s2 {
197                wnaf_2.iter_mut().for_each(|e| *e = -*e);
198            }
199
200            (wnaf_1, wnaf_2)
201        };
202
203        let naf_add = |table: &[crate::templates::short_weierstrass_jacobian::Affine<Self>],
204                       naf: i32,
205                       acc: &mut crate::templates::short_weierstrass_jacobian::Projective<Self>| {
206            if naf != 0 {
207                let mut p_1 = table[(naf.abs() >> 1) as usize];
208                if naf < 0 {
209                    p_1 = p_1.neg();
210                }
211                acc.add_assign_mixed(&p_1);
212            }
213        };
214
215        // Recode scalars.
216        let (naf_1, naf_2) = wnaf(decomposition.0, decomposition.1, decomposition.2, decomposition.3);
217        let max_len = naf_1.len().max(naf_2.len());
218        let mut acc = crate::templates::short_weierstrass_jacobian::Projective::<Self>::zero();
219        for i in (0..max_len).rev() {
220            if i < naf_1.len() {
221                naf_add(&t_1, naf_1[i], &mut acc)
222            }
223
224            if i < naf_2.len() {
225                naf_add(&t_2, naf_2[i], &mut acc)
226            }
227
228            if i != 0 {
229                acc.double_in_place();
230            }
231        }
232
233        acc
234    }
235}
236
237pub const G2_GENERATOR_X: Fq2 = field!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
238pub const G2_GENERATOR_Y: Fq2 = field!(Fq2, G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1);
239
240///
241/// G2_GENERATOR_X_C0 =
242/// 170590608266080109581922461902299092015242589883741236963254737235977648828052995125541529645051927918098146183295
243///
244/// See `snarkvm_algorithms::hash_to_curve::tests::bls12_377` for tests.
245///
246pub const G2_GENERATOR_X_C0: Fq = field!(
247    Fq,
248    BigInteger384::new([
249        1394603105513884269,
250        11069732150289508451,
251        4261960060090787184,
252        13457254148541472797,
253        3177258746859163322,
254        82258727112085846
255    ])
256);
257
258///
259/// G2_GENERATOR_X_C1 =
260/// 83407003718128594709087171351153471074446327721872642659202721143408712182996929763094113874399921859453255070254
261///
262/// See `snarkvm_algorithms::hash_to_curve::tests::bls12_377` for tests.
263///
264pub const G2_GENERATOR_X_C1: Fq = field!(
265    Fq,
266    BigInteger384::new([
267        12672065269715576738,
268        3451530808602826578,
269        9486610028138952262,
270        5031487885431614078,
271        9858745210421513581,
272        63301617551232910
273    ])
274);
275
276///
277/// G2_GENERATOR_Y_C0 =
278/// 1843833842842620867708835993770650838640642469700861403869757682057607397502738488921663703124647238454792872005
279///
280/// See `snarkvm_algorithms::hash_to_curve::tests::bls12_377` for tests.
281///
282pub const G2_GENERATOR_Y_C0: Fq = field!(
283    Fq,
284    BigInteger384::new([
285        1855632670224768760,
286        2989378521406112342,
287        9748867374972564648,
288        3204895972998458874,
289        16520689795595505429,
290        61918742406142643
291    ])
292);
293
294///
295/// G2_GENERATOR_Y_C1 =
296/// 33145532013610981697337930729788870077912093258611421158732879580766461459275194744385880708057348608045241477209
297///
298/// See `snarkvm_algorithms::hash_to_curve::tests::bls12_377` for tests.
299///
300pub const G2_GENERATOR_Y_C1: Fq = field!(
301    Fq,
302    BigInteger384::new([
303        1532128906028652860,
304        14539073382194201855,
305        10828918286556702479,
306        14664598863867299115,
307        483199896405477997,
308        73741830940675480
309    ])
310);