diff --git a/.github/workflows/elliptic-curve.yml b/.github/workflows/elliptic-curve.yml index ac83091c3..dacf100a5 100644 --- a/.github/workflows/elliptic-curve.yml +++ b/.github/workflows/elliptic-curve.yml @@ -46,7 +46,6 @@ jobs: - run: cargo build --target ${{ matrix.target }} --release --no-default-features - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features critical-section - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features dev - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features digest - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdh @@ -54,7 +53,6 @@ jobs: - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pkcs8 - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features sec1 - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features serde - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features wnaf - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,arithmetic - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,arithmetic,pkcs8 - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,serde @@ -66,7 +64,7 @@ jobs: with: working-directory: ${{ github.workflow }} stable-cmd: | - cargo hack check --feature-powerset --no-dev-deps --skip basepoint-table + cargo hack check --feature-powerset --no-dev-deps cargo check --all-features test: diff --git a/Cargo.lock b/Cargo.lock index d4b284212..e1ccc3c71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,12 +125,6 @@ dependencies = [ "libc", ] -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crypto" version = "0.6.0-pre" @@ -217,14 +211,12 @@ dependencies = [ "hex-literal", "hkdf", "hybrid-array", - "once_cell", "pem-rfc7468", "pkcs8", "rand_core", "sec1", "serdect", "subtle", - "wnaf", "zeroize", ] @@ -410,16 +402,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" -dependencies = [ - "critical-section", - "portable-atomic", -] - [[package]] name = "password-hash" version = "0.6.1" @@ -460,12 +442,6 @@ dependencies = [ "spki", ] -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - [[package]] name = "prettyplease" version = "0.2.37" @@ -797,16 +773,6 @@ dependencies = [ "wasmparser", ] -[[package]] -name = "wnaf" -version = "0.14.0-pre.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b8f9936fa4378fbe26130d702e51a9d723b22a073105500dfd80d9bb508199" -dependencies = [ - "ff", - "group", -] - [[package]] name = "zeroize" version = "1.8.2" diff --git a/elliptic-curve/Cargo.toml b/elliptic-curve/Cargo.toml index ea6a782db..936c57d9e 100644 --- a/elliptic-curve/Cargo.toml +++ b/elliptic-curve/Cargo.toml @@ -30,12 +30,10 @@ ff = { version = "0.14", optional = true, default-features = false } group = { version = "0.14", optional = true, default-features = false } hkdf = { version = "0.13", optional = true, default-features = false } hex-literal = { version = "1", optional = true } -once_cell = { version = "1.21", optional = true, default-features = false } pem-rfc7468 = { version = "1", optional = true, features = ["alloc"] } pkcs8 = { version = "0.11", optional = true, default-features = false } sec1 = { version = "0.8", optional = true, features = ["ctutils", "subtle", "zeroize"] } serdect = { version = "0.4", optional = true, default-features = false, features = ["alloc"] } -wnaf = { version = "0.14.0-pre.0", optional = true } [dev-dependencies] hex-literal = "1" @@ -52,14 +50,11 @@ alloc = [ ] std = [ "alloc", - "once_cell?/std", "pkcs8?/std", "sec1?/std" ] arithmetic = ["group"] -basepoint-table = ["arithmetic"] -critical-section = ["basepoint-table", "once_cell/critical-section"] dev = ["arithmetic", "dep:hex-literal", "pem", "pkcs8"] ecdh = ["arithmetic", "digest", "dep:hkdf"] getrandom = ["arithmetic", "bigint/getrandom", "common/getrandom"] @@ -67,10 +62,9 @@ group = ["dep:group", "ff"] pkcs8 = ["dep:pkcs8", "sec1"] pem = ["dep:pem-rfc7468", "alloc", "arithmetic", "pkcs8/pem", "sec1/pem"] serde = ["dep:serdect", "alloc", "pkcs8", "sec1/serde"] -wnaf = ["alloc", "arithmetic", "dep:wnaf"] [lints] workspace = true [package.metadata.docs.rs] -features = ["basepoint-table", "bits", "ecdh", "pem", "std"] +features = ["ecdh", "pem", "serde", "std"] diff --git a/elliptic-curve/src/lib.rs b/elliptic-curve/src/lib.rs index 5a4c02fda..894645e76 100644 --- a/elliptic-curve/src/lib.rs +++ b/elliptic-curve/src/lib.rs @@ -106,8 +106,6 @@ pub use zeroize; pub use crate::error::{DecodeError, DecodeResult}; #[cfg(feature = "pkcs8")] pub use pkcs8; -#[cfg(feature = "wnaf")] -pub use wnaf; #[cfg(feature = "arithmetic")] pub use { crate::{ diff --git a/elliptic-curve/src/point.rs b/elliptic-curve/src/point.rs index 6fd143d0e..4ed30af64 100644 --- a/elliptic-curve/src/point.rs +++ b/elliptic-curve/src/point.rs @@ -1,18 +1,11 @@ //! Traits for elliptic curve points. -mod basepoint_table; -mod lookup_table; mod non_identity; -#[cfg(all(feature = "basepoint-table", feature = "wnaf"))] -pub use self::basepoint_table::vartime::{BasepointTableVartime, PointWithBasepointTableVartime}; -#[cfg(feature = "basepoint-table")] -pub use self::basepoint_table::{BasepointTable, PointWithBasepointTable}; - +#[cfg(feature = "arithmetic")] +pub use self::non_identity::NonIdentity; use crate::{Curve, FieldBytes}; use subtle::{Choice, CtOption}; -#[cfg(feature = "arithmetic")] -pub use {self::non_identity::NonIdentity, lookup_table::LookupTable}; #[cfg(feature = "arithmetic")] use crate::CurveArithmetic; diff --git a/elliptic-curve/src/point/basepoint_table.rs b/elliptic-curve/src/point/basepoint_table.rs deleted file mode 100644 index 4004de6e0..000000000 --- a/elliptic-curve/src/point/basepoint_table.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! Precomputed basepoint tables for accelerating fixed-base scalar multiplication. - -#![cfg(feature = "basepoint-table")] -#![allow(clippy::cast_possible_truncation, clippy::needless_range_loop)] - -#[cfg(not(any(feature = "critical-section", feature = "std")))] -compile_error!("`basepoint-table` feature requires either `critical-section` or `std`"); - -use super::LookupTable; -use group::Group; -use subtle::ConditionallySelectable; -use {core::ops::Deref, ff::PrimeField}; - -#[cfg(feature = "critical-section")] -use once_cell::sync::Lazy as LazyLock; -#[cfg(all(feature = "std", not(feature = "critical-section")))] -use std::sync::LazyLock; - -/// Associate a precomputed `BASEPOINT_TABLE` constant with a curve point. -pub trait PointWithBasepointTable: Group { - /// Basepoint table for this curve. - const BASEPOINT_TABLE: &'static BasepointTable; -} - -/// Precomputed lookup table of multiples of a base point, a.k.a. generator. -/// -/// This type leverages lazy computation, and requires one of the following crate features to be -/// enabled in order to work: -/// - `std`: leverages `std::sync::LazyLock` -/// - `critical-section`: leverages `once_cell::sync::Lazy` via the `critical-section` crate, -/// enabling the feature to be used in `no_std` contexts. -#[derive(Debug)] -pub struct BasepointTable { - tables: LazyLock<[LookupTable; WINDOW_SIZE]>, -} - -impl BasepointTable -where - Point: ConditionallySelectable + Default + Group, -{ - /// Create a new [`BasepointTable`] which is lazily initialized on first use and can be bound - /// to a constant. - /// - /// Computed using the `Point`'s [`Group::generator`] as the base point. - pub const fn new() -> Self { - /// Inner function to initialize the table. - fn init_table() -> [LookupTable; N] - where - Point: ConditionallySelectable + Default + Group, - { - // Ensure basepoint table contains the expected number of entries for the scalar's size - const { - assert!( - N as u32 == 1 + Point::Scalar::NUM_BITS / 8, - "incorrectly sized basepoint table" - ); - } - - let mut generator = Point::generator(); - let mut res = [LookupTable::::default(); N]; - - for i in 0..N { - res[i] = LookupTable::new(generator); - // We are storing tables spaced by two radix steps, - // to decrease the size of the precomputed data. - for _ in 0..8 { - generator = generator.double(); - } - } - - res - } - - Self { - tables: LazyLock::new(init_table), - } - } -} - -impl Default for BasepointTable -where - Point: ConditionallySelectable + Default + Group, -{ - fn default() -> Self { - Self::new() - } -} - -impl Deref for BasepointTable { - type Target = [LookupTable; WINDOW_SIZE]; - - #[inline] - fn deref(&self) -> &[LookupTable; WINDOW_SIZE] { - &self.tables - } -} - -#[cfg(feature = "wnaf")] -pub(super) mod vartime { - use super::LazyLock; - use alloc::vec::Vec; - use core::ops::Mul; - use group::Group; - use wnaf::{WnafBase, WnafScalar}; - - /// Associate a precomputed `BASEPOINT_TABLE_VARTIME` constant with a curve point. - pub trait PointWithBasepointTableVartime: Group { - /// Basepoint table for this curve. - const BASEPOINT_TABLE_VARTIME: &'static BasepointTableVartime; - } - - /// Window table for a curve's base point (a.k.a. generator) precomputed to improve the speed of - /// variable-time scalar multiplication. - /// - ///
- /// Security Warning - /// - /// Variable-time scalar multiplication can potentially leak secret values and should NOT be - /// used with them. - ///
- /// - /// This type leverages lazy computation, and requires one of the following crate features to be - /// enabled in order to work: - /// - `std`: leverages `std::sync::LazyLock` - /// - `critical-section`: leverages `once_cell::sync::Lazy` via the `critical-section` crate, - /// enabling the feature to be used in `no_std` contexts. - #[derive(Debug)] - pub struct BasepointTableVartime { - table: LazyLock>, - } - - impl BasepointTableVartime { - /// Create a new [`BasepointTableVartime`] which is lazily initialized on first use and can - /// be bound to a constant. - /// - /// Computed using the `Point`'s [`Group::generator`] as the base point. - pub const fn new() -> Self { - /// Inner function to initialize the wNAF context. - fn init_wnaf() -> WnafBase - where - Point: Group, - { - WnafBase::new(Point::generator()) - } - - Self { - table: LazyLock::new(init_wnaf), - } - } - - /// Multiply `Point::generator` by the given scalar in variable-time, using the precomputed - /// window table to accelerate the scalar multiplication. - pub fn mul(&self, scalar: &Point::Scalar) -> Point { - self.table.mul(&WnafScalar::new(scalar)) - } - - /// Multiply `Point::generator` by the given scalar in variable-time, then compute a linear - /// combination of the remaining points and scalars, i.e. - /// - /// ```text - /// scalar * G + scalars[0] * Points[0] + ... - /// ``` - pub fn lincomb( - &self, - scalar: &Point::Scalar, - points_and_scalars: &[(Point, Point::Scalar)], - ) -> Point { - let mut bases = Vec::with_capacity(points_and_scalars.len() + 1); - bases.push(self.table.clone()); - bases.extend( - points_and_scalars - .iter() - .map(|(point, _)| WnafBase::new(*point)), - ); - - let mut scalars = Vec::with_capacity(points_and_scalars.len() + 1); - scalars.push(WnafScalar::new(scalar)); - scalars.extend( - points_and_scalars - .iter() - .map(|(_, scalar)| WnafScalar::new(scalar)), - ); - - WnafBase::multiscalar_mul(scalars, bases) - } - } - - impl Default for BasepointTableVartime { - fn default() -> Self { - Self::new() - } - } -} diff --git a/elliptic-curve/src/point/lookup_table.rs b/elliptic-curve/src/point/lookup_table.rs deleted file mode 100644 index 9e13daa6d..000000000 --- a/elliptic-curve/src/point/lookup_table.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Precomputed lookup tables which allow multiples of an elliptic curve point to be selected in -//! constant time. - -#![cfg(feature = "arithmetic")] - -use group::Group; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; - -/// Internal constant for the number of entries in a [`LookupTable`]. -/// -/// This is defined separately from `LookupTable::SIZE` because we can't use an inherent associated -/// constant of a generic type in generic contexts, and this doesn't vary depending on `Point`. -const LUT_SIZE: usize = 8; - -/// Lookup table containing precomputed values `[p, 2p, 3p, ..., 8p]` -#[derive(Clone, Copy, Debug, Default)] -pub struct LookupTable { - points: [Point; LUT_SIZE], -} - -impl LookupTable -where - Point: ConditionallySelectable + Group, -{ - /// Number of entries in the lookup table. - pub const SIZE: usize = LUT_SIZE; - - /// Compute a new lookup table from the given point. - #[inline] - pub fn new(p: Point) -> Self { - let mut points = [p; LUT_SIZE]; - - for j in 0..(LUT_SIZE - 1) { - points[j + 1] = p + points[j]; - } - - Self { points } - } - - /// Given `-8 <= x <= 8`, returns `x * p` in constant time. - #[allow(clippy::cast_sign_loss)] - #[inline] - pub fn select(&self, x: i8) -> Point { - debug_assert!((-8..=8).contains(&x)); - - // Compute xabs = |x| - let xmask = x >> 7; - let xabs = (x + xmask) ^ xmask; - - // Get an array element in constant time - let mut t = Point::identity(); - - #[allow(clippy::cast_possible_truncation)] - for j in 1..(LUT_SIZE + 1) { - let c = (xabs as u8).ct_eq(&(j as u8)); - t.conditional_assign(&self.points[j - 1], c); - } - // Now t == |x| * p. - - let neg_mask = Choice::from((xmask & 1) as u8); - t.conditional_assign(&-t, neg_mask); - // Now t == x * p. - - t - } -}