arnaucube
arnaucube/ark-curves-cherry-pickedPublic Self-hosted repository
ark-curves-cherry-picked/bls12_377/src/curves/g2.rs
bls12_377/src/curves/g2.rsRaw
  1use ark_ec::{
  2    bls12::Bls12Config,
  3    models::{short_weierstrass::SWCurveConfig, CurveConfig},
  4    short_weierstrass::{Affine, Projective},
  5    AffineRepr, CurveGroup, Group,
  6};
  7use ark_ff::{Field, MontFp, Zero};
  8use ark_std::ops::Neg;
  9
 10use crate::*;
 11
 12pub type G2Affine = Affine<Config>;
 13#[derive(Clone, Default, PartialEq, Eq)]
 14pub struct Config;
 15
 16impl CurveConfig for Config {
 17    type BaseField = Fq2;
 18    type ScalarField = Fr;
 19
 20    /// COFACTOR =
 21    /// 7923214915284317143930293550643874566881017850177945424769256759165301436616933228209277966774092486467289478618404761412630691835764674559376407658497
 22    #[rustfmt::skip]
 23    const COFACTOR: &'static [u64] = &[
 24        0x0000000000000001,
 25        0x452217cc90000000,
 26        0xa0f3622fba094800,
 27        0xd693e8c36676bd09,
 28        0x8c505634fae2e189,
 29        0xfbb36b00e1dcc40c,
 30        0xddd88d99a6f6a829,
 31        0x26ba558ae9562a,
 32    ];
 33
 34    /// COFACTOR_INV = COFACTOR^{-1} mod r
 35    /// = 6764900296503390671038341982857278410319949526107311149686707033187604810669
 36    const COFACTOR_INV: Fr =
 37        MontFp!("6764900296503390671038341982857278410319949526107311149686707033187604810669");
 38}
 39
 40impl SWCurveConfig for Config {
 41    /// COEFF_A = [0, 0]
 42    const COEFF_A: Fq2 = Fq2::new(g1::Config::COEFF_A, g1::Config::COEFF_A);
 43
 44    // As per https://eprint.iacr.org/2012/072.pdf,
 45    // this curve has b' = b/i, where b is the COEFF_B of G1, and x^6 -i is
 46    // the irreducible poly used to extend from Fp2 to Fp12.
 47    // In our case, i = u (App A.3, T_6).
 48    /// COEFF_B = [0,
 49    /// 155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906]
 50    const COEFF_B: Fq2 = Fq2::new(
 51        Fq::ZERO,
 52        MontFp!("155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874906"),
 53    );
 54
 55    /// AFFINE_GENERATOR_COEFFS = (G2_GENERATOR_X, G2_GENERATOR_Y)
 56    const GENERATOR: G2Affine = G2Affine::new_unchecked(G2_GENERATOR_X, G2_GENERATOR_Y);
 57
 58    #[inline(always)]
 59    fn mul_by_a(_: Self::BaseField) -> Self::BaseField {
 60        Self::BaseField::zero()
 61    }
 62
 63    #[inline]
 64    fn clear_cofactor(p: &G2Affine) -> G2Affine {
 65        // Based on Section 4.1 of https://eprint.iacr.org/2017/419.pdf
 66        // [h(ψ)]P = [x^2 − x − 1]P + [x − 1]ψ(P) + (ψ^2)(2P)
 67
 68        let x: &'static [u64] = crate::Config::X;
 69        let p_projective = p.into_group();
 70
 71        // [x]P
 72        let x_p = Config::mul_affine(p, x);
 73        // ψ(P)
 74        let psi_p = p_power_endomorphism(p);
 75        // (ψ^2)(2P)
 76        let mut psi2_p2 = double_p_power_endomorphism(&p_projective.double());
 77
 78        // tmp = [x]P + ψ(P)
 79        let mut tmp = x_p;
 80        tmp += &psi_p;
 81
 82        // tmp2 = [x^2]P + [x]ψ(P)
 83        let mut tmp2: Projective<Config> = tmp;
 84        tmp2 = tmp2.mul_bigint(x);
 85
 86        // add up all the terms
 87        psi2_p2 += tmp2;
 88        psi2_p2 -= x_p;
 89        psi2_p2 += &-psi_p;
 90        (psi2_p2 - p_projective).into_affine()
 91    }
 92}
 93
 94pub const G2_GENERATOR_X: Fq2 = Fq2::new(G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
 95pub const G2_GENERATOR_Y: Fq2 = Fq2::new(G2_GENERATOR_Y_C0, G2_GENERATOR_Y_C1);
 96
 97/// G2_GENERATOR_X_C0 =
 98/// 233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294
 99pub const G2_GENERATOR_X_C0: Fq = MontFp!("233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294");
100
101/// G2_GENERATOR_X_C1 =
102/// 140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118
103pub const G2_GENERATOR_X_C1: Fq = MontFp!("140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118");
104
105/// G2_GENERATOR_Y_C0 =
106/// 63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423
107pub const G2_GENERATOR_Y_C0: Fq = MontFp!("63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423");
108
109/// G2_GENERATOR_Y_C1 =
110/// 149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491
111pub const G2_GENERATOR_Y_C1: Fq = MontFp!("149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491");
112
113// PSI_X = u^((p-1)/3)
114const P_POWER_ENDOMORPHISM_COEFF_0 : Fq2 = Fq2::new(
115    MontFp!(
116        "80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946"
117    ),
118    Fq::ZERO,
119);
120
121// PSI_Y = u^((p-1)/2)
122const P_POWER_ENDOMORPHISM_COEFF_1: Fq2 = Fq2::new(
123    MontFp!(
124        "216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499"),
125        Fq::ZERO,
126    );
127
128// PSI_2_X = u^((p^2 - 1)/3)
129const DOUBLE_P_POWER_ENDOMORPHISM_COEFF_0: Fq2 = Fq2::new(
130        MontFp!("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945"),
131        Fq::ZERO
132    );
133
134/// psi(x,y) is the untwist-Frobenius-twist endomorhism on E'(Fq2)
135fn p_power_endomorphism(p: &Affine<Config>) -> Affine<Config> {
136    // The p-power endomorphism for G2 is defined as follows:
137    // 1. Note that G2 is defined on curve E': y^2 = x^3 + 1/u.
138    //    To map a point (x, y) in E' to (s, t) in E,
139    //    one set s = x * (u ^ (1/3)), t = y * (u ^ (1/2)),
140    //    because E: y^2 = x^3 + 1.
141    // 2. Apply the Frobenius endomorphism (s, t) => (s', t'),
142    //    another point on curve E, where s' = s^p, t' = t^p.
143    // 3. Map the point from E back to E'; that is,
144    //    one set x' = s' / ((u) ^ (1/3)), y' = t' / ((u) ^ (1/2)).
145    //
146    // To sum up, it maps
147    // (x,y) -> (x^p * (u ^ ((p-1)/3)), y^p * (u ^ ((p-1)/2)))
148    // as implemented in the code as follows.
149
150    let mut res = *p;
151    res.x.frobenius_map_in_place(1);
152    res.y.frobenius_map_in_place(1);
153
154    res.x *= P_POWER_ENDOMORPHISM_COEFF_0;
155    res.y *= P_POWER_ENDOMORPHISM_COEFF_1;
156
157    res
158}
159
160/// For a p-power endomorphism psi(P), compute psi(psi(P))
161fn double_p_power_endomorphism(p: &Projective<Config>) -> Projective<Config> {
162    // p_power_endomorphism(&p_power_endomorphism(&p.into_affine())).into()
163    let mut res = *p;
164
165    res.x *= DOUBLE_P_POWER_ENDOMORPHISM_COEFF_0;
166    // u^((p^2 - 1)/2) == -1
167    res.y = res.y.neg();
168
169    res
170}
171
172#[cfg(test)]
173mod test {
174
175    use super::*;
176    use ark_std::{rand::Rng, UniformRand};
177
178    fn sample_unchecked() -> Affine<g2::Config> {
179        let mut rng = ark_std::test_rng();
180        loop {
181            let x1 = Fq::rand(&mut rng);
182            let x2 = Fq::rand(&mut rng);
183            let greatest = rng.gen();
184            let x = Fq2::new(x1, x2);
185
186            if let Some(p) = Affine::get_point_from_x_unchecked(x, greatest) {
187                return p;
188            }
189        }
190    }
191
192    #[test]
193    fn test_psi_2() {
194        let p = sample_unchecked();
195        let psi_p = p_power_endomorphism(&p);
196        let psi2_p_composed = p_power_endomorphism(&psi_p);
197        let psi2_p_optimised = double_p_power_endomorphism(&p.into());
198
199        assert_eq!(psi2_p_composed, psi2_p_optimised);
200    }
201
202    #[test]
203    fn test_cofactor_clearing() {
204        let h_eff = &[
205            0x1e34800000000000,
206            0xcf664765b0000003,
207            0x8e8e73ad8a538800,
208            0x78ba279637388559,
209            0xb85860aaaad29276,
210            0xf7ee7c4b03103b45,
211            0x8f6ade35a5c7d769,
212            0xa951764c46f4edd2,
213            0x53648d3d9502abfb,
214            0x1f60243677e306,
215        ];
216        const SAMPLES: usize = 10;
217        for _ in 0..SAMPLES {
218            let p: Affine<g2::Config> = sample_unchecked();
219            let optimised = p.clear_cofactor();
220            let naive = g2::Config::mul_affine(&p, h_eff);
221            assert_eq!(optimised.into_group(), naive);
222            assert!(optimised.is_on_curve());
223            assert!(optimised.is_in_correct_subgroup_assuming_on_curve());
224        }
225    }
226}