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

Use Scott's subgroup membership tests for G1 and G2 of BLS12-381. #74

Merged
merged 28 commits into from
Sep 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9cb9eb1
implementation of the fast subgroup check for bls12_381
simonmasson Sep 7, 2021
0ac5781
add a bench
simonmasson Sep 7, 2021
dc1893a
subgroup check for g1
simonmasson Sep 8, 2021
42ac45d
subgroup check modifications
simonmasson Sep 8, 2021
fff08cf
remove useless test
simonmasson Sep 8, 2021
9c5d979
fmt
simonmasson Sep 8, 2021
0f0ece9
need the last version of arkworks/algebra
simonmasson Sep 8, 2021
8c8de24
remove Parameters0
simonmasson Sep 10, 2021
f378718
using projective points is more efficient
simonmasson Sep 10, 2021
8f25a9d
use of projective coordinates in G2
simonmasson Sep 10, 2021
01163e0
fmt
simonmasson Sep 10, 2021
d077d6e
documentation on the constants and the psi function
simonmasson Sep 10, 2021
d557005
references for algorithms of eprint 2021/1130
simonmasson Sep 10, 2021
65046fd
fmt
simonmasson Sep 10, 2021
402b153
sed ^ **
simonmasson Sep 13, 2021
03e0bbe
minor improvement
simonmasson Sep 13, 2021
39ab93f
fmt
simonmasson Sep 14, 2021
4847737
fix Cargo toml
weikengchen Sep 17, 2021
79e7617
nits
weikengchen Sep 18, 2021
d41955e
some cleanup for g1
weikengchen Sep 18, 2021
e88dd5d
add the beta test back
weikengchen Sep 18, 2021
51832bc
fmt
weikengchen Sep 18, 2021
17488f9
g2
weikengchen Sep 19, 2021
7b11a07
changelog
weikengchen Sep 19, 2021
03633f9
add a note on the Cargo.toml
weikengchen Sep 19, 2021
345af9d
nits
weikengchen Sep 19, 2021
7edc467
avoid variable name conflicts
weikengchen Sep 19, 2021
6c43cc6
add the early-out optimization
weikengchen Sep 25, 2021
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### Improvements

- [\#74](https://github.com/arkworks-rs/curves/pull/74) Use Scott's subgroup membership tests for `G1` and `G2` of BLS12-381.

### Bug fixes

## v0.3.0
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ lto = "thin"
incremental = true
debug-assertions = true
debug = true

# To be removed in the new release.
[patch.crates-io]
ark-ec = { git = "https://github.com/arkworks-rs/algebra" }
ark-ff = { git = "https://github.com/arkworks-rs/algebra" }
ark-serialize = { git = "https://github.com/arkworks-rs/algebra" }
36 changes: 35 additions & 1 deletion bls12_381/src/curves/g1.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::*;
use ark_ec::{
bls12,
bls12::Bls12Parameters,
models::{ModelParameters, SWModelParameters},
short_weierstrass_jacobian::GroupAffine,
AffineCurve, ProjectiveCurve,
};
use ark_ff::{field_new, Zero};
use ark_ff::{biginteger::BigInteger256, field_new, Zero};
use ark_std::ops::Neg;

pub type G1Affine = bls12::G1Affine<crate::Parameters>;
pub type G1Projective = bls12::G1Projective<crate::Parameters>;
Expand Down Expand Up @@ -40,6 +44,25 @@ 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 {
// Algorithm from Section 6 of https://eprint.iacr.org/2021/1130.
//
// Check that endomorphism_p(P) == -[X^2]P

let x = BigInteger256::new([crate::Parameters::X[0], 0, 0, 0]);

// An early-out optimization described in Section 6.
// If uP == P but P != point of infinity, then the point is not in the right subgroup.
let x_times_p = p.mul(x);
if x_times_p.eq(p) && !p.infinity {
return false;
}

let minus_x_squared_times_p = x_times_p.mul(x).neg();
let endomorphism_p = endomorphism(p);
minus_x_squared_times_p.eq(&endomorphism_p)
}
}

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

/// BETA is a non-trivial cubic root of unity in Fq.
pub const BETA: Fq = field_new!(Fq, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350");

pub fn endomorphism(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
// Endomorphism of the points on the curve.
// endomorphism_p(x,y) = (BETA * x, y) where BETA is a non-trivial cubic root of unity in Fq.
let mut res = (*p).clone();
res.x *= BETA;
res
}
69 changes: 68 additions & 1 deletion bls12_381/src/curves/g2.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
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, field_new, Field, Zero};

pub type G2Affine = bls12::G2Affine<crate::Parameters>;
pub type G2Projective = bls12::G2Projective<crate::Parameters>;
Expand Down Expand Up @@ -51,6 +54,21 @@ impl SWModelParameters for Parameters {
fn mul_by_a(_: &Self::BaseField) -> Self::BaseField {
Self::BaseField::zero()
}

fn is_in_correct_subgroup_assuming_on_curve(point: &GroupAffine<Parameters>) -> bool {
// Algorithm from Section 4 of https://eprint.iacr.org/2021/1130.
//
// Checks that [p]P = [X]P

let mut x_times_point = point.mul(BigInteger256([crate::Parameters::X[0], 0, 0, 0]));
if crate::Parameters::X_IS_NEGATIVE {
x_times_point = -x_times_point;
}

let p_times_point = p_power_endomorphism(point);

x_times_point.eq(&p_times_point)
}
}

pub const G2_GENERATOR_X: Fq2 = field_new!(Fq2, G2_GENERATOR_X_C0, G2_GENERATOR_X_C1);
Expand All @@ -75,3 +93,52 @@ 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

// PSI_X = 1/(u+1)^((p-1)/3)
pub const P_POWER_ENDOMORPHISM_COEFF_0 : Fq2 = field_new!(
Fq2,
FQ_ZERO,
field_new!(
Fq,
"4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"
)
);

// PSI_Y = 1/(u+1)^((p-1)/2)
pub const P_POWER_ENDOMORPHISM_COEFF_1: Fq2 = field_new!(
Fq2,
field_new!(
Fq,
"2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"),
field_new!(
Fq,
"1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257")
);

pub fn p_power_endomorphism(p: &GroupAffine<Parameters>) -> GroupAffine<Parameters> {
// 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). To map a point (x, y) in E' to (s, t) in E,
// one set s = x / ((u+1) ^ (1/3)), t = y / ((u+1) ^ (1/2)), because E: y^2 = x^3 + 4.
// 2. Apply the Frobenius endomorphism (s, t) => (s', t'), another point on curve E,
// where s' = s^p, t' = t^p.
// 3. Map the point from E back to E'; that is,
// one set x' = s' * ((u+1) ^ (1/3)), y' = t' * ((u+1) ^ (1/2)).
//
// To sum up, it maps
// (x,y) -> (x^p / ((u+1)^((p-1)/3)), y^p / ((u+1)^((p-1)/2)))
// as implemented in the code as follows.

let mut res = *p;
res.x.frobenius_map(1);
res.y.frobenius_map(1);

let tmp_x = res.x.clone();
res.x.c0 = -P_POWER_ENDOMORPHISM_COEFF_0.c1 * &tmp_x.c1;
res.x.c1 = P_POWER_ENDOMORPHISM_COEFF_0.c1 * &tmp_x.c0;
res.y *= P_POWER_ENDOMORPHISM_COEFF_1;

res
}
60 changes: 58 additions & 2 deletions bls12_381/src/curves/tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#![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,
BitIteratorBE, One, UniformRand, Zero,
};
use ark_serialize::CanonicalSerialize;
use ark_std::rand::Rng;
Expand All @@ -11,6 +15,7 @@ use core::ops::{AddAssign, MulAssign};

use crate::{g1, g2, Bls12_381, Fq, Fq12, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective};
use ark_algebra_test_templates::{curves::*, groups::*};
use ark_ec::group::Group;

#[test]
fn test_g1_projective_curve() {
Expand Down Expand Up @@ -115,3 +120,54 @@ fn test_g1_generator_raw() {
x.add_assign(&Fq::one());
}
}

#[test]
fn test_g1_endomorphism_beta() {
assert!(g1::BETA.pow(&[3u64]).is_one());
}

#[test]
fn test_g1_subgroup_membership_via_endomorphism() {
let mut rng = test_rng();
let generator = G1Projective::rand(&mut rng).into_affine();
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
}

#[test]
fn test_g1_subgroup_non_membership_via_endomorphism() {
let mut rng = test_rng();
loop {
let x = Fq::rand(&mut rng);
let greatest = rng.gen();

if let Some(p) = G1Affine::get_point_from_x(x, greatest) {
if !p.into_projective().mul(Fr::characteristic()).is_zero() {
assert!(!p.is_in_correct_subgroup_assuming_on_curve());
return;
}
}
}
}

#[test]
fn test_g2_subgroup_membership_via_endomorphism() {
let mut rng = test_rng();
let generator = G2Projective::rand(&mut rng).into_affine();
assert!(generator.is_in_correct_subgroup_assuming_on_curve());
}

#[test]
fn test_g2_subgroup_non_membership_via_endomorphism() {
let mut rng = test_rng();
loop {
let x = Fq2::rand(&mut rng);
let greatest = rng.gen();

if let Some(p) = G2Affine::get_point_from_x(x, greatest) {
if !p.into_projective().mul(Fr::characteristic()).is_zero() {
assert!(!p.is_in_correct_subgroup_assuming_on_curve());
return;
}
}
}
}
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