Squashed 'bls12_381/' changes from 1a2e9f3..d0ea5d4

d0ea5d4 Merge pull request #32 from narodnik/sum
24aa1a4 Merge pull request #31 from zkcrypto/release-0.1.1
fb7c4cb add cargo fmt for sum traits (code we added)
ccef392 add sum iterator implementations
82e14ed Release 0.1.1
a3608d4 Put endo optimizations behind endo crate feature.
e32494e Merge pull request #18 from mmaker/master
948b199 Fix typo in comment.
b3d1fe1 Merge pull request #27 from rex4539/fix-typos
253f681 Merge pull request #25 from mmaker/fix/sage-script
c55f88f Fix typos
14b5e16 No need to define a polynomial ring in notes/design.rs.
c9d17f6 Make sage script in notes/design.rs work with sage 3.9.
af9ec4d Minor changes to comments documenting `clear_cofactor`
7dc6f31 Add clear_cofactor.

git-subtree-dir: bls12_381
git-subtree-split: d0ea5d4958cae999dea1800207704171aa07a9ef
This commit is contained in:
Jack Grigg 2020-08-12 18:25:52 +01:00
parent dbd9bd1b9b
commit a5a6f57c5a
8 changed files with 462 additions and 11 deletions

View File

@ -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

View File

@ -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 = []

View File

@ -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)
@ -26,7 +27,7 @@ BLS12-381 is a pairing-friendly elliptic curve construction from the [BLS family
* q = z<sup>4</sup> - z<sup>2</sup> + 1
* = `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001`
... yielding two **source groups** G<sub>1</sub> and G<sub>2</sub>, each of 255-bit prime order `q`, such that an efficiently computable non-degenerate bilinear pairing function `e` exists into a third **target group** G<sub>T</sub>. Specifically, G<sub>1</sub> is the `q`-order subgroup of E(F<sub>p</sub>) : y<sup>2</sup> = x<sup>3</sup> + 4 and G<sub>2</sub> is the `q`-order subgroup of E'(F<sub>p<sup>2</sup></sub>) : y<sup>2</sup> = x<sup>3</sup> + 4(u + 1) where the extention field F<sub>p<sup>2</sup></sub> is defined as F<sub>p</sub>(u) / (u<sup>2</sup> + 1).
... yielding two **source groups** G<sub>1</sub> and G<sub>2</sub>, each of 255-bit prime order `q`, such that an efficiently computable non-degenerate bilinear pairing function `e` exists into a third **target group** G<sub>T</sub>. Specifically, G<sub>1</sub> is the `q`-order subgroup of E(F<sub>p</sub>) : y<sup>2</sup> = x<sup>3</sup> + 4 and G<sub>2</sub> is the `q`-order subgroup of E'(F<sub>p<sup>2</sup></sub>) : y<sup>2</sup> = x<sup>3</sup> + 4(u + 1) where the extension field F<sub>p<sup>2</sup></sub> is defined as F<sub>p</sub>(u) / (u<sup>2</sup> + 1).
BLS12-381 is chosen so that `z` has small Hamming weight (to improve pairing performance) and also so that `GF(q)` has a large 2<sup>32</sup> primitive root of unity for performing radix-2 fast Fourier transforms for efficient multi-point evaluation and interpolation. It is also chosen so that it exists in a particularly efficient and rigid subfamily of BLS12 curves.
@ -34,7 +35,7 @@ BLS12-381 is chosen so that `z` has small Hamming weight (to improve pairing per
Pairing-friendly elliptic curve constructions are (necessarily) less secure than conventional elliptic curves due to their small "embedding degree". Given a small enough embedding degree, the pairing function itself would allow for a break in DLP hardness if it projected into a weak target group, as weaknesses in this target group are immediately translated into weaknesses in the source group.
In order to achieve reasonable security without an unreasonably expensive pairing function, a careful choice of embedding degree, base field characteristic and prime subgroup order must be made. BLS12-381 uses an embedding degree of 12 to ensure fast pairing performance but a choice of a 381-bit base field characteristic to yeild a 255-bit subgroup order (for protection against [Pollard's rho algorithm](https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm)) while reaching close to a 128-bit security level.
In order to achieve reasonable security without an unreasonably expensive pairing function, a careful choice of embedding degree, base field characteristic and prime subgroup order must be made. BLS12-381 uses an embedding degree of 12 to ensure fast pairing performance but a choice of a 381-bit base field characteristic to yield a 255-bit subgroup order (for protection against [Pollard's rho algorithm](https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm)) while reaching close to a 128-bit security level.
There are [known optimizations](https://ellipticnews.wordpress.com/2016/05/02/kim-barbulescu-variant-of-the-number-field-sieve-to-compute-discrete-logarithms-in-finite-fields/) of the [Number Field Sieve algorithm](https://en.wikipedia.org/wiki/General_number_field_sieve) which could be used to weaken DLP security in the target group by taking advantage of its structure, as it is a multiplicative subgroup of a low-degree extension field. However, these attacks require an (as of yet unknown) efficient algorithm for scanning a large space of polynomials. Even if the attack were practical it would only reduce security to roughly 117 to 120 bits. (This contrasts with 254-bit BN curves which usually have less than 100 bits of security in the same situation.)

View File

@ -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.

106
src/g1.rs
View File

@ -1,5 +1,7 @@
//! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.
use core::borrow::Borrow;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@ -140,6 +142,18 @@ impl<'a, 'b> Sub<&'b G1Affine> for &'a G1Projective {
}
}
impl<T> Sum<T> for G1Projective
where
T: Borrow<G1Projective>,
{
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = T>,
{
iter.fold(Self::identity(), |acc, item| acc + item.borrow())
}
}
impl_binops_additive!(G1Projective, G1Affine);
impl_binops_additive_specify_output!(G1Affine, G1Projective, G1Projective);
@ -735,6 +749,34 @@ impl G1Projective {
acc
}
/// Multiply `self` by `crate::BLS_X`, using double and add.
fn mul_by_x(&self) -> G1Projective {
let mut xself = G1Projective::identity();
// NOTE: in BLS12-381 we can just skip the first bit.
let mut x = crate::BLS_X >> 1;
let mut tmp = *self;
while x != 0 {
tmp = tmp.double();
if x % 2 == 1 {
xself += tmp;
}
x >>= 1;
}
// finally, flip the sign
if crate::BLS_X_IS_NEGATIVE {
xself = -xself;
}
xself
}
/// Multiplies by $(1 - z)$, where $z$ is the parameter of BLS12-381, which
/// [suffices to clear](https://ia.cr/2019/403) the cofactor and map
/// elliptic curve points to elements of $\mathbb{G}\_1$.
pub fn clear_cofactor(&self) -> G1Projective {
self - self.mul_by_x()
}
/// Converts a batch of `G1Projective` elements into `G1Affine` elements. This
/// function will panic if `p.len() != q.len()`.
pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) {
@ -1303,6 +1345,70 @@ fn test_is_torsion_free() {
assert!(bool::from(G1Affine::generator().is_torsion_free()));
}
#[test]
fn test_mul_by_x() {
// multiplying by `x` a point in G1 is the same as multiplying by
// the equivalent scalar.
let generator = G1Projective::generator();
let x = if crate::BLS_X_IS_NEGATIVE {
-Scalar::from(crate::BLS_X)
} else {
Scalar::from(crate::BLS_X)
};
assert_eq!(generator.mul_by_x(), generator * x);
let point = G1Projective::generator() * Scalar::from(42);
assert_eq!(point.mul_by_x(), point * x);
}
#[test]
fn test_clear_cofactor() {
// the generator (and the identity) are always on the curve,
// even after clearing the cofactor
let generator = G1Projective::generator();
assert!(bool::from(generator.clear_cofactor().is_on_curve()));
let id = G1Projective::identity();
assert!(bool::from(id.clear_cofactor().is_on_curve()));
let point = G1Projective {
x: Fp::from_raw_unchecked([
0x48af5ff540c817f0,
0xd73893acaf379d5a,
0xe6c43584e18e023c,
0x1eda39c30f188b3e,
0xf618c6d3ccc0f8d8,
0x0073542cd671e16c,
]),
y: Fp::from_raw_unchecked([
0x57bf8be79461d0ba,
0xfc61459cee3547c3,
0x0d23567df1ef147b,
0x0ee187bcce1d9b64,
0xb0c8cfbe9dc8fdc1,
0x1328661767ef368b,
]),
z: Fp::from_raw_unchecked([
0x3d2d1c670671394e,
0x0ee3a800a2f7c1ca,
0x270f4f21da2e5050,
0xe02840a53f1be768,
0x55debeb597512690,
0x08bd25353dc8f791,
]),
};
assert!(bool::from(point.is_on_curve()));
assert!(!bool::from(G1Affine::from(point).is_torsion_free()));
let cleared_point = point.clear_cofactor();
assert!(bool::from(cleared_point.is_on_curve()));
assert!(bool::from(G1Affine::from(cleared_point).is_torsion_free()));
// in BLS12-381 the cofactor in G1 can be
// cleared multiplying by (1-x)
let h_eff = Scalar::from(1) + Scalar::from(crate::BLS_X);
assert_eq!(point.clear_cofactor(), point * h_eff);
}
#[test]
fn test_batch_normalize() {
let a = G1Projective::generator().double();

325
src/g2.rs
View File

@ -1,5 +1,7 @@
//! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.
use core::borrow::Borrow;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@ -141,6 +143,18 @@ impl<'a, 'b> Sub<&'b G2Affine> for &'a G2Projective {
}
}
impl<T> Sum<T> for G2Projective
where
T: Borrow<G2Projective>,
{
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = T>,
{
iter.fold(Self::identity(), |acc, item| acc + item.borrow())
}
}
impl_binops_additive!(G2Projective, G2Affine);
impl_binops_additive_specify_output!(G2Affine, G2Projective, G2Projective);
@ -805,7 +819,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 +841,132 @@ impl G2Projective {
acc
}
#[cfg(feature = "endo")]
fn psi(&self) -> G2Projective {
// 1 / ((u+1) ^ ((q-1)/3))
let psi_coeff_x = Fp2 {
c0: Fp::zero(),
c1: Fp::from_raw_unchecked([
0x890dc9e4867545c3,
0x2af322533285a5d5,
0x50880866309b7e2c,
0xa20d1b8c7e881024,
0x14e4f04fe2db9068,
0x14e56d3f1564853a,
]),
};
// 1 / ((u+1) ^ (p-1)/2)
let psi_coeff_y = Fp2 {
c0: Fp::from_raw_unchecked([
0x3e2f585da55c9ad1,
0x4294213d86c18183,
0x382844c88b623732,
0x92ad2afd19103e18,
0x1d794e4fac7cf0b9,
0x0bd592fc7d825ec8,
]),
c1: Fp::from_raw_unchecked([
0x7bcfa7a25aa30fda,
0xdc17dec12a927e7c,
0x2f088dd86b4ebef1,
0xd1ca2087da74d4a7,
0x2da2596696cebc1d,
0x0e2b7eedbbfd87d2,
]),
};
G2Projective {
// x = frobenius(x)/((u+1)^((p-1)/3))
x: self.x.frobenius_map() * psi_coeff_x,
// y = frobenius(y)/(u+1)^((p-1)/2)
y: self.y.frobenius_map() * psi_coeff_y,
// z = frobenius(z)
z: self.z.frobenius_map(),
}
}
#[cfg(feature = "endo")]
fn psi2(&self) -> G2Projective {
// 1 / 2 ^ ((q-1)/3)
let psi2_coeff_x = Fp2 {
c0: Fp::from_raw_unchecked([
0xcd03c9e48671f071,
0x5dab22461fcda5d2,
0x587042afd3851b95,
0x8eb60ebe01bacb9e,
0x03f97d6e83d050d2,
0x18f0206554638741,
]),
c1: Fp::zero(),
};
G2Projective {
// x = frobenius^2(x)/2^((p-1)/3)
x: self.x.frobenius_map().frobenius_map() * psi2_coeff_x,
// y = -frobenius^2(y)
y: self.y.frobenius_map().frobenius_map().neg(),
// z = z
z: self.z,
}
}
/// 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.
let mut x = crate::BLS_X >> 1;
let mut acc = *self;
while x != 0 {
acc = acc.double();
if x % 2 == 1 {
xself += acc;
}
x >>= 1;
}
// finally, flip the sign
if crate::BLS_X_IS_NEGATIVE {
xself = -xself;
}
xself
}
/// Clears the cofactor, using [Budroni-Pintore](https://ia.cr/2017/419).
/// 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 {
#[cfg(feature = "endo")]
fn clear_cofactor(this: &G2Projective) -> G2Projective {
let t1 = this.mul_by_x(); // [x] P
let t2 = this.psi(); // 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
/// function will panic if `p.len() != q.len()`.
pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) {
@ -1551,6 +1691,189 @@ 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
// the equivalent scalar.
let generator = G2Projective::generator();
let x = if crate::BLS_X_IS_NEGATIVE {
-Scalar::from(crate::BLS_X)
} else {
Scalar::from(crate::BLS_X)
};
assert_eq!(generator.mul_by_x(), generator * x);
let point = G2Projective::generator() * Scalar::from(42);
assert_eq!(point.mul_by_x(), point * x);
}
#[cfg(feature = "endo")]
#[test]
fn test_psi() {
let generator = G2Projective::generator();
// `point` is a random point in the curve
let point = G2Projective {
x: Fp2 {
c0: Fp::from_raw_unchecked([
0xee4c8cb7c047eaf2,
0x44ca22eee036b604,
0x33b3affb2aefe101,
0x15d3e45bbafaeb02,
0x7bfc2154cd7419a4,
0x0a2d0c2b756e5edc,
]),
c1: Fp::from_raw_unchecked([
0xfc224361029a8777,
0x4cbf2baab8740924,
0xc5008c6ec6592c89,
0xecc2c57b472a9c2d,
0x8613eafd9d81ffb1,
0x10fe54daa2d3d495,
]),
},
y: Fp2 {
c0: Fp::from_raw_unchecked([
0x7de7edc43953b75c,
0x58be1d2de35e87dc,
0x5731d30b0e337b40,
0xbe93b60cfeaae4c9,
0x8b22c203764bedca,
0x01616c8d1033b771,
]),
c1: Fp::from_raw_unchecked([
0xea126fe476b5733b,
0x85cee68b5dae1652,
0x98247779f7272b04,
0xa649c8b468c6e808,
0xb5b9a62dff0c4e45,
0x1555b67fc7bbe73d,
]),
},
z: Fp2 {
c0: Fp::from_raw_unchecked([
0x0ef2ddffab187c0a,
0x2424522b7d5ecbfc,
0xc6f341a3398054f4,
0x5523ddf409502df0,
0xd55c0b5a88e0dd97,
0x066428d704923e52,
]),
c1: Fp::from_raw_unchecked([
0x538bbe0c95b4878d,
0xad04a50379522881,
0x6d5c05bf5c12fb64,
0x4ce4a069a2d34787,
0x59ea6c8d0dffaeaf,
0x0d42a083a75bd6f3,
]),
},
};
assert!(bool::from(point.is_on_curve()));
// psi2(P) = psi(psi(P))
assert_eq!(generator.psi2(), generator.psi().psi());
assert_eq!(point.psi2(), point.psi().psi());
// psi(P) is a morphism
assert_eq!(generator.double().psi(), generator.psi().double());
assert_eq!(point.psi() + generator.psi(), (point + generator).psi());
// psi(P) behaves in the same way on the same projective point
let mut normalized_point = [G2Affine::identity()];
G2Projective::batch_normalize(&[point], &mut normalized_point);
let normalized_point = G2Projective::from(normalized_point[0]);
assert_eq!(point.psi(), normalized_point.psi());
assert_eq!(point.psi2(), normalized_point.psi2());
}
#[test]
fn test_clear_cofactor() {
// `point` is a random point in the curve
let point = G2Projective {
x: Fp2 {
c0: Fp::from_raw_unchecked([
0xee4c8cb7c047eaf2,
0x44ca22eee036b604,
0x33b3affb2aefe101,
0x15d3e45bbafaeb02,
0x7bfc2154cd7419a4,
0x0a2d0c2b756e5edc,
]),
c1: Fp::from_raw_unchecked([
0xfc224361029a8777,
0x4cbf2baab8740924,
0xc5008c6ec6592c89,
0xecc2c57b472a9c2d,
0x8613eafd9d81ffb1,
0x10fe54daa2d3d495,
]),
},
y: Fp2 {
c0: Fp::from_raw_unchecked([
0x7de7edc43953b75c,
0x58be1d2de35e87dc,
0x5731d30b0e337b40,
0xbe93b60cfeaae4c9,
0x8b22c203764bedca,
0x01616c8d1033b771,
]),
c1: Fp::from_raw_unchecked([
0xea126fe476b5733b,
0x85cee68b5dae1652,
0x98247779f7272b04,
0xa649c8b468c6e808,
0xb5b9a62dff0c4e45,
0x1555b67fc7bbe73d,
]),
},
z: Fp2 {
c0: Fp::from_raw_unchecked([
0x0ef2ddffab187c0a,
0x2424522b7d5ecbfc,
0xc6f341a3398054f4,
0x5523ddf409502df0,
0xd55c0b5a88e0dd97,
0x066428d704923e52,
]),
c1: Fp::from_raw_unchecked([
0x538bbe0c95b4878d,
0xad04a50379522881,
0x6d5c05bf5c12fb64,
0x4ce4a069a2d34787,
0x59ea6c8d0dffaeaf,
0x0d42a083a75bd6f3,
]),
},
};
assert!(bool::from(point.is_on_curve()));
assert!(!bool::from(G2Affine::from(point).is_torsion_free()));
let cleared_point = point.clear_cofactor();
assert!(bool::from(cleared_point.is_on_curve()));
assert!(bool::from(G2Affine::from(cleared_point).is_torsion_free()));
// the generator (and the identity) are always on the curve,
// even after clearing the cofactor
let generator = G2Projective::generator();
assert!(bool::from(generator.clear_cofactor().is_on_curve()));
let id = G2Projective::identity();
assert!(bool::from(id.clear_cofactor().is_on_curve()));
// test the effect on q-torsion points multiplying by h_eff modulo |Scalar|
// h_eff % q = 0x2b116900400069009a40200040001ffff
let h_eff_modq: [u8; 32] = [
0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16,
0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
];
assert_eq!(generator.clear_cofactor(), generator.multiply(&h_eff_modq));
assert_eq!(
cleared_point.clear_cofactor(),
cleared_point.multiply(&h_eff_modq)
);
}
#[test]
fn test_batch_normalize() {
let a = G2Projective::generator().double();

View File

@ -46,10 +46,9 @@
//! 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
//! print("g1 generator: {}".format(p))
//! break
//! Fqx.<j> = PolynomialRing(Fq, 'j')
//! Fq2.<i> = GF(q^2, modulus=j^2 + 1)
//! Fq2.<i> = GF(q^2, modulus=[1, 0, 1])
//! ec2 = EllipticCurve(Fq2, [0, (4 * (1 + i))])
//! assert(ec2.order() == (r * g2_h(param)))
//! for x in range(0,100):
@ -57,7 +56,7 @@
//! 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
//! if not p.is_zero() and (p * r).is_zero():
//! print("g2 generator: {}".format(p))
//! break
//! ```

View File

@ -256,7 +256,7 @@ impl Scalar {
//
// and computing their sum in the field. It remains to see that arbitrary 256-bit
// numbers can be placed into Montgomery form safely using the reduction. The
// reduction works so long as the product is less than R=2^256 multipled by
// reduction works so long as the product is less than R=2^256 multiplied by
// the modulus. This holds because for any `c` smaller than the modulus, we have
// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
// reduction always works so long as `c` is in the field; in this case it is either the