diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39066dbfd..1388989f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,18 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --verbose --release --tests + args: --verbose --release --tests --features endo - name: Run tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose --release --features endo + - name: Build tests (no endomorphism) + uses: actions-rs/cargo@v1 + with: + command: build + args: --verbose --release --tests + - name: Run tests (no endomorphism) uses: actions-rs/cargo@v1 with: command: test diff --git a/Cargo.toml b/Cargo.toml index 0bfb0d443..b4354ef8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://github.com/zkcrypto/bls12_381" license = "MIT/Apache-2.0" name = "bls12_381" repository = "https://github.com/zkcrypto/bls12_381" -version = "0.1.0" +version = "0.1.1" edition = "2018" [package.metadata.docs.rs] @@ -30,3 +30,6 @@ groups = [] pairings = ["groups"] alloc = [] nightly = ["subtle/nightly"] + +# GLV patents US7110538B2 and US7995752B2 expire in September 2020. +endo = [] diff --git a/README.md b/README.md index 0550c9352..70a238e50 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ This crate provides an implementation of the BLS12-381 pairing-friendly elliptic * `pairings` (on by default): Enables some APIs for performing pairings. * `alloc` (on by default): Enables APIs that require an allocator; these include pairing optimizations. * `nightly`: Enables `subtle/nightly` which tries to prevent compiler optimizations that could jeopardize constant time operations. Requires the nightly Rust compiler. +* `endo`: Enables optimizations that leverage curve endomorphisms, which may run foul of patents US7110538B2 and US7995752B2 set to expire in September 2020. ## [Documentation](https://docs.rs/bls12_381) diff --git a/RELEASES.md b/RELEASES.md index 69afd5204..85fcd4ae5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,12 @@ +# 0.1.1 + +Added `clear_cofactor` methods to `G1Projective` and `G2Projective`. If the crate feature `endo` +is enabled the G2 cofactor clearing will use the curve endomorphism technique described by +[Budroni-Pintore](https://ia.cr/2017/419). If the crate feature `endo` is _not_ enabled then +the code will simulate the effects of the Budroni-Pintore cofactor clearing in order to keep +the API consistent. In September 2020, when patents US7110538B2 and US7995752B2 expire, the +endo feature will be made default. However, for now it must be explicitly enabled. + # 0.1.0 Initial release. diff --git a/src/g2.rs b/src/g2.rs index a4d42da05..16aaa8bc8 100644 --- a/src/g2.rs +++ b/src/g2.rs @@ -805,7 +805,7 @@ impl G2Projective { G2Projective::conditional_select(&res, &tmp, (!f1) & (!f2) & (!f3)) } - fn multiply(&self, by: &[u8; 32]) -> G2Projective { + fn multiply(&self, by: &[u8]) -> G2Projective { let mut acc = G2Projective::identity(); // This is a simple double-and-add implementation of point @@ -827,6 +827,7 @@ impl G2Projective { acc } + #[cfg(feature = "endo")] fn psi(&self) -> G2Projective { // 1 / ((u+1) ^ ((q-1)/3)) let psi_coeff_x = Fp2 { @@ -870,6 +871,7 @@ impl G2Projective { } } + #[cfg(feature = "endo")] fn psi2(&self) -> G2Projective { // 1 / 2 ^ ((q-1)/3) let psi2_coeff_x = Fp2 { @@ -895,6 +897,7 @@ impl G2Projective { } /// Multiply `self` by `crate::BLS_X`, using double and add. + #[cfg(feature = "endo")] fn mul_by_x(&self) -> G2Projective { let mut xself = G2Projective::identity(); // NOTE: in BLS12-381 we can just skip the first bit. @@ -918,15 +921,36 @@ impl G2Projective { /// This is equivalent to multiplying by $h\_\textrm{eff} = 3(z^2 - 1) \cdot /// h_2$, where $h_2$ is the cofactor of $\mathbb{G}\_2$ and $z$ is the /// parameter of BLS12-381. + /// + /// The endomorphism is only actually used if the crate feature `endo` is + /// enabled, and it is disabled by default to mitigate potential patent + /// issues. pub fn clear_cofactor(&self) -> G2Projective { - let t1 = self.mul_by_x(); // [x] P - let t2 = self.psi(); // psi(P) + #[cfg(feature = "endo")] + fn clear_cofactor(this: &G2Projective) -> G2Projective { + let t1 = this.mul_by_x(); // [x] P + let t2 = this.psi(); // psi(P) - self.double().psi2() // psi^2(2P) - + (t1 + t2).mul_by_x() // psi^2(2P) + [x^2] P + [x] psi(P) - - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P) - - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P) - - self // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P) + this.double().psi2() // psi^2(2P) + + (t1 + t2).mul_by_x() // psi^2(2P) + [x^2] P + [x] psi(P) + - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P) + - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P) + - this // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P) + } + + #[cfg(not(feature = "endo"))] + fn clear_cofactor(this: &G2Projective) -> G2Projective { + this.multiply(&[ + 0x51, 0x55, 0xa9, 0xaa, 0x5, 0x0, 0x2, 0xe8, 0xb4, 0xf6, 0xbb, 0xde, 0xa, 0x4c, + 0x89, 0x59, 0xa3, 0xf6, 0x89, 0x66, 0xc0, 0xcb, 0x54, 0xe9, 0x1a, 0x7c, 0x47, 0xd7, + 0x69, 0xec, 0xc0, 0x2e, 0xb0, 0x12, 0x12, 0x5d, 0x1, 0xbf, 0x82, 0x6d, 0x95, 0xdb, + 0x31, 0x87, 0x17, 0x2f, 0x9c, 0x32, 0xe1, 0xff, 0x8, 0x15, 0x3, 0xff, 0x86, 0x99, + 0x68, 0xd7, 0x5a, 0x14, 0xe9, 0xa8, 0xe2, 0x88, 0x28, 0x35, 0x1b, 0xa9, 0xe, 0x6a, + 0x4c, 0x58, 0xb3, 0x75, 0xee, 0xf2, 0x8, 0x9f, 0xc6, 0xb, + ]) + } + + clear_cofactor(self) } /// Converts a batch of `G2Projective` elements into `G2Affine` elements. This @@ -1653,6 +1677,7 @@ fn test_is_torsion_free() { assert!(bool::from(G2Affine::generator().is_torsion_free())); } +#[cfg(feature = "endo")] #[test] fn test_mul_by_x() { // multiplying by `x` a point in G2 is the same as multiplying by @@ -1669,6 +1694,7 @@ fn test_mul_by_x() { assert_eq!(point.mul_by_x(), point * x); } +#[cfg(feature = "endo")] #[test] fn test_psi() { let generator = G2Projective::generator();