Add generators for G1 and G2.
This commit is contained in:
parent
f3adaa923c
commit
352fa7072a
127
src/g1.rs
127
src/g1.rs
|
@ -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
188
src/g2.rs
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
//! ```
|
Loading…
Reference in New Issue