mirror of
https://github.com/arnaucube/ark-curves-cherry-picked.git
synced 2026-01-09 23:41:30 +01:00
Faster cofactor clearing for G1 & G2 of bls12-381 + benchmarking (#103)
This commit is contained in:
@@ -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_ff::{Field, MontFp, PrimeField, Zero};
|
||||||
use ark_std::ops::Neg;
|
use ark_std::{ops::Neg, One};
|
||||||
|
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
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<Parameters>) -> Affine<Parameters> {
|
|||||||
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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},
|
short_weierstrass::{Affine, Projective, SWCurveConfig},
|
||||||
AffineRepr,
|
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<Parameters>) -> Affine<Parameters> {
|
|||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use ark_ec::pairing::{MillerLoopOutput, PairingOutput};
|
use ark_ec::{
|
||||||
use ark_ec::{models::short_weierstrass::SWCurveConfig, pairing::Pairing};
|
models::short_weierstrass::SWCurveConfig,
|
||||||
|
pairing::{MillerLoopOutput, Pairing, PairingOutput},
|
||||||
|
};
|
||||||
use ark_ff::{
|
use ark_ff::{
|
||||||
biginteger::BigInteger832,
|
biginteger::BigInteger832,
|
||||||
fields::{BitIteratorBE, Field},
|
fields::{BitIteratorBE, Field},
|
||||||
|
|||||||
@@ -512,8 +512,10 @@ pub mod curves {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod pairing {
|
pub mod pairing {
|
||||||
use ark_ec::pairing::PairingOutput;
|
use ark_ec::{
|
||||||
use ark_ec::{pairing::Pairing, CurveGroup};
|
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};
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ pub type EdwardsProjective = Projective<BandersnatchParameters>;
|
|||||||
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
|
/// `bandersnatch` is an incomplete twisted Edwards curve. These curves have
|
||||||
/// the form: ax² + y² = 1 + dx²y².
|
/// 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²
|
||||||
|
|||||||
Reference in New Issue
Block a user