From 2519aa844d0d2fab93e21b40fc7fa7594f310975 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Tue, 14 Nov 2023 12:56:51 +0200 Subject: [PATCH 01/10] refactored `lincomb` into ``lincomb_array` and `lincomb_slice` --- k256/src/arithmetic.rs | 2 +- k256/src/arithmetic/mul.rs | 163 ++++++++++++++++++------------------- k256/src/lib.rs | 9 +- 3 files changed, 86 insertions(+), 88 deletions(-) diff --git a/k256/src/arithmetic.rs b/k256/src/arithmetic.rs index d738c091..04937911 100644 --- a/k256/src/arithmetic.rs +++ b/k256/src/arithmetic.rs @@ -12,7 +12,7 @@ pub(crate) mod scalar; mod dev; pub use field::FieldElement; -pub use mul::lincomb; +pub use mul::{lincomb_array, lincomb_slice}; use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; use crate::Secp256k1; diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index f8a20c7f..13445024 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -278,93 +278,67 @@ impl Default for Radix16Decomposition { } } -/// Maps an array `x` to an array using the predicate `f`. -/// We can't use the standard `map()` because as of Rust 1.51 we cannot collect into arrays. -/// Consequently, since we cannot have an uninitialized array (without `unsafe`), -/// a default value needs to be provided. -fn static_map( - f: impl Fn(T) -> V, - x: &[T; N], - default: V, -) -> [V; N] { - let mut res = [default; N]; - for i in 0..N { - res[i] = f(x[i]); - } - res -} - -/// Maps two arrays `x` and `y` into an array using a predicate `f` that takes two arguments. -fn static_zip_map( - f: impl Fn(T, S) -> V, - x: &[T; N], - y: &[S; N], - default: V, -) -> [V; N] { - let mut res = [default; N]; - for i in 0..N { - res[i] = f(x[i], y[i]); - } - res -} - /// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N` #[inline(always)] -pub fn lincomb(xs: &[ProjectivePoint; N], ks: &[Scalar; N]) -> ProjectivePoint { - let rs = static_map( - |k| decompose_scalar(&k), - ks, - (Scalar::default(), Scalar::default()), - ); - let r1s = static_map(|(r1, _r2)| r1, &rs, Scalar::default()); - let r2s = static_map(|(_r1, r2)| r2, &rs, Scalar::default()); - - let xs_beta = static_map(|x| x.endomorphism(), xs, ProjectivePoint::default()); - - let r1_signs = static_map(|r| r.is_high(), &r1s, Choice::from(0u8)); - let r2_signs = static_map(|r| r.is_high(), &r2s, Choice::from(0u8)); - - let r1s_c = static_zip_map( - |r, r_sign| Scalar::conditional_select(&r, &-r, r_sign), - &r1s, - &r1_signs, - Scalar::default(), - ); - let r2s_c = static_zip_map( - |r, r_sign| Scalar::conditional_select(&r, &-r, r_sign), - &r2s, - &r2_signs, - Scalar::default(), - ); - - let tables1 = static_zip_map( - |x, r_sign| LookupTable::from(&ProjectivePoint::conditional_select(&x, &-x, r_sign)), - xs, - &r1_signs, - LookupTable::default(), - ); - let tables2 = static_zip_map( - |x, r_sign| LookupTable::from(&ProjectivePoint::conditional_select(&x, &-x, r_sign)), - &xs_beta, - &r2_signs, - LookupTable::default(), - ); - - let digits1 = static_map( - |r| Radix16Decomposition::<33>::new(&r), - &r1s_c, +pub fn lincomb_array(xks: &[(ProjectivePoint, Scalar); N]) -> ProjectivePoint { + let mut tables = [(LookupTable::default(), LookupTable::default()); N]; + let mut digits = [( Radix16Decomposition::<33>::default(), - ); - let digits2 = static_map( - |r| Radix16Decomposition::<33>::new(&r), - &r2s_c, Radix16Decomposition::<33>::default(), - ); + ); N]; + + lincomb(xks, &mut tables, &mut digits) +} + +#[cfg(feature = "alloc")] +pub fn lincomb_slice(xks: &[(ProjectivePoint, Scalar)]) -> ProjectivePoint { + let mut tables = vec![(LookupTable::default(), LookupTable::default()); xks.len()]; + let mut digits = vec![ + ( + Radix16Decomposition::<33>::default(), + Radix16Decomposition::<33>::default(), + ); + xks.len() + ]; + + lincomb(xks, &mut tables, &mut digits) +} + +fn lincomb( + xks: &[(ProjectivePoint, Scalar)], + tables: &mut [(LookupTable, LookupTable)], + digits: &mut [(Radix16Decomposition<33>, Radix16Decomposition<33>)], +) -> ProjectivePoint { + xks.iter().enumerate().for_each(|(i, (x, k))| { + let (r1, r2) = decompose_scalar(k); + let x_beta = x.endomorphism(); + let (r1_sign, r2_sign) = (r1.is_high(), r2.is_high()); + + let (r1_c, r2_c) = ( + Scalar::conditional_select(&r1, &-r1, r1_sign), + Scalar::conditional_select(&r2, &-r2, r2_sign), + ); + + tables[i] = ( + LookupTable::from(&ProjectivePoint::conditional_select(x, &-*x, r1_sign)), + LookupTable::from(&ProjectivePoint::conditional_select( + &x_beta, &-x_beta, r2_sign, + )), + ); + + digits[i] = ( + Radix16Decomposition::<33>::new(&r1_c), + Radix16Decomposition::<33>::new(&r2_c), + ) + }); let mut acc = ProjectivePoint::IDENTITY; - for component in 0..N { - acc += &tables1[component].select(digits1[component].0[32]); - acc += &tables2[component].select(digits2[component].0[32]); + for component in 0..xks.len() { + let (digit1, digit2) = digits[component]; + let (table1, table2) = tables[component]; + + acc += &table1.select(digit1.0[32]); + acc += &table2.select(digit2.0[32]); } for i in (0..32).rev() { @@ -372,9 +346,12 @@ pub fn lincomb(xs: &[ProjectivePoint; N], ks: &[Scalar; N]) -> P acc = acc.double(); } - for component in 0..N { - acc += &tables1[component].select(digits1[component].0[i]); - acc += &tables2[component].select(digits2[component].0[i]); + for component in 0..xks.len() { + let (digit1, digit2) = digits[component]; + let (table1, table2) = tables[component]; + + acc += &table1.select(digit1.0[i]); + acc += &table2.select(digit2.0[i]); } } acc @@ -429,7 +406,7 @@ impl MulByGenerator for ProjectivePoint { #[inline(always)] fn mul(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint { - lincomb(&[*x], &[*k]) + lincomb_array(&[(*x, *k)]) } impl LinearCombination for ProjectivePoint { @@ -439,7 +416,7 @@ impl LinearCombination for ProjectivePoint { y: &ProjectivePoint, l: &Scalar, ) -> ProjectivePoint { - lincomb(&[*x, *y], &[*k, *l]) + lincomb_array(&[(*x, *k), (*y, *l)]) } } @@ -481,6 +458,7 @@ impl MulAssign<&Scalar> for ProjectivePoint { #[cfg(test)] mod tests { + use super::*; use crate::arithmetic::{ProjectivePoint, Scalar}; use elliptic_curve::{ ops::{LinearCombination, MulByGenerator}, @@ -507,4 +485,17 @@ mod tests { let test = ProjectivePoint::mul_by_generator(&k); assert_eq!(reference, test); } + + #[cfg(feature = "alloc")] + #[test] + fn test_lincomb_slice() { + 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_slice(&[(x, k), (y, l)]); + assert_eq!(reference, test); + } } diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 65b30f94..60551601 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -26,6 +26,11 @@ //! //! Please see type-specific documentation for more information. +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + #[cfg(feature = "arithmetic")] mod arithmetic; @@ -44,7 +49,9 @@ pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{affine::AffinePoint, lincomb, projective::ProjectivePoint, scalar::Scalar}; +pub use arithmetic::{ + affine::AffinePoint, lincomb_array, lincomb_slice, projective::ProjectivePoint, scalar::Scalar, +}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement; From eb6854fa803b9afb4f1aea7224a4d00821e634af Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Tue, 14 Nov 2023 22:35:47 +0200 Subject: [PATCH 02/10] fix expose --- k256/src/arithmetic.rs | 4 +++- k256/src/lib.rs | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/k256/src/arithmetic.rs b/k256/src/arithmetic.rs index 04937911..ab46ba1c 100644 --- a/k256/src/arithmetic.rs +++ b/k256/src/arithmetic.rs @@ -12,7 +12,9 @@ pub(crate) mod scalar; mod dev; pub use field::FieldElement; -pub use mul::{lincomb_array, lincomb_slice}; +pub use mul::lincomb_array; +#[cfg(feature = "alloc")] +pub use mul::lincomb_slice; use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; use crate::Secp256k1; diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 60551601..5c03ebb1 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -49,9 +49,11 @@ pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{ - affine::AffinePoint, lincomb_array, lincomb_slice, projective::ProjectivePoint, scalar::Scalar, -}; +pub use arithmetic::lincomb_array; +#[cfg(all(feature = "alloc", feature = "arithmetic"))] +pub use arithmetic::lincomb_slice; +#[cfg(feature = "arithmetic")] +pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement; From de7a233d7319e3cddd3cb010f933b51fda434c08 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Tue, 14 Nov 2023 23:12:29 +0200 Subject: [PATCH 03/10] missing doc --- k256/src/arithmetic/mul.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 13445024..6eefcad7 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -278,7 +278,8 @@ impl Default for Radix16Decomposition { } } -/// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N` +/// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N`. +/// Works over a const-generic array and thus does not require `alloc`. #[inline(always)] pub fn lincomb_array(xks: &[(ProjectivePoint, Scalar); N]) -> ProjectivePoint { let mut tables = [(LookupTable::default(), LookupTable::default()); N]; @@ -290,6 +291,8 @@ pub fn lincomb_array(xks: &[(ProjectivePoint, Scalar); N]) -> Pr lincomb(xks, &mut tables, &mut digits) } +/// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N` +/// Work over a (possibly dynamically allocated) slice and requires `alloc` due to internal allocations. #[cfg(feature = "alloc")] pub fn lincomb_slice(xks: &[(ProjectivePoint, Scalar)]) -> ProjectivePoint { let mut tables = vec![(LookupTable::default(), LookupTable::default()); xks.len()]; From 4191f3525b33bac6ca7db152203faf6ed25a4dac Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 15 Nov 2023 00:24:53 +0200 Subject: [PATCH 04/10] `LinearCombination` trait --- k256/src/arithmetic.rs | 14 +++++--- k256/src/arithmetic/mul.rs | 65 ++++++++++++++++++++------------------ k256/src/lib.rs | 8 ++--- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/k256/src/arithmetic.rs b/k256/src/arithmetic.rs index ab46ba1c..524c7ed1 100644 --- a/k256/src/arithmetic.rs +++ b/k256/src/arithmetic.rs @@ -12,13 +12,19 @@ pub(crate) mod scalar; mod dev; pub use field::FieldElement; -pub use mul::lincomb_array; -#[cfg(feature = "alloc")] -pub use mul::lincomb_slice; use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; use crate::Secp256k1; -use elliptic_curve::CurveArithmetic; +use elliptic_curve::{group, CurveArithmetic}; + +/// Linear combination. +/// +/// This trait enables providing an optimized implementation of +/// linear combinations (e.g. Shamir's Trick). +pub trait LinearCombination>: group::Curve { + /// Calculates `x1 * k1 + ... + xn * kn`. + fn linear_combination(points_and_scalars: PointsAndScalars) -> Self; +} impl CurveArithmetic for Secp256k1 { type AffinePoint = AffinePoint; diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 6eefcad7..ce7b7a22 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -40,13 +40,16 @@ ))] compile_error!("`precomputed-tables` feature requires either `critical-section` or `std`"); +use crate::arithmetic::LinearCombination; use crate::arithmetic::{ scalar::{Scalar, WideScalar}, ProjectivePoint, }; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; use core::ops::{Mul, MulAssign}; use elliptic_curve::{ - ops::{LinearCombination, MulByGenerator}, + ops::MulByGenerator, scalar::IsHigh, subtle::{Choice, ConditionallySelectable, ConstantTimeEq}, }; @@ -278,33 +281,33 @@ impl Default for Radix16Decomposition { } } -/// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N`. -/// Works over a const-generic array and thus does not require `alloc`. -#[inline(always)] -pub fn lincomb_array(xks: &[(ProjectivePoint, Scalar); N]) -> ProjectivePoint { - let mut tables = [(LookupTable::default(), LookupTable::default()); N]; - let mut digits = [( - Radix16Decomposition::<33>::default(), - Radix16Decomposition::<33>::default(), - ); N]; - - lincomb(xks, &mut tables, &mut digits) -} - -/// Calculates a linear combination `sum(x[i] * k[i])`, `i = 0..N` -/// Work over a (possibly dynamically allocated) slice and requires `alloc` due to internal allocations. -#[cfg(feature = "alloc")] -pub fn lincomb_slice(xks: &[(ProjectivePoint, Scalar)]) -> ProjectivePoint { - let mut tables = vec![(LookupTable::default(), LookupTable::default()); xks.len()]; - let mut digits = vec![ - ( +impl LinearCombination<&[(ProjectivePoint, Scalar); N]> for ProjectivePoint { + fn linear_combination(points_and_scalars: &[(ProjectivePoint, Scalar); N]) -> Self { + let mut tables = [(LookupTable::default(), LookupTable::default()); N]; + let mut digits = [( Radix16Decomposition::<33>::default(), Radix16Decomposition::<33>::default(), - ); - xks.len() - ]; + ); N]; - lincomb(xks, &mut tables, &mut digits) + lincomb(points_and_scalars, &mut tables, &mut digits) + } +} + +#[cfg(feature = "alloc")] +impl LinearCombination> for ProjectivePoint { + fn linear_combination(points_and_scalars: Vec<(ProjectivePoint, Scalar)>) -> Self { + let mut tables = + vec![(LookupTable::default(), LookupTable::default()); points_and_scalars.len()]; + let mut digits = vec![ + ( + Radix16Decomposition::<33>::default(), + Radix16Decomposition::<33>::default(), + ); + points_and_scalars.len() + ]; + + lincomb(points_and_scalars.as_slice(), &mut tables, &mut digits) + } } fn lincomb( @@ -409,17 +412,17 @@ impl MulByGenerator for ProjectivePoint { #[inline(always)] fn mul(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint { - lincomb_array(&[(*x, *k)]) + ProjectivePoint::linear_combination(&[(*x, *k)]) } -impl LinearCombination for ProjectivePoint { +impl elliptic_curve::ops::LinearCombination for ProjectivePoint { fn lincomb( x: &ProjectivePoint, k: &Scalar, y: &ProjectivePoint, l: &Scalar, ) -> ProjectivePoint { - lincomb_array(&[(*x, *k), (*y, *l)]) + ProjectivePoint::linear_combination(&[(*x, *k), (*y, *l)]) } } @@ -464,7 +467,7 @@ mod tests { use super::*; use crate::arithmetic::{ProjectivePoint, Scalar}; use elliptic_curve::{ - ops::{LinearCombination, MulByGenerator}, + ops::{LinearCombination as _, MulByGenerator}, rand_core::OsRng, Field, Group, }; @@ -491,14 +494,14 @@ mod tests { #[cfg(feature = "alloc")] #[test] - fn test_lincomb_slice() { + fn test_lincomb_vec() { 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_slice(&[(x, k), (y, l)]); + let test = ProjectivePoint::linear_combination(vec![(x, k), (y, l)]); assert_eq!(reference, test); } } diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 5c03ebb1..81f1285d 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -49,11 +49,9 @@ pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] -pub use arithmetic::lincomb_array; -#[cfg(all(feature = "alloc", feature = "arithmetic"))] -pub use arithmetic::lincomb_slice; -#[cfg(feature = "arithmetic")] -pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; +pub use arithmetic::{ + affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar, LinearCombination, +}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement; From 71d27c75055b8d73054a376b860f79b6f7b89472 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 15 Nov 2023 10:39:26 +0200 Subject: [PATCH 05/10] Work with LinearCombinationExt --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- k256/src/arithmetic.rs | 11 +---------- k256/src/arithmetic/mul.rs | 23 ++++++----------------- k256/src/lib.rs | 4 +--- 5 files changed, 11 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47d17f65..5a9e0f3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" version = "0.13.6" -source = "git+https://github.com/RustCrypto/traits.git#4a663341473273c73fd2ca7e37dadd9ba7013fd2" +source = "git+https://github.com/RustCrypto/traits.git?branch=elliptic-curve/linear-combination-ext-trait#7b4a076e07e7b141bd4f72e3a6e89d20db74b2a2" dependencies = [ "base16ct", "base64ct", diff --git a/Cargo.toml b/Cargo.toml index 483c058c..1ff5327a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,5 @@ members = [ [profile.dev] opt-level = 2 -[patch.crates-io.elliptic-curve] -git = "https://github.com/RustCrypto/traits.git" +[patch.crates-io] +elliptic-curve = {git = "https://github.com/RustCrypto/traits.git", branch = "elliptic-curve/linear-combination-ext-trait"} diff --git a/k256/src/arithmetic.rs b/k256/src/arithmetic.rs index 524c7ed1..b6ba5673 100644 --- a/k256/src/arithmetic.rs +++ b/k256/src/arithmetic.rs @@ -15,16 +15,7 @@ pub use field::FieldElement; use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; use crate::Secp256k1; -use elliptic_curve::{group, CurveArithmetic}; - -/// Linear combination. -/// -/// This trait enables providing an optimized implementation of -/// linear combinations (e.g. Shamir's Trick). -pub trait LinearCombination>: group::Curve { - /// Calculates `x1 * k1 + ... + xn * kn`. - fn linear_combination(points_and_scalars: PointsAndScalars) -> Self; -} +use elliptic_curve::CurveArithmetic; impl CurveArithmetic for Secp256k1 { type AffinePoint = AffinePoint; diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 077dd3ae..60bd2d76 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -40,7 +40,6 @@ ))] compile_error!("`precomputed-tables` feature requires either `critical-section` or `std`"); -use crate::arithmetic::LinearCombination; use crate::arithmetic::{ scalar::{Scalar, WideScalar}, ProjectivePoint, @@ -48,6 +47,7 @@ use crate::arithmetic::{ #[cfg(feature = "alloc")] use alloc::vec::Vec; use core::ops::{Mul, MulAssign}; +use elliptic_curve::ops::LinearCombinationExt as LinearCombination; use elliptic_curve::{ ops::MulByGenerator, scalar::IsHigh, @@ -281,8 +281,8 @@ impl Default for Radix16Decomposition { } } -impl LinearCombination<&[(ProjectivePoint, Scalar); N]> for ProjectivePoint { - fn linear_combination(points_and_scalars: &[(ProjectivePoint, Scalar); N]) -> Self { +impl LinearCombination<[(ProjectivePoint, Scalar); N]> for ProjectivePoint { + fn lincomb_ext(points_and_scalars: &[(ProjectivePoint, Scalar); N]) -> Self { let mut tables = [(LookupTable::default(), LookupTable::default()); N]; let mut digits = [( Radix16Decomposition::<33>::default(), @@ -295,7 +295,7 @@ impl LinearCombination<&[(ProjectivePoint, Scalar); N]> for Proj #[cfg(feature = "alloc")] impl LinearCombination> for ProjectivePoint { - fn linear_combination(points_and_scalars: Vec<(ProjectivePoint, Scalar)>) -> Self { + fn lincomb_ext(points_and_scalars: &Vec<(ProjectivePoint, Scalar)>) -> Self { let mut tables = vec![(LookupTable::default(), LookupTable::default()); points_and_scalars.len()]; let mut digits = vec![ @@ -412,18 +412,7 @@ impl MulByGenerator for ProjectivePoint { #[inline(always)] fn mul(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint { - ProjectivePoint::linear_combination(&[(*x, *k)]) -} - -impl elliptic_curve::ops::LinearCombination for ProjectivePoint { - fn lincomb( - x: &ProjectivePoint, - k: &Scalar, - y: &ProjectivePoint, - l: &Scalar, - ) -> ProjectivePoint { - ProjectivePoint::linear_combination(&[(*x, *k), (*y, *l)]) - } + ProjectivePoint::lincomb_ext(&[(*x, *k)]) } impl Mul for ProjectivePoint { @@ -501,7 +490,7 @@ mod tests { let l = Scalar::random(&mut OsRng); let reference = &x * &k + &y * &l; - let test = ProjectivePoint::linear_combination(vec![(x, k), (y, l)]); + let test = ProjectivePoint::lincomb_ext(&vec![(x, k), (y, l)]); assert_eq!(reference, test); } } diff --git a/k256/src/lib.rs b/k256/src/lib.rs index 5a0df2f2..f47f4882 100644 --- a/k256/src/lib.rs +++ b/k256/src/lib.rs @@ -50,9 +50,7 @@ pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{ - affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar, LinearCombination, -}; +pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement; From def83403c62a6d25c17fb3a527de06a411c463e6 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 15 Nov 2023 16:44:49 +0100 Subject: [PATCH 06/10] Update k256/src/arithmetic/mul.rs Co-authored-by: Tony Arcieri --- k256/src/arithmetic/mul.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 60bd2d76..48651ab7 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -294,7 +294,7 @@ impl LinearCombination<[(ProjectivePoint, Scalar); N]> for Proje } #[cfg(feature = "alloc")] -impl LinearCombination> for ProjectivePoint { +impl LinearCombination<[(ProjectivePoint, Scalar)]> for ProjectivePoint { fn lincomb_ext(points_and_scalars: &Vec<(ProjectivePoint, Scalar)>) -> Self { let mut tables = vec![(LookupTable::default(), LookupTable::default()); points_and_scalars.len()]; From db841c507d31f68abe61d430af4d8b586d5c4056 Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 15 Nov 2023 16:47:51 +0100 Subject: [PATCH 07/10] Can't compile --- Cargo.lock | 2 +- Cargo.toml | 2 +- k256/src/arithmetic/mul.rs | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a9e0f3b..148bb4b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" version = "0.13.6" -source = "git+https://github.com/RustCrypto/traits.git?branch=elliptic-curve/linear-combination-ext-trait#7b4a076e07e7b141bd4f72e3a6e89d20db74b2a2" +source = "git+https://github.com/RustCrypto/traits.git#37507fd8a1314398f9e0d7bbdf25467071b2c72e" dependencies = [ "base16ct", "base64ct", diff --git a/Cargo.toml b/Cargo.toml index 1ff5327a..2bb4c963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,4 @@ members = [ opt-level = 2 [patch.crates-io] -elliptic-curve = {git = "https://github.com/RustCrypto/traits.git", branch = "elliptic-curve/linear-combination-ext-trait"} +elliptic-curve = {git = "https://github.com/RustCrypto/traits.git"} diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 48651ab7..779b8f72 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -44,8 +44,7 @@ use crate::arithmetic::{ scalar::{Scalar, WideScalar}, ProjectivePoint, }; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; + use core::ops::{Mul, MulAssign}; use elliptic_curve::ops::LinearCombinationExt as LinearCombination; use elliptic_curve::{ @@ -295,7 +294,7 @@ impl LinearCombination<[(ProjectivePoint, Scalar); N]> for Proje #[cfg(feature = "alloc")] impl LinearCombination<[(ProjectivePoint, Scalar)]> for ProjectivePoint { - fn lincomb_ext(points_and_scalars: &Vec<(ProjectivePoint, Scalar)>) -> Self { + fn lincomb_ext(points_and_scalars: &[(ProjectivePoint, Scalar)]) -> Self { let mut tables = vec![(LookupTable::default(), LookupTable::default()); points_and_scalars.len()]; let mut digits = vec![ @@ -306,7 +305,7 @@ impl LinearCombination<[(ProjectivePoint, Scalar)]> for ProjectivePoint { points_and_scalars.len() ]; - lincomb(points_and_scalars.as_slice(), &mut tables, &mut digits) + lincomb(points_and_scalars, &mut tables, &mut digits) } } From 09cc0352df39b16a67a02e9be64d312d644e3a0f Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 15 Nov 2023 09:44:39 -0700 Subject: [PATCH 08/10] Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 148bb4b1..0440b759 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" version = "0.13.6" -source = "git+https://github.com/RustCrypto/traits.git#37507fd8a1314398f9e0d7bbdf25467071b2c72e" +source = "git+https://github.com/RustCrypto/traits.git#723a1a309c4d987ec54c4c1f7bfe3686dc8d5a29" dependencies = [ "base16ct", "base64ct", From acefafdf4a63f1c04650aef54e50ac7631fc7566 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 15 Nov 2023 09:54:44 -0700 Subject: [PATCH 09/10] Update Cargo.toml --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2bb4c963..483c058c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,5 @@ members = [ [profile.dev] opt-level = 2 -[patch.crates-io] -elliptic-curve = {git = "https://github.com/RustCrypto/traits.git"} +[patch.crates-io.elliptic-curve] +git = "https://github.com/RustCrypto/traits.git" From 3bcf3b1016a12e57bc2763f364914f9dc4bba34b Mon Sep 17 00:00:00 2001 From: Yehonatan Cohen Scaly Date: Wed, 15 Nov 2023 18:09:41 +0100 Subject: [PATCH 10/10] Fixed slice --- Cargo.lock | 2 +- Cargo.toml | 2 +- k256/src/arithmetic/mul.rs | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 148bb4b1..4c4f1acf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" version = "0.13.6" -source = "git+https://github.com/RustCrypto/traits.git#37507fd8a1314398f9e0d7bbdf25467071b2c72e" +source = "git+https://github.com/RustCrypto/traits.git?branch=elliptic-curve/linear-combination-ext-sized-bound#4cfb7feab809023139432ee0276a0fc88a6257f8" dependencies = [ "base16ct", "base64ct", diff --git a/Cargo.toml b/Cargo.toml index 2bb4c963..6e6e5483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,4 @@ members = [ opt-level = 2 [patch.crates-io] -elliptic-curve = {git = "https://github.com/RustCrypto/traits.git"} +elliptic-curve = {git = "https://github.com/RustCrypto/traits.git", branch = "elliptic-curve/linear-combination-ext-sized-bound" } diff --git a/k256/src/arithmetic/mul.rs b/k256/src/arithmetic/mul.rs index 779b8f72..6354a7d2 100644 --- a/k256/src/arithmetic/mul.rs +++ b/k256/src/arithmetic/mul.rs @@ -482,14 +482,16 @@ mod tests { #[cfg(feature = "alloc")] #[test] - fn test_lincomb_vec() { + fn test_lincomb_slice() { 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 = ProjectivePoint::lincomb_ext(&vec![(x, k), (y, l)]); + let points_and_scalars = vec![(x, k), (y, l)]; + + let test = ProjectivePoint::lincomb_ext(points_and_scalars.as_slice()); assert_eq!(reference, test); } }