Add implementation of scalar multiplication for G1/G2.

This commit is contained in:
Sean Bowe 2019-08-11 19:29:59 -06:00
parent 50c599ec96
commit 526209abdf
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
3 changed files with 180 additions and 2 deletions

View File

@ -11,12 +11,16 @@ fn criterion_benchmark(c: &mut Criterion) {
{
let name = "G1Affine";
let a = G1Affine::generator();
let s = Scalar::from_raw([1, 2, 3, 4]);
c.bench_function(&format!("{} check on curve", name), move |b| {
b.iter(|| black_box(a).is_on_curve())
});
c.bench_function(&format!("{} check equality", name), move |b| {
b.iter(|| black_box(a) == black_box(a))
});
c.bench_function(&format!("{} scalar multiplication", name), move |b| {
b.iter(|| black_box(a) * black_box(s))
});
}
// G1Projective
@ -24,6 +28,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let name = "G1Projective";
let a = G1Projective::generator();
let a_affine = G1Affine::generator();
let s = Scalar::from_raw([1, 2, 3, 4]);
c.bench_function(&format!("{} check on curve", name), move |b| {
b.iter(|| black_box(a).is_on_curve())
});
@ -42,18 +47,25 @@ fn criterion_benchmark(c: &mut Criterion) {
c.bench_function(&format!("{} mixed addition", name), move |b| {
b.iter(|| black_box(a).add_mixed(&a_affine))
});
c.bench_function(&format!("{} scalar multiplication", name), move |b| {
b.iter(|| black_box(a) * black_box(s))
});
}
// G2Affine
{
let name = "G2Affine";
let a = G2Affine::generator();
let s = Scalar::from_raw([1, 2, 3, 4]);
c.bench_function(&format!("{} check on curve", name), move |b| {
b.iter(|| black_box(a).is_on_curve())
});
c.bench_function(&format!("{} check equality", name), move |b| {
b.iter(|| black_box(a) == black_box(a))
});
c.bench_function(&format!("{} scalar multiplication", name), move |b| {
b.iter(|| black_box(a) * black_box(s))
});
}
// G2Projective
@ -61,6 +73,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let name = "G2Projective";
let a = G2Projective::generator();
let a_affine = G2Affine::generator();
let s = Scalar::from_raw([1, 2, 3, 4]);
c.bench_function(&format!("{} check on curve", name), move |b| {
b.iter(|| black_box(a).is_on_curve())
});
@ -79,6 +92,9 @@ fn criterion_benchmark(c: &mut Criterion) {
c.bench_function(&format!("{} mixed addition", name), move |b| {
b.iter(|| black_box(a).add_mixed(&a_affine))
});
c.bench_function(&format!("{} scalar multiplication", name), move |b| {
b.iter(|| black_box(a) * black_box(s))
});
}
}

View File

@ -1,10 +1,11 @@
//! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.
use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::fp::Fp;
use crate::Scalar;
/// 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
@ -296,7 +297,25 @@ impl<'a, 'b> Sub<&'b G1Projective> for &'a G1Projective {
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a G1Projective {
type Output = G1Projective;
fn mul(self, other: &'b Scalar) -> Self::Output {
self.multiply(&other.to_bytes())
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a G1Affine {
type Output = G1Projective;
fn mul(self, other: &'b Scalar) -> Self::Output {
G1Projective::from(self).multiply(&other.to_bytes())
}
}
impl_binops_additive!(G1Projective, G1Projective);
impl_binops_multiplicative!(G1Projective, Scalar);
impl_binops_multiplicative_mixed!(G1Affine, Scalar, G1Projective);
impl G1Projective {
/// Returns the identity of the group: the point at infinity.
@ -500,6 +519,28 @@ impl G1Projective {
G1Projective::conditional_select(&res, &tmp, (!f1) & (!f2) & (!f3))
}
fn multiply(&self, by: &[u8; 32]) -> G1Projective {
let mut acc = G1Projective::identity();
// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We skip the leading bit because it's always unset for Fq
// elements.
for bit in by
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = G1Projective::conditional_select(&acc, &(acc + self), bit);
}
acc
}
/// Returns true if this element is the identity (the point at infinity).
#[inline]
pub fn is_identity(&self) -> Choice {
@ -960,3 +1001,43 @@ fn test_affine_negation_and_subtraction() {
assert_eq!(G1Projective::from(a) + (-a), G1Projective::identity());
assert_eq!(G1Projective::from(a) + (-a), G1Projective::from(a) - a);
}
#[test]
fn test_projective_scalar_multiplication() {
let g = G1Projective::generator();
let a = Scalar::from_raw([
0x2b568297a56da71c,
0xd8c39ecb0ef375d1,
0x435c38da67bfbf96,
0x8088a05026b659b2,
]);
let b = Scalar::from_raw([
0x785fdd9b26ef8b85,
0xc997f25837695c18,
0x4c8dbc39e7b756c1,
0x70d9b6cc6d87df20,
]);
let c = a * b;
assert_eq!((g * a) * b, g * c);
}
#[test]
fn test_affine_scalar_multiplication() {
let g = G1Affine::generator();
let a = Scalar::from_raw([
0x2b568297a56da71c,
0xd8c39ecb0ef375d1,
0x435c38da67bfbf96,
0x8088a05026b659b2,
]);
let b = Scalar::from_raw([
0x785fdd9b26ef8b85,
0xc997f25837695c18,
0x4c8dbc39e7b756c1,
0x70d9b6cc6d87df20,
]);
let c = a * b;
assert_eq!(G1Affine::from(g * a) * b, g * c);
}

View File

@ -1,11 +1,12 @@
//! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.
use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::fp::Fp;
use crate::fp2::Fp2;
use crate::Scalar;
/// 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
@ -327,7 +328,25 @@ impl<'a, 'b> Sub<&'b G2Projective> for &'a G2Projective {
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a G2Projective {
type Output = G2Projective;
fn mul(self, other: &'b Scalar) -> Self::Output {
self.multiply(&other.to_bytes())
}
}
impl<'a, 'b> Mul<&'b Scalar> for &'a G2Affine {
type Output = G2Projective;
fn mul(self, other: &'b Scalar) -> Self::Output {
G2Projective::from(self).multiply(&other.to_bytes())
}
}
impl_binops_additive!(G2Projective, G2Projective);
impl_binops_multiplicative!(G2Projective, Scalar);
impl_binops_multiplicative_mixed!(G2Affine, Scalar, G2Projective);
impl G2Projective {
/// Returns the identity of the group: the point at infinity.
@ -551,6 +570,28 @@ impl G2Projective {
G2Projective::conditional_select(&res, &tmp, (!f1) & (!f2) & (!f3))
}
fn multiply(&self, by: &[u8; 32]) -> G2Projective {
let mut acc = G2Projective::identity();
// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We skip the leading bit because it's always unset for Fq
// elements.
for bit in by
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = G2Projective::conditional_select(&acc, &(acc + self), bit);
}
acc
}
/// Returns true if this element is the identity (the point at infinity).
#[inline]
pub fn is_identity(&self) -> Choice {
@ -1147,3 +1188,43 @@ fn test_affine_negation_and_subtraction() {
assert_eq!(G2Projective::from(a) + (-a), G2Projective::identity());
assert_eq!(G2Projective::from(a) + (-a), G2Projective::from(a) - a);
}
#[test]
fn test_projective_scalar_multiplication() {
let g = G2Projective::generator();
let a = Scalar::from_raw([
0x2b568297a56da71c,
0xd8c39ecb0ef375d1,
0x435c38da67bfbf96,
0x8088a05026b659b2,
]);
let b = Scalar::from_raw([
0x785fdd9b26ef8b85,
0xc997f25837695c18,
0x4c8dbc39e7b756c1,
0x70d9b6cc6d87df20,
]);
let c = a * b;
assert_eq!((g * a) * b, g * c);
}
#[test]
fn test_affine_scalar_multiplication() {
let g = G2Affine::generator();
let a = Scalar::from_raw([
0x2b568297a56da71c,
0xd8c39ecb0ef375d1,
0x435c38da67bfbf96,
0x8088a05026b659b2,
]);
let b = Scalar::from_raw([
0x785fdd9b26ef8b85,
0xc997f25837695c18,
0x4c8dbc39e7b756c1,
0x70d9b6cc6d87df20,
]);
let c = a * b;
assert_eq!(G2Affine::from(g * a) * b, g * c);
}