From 5c14bea456532065332d021970e4dd09ea601908 Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Fri, 16 Jul 2021 16:12:57 -0700 Subject: [PATCH] Add lincomb() as an alias for a 2-point linear combination --- k256/bench/scalar.rs | 11 ++++++++++- k256/src/arithmetic.rs | 1 + k256/src/arithmetic/mul.rs | 30 ++++++++++++++++++++++++++++++ k256/src/ecdsa/recoverable.rs | 4 ++-- k256/src/ecdsa/verify.rs | 14 ++++++++++---- k256/src/lib.rs | 2 +- 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/k256/bench/scalar.rs b/k256/bench/scalar.rs index 6be3901d..091b691e 100644 --- a/k256/bench/scalar.rs +++ b/k256/bench/scalar.rs @@ -6,7 +6,7 @@ use criterion::{ use hex_literal::hex; use k256::{ elliptic_curve::{generic_array::arr, group::ff::PrimeField}, - ProjectivePoint, Scalar, + lincomb, ProjectivePoint, Scalar, }; fn test_scalar_x() -> Scalar { @@ -34,9 +34,18 @@ fn bench_point_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { group.bench_function("point-scalar mul", |b| b.iter(|| &p * &s)); } +fn bench_point_lincomb<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let p = ProjectivePoint::generator(); + let m = hex!("AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522"); + let s = Scalar::from_repr(m.into()).unwrap(); + group.bench_function("lincomb via mul+add", |b| b.iter(|| &p * &s + &p * &s)); + group.bench_function("lincomb()", |b| b.iter(|| lincomb(&p, &s, &p, &s))); +} + fn bench_high_level(c: &mut Criterion) { let mut group = c.benchmark_group("high-level operations"); bench_point_mul(&mut group); + bench_point_lincomb(&mut group); group.finish(); } diff --git a/k256/src/arithmetic.rs b/k256/src/arithmetic.rs index 2c18d648..ea876610 100644 --- a/k256/src/arithmetic.rs +++ b/k256/src/arithmetic.rs @@ -8,6 +8,7 @@ pub(crate) mod scalar; mod util; pub use field::FieldElement; +pub use mul::lincomb; use affine::AffinePoint; use projective::ProjectivePoint; diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index d1125bed..f6275e7e 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -298,6 +298,16 @@ fn mul(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint { lincomb_generic(&[*x], &[*k]) } +/// Calculates `x * k + y * l`. +pub fn lincomb( + x: &ProjectivePoint, + k: &Scalar, + y: &ProjectivePoint, + l: &Scalar, +) -> ProjectivePoint { + lincomb_generic(&[*x, *y], &[*k, *l]) +} + impl Mul for ProjectivePoint { type Output = ProjectivePoint; @@ -333,3 +343,23 @@ impl MulAssign<&Scalar> for ProjectivePoint { *self = mul(self, rhs); } } + +#[cfg(test)] +mod tests { + use super::lincomb; + use crate::arithmetic::{ProjectivePoint, Scalar}; + use elliptic_curve::rand_core::OsRng; + use elliptic_curve::{Field, Group}; + + #[test] + fn test_lincomb() { + let x = ProjectivePoint::random(&mut OsRng); + let y = ProjectivePoint::random(&mut OsRng); + let k = Scalar::random(&mut OsRng); + let l = Scalar::random(&mut OsRng); + + let reference = &x * &k + &y * &l; + let test = lincomb(&x, &k, &y, &l); + assert_eq!(reference, test); + } +} diff --git a/k256/src/ecdsa/recoverable.rs b/k256/src/ecdsa/recoverable.rs index dd8dd7e5..36f05147 100644 --- a/k256/src/ecdsa/recoverable.rs +++ b/k256/src/ecdsa/recoverable.rs @@ -51,7 +51,7 @@ use crate::{ consts::U32, generic_array::GenericArray, ops::Invert, subtle::Choice, weierstrass::DecompressPoint, }, - AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, Scalar, + lincomb, AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, Scalar, }; #[cfg(feature = "keccak256")] @@ -185,7 +185,7 @@ impl Signature { let r_inv = r.invert().unwrap(); let u1 = -(r_inv * z); let u2 = r_inv * *s; - let pk = ((ProjectivePoint::generator() * u1) + (R * u2)).to_affine(); + let pk = lincomb(&ProjectivePoint::generator(), &u1, &R, &u2).to_affine(); // TODO(tarcieri): ensure the signature verifies? Ok(VerifyingKey::from(&pk)) diff --git a/k256/src/ecdsa/verify.rs b/k256/src/ecdsa/verify.rs index 57c9ef90..a5bb5624 100644 --- a/k256/src/ecdsa/verify.rs +++ b/k256/src/ecdsa/verify.rs @@ -2,7 +2,8 @@ use super::{recoverable, Error, Signature}; use crate::{ - AffinePoint, CompressedPoint, EncodedPoint, ProjectivePoint, PublicKey, Scalar, Secp256k1, + lincomb, AffinePoint, CompressedPoint, EncodedPoint, ProjectivePoint, PublicKey, Scalar, + Secp256k1, }; use core::convert::TryFrom; use ecdsa_core::{hazmat::VerifyPrimitive, signature}; @@ -90,9 +91,14 @@ impl VerifyPrimitive for AffinePoint { let u1 = z * &s_inv; let u2 = *r * s_inv; - let x = ((ProjectivePoint::generator() * u1) + (ProjectivePoint::from(*self) * u2)) - .to_affine() - .x; + let x = lincomb( + &ProjectivePoint::generator(), + &u1, + &ProjectivePoint::from(*self), + &u2, + ) + .to_affine() + .x; if Scalar::from_bytes_reduced(&x.to_bytes()).eq(&r) { Ok(()) diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 2bc85323..b45af6d8 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -67,7 +67,7 @@ pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; +pub use arithmetic::{affine::AffinePoint, lincomb, projective::ProjectivePoint, scalar::Scalar}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement;