Browse Source

Faster cofactor clearing for G1 & G2 of bls12-381 + benchmarking (#103)

cherry-pick
mmagician 2 years ago
committed by GitHub
parent
commit
4bcf87de22
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 13 deletions
  1. +48
    -5
      bls12_381/src/curves/g1.rs
  2. +87
    -2
      bls12_381/src/curves/g2.rs
  3. +4
    -2
      cp6_782/src/curves/mod.rs
  4. +4
    -2
      curve-constraint-tests/src/lib.rs
  5. +2
    -2
      ed_on_bls12_381_bandersnatch/src/curves/mod.rs

+ 48
- 5
bls12_381/src/curves/g1.rs

@ -1,3 +1,4 @@
use crate::*;
use ark_ec::{ use ark_ec::{
bls12, bls12,
bls12::Bls12Parameters, bls12::Bls12Parameters,
@ -5,11 +6,8 @@ use ark_ec::{
short_weierstrass::{Affine, SWCurveConfig}, short_weierstrass::{Affine, SWCurveConfig},
AffineRepr, Group, AffineRepr, Group,
}; };
use ark_ff::{Field, MontFp, Zero};
use ark_std::ops::Neg;
use crate::*;
use ark_ff::{Field, MontFp, PrimeField, Zero};
use ark_std::{ops::Neg, One};
pub type G1Affine = bls12::G1Affine<crate::Parameters>; pub type G1Affine = bls12::G1Affine<crate::Parameters>;
pub type G1Projective = bls12::G1Projective<crate::Parameters>; pub type G1Projective = bls12::G1Projective<crate::Parameters>;
@ -62,6 +60,21 @@ impl SWCurveConfig for Parameters {
let endomorphism_p = endomorphism(p); let endomorphism_p = endomorphism(p);
minus_x_squared_times_p.eq(&endomorphism_p) minus_x_squared_times_p.eq(&endomorphism_p)
} }
#[inline]
fn clear_cofactor(p: &G1Affine) -> G1Affine {
// Using the effective cofactor, as explained in
// Section 5 of https://eprint.iacr.org/2019/403.pdf.
//
// It is enough to multiply by (1 - x), instead of (x - 1)^2 / 3
let h_eff = one_minus_x().into_bigint();
Parameters::mul_affine(&p, h_eff.as_ref()).into()
}
}
fn one_minus_x() -> Fr {
const X: Fr = Fr::from_sign_and_limbs(!crate::Parameters::X_IS_NEGATIVE, crate::Parameters::X);
Fr::one() - X
} }
/// G1_GENERATOR_X = /// G1_GENERATOR_X =
@ -83,3 +96,33 @@ pub fn endomorphism(p: &Affine) -> Affine {
res.x *= BETA; res.x *= BETA;
res res
} }
#[cfg(test)]
mod test {
use super::*;
use ark_std::{rand::Rng, UniformRand};
fn sample_unchecked() -> Affine<g1::Parameters> {
let mut rng = ark_std::test_rng();
loop {
let x = Fq::rand(&mut rng);
let greatest = rng.gen();
if let Some(p) = Affine::get_point_from_x_unchecked(x, greatest) {
return p;
}
}
}
#[test]
fn test_cofactor_clearing() {
const SAMPLES: usize = 100;
for _ in 0..SAMPLES {
let p: Affine<g1::Parameters> = sample_unchecked();
let p = p.clear_cofactor();
assert!(p.is_on_curve());
assert!(p.is_in_correct_subgroup_assuming_on_curve());
}
}
}

+ 87
- 2
bls12_381/src/curves/g2.rs

@ -1,9 +1,11 @@
use ark_std::ops::Neg;
use ark_ec::{ use ark_ec::{
bls12, bls12,
bls12::Bls12Parameters, bls12::Bls12Parameters,
models::CurveConfig, models::CurveConfig,
short_weierstrass::{Affine, SWCurveConfig},
AffineRepr,
short_weierstrass::{Affine, Projective, SWCurveConfig},
AffineRepr, CurveGroup, Group,
}; };
use ark_ff::{Field, MontFp, Zero}; use ark_ff::{Field, MontFp, Zero};
@ -69,6 +71,40 @@ impl SWCurveConfig for Parameters {
x_times_point.eq(&p_times_point) x_times_point.eq(&p_times_point)
} }
#[inline]
fn clear_cofactor(p: &G2Affine) -> G2Affine {
// Based on Section 4.1 of https://eprint.iacr.org/2017/419.pdf
// [h(ψ)]P = [x^2 − x − 1]P + [x − 1]ψ(P) + (ψ^2)(2P)
// x = -15132376222941642752
// When multiplying, use -c1 instead, and then negate the result. That's much
// more efficient, since the scalar -c1 has less limbs and a much lower Hamming
// weight.
let x: &'static [u64] = crate::Parameters::X;
let p_projective = p.into_group();
// [x]P
let x_p = Parameters::mul_affine(p, &x).neg();
// ψ(P)
let psi_p = p_power_endomorphism(&p);
// (ψ^2)(2P)
let mut psi2_p2 = double_p_power_endomorphism(&p_projective.double());
// tmp = [x]P + ψ(P)
let mut tmp = x_p.clone();
tmp += &psi_p;
// tmp2 = [x^2]P + [x]ψ(P)
let mut tmp2: Projective<Parameters> = tmp;
tmp2 = tmp2.mul_bigint(x).neg();
// add up all the terms
psi2_p2 += tmp2;
psi2_p2 -= x_p;
psi2_p2 += &-psi_p;
(psi2_p2 - p_projective).into_affine()
}
} }
pub const G2_GENERATOR_X: Fq2 = Fq2::new(G2_GENERATOR_X_C0, G2_GENERATOR_X_C1); pub const G2_GENERATOR_X: Fq2 = Fq2::new(G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
@ -109,6 +145,11 @@ pub const P_POWER_ENDOMORPHISM_COEFF_1: Fq2 = Fq2::new(
"1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257") "1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257")
); );
pub const DOUBLE_P_POWER_ENDOMORPHISM: Fq2 = Fq2::new(
MontFp!("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"),
Fq::ZERO
);
pub fn p_power_endomorphism(p: &Affine<Parameters>) -> Affine<Parameters> { pub fn p_power_endomorphism(p: &Affine<Parameters>) -> Affine<Parameters> {
// The p-power endomorphism for G2 is defined as follows: // The p-power endomorphism for G2 is defined as follows:
// 1. Note that G2 is defined on curve E': y^2 = x^3 + 4(u+1). // 1. Note that G2 is defined on curve E': y^2 = x^3 + 4(u+1).
@ -135,3 +176,47 @@ pub fn p_power_endomorphism(p: &Affine) -> Affine {
res res
} }
/// For a p-power endomorphism psi(P), compute psi(psi(P))
pub fn double_p_power_endomorphism(p: &Projective<Parameters>) -> Projective<Parameters> {
let mut res = *p;
res.x *= DOUBLE_P_POWER_ENDOMORPHISM;
res.y = res.y.neg();
res
}
#[cfg(test)]
mod test {
use super::*;
use ark_std::UniformRand;
#[test]
fn test_cofactor_clearing() {
// multiplying by h_eff and clearing the cofactor by the efficient
// endomorphism-based method should yield the same result.
let h_eff: &'static [u64] = &[
0xe8020005aaa95551,
0x59894c0adebbf6b4,
0xe954cbc06689f6a3,
0x2ec0ec69d7477c1a,
0x6d82bf015d1212b0,
0x329c2f178731db95,
0x9986ff031508ffe1,
0x88e2a8e9145ad768,
0x584c6a0ea91b3528,
0xbc69f08f2ee75b3,
];
let mut rng = ark_std::test_rng();
const SAMPLES: usize = 10;
for _ in 0..SAMPLES {
let p = Affine::<g2::Parameters>::rand(&mut rng);
let optimised = p.clear_cofactor().into_group();
let naive = g2::Parameters::mul_affine(&p, h_eff);
assert_eq!(optimised, naive);
}
}
}

+ 4
- 2
cp6_782/src/curves/mod.rs

@ -1,5 +1,7 @@
use ark_ec::pairing::{MillerLoopOutput, PairingOutput};
use ark_ec::{models::short_weierstrass::SWCurveConfig, pairing::Pairing};
use ark_ec::{
models::short_weierstrass::SWCurveConfig,
pairing::{MillerLoopOutput, Pairing, PairingOutput},
};
use ark_ff::{ use ark_ff::{
biginteger::BigInteger832, biginteger::BigInteger832,
fields::{BitIteratorBE, Field}, fields::{BitIteratorBE, Field},

+ 4
- 2
curve-constraint-tests/src/lib.rs

@ -512,8 +512,10 @@ pub mod curves {
} }
pub mod pairing { pub mod pairing {
use ark_ec::pairing::PairingOutput;
use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ec::{
pairing::{Pairing, PairingOutput},
CurveGroup,
};
use ark_ff::{BitIteratorLE, Field, PrimeField}; use ark_ff::{BitIteratorLE, Field, PrimeField};
use ark_r1cs_std::prelude::*; use ark_r1cs_std::prelude::*;
use ark_relations::r1cs::{ConstraintSystem, SynthesisError}; use ark_relations::r1cs::{ConstraintSystem, SynthesisError};

+ 2
- 2
ed_on_bls12_381_bandersnatch/src/curves/mod.rs

@ -16,8 +16,8 @@ pub type EdwardsProjective = Projective;
pub type SWAffine = short_weierstrass::Affine<BandersnatchParameters>; pub type SWAffine = short_weierstrass::Affine<BandersnatchParameters>;
pub type SWProjective = short_weierstrass::Projective<BandersnatchParameters>; pub type SWProjective = short_weierstrass::Projective<BandersnatchParameters>;
/// `bandersnatch` is an incomplete twisted Edwards curve. These curves have equations of
/// the form: ax² + y² = 1 + dx²y².
/// `bandersnatch` is an incomplete twisted Edwards curve. These curves have
/// equations of the form: ax² + y² = 1 + dx²y².
/// over some base finite field Fq. /// over some base finite field Fq.
/// ///
/// bandersnatch's curve equation: -5x² + y² = 1 + dx²y² /// bandersnatch's curve equation: -5x² + y² = 1 + dx²y²

Loading…
Cancel
Save