Add generators for G1 and G2.

This commit is contained in:
Sean Bowe 2019-08-11 02:52:55 -06:00
parent f3adaa923c
commit 352fa7072a
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
4 changed files with 382 additions and 2 deletions

127
src/g1.rs
View File

@ -1,7 +1,7 @@
//! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.
use crate::fp::Fp;
use subtle::Choice;
use subtle::{Choice, ConstantTimeEq};
/// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space.
/// It is ideal to keep elements in this representation to reduce memory usage and
@ -16,6 +16,57 @@ pub struct G1Affine {
infinity: Choice,
}
const B: Fp = Fp::from_raw_unchecked([
0xaa270000000cfff3,
0x53cc0032fc34000a,
0x478fe97a6b0a807f,
0xb1d37ebee6ba24d7,
0x8ec9733bbf78ab2f,
0x9d645513d83de7e,
]);
impl G1Affine {
/// Returns the identity of the group: the point at infinity.
pub fn identity() -> G1Affine {
G1Affine {
x: Fp::zero(),
y: Fp::one(),
infinity: Choice::from(1u8),
}
}
/// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
/// for how this generator is chosen.
pub fn generator() -> G1Affine {
G1Affine {
x: Fp::from_raw_unchecked([
0x5cb38790fd530c16,
0x7817fc679976fff5,
0x154f95c7143ba1c1,
0xf0ae6acdf3d0e747,
0xedce6ecc21dbf440,
0x120177419e0bfb75,
]),
y: Fp::from_raw_unchecked([
0xbaac93d50ce72271,
0x8c22631a7918fd8e,
0xdd595f13570725ce,
0x51ac582950405194,
0xe1c8c3fad0059c0,
0xbbc3efc5008a26a,
]),
infinity: Choice::from(0u8),
}
}
/// Returns true if this point is on the curve. This should always return
/// true unless an "unchecked" API was used.
pub fn is_on_curve(&self) -> Choice {
// y^2 - x^3 ?= 4
(self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
}
}
/// This is an element of $\mathbb{G}_1$ represented in the projective coordinate space.
#[derive(Copy, Clone, Debug)]
pub struct G1Projective {
@ -23,3 +74,77 @@ pub struct G1Projective {
y: Fp,
z: Fp,
}
impl G1Projective {
/// Returns the identity of the group: the point at infinity.
pub fn identity() -> G1Projective {
G1Projective {
x: Fp::zero(),
y: Fp::one(),
z: Fp::zero(),
}
}
/// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
/// for how this generator is chosen.
pub fn generator() -> G1Projective {
G1Projective {
x: Fp::from_raw_unchecked([
0x5cb38790fd530c16,
0x7817fc679976fff5,
0x154f95c7143ba1c1,
0xf0ae6acdf3d0e747,
0xedce6ecc21dbf440,
0x120177419e0bfb75,
]),
y: Fp::from_raw_unchecked([
0xbaac93d50ce72271,
0x8c22631a7918fd8e,
0xdd595f13570725ce,
0x51ac582950405194,
0xe1c8c3fad0059c0,
0xbbc3efc5008a26a,
]),
z: Fp::one(),
}
}
/// Returns true if this point is on the curve. This should always return
/// true unless an "unchecked" API was used.
pub fn is_on_curve(&self) -> Choice {
// Y^2 - X^3 = 4(Z^6)
(self.y.square() - (self.x.square() * self.x))
.ct_eq(&((self.z.square() * self.z).square() * B))
| self.z.is_zero()
}
}
#[test]
fn test_is_on_curve() {
assert!(bool::from(G1Affine::identity().is_on_curve()));
assert!(bool::from(G1Affine::generator().is_on_curve()));
assert!(bool::from(G1Projective::identity().is_on_curve()));
assert!(bool::from(G1Projective::generator().is_on_curve()));
let z = Fp::from_raw_unchecked([
0xba7afa1f9a6fe250,
0xfa0f5b595eafe731,
0x3bdc477694c306e7,
0x2149be4b3949fa24,
0x64aa6e0649b2078c,
0x12b108ac33643c3e,
]);
let gen = G1Affine::generator();
let mut test = G1Projective {
x: gen.x * (z.square()),
y: gen.y * (z.square() * z),
z,
};
assert!(bool::from(test.is_on_curve()));
test.x = z;
assert!(!bool::from(test.is_on_curve()));
}

188
src/g2.rs
View File

@ -1,7 +1,8 @@
//! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.
use crate::fp::Fp;
use crate::fp2::Fp2;
use subtle::Choice;
use subtle::{Choice, ConstantTimeEq};
/// This is an element of $\mathbb{G}_2$ represented in the affine coordinate space.
/// It is ideal to keep elements in this representation to reduce memory usage and
@ -16,6 +17,87 @@ pub struct G2Affine {
infinity: Choice,
}
const B: Fp2 = Fp2 {
c0: Fp::from_raw_unchecked([
0xaa270000000cfff3,
0x53cc0032fc34000a,
0x478fe97a6b0a807f,
0xb1d37ebee6ba24d7,
0x8ec9733bbf78ab2f,
0x9d645513d83de7e,
]),
c1: Fp::from_raw_unchecked([
0xaa270000000cfff3,
0x53cc0032fc34000a,
0x478fe97a6b0a807f,
0xb1d37ebee6ba24d7,
0x8ec9733bbf78ab2f,
0x9d645513d83de7e,
]),
};
impl G2Affine {
/// Returns the identity of the group: the point at infinity.
pub fn identity() -> G2Affine {
G2Affine {
x: Fp2::zero(),
y: Fp2::one(),
infinity: Choice::from(1u8),
}
}
/// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
/// for how this generator is chosen.
pub fn generator() -> G2Affine {
G2Affine {
x: Fp2 {
c0: Fp::from_raw_unchecked([
0xf5f28fa202940a10,
0xb3f5fb2687b4961a,
0xa1a893b53e2ae580,
0x9894999d1a3caee9,
0x6f67b7631863366b,
0x58191924350bcd7,
]),
c1: Fp::from_raw_unchecked([
0xa5a9c0759e23f606,
0xaaa0c59dbccd60c3,
0x3bb17e18e2867806,
0x1b1ab6cc8541b367,
0xc2b6ed0ef2158547,
0x11922a097360edf3,
]),
},
y: Fp2 {
c0: Fp::from_raw_unchecked([
0x4c730af860494c4a,
0x597cfa1f5e369c5a,
0xe7e6856caa0a635a,
0xbbefb5e96e0d495f,
0x7d3a975f0ef25a2,
0x83fd8e7e80dae5,
]),
c1: Fp::from_raw_unchecked([
0xadc0fc92df64b05d,
0x18aa270a2b1461dc,
0x86adac6a3be4eba0,
0x79495c4ec93da33a,
0xe7175850a43ccaed,
0xb2bc2a163de1bf2,
]),
},
infinity: Choice::from(0u8),
}
}
/// Returns true if this point is on the curve. This should always return
/// true unless an "unchecked" API was used.
pub fn is_on_curve(&self) -> Choice {
// y^2 - x^3 ?= 4(u + 1)
(self.y.square() - (self.x.square() * self.x)).ct_eq(&B) | self.infinity
}
}
/// This is an element of $\mathbb{G}_2$ represented in the projective coordinate space.
#[derive(Copy, Clone, Debug)]
pub struct G2Projective {
@ -23,3 +105,107 @@ pub struct G2Projective {
y: Fp2,
z: Fp2,
}
impl G2Projective {
/// Returns the identity of the group: the point at infinity.
pub fn identity() -> G2Projective {
G2Projective {
x: Fp2::zero(),
y: Fp2::one(),
z: Fp2::zero(),
}
}
/// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators)
/// for how this generator is chosen.
pub fn generator() -> G2Projective {
G2Projective {
x: Fp2 {
c0: Fp::from_raw_unchecked([
0xf5f28fa202940a10,
0xb3f5fb2687b4961a,
0xa1a893b53e2ae580,
0x9894999d1a3caee9,
0x6f67b7631863366b,
0x58191924350bcd7,
]),
c1: Fp::from_raw_unchecked([
0xa5a9c0759e23f606,
0xaaa0c59dbccd60c3,
0x3bb17e18e2867806,
0x1b1ab6cc8541b367,
0xc2b6ed0ef2158547,
0x11922a097360edf3,
]),
},
y: Fp2 {
c0: Fp::from_raw_unchecked([
0x4c730af860494c4a,
0x597cfa1f5e369c5a,
0xe7e6856caa0a635a,
0xbbefb5e96e0d495f,
0x7d3a975f0ef25a2,
0x83fd8e7e80dae5,
]),
c1: Fp::from_raw_unchecked([
0xadc0fc92df64b05d,
0x18aa270a2b1461dc,
0x86adac6a3be4eba0,
0x79495c4ec93da33a,
0xe7175850a43ccaed,
0xb2bc2a163de1bf2,
]),
},
z: Fp2::one(),
}
}
/// Returns true if this point is on the curve. This should always return
/// true unless an "unchecked" API was used.
pub fn is_on_curve(&self) -> Choice {
// Y^2 - X^3 = 4(u + 1)(Z^6)
(self.y.square() - (self.x.square() * self.x))
.ct_eq(&((self.z.square() * self.z).square() * B))
| self.z.is_zero()
}
}
#[test]
fn test_is_on_curve() {
assert!(bool::from(G2Affine::identity().is_on_curve()));
assert!(bool::from(G2Affine::generator().is_on_curve()));
assert!(bool::from(G2Projective::identity().is_on_curve()));
assert!(bool::from(G2Projective::generator().is_on_curve()));
let z = Fp2 {
c0: Fp::from_raw_unchecked([
0xba7afa1f9a6fe250,
0xfa0f5b595eafe731,
0x3bdc477694c306e7,
0x2149be4b3949fa24,
0x64aa6e0649b2078c,
0x12b108ac33643c3e,
]),
c1: Fp::from_raw_unchecked([
0x125325df3d35b5a8,
0xdc469ef5555d7fe3,
0x2d716d2443106a9,
0x5a1db59a6ff37d0,
0x7cf7784e5300bb8f,
0x16a88922c7a5e844,
]),
};
let gen = G2Affine::generator();
let mut test = G2Projective {
x: gen.x * (z.square()),
y: gen.y * (z.square() * z),
z,
};
assert!(bool::from(test.is_on_curve()));
test.x = z;
assert!(!bool::from(test.is_on_curve()));
}

View File

@ -26,6 +26,12 @@ extern crate std;
#[macro_use]
mod util;
/// Notes about how the BLS12-381 elliptic curve is designed, specified
/// and implemented by this library.
pub mod notes {
pub mod design;
}
mod scalar;
pub use scalar::Scalar;

63
src/notes/design.rs Normal file
View File

@ -0,0 +1,63 @@
//! # Design of BLS12-381
//! ## Fixed Generators
//!
//! Although any generator produced by hashing to $\mathbb{G}_1$ or $\mathbb{G}_2$ is
//! safe to use in a cryptographic protocol, we specify some simple, fixed generators.
//!
//! In order to derive these generators, we select the lexicographically smallest
//! valid $x$-coordinate and the lexicographically smallest corresponding $y$-coordinate,
//! and then scale the resulting point by the cofactor, such that the result is not the
//! identity. This results in the following fixed generators:
//!
//! 1. $\mathbb{G}_1$
//! * $x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507$
//! * $y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569$
//! 2. $\mathbb{G}_2$
//! * $x = 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 + 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758 u$
//! * $y = 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 + 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582 u$
//!
//! This can be derived using the following sage script:
//!
//! ```norun
//! param = -0xd201000000010000
//! def r(x):
//! return (x**4) - (x**2) + 1
//! def q(x):
//! return (((x - 1) ** 2) * ((x**4) - (x**2) + 1) // 3) + x
//! def g1_h(x):
//! return ((x-1)**2) // 3
//! def g2_h(x):
//! return ((x**8) - (4 * (x**7)) + (5 * (x**6)) - (4 * (x**4)) + (6 * (x**3)) - (4 * (x**2)) - (4*x) + 13) // 9
//! q = q(param)
//! r = r(param)
//! Fq = GF(q)
//! ec = EllipticCurve(Fq, [0, 4])
//! def psqrt(v):
//! assert(not v.is_zero())
//! a = sqrt(v)
//! b = -a
//! if a < b:
//! return a
//! else:
//! return b
//! for x in range(0,100):
//! rhs = Fq(x)^3 + 4
//! if rhs.is_square():
//! y = psqrt(rhs)
//! p = ec(x, y) * g1_h(param)
//! if (not p.is_zero()) and (p * r).is_zero():
//! print "g1 generator: %s" % p
//! break
//! Fqx.<j> = PolynomialRing(Fq, 'j')
//! Fq2.<i> = GF(q^2, modulus=j^2 + 1)
//! ec2 = EllipticCurve(Fq2, [0, (4 * (1 + i))])
//! assert(ec2.order() == (r * g2_h(param)))
//! for x in range(0,100):
//! rhs = (Fq2(x))^3 + (4 * (1 + i))
//! if rhs.is_square():
//! y = psqrt(rhs)
//! p = ec2(Fq2(x), y) * g2_h(param)
//! if (not p.is_zero()) and (p * r).is_zero():
//! print "g2 generator: %s" % p
//! break
//! ```