Faster squaring in extension fields (#318)

* Faster squaring for extension fields; use in cube().

* Add squaring to arithmetic benchmark.

* Rename variable to remove warning; adjust comment.

* Inline always (improves latency measurements a lot).
This commit is contained in:
Hamish Ivey-Law 2021-10-22 16:05:00 +11:00 committed by GitHub
parent 001c979599
commit c406f464b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 1 deletions

View File

@ -34,6 +34,32 @@ pub(crate) fn bench_field<F: Field>(c: &mut Criterion) {
)
});
c.bench_function(&format!("sqr-throughput<{}>", type_name::<F>()), |b| {
b.iter_batched(
|| (F::rand(), F::rand(), F::rand(), F::rand()),
|(mut x, mut y, mut z, mut w)| {
for _ in 0..25 {
(x, y, z, w) = (x.square(), y.square(), z.square(), w.square());
}
(x, y, z, w)
},
BatchSize::SmallInput,
)
});
c.bench_function(&format!("sqr-latency<{}>", type_name::<F>()), |b| {
b.iter_batched(
|| F::rand(),
|mut x| {
for _ in 0..100 {
x = x.square();
}
x
},
BatchSize::SmallInput,
)
});
c.bench_function(&format!("add-throughput<{}>", type_name::<F>()), |b| {
b.iter_batched(
|| {

View File

@ -70,6 +70,19 @@ impl<F: Extendable<2>> Field for QuadraticExtension<F> {
F::order() * F::order()
}
#[inline(always)]
fn square(&self) -> Self {
// Specialising mul reduces the computation of c1 from 2 muls
// and one add to one mul and a shift
let Self([a0, a1]) = *self;
let c0 = a0.square() + <Self as OEF<2>>::W * a1.square();
let c1 = a0 * a1.double();
Self([c0, c1])
}
// Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
fn try_inverse(&self) -> Option<Self> {
if self.is_zero() {

View File

@ -72,6 +72,19 @@ impl<F: Extendable<4>> Field for QuarticExtension<F> {
F::order().pow(4u32)
}
#[inline(always)]
fn square(&self) -> Self {
let Self([a0, a1, a2, a3]) = *self;
let w = <Self as OEF<4>>::W;
let c0 = a0.square() + w * (a1 * a3.double() + a2.square());
let c1 = (a0 * a1 + w * a2 * a3).double();
let c2 = a0 * a2.double() + a1.square() + w * a3.square();
let c3 = (a0 * a3 + a1 * a2).double();
Self([c0, c1, c2, c3])
}
// Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
fn try_inverse(&self) -> Option<Self> {
if self.is_zero() {

View File

@ -74,12 +74,16 @@ pub trait Field:
*self == Self::ONE
}
fn double(&self) -> Self {
*self + *self
}
fn square(&self) -> Self {
*self * *self
}
fn cube(&self) -> Self {
*self * *self * *self
self.square() * *self
}
/// Compute the multiplicative inverse of this field element.