Skip to content
This repository has been archived by the owner on Dec 18, 2023. It is now read-only.

Fast subgroup check for bls12_381 #73

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions bls12_381/src/curves/g1.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::*;
use ark_ec::bls12::Bls12Parameters;
use ark_ec::{
bls12,
models::{ModelParameters, SWModelParameters},
short_weierstrass_jacobian::GroupAffine,
AffineCurve,
};
use ark_ff::{field_new, Zero};
use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, Zero};

pub type G1Affine = bls12::G1Affine<crate::Parameters>;
pub type G1Projective = bls12::G1Projective<crate::Parameters>;
pub type G1Affine = bls12::G1Affine<crate::Parameters0>;
pub type G1Projective = bls12::G1Projective<crate::Parameters0>;

#[derive(Clone, Default, PartialEq, Eq)]
pub struct Parameters;
Expand Down Expand Up @@ -40,6 +43,18 @@ impl SWModelParameters for Parameters {
fn mul_by_a(_: &Self::BaseField) -> Self::BaseField {
Self::BaseField::zero()
}

fn is_in_correct_subgroup_assuming_on_curve(p: &GroupAffine<Parameters>) -> bool {
// r = (u⁴ - u² + 1) = u² * (u²-1) + 1 = u² * lambda + 1
// [r]P = 0 iff [u²] sigma(P) + P = 0
let sigma_p = sigma(p);
let mut mul_sigma_p: GroupAffine<_> =
sigma_p.mul(BigInteger([Parameters0::X[0], 0, 0, 0])).into();
mul_sigma_p = mul_sigma_p
.mul(BigInteger([Parameters0::X[0], 0, 0, 0]))
.into();
(mul_sigma_p + *p).is_zero()
}
}

/// G1_GENERATOR_X =
Expand All @@ -51,3 +66,11 @@ pub const G1_GENERATOR_X: Fq = field_new!(Fq, "368541675371338701678108831518307
/// 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
#[rustfmt::skip]
pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569");

pub const BETA: Fq = field_new!(Fq,"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436");

pub fn sigma(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
let mut sigma_p = *p;
sigma_p.x *= BETA;
sigma_p
}
78 changes: 75 additions & 3 deletions bls12_381/src/curves/g2.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::*;
use ark_ec::bls12::Bls12Parameters;
use ark_ec::{
bls12,
models::{ModelParameters, SWModelParameters},
short_weierstrass_jacobian::GroupAffine,
AffineCurve,
};
use ark_ff::{field_new, Zero};
use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, Field, Zero};

pub type G2Affine = bls12::G2Affine<crate::Parameters>;
pub type G2Projective = bls12::G2Projective<crate::Parameters>;
pub type G2Affine = bls12::G2Affine<crate::Parameters0>;
pub type G2Projective = bls12::G2Projective<crate::Parameters0>;

#[derive(Clone, Default, PartialEq, Eq)]
pub struct Parameters;
Expand Down Expand Up @@ -51,6 +54,17 @@ impl SWModelParameters for Parameters {
fn mul_by_a(_: &Self::BaseField) -> Self::BaseField {
Self::BaseField::zero()
}

fn is_in_correct_subgroup_assuming_on_curve(p: &GroupAffine<Parameters>) -> bool {
let psi2_p = psi2(p);
let psi3_p = psi3(p);
let mut mul_psi3_p: GroupAffine<_> =
psi3_p.mul(BigInteger([Parameters0::X[0], 0, 0, 0])).into();
if Parameters0::X_IS_NEGATIVE {
mul_psi3_p = -mul_psi3_p;
}
(mul_psi3_p + (-psi2_p) + *p).is_zero()
}
}

pub const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
Expand All @@ -75,3 +89,61 @@ pub const G2_GENERATOR_Y_C0: Fq = field_new!(Fq, "198515060228729193556805452117
/// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582
#[rustfmt::skip]
pub const G2_GENERATOR_Y_C1: Fq = field_new!(Fq, "927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582");

// psi(x,y) = (x^p * PSI_X, y^p * PSI_Y) is the Frobenius composed
// with the quadratic twist and its inverse
pub const PSI_X:Fq2 = field_new!(
Fq2,
FQ_ZERO,
field_new!(
Fq,
"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"
)
);
pub const PSI_Y: Fq2 = field_new!(
Fq2,
field_new!(
Fq,
"2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"),
field_new!(
Fq,
"1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257")
);
pub fn psi(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
let mut psi_p = *p;
psi_p.x.frobenius_map(1);
psi_p.y.frobenius_map(1);
// psi_p.x *= PSI_X but PSI_X.c0 = 0
let tmp = psi_p.x;
psi_p.x.c0 = -tmp.c1 * PSI_X.c1;
psi_p.x.c1 = tmp.c0 * PSI_X.c1;
psi_p.y *= PSI_Y;
psi_p
}

// psi2(x,y) = psi²(x,y) = (x*PSI2_X, -y) where PSI2_X = PSI_X^{p+1}
// is in Fq and PSI_Y^{p+1} = -1.
pub const PSI2_X:Fq =
field_new!(
Fq,
"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"
);
pub fn psi2(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
let mut psi2_p = -*p;
psi2_p.x.mul_assign_by_basefield(&PSI2_X);
psi2_p
}

// psi3(x,y) = psi³(x,y) = (x^p*(-u), -y^p * PSI_Y)
// (PSI2_X^p * PSI_X = -u and (-1)^p = -1)
pub fn psi3(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
let mut psi3_p = p.clone();
psi3_p.x.frobenius_map(1);
psi3_p.y.frobenius_map(1);
// psi3_p.x *= (-u)
let tmp = psi3_p.x;
psi3_p.x.c1 = -tmp.c0;
psi3_p.x.c0 = tmp.c1; // * (-u²) but u² = -1
psi3_p.y *= PSI_Y;
-psi3_p
}
6 changes: 3 additions & 3 deletions bls12_381/src/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ pub use self::{
g2::{G2Affine, G2Projective},
};

pub type Bls12_381 = Bls12<Parameters>;
pub type Bls12_381 = Bls12<Parameters0>;

pub struct Parameters;
pub struct Parameters0;

impl Bls12Parameters for Parameters {
impl Bls12Parameters for Parameters0 {
const X: &'static [u64] = &[0xd201000000010000];
const X_IS_NEGATIVE: bool = true;
const TWIST_TYPE: TwistType = TwistType::M;
Expand Down
27 changes: 26 additions & 1 deletion bls12_381/src/curves/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#![allow(unused_imports)]
use ark_ec::{models::SWModelParameters, AffineCurve, PairingEngine, ProjectiveCurve};
use ark_ec::{
models::SWModelParameters,
short_weierstrass_jacobian::{GroupAffine, GroupProjective},
AffineCurve, PairingEngine, ProjectiveCurve,
};
use ark_ff::{
fields::{Field, FpParameters, PrimeField, SquareRootField},
One, Zero,
Expand Down Expand Up @@ -115,3 +119,24 @@ fn test_g1_generator_raw() {
x.add_assign(&Fq::one());
}
}

#[test]
fn test_psi() {
let generator = G2Affine::prime_subgroup_generator();
let mut psi_generator = g2::psi(&generator);
psi_generator = g2::psi(&psi_generator);
let psi2_generator = g2::psi2(&generator);
assert_eq!(psi_generator, psi2_generator);
psi_generator = g2::psi(&psi_generator);
let psi3_generator = g2::psi3(&generator);
assert_eq!(psi3_generator, psi_generator);
}

#[test]
fn test_sigma() {
let generator = G1Affine::prime_subgroup_generator();
let mut sigma_generator = g1::sigma(&generator);
sigma_generator = g1::sigma(&sigma_generator);
sigma_generator = g1::sigma(&sigma_generator);
assert_eq!(sigma_generator, generator);
}
27 changes: 27 additions & 0 deletions curve-benches/src/macros/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,32 @@ macro_rules! ec_bench {
});
}

fn deser_uncompressed(b: &mut $crate::bencher::Bencher) {
use ark_ec::ProjectiveCurve;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
const SAMPLES: usize = 1000;

let mut rng = ark_std::test_rng();

let mut num_bytes = 0;
let tmp = <$projective>::rand(&mut rng).into_affine();
let v: Vec<_> = (0..SAMPLES)
.flat_map(|_| {
let mut bytes = Vec::with_capacity(1000);
tmp.serialize_uncompressed(&mut bytes).unwrap();
num_bytes = bytes.len();
bytes
})
.collect();

let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
let index = count * num_bytes;
<$affine>::deserialize_uncompressed(&v[index..(index + num_bytes)]).unwrap()
});
}

fn msm_131072(b: &mut $crate::bencher::Bencher) {
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
const SAMPLES: usize = 131072;
Expand Down Expand Up @@ -224,6 +250,7 @@ macro_rules! ec_bench {
deser,
ser_unchecked,
deser_unchecked,
deser_uncompressed,
msm_131072,
);
};
Expand Down