Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
akakou committed Jun 14, 2022
2 parents 86c2215 + 34dab74 commit e0489d0
Show file tree
Hide file tree
Showing 18 changed files with 1,302 additions and 399 deletions.
20 changes: 5 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.51.0
toolchain: 1.56.0
override: true

# Ensure all code has been formatted with rustfmt
Expand All @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.51.0
toolchain: 1.56.0
override: true
- name: cargo fetch
uses: actions-rs/cargo@v1
Expand All @@ -43,22 +43,12 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --tests --features endo,experimental
args: --verbose --release --tests --features experimental,zeroize
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release --features endo,experimental
- 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
args: --verbose --release
args: --verbose --release --features experimental,zeroize

no-std:
name: Check no-std target ${{ matrix.target }}
Expand All @@ -74,7 +64,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.51.0
toolchain: 1.56.0
override: true
- run: rustup target add ${{ matrix.target }}
- name: cargo fetch
Expand Down
29 changes: 12 additions & 17 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ homepage = "https://github.com/zkcrypto/bls12_381"
license = "MIT/Apache-2.0"
name = "bls12_381"
repository = "https://github.com/zkcrypto/bls12_381"
version = "0.5.0"
edition = "2018"
version = "0.7.0"
edition = "2021"

[package.metadata.docs.rs]
rustdoc-args = [ "--html-in-header", "katex-header.html" ]
Expand All @@ -37,43 +37,38 @@ version = "0.9"
optional = true

[dependencies.ff]
version = "0.10"
version = "0.12"
default-features = false
features = ["derive"]


[dependencies.group]
version = "0.10"
version = "0.12"
default-features = false
optional = true

[dependencies.pairing]
version = "0.20"
version = "0.22"
optional = true

[dependencies.rand_core]
version = "0.6"
default-features = false

[dependencies.subtle]
version = "2.2.1"
version = "2.4.1"
default-features = false

[dependencies.serde]
version = "1.0"
optional = true
[dependencies.zeroize]
version = "1.4"
default-features = false

[dev-dependencies.serde_test]
version = "1.0"
optional = true

[features]
default = ["groups", "pairings", "alloc", "bits", "endo"]
default = ["groups", "pairings", "alloc", "bits"]
bits = ["ff/bits"]
groups = ["group"]
pairings = ["groups", "pairing"]
alloc = ["group/alloc"]
experimental = ["digest"]
nightly = ["subtle/nightly"]

# Deprecated.
# GLV patents US7110538B2 and US7995752B2 expired in September 2020.
endo = []
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This crate provides an implementation of the BLS12-381 pairing-friendly elliptic curve construction.

* **This implementation has not been reviewed or audited. Use at your own risk.**
* This implementation targets Rust `1.51` or later.
* This implementation targets Rust `1.56` or later.
* This implementation does not require the Rust standard library.
* All operations are constant time unless explicitly noted.

Expand All @@ -14,9 +14,8 @@ 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` (on by default): Enables optimizations that leverage curve endomorphisms. Deprecated, will be removed in a future release.
* `experimental`: Enables experimental features. These features have no backwards-compatibility guarantees and may change at any time; users that depend on specific behaviour should pin an exact version of this crate. The current list of experimental features:
* Hashing to curves ([Internet Draft v11](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11))
* Hashing to curves ([Internet Draft v12](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12))

## [Documentation](https://docs.rs/bls12_381)

Expand Down
30 changes: 30 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
# 0.7.0

## Changed
- MSRV bumped to `1.56.0`
- Bumped dependencies to `ff 0.12`, `group 0.12`, `pairing 0.22`.

# 0.6.1

## Changed
- G2 arithmetic is now 25-30% faster across the board.
- Pairings are now 10-15% faster.

# 0.6.0

## Fixed
- `bls12_381::Gt::default()` now returns `Gt::identity()` instead of a nonsensical value.

## Added
- Zeroization support for most public types, behind the `zeroize` feature flag.
- `bls12_381::MillerLoopResult` trait implementations:
- `Default`
- `AddAssign<MillerLoopResult>`
- `AddAssign<&MillerLoopResult>`

## Changed
- Bumped dependencies to `ff 0.11`, `group 0.11`, `pairing 0.21`.

## Removed
- The deprecated `endo` feature flag.

# 0.5.0

## Added
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.51.0
1.56.0
77 changes: 75 additions & 2 deletions src/fp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! This module provides an implementation of the BLS12-381 base field `GF(p)`
//! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`
use core::convert::TryFrom;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use rand_core::RngCore;
Expand Down Expand Up @@ -32,6 +31,9 @@ impl Default for Fp {
}
}

#[cfg(feature = "zeroize")]
impl zeroize::DefaultIsZeroes for Fp {}

impl ConstantTimeEq for Fp {
fn ct_eq(&self, other: &Self) -> Choice {
self.0[0].ct_eq(&other.0[0])
Expand Down Expand Up @@ -206,7 +208,7 @@ impl Fp {

/// Converts an element of `Fp` into a byte representation in
/// big-endian byte order.
pub fn to_bytes(&self) -> [u8; 48] {
pub fn to_bytes(self) -> [u8; 48] {
// Turn into canonical form by computing
// (a.R) / R = a
let tmp = Fp::montgomery_reduce(
Expand Down Expand Up @@ -420,6 +422,67 @@ impl Fp {
(&rhs.neg()).add(self)
}

/// Returns `c = a.zip(b).fold(0, |acc, (a_i, b_i)| acc + a_i * b_i)`.
///
/// Implements Algorithm 2 from Patrick Longa's
/// [ePrint 2022-367](https://eprint.iacr.org/2022/367) §3.
#[inline]
pub(crate) fn sum_of_products<const T: usize>(a: [Fp; T], b: [Fp; T]) -> Fp {
// For a single `a x b` multiplication, operand scanning (schoolbook) takes each
// limb of `a` in turn, and multiplies it by all of the limbs of `b` to compute
// the result as a double-width intermediate representation, which is then fully
// reduced at the end. Here however we have pairs of multiplications (a_i, b_i),
// the results of which are summed.
//
// The intuition for this algorithm is two-fold:
// - We can interleave the operand scanning for each pair, by processing the jth
// limb of each `a_i` together. As these have the same offset within the overall
// operand scanning flow, their results can be summed directly.
// - We can interleave the multiplication and reduction steps, resulting in a
// single bitshift by the limb size after each iteration. This means we only
// need to store a single extra limb overall, instead of keeping around all the
// intermediate results and eventually having twice as many limbs.

// Algorithm 2, line 2
let (u0, u1, u2, u3, u4, u5) =
(0..6).fold((0, 0, 0, 0, 0, 0), |(u0, u1, u2, u3, u4, u5), j| {
// Algorithm 2, line 3
// For each pair in the overall sum of products:
let (t0, t1, t2, t3, t4, t5, t6) = (0..T).fold(
(u0, u1, u2, u3, u4, u5, 0),
|(t0, t1, t2, t3, t4, t5, t6), i| {
// Compute digit_j x row and accumulate into `u`.
let (t0, carry) = mac(t0, a[i].0[j], b[i].0[0], 0);
let (t1, carry) = mac(t1, a[i].0[j], b[i].0[1], carry);
let (t2, carry) = mac(t2, a[i].0[j], b[i].0[2], carry);
let (t3, carry) = mac(t3, a[i].0[j], b[i].0[3], carry);
let (t4, carry) = mac(t4, a[i].0[j], b[i].0[4], carry);
let (t5, carry) = mac(t5, a[i].0[j], b[i].0[5], carry);
let (t6, _) = adc(t6, 0, carry);

(t0, t1, t2, t3, t4, t5, t6)
},
);

// Algorithm 2, lines 4-5
// This is a single step of the usual Montgomery reduction process.
let k = t0.wrapping_mul(INV);
let (_, carry) = mac(t0, k, MODULUS[0], 0);
let (r1, carry) = mac(t1, k, MODULUS[1], carry);
let (r2, carry) = mac(t2, k, MODULUS[2], carry);
let (r3, carry) = mac(t3, k, MODULUS[3], carry);
let (r4, carry) = mac(t4, k, MODULUS[4], carry);
let (r5, carry) = mac(t5, k, MODULUS[5], carry);
let (r6, _) = adc(t6, 0, carry);

(r1, r2, r3, r4, r5, r6)
});

// Because we represent F_p elements in non-redundant form, we need a final
// conditional subtraction to ensure the output is in range.
(&Fp([u0, u1, u2, u3, u4, u5])).subtract_p()
}

#[inline(always)]
pub(crate) const fn montgomery_reduce(
t0: u64,
Expand Down Expand Up @@ -914,3 +977,13 @@ fn test_lexicographic_largest() {
.lexicographically_largest()
));
}

#[cfg(feature = "zeroize")]
#[test]
fn test_zeroize() {
use zeroize::Zeroize;

let mut a = Fp::one();
a.zeroize();
assert!(bool::from(a.is_zero()));
}
13 changes: 13 additions & 0 deletions src/fp12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ impl Default for Fp12 {
}
}

#[cfg(feature = "zeroize")]
impl zeroize::DefaultIsZeroes for Fp12 {}

impl fmt::Debug for Fp12 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?} + ({:?})*w", self.c0, self.c1)
Expand Down Expand Up @@ -644,3 +647,13 @@ fn test_arithmetic() {
.frobenius_map()
);
}

#[cfg(feature = "zeroize")]
#[test]
fn test_zeroize() {
use zeroize::Zeroize;

let mut a = Fp12::one();
a.zeroize();
assert!(bool::from(a.is_zero()));
}
49 changes: 27 additions & 22 deletions src/fp2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ impl Default for Fp2 {
}
}

#[cfg(feature = "zeroize")]
impl zeroize::DefaultIsZeroes for Fp2 {}

impl From<Fp> for Fp2 {
fn from(f: Fp) -> Fp2 {
Fp2 {
Expand Down Expand Up @@ -199,31 +202,23 @@ impl Fp2 {
}
}

pub const fn mul(&self, rhs: &Fp2) -> Fp2 {
// Karatsuba multiplication:
pub fn mul(&self, rhs: &Fp2) -> Fp2 {
// F_{p^2} x F_{p^2} multiplication implemented with operand scanning (schoolbook)
// computes the result as:
//
// v0 = a0 * b0
// v1 = a1 * b1
// c0 = v0 + \beta * v1
// c1 = (a0 + a1) * (b0 + b1) - v0 - v1
// a·b = (a_0 b_0 + a_1 b_1 β) + (a_0 b_1 + a_1 b_0)i
//
// In BLS12-381's F_{p^2}, our \beta is -1 so we
// can modify this formula. (Also, since we always
// subtract v1, we can compute v1 = -a1 * b1.)
// In BLS12-381's F_{p^2}, our β is -1, so the resulting F_{p^2} element is:
//
// c_0 = a_0 b_0 - a_1 b_1
// c_1 = a_0 b_1 + a_1 b_0
//
// v0 = a0 * b0
// v1 = (-a1) * b1
// c0 = v0 + v1
// c1 = (a0 + a1) * (b0 + b1) - v0 + v1

let v0 = (&self.c0).mul(&rhs.c0);
let v1 = (&(&self.c1).neg()).mul(&rhs.c1);
let c0 = (&v0).add(&v1);
let c1 = (&(&self.c0).add(&self.c1)).mul(&(&rhs.c0).add(&rhs.c1));
let c1 = (&c1).sub(&v0);
let c1 = (&c1).add(&v1);

Fp2 { c0, c1 }
// Each of these is a "sum of products", which we can compute efficiently.

Fp2 {
c0: Fp::sum_of_products([self.c0, -self.c1], [rhs.c0, rhs.c1]),
c1: Fp::sum_of_products([self.c0, self.c1], [rhs.c1, rhs.c0]),
}
}

pub const fn add(&self, rhs: &Fp2) -> Fp2 {
Expand Down Expand Up @@ -890,3 +885,13 @@ fn test_lexicographic_largest() {
.lexicographically_largest()
));
}

#[cfg(feature = "zeroize")]
#[test]
fn test_zeroize() {
use zeroize::Zeroize;

let mut a = Fp2::one();
a.zeroize();
assert!(bool::from(a.is_zero()));
}
Loading

0 comments on commit e0489d0

Please sign in to comment.