diff --git a/Cargo.lock b/Cargo.lock index 521a4c6c1..30638039e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,6 @@ dependencies = [ "hybrid-array", "num-traits", "rand_core", - "subtle", "zeroize", ] @@ -234,6 +233,7 @@ dependencies = [ "base16ct", "crypto-bigint", "crypto-common", + "ctutils", "digest", "hex-literal", "hkdf", @@ -329,11 +329,11 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" dependencies = [ - "subtle", + "ctutils", "typenum", "zeroize", ] @@ -541,9 +541,9 @@ checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "rustcrypto-ff" -version = "0.14.0-rc.0" +version = "0.14.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5db129183b2c139d7d87d08be57cba626c715789db17aec65c8866bfd767d1f" +checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6" dependencies = [ "bitvec", "rand_core", @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "rustcrypto-group" -version = "0.14.0-rc.0" +version = "0.14.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c4b1463f274a3ff6fb2f44da43e576cb9424367bd96f185ead87b52fe00523" +checksum = "369f9b61aa45933c062c9f6b5c3c50ab710687eca83dd3802653b140b43f85ed" dependencies = [ "rand_core", "rustcrypto-ff", @@ -579,16 +579,15 @@ dependencies = [ [[package]] name = "sec1" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46b9a5ab87780a3189a1d704766579517a04ad59de653b7aad7d38e8a15f7dc" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" dependencies = [ "base16ct", "ctutils", "der", "hybrid-array", "serdect", - "subtle", "zeroize", ] diff --git a/elliptic-curve/Cargo.toml b/elliptic-curve/Cargo.toml index 04d08eac1..b9a44adf4 100644 --- a/elliptic-curve/Cargo.toml +++ b/elliptic-curve/Cargo.toml @@ -17,9 +17,10 @@ and public/secret keys composed thereof. """ [dependencies] -array = { package = "hybrid-array", version = "0.4", default-features = false, features = ["zeroize"] } -bigint = { package = "crypto-bigint", version = "0.7", default-features = false, features = ["hybrid-array", "rand_core", "subtle", "zeroize"] } +array = { package = "hybrid-array", version = "0.4.10", default-features = false, features = ["ctutils", "zeroize"] } +bigint = { package = "crypto-bigint", version = "0.7", default-features = false, features = ["hybrid-array", "rand_core", "zeroize"] } base16ct = "1" +ctutils = { version = "0.4", features = ["subtle"] } common = { package = "crypto-common", version = "0.2", features = ["rand_core"] } rand_core = { version = "0.10", default-features = false } subtle = { version = "2.6", default-features = false } @@ -27,14 +28,14 @@ zeroize = { version = "1.7", default-features = false } # optional dependencies digest = { version = "0.11", optional = true } -ff = { version = "0.14.0-rc.0", package = "rustcrypto-ff", optional = true, default-features = false } -group = { version = "0.14.0-rc.0", package = "rustcrypto-group", optional = true, default-features = false } +ff = { version = "0.14.0-rc.1", package = "rustcrypto-ff", optional = true, default-features = false } +group = { version = "0.14.0-rc.1", package = "rustcrypto-group", 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.0-rc.10", optional = true, default-features = false } -sec1 = { version = "0.8", optional = true, features = ["ctutils", "subtle", "zeroize"] } +sec1 = { version = "0.8.1", optional = true, features = ["ctutils", "zeroize"] } serdect = { version = "0.4", optional = true, default-features = false, features = ["alloc"] } [dev-dependencies] diff --git a/elliptic-curve/src/arithmetic.rs b/elliptic-curve/src/arithmetic.rs index 7a0025e41..89ef6efa9 100644 --- a/elliptic-curve/src/arithmetic.rs +++ b/elliptic-curve/src/arithmetic.rs @@ -2,7 +2,7 @@ use crate::{ Curve, CurveGroup, Error, FieldBytes, Group, NonZeroScalar, PrimeCurve, ScalarValue, - ctutils::{CtEq, CtSelect}, + ctutils::{CtEq, CtOption, CtSelect}, ops::{Invert, LinearCombination, Mul, Reduce}, point::{AffineCoordinates, NonIdentity}, scalar::{FromUintUnchecked, IsHigh}, @@ -10,7 +10,6 @@ use crate::{ use bigint::modular::Retrieve; use common::Generate; use core::fmt::Debug; -use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::DefaultIsZeroes; /// Elliptic curve with an arithmetic implementation. @@ -19,8 +18,6 @@ pub trait CurveArithmetic: Curve { type AffinePoint: 'static + AffineCoordinates> + Copy - + ConditionallySelectable - + ConstantTimeEq + CtEq + CtSelect + Debug @@ -46,9 +43,7 @@ pub trait CurveArithmetic: Curve { /// - [`Sized`] /// - [`Send`] /// - [`Sync`] - type ProjectivePoint: ConditionallySelectable - + ConstantTimeEq - + CtEq + type ProjectivePoint: CtEq + CtSelect + Default + DefaultIsZeroes @@ -68,8 +63,8 @@ pub trait CurveArithmetic: Curve { /// - `'static` /// - [`Copy`] /// - [`Clone`] - /// - [`ConditionallySelectable`] - /// - [`ConstantTimeEq`] + /// - [`CtSelect`] + /// - [`CtEq`] /// - [`Debug`] /// - [`Default`] /// - [`Send`] diff --git a/elliptic-curve/src/dev/mock_curve.rs b/elliptic-curve/src/dev/mock_curve.rs index 0d546ae77..28156a013 100644 --- a/elliptic-curve/src/dev/mock_curve.rs +++ b/elliptic-curve/src/dev/mock_curve.rs @@ -8,14 +8,12 @@ use crate::{ BatchNormalize, Curve, CurveArithmetic, CurveGroup, FieldBytesEncoding, Generate, PrimeCurve, array::typenum::U32, bigint::{Limb, Odd, U256, modular::Retrieve}, - ctutils, error::{Error, Result}, ops::{Invert, LinearCombination, Reduce, ShrAssign}, point::{AffineCoordinates, NonIdentity}, rand_core::{TryCryptoRng, TryRng}, scalar::{FromUintUnchecked, IsHigh}, sec1::{CompressedPoint, FromSec1Point, ToSec1Point}, - subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, }; use core::{ @@ -23,6 +21,7 @@ use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use ctutils::{Choice, CtEq, CtOption, CtSelect}; use ff::{Field, PrimeField}; use hex_literal::hex; use pkcs8::AssociatedOid; @@ -107,8 +106,8 @@ impl Field for Scalar { } } - fn is_zero(&self) -> Choice { - self.0.is_zero() + fn is_zero(&self) -> subtle::Choice { + self.0.is_zero().into() } fn square(&self) -> Self { @@ -119,15 +118,15 @@ impl Field for Scalar { self.add(self) } - fn invert(&self) -> CtOption { + fn invert(&self) -> subtle::CtOption { unimplemented!(); } - fn sqrt(&self) -> CtOption { + fn sqrt(&self) -> subtle::CtOption { unimplemented!(); } - fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + fn sqrt_ratio(_num: &Self, _div: &Self) -> (subtle::Choice, Self) { unimplemented!(); } } @@ -146,16 +145,16 @@ impl PrimeField for Scalar { const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS! const DELTA: Self = Self::ZERO; // BOGUS! - fn from_repr(bytes: FieldBytes) -> CtOption { - ScalarValue::from_bytes(&bytes).map(Self) + fn from_repr(bytes: FieldBytes) -> subtle::CtOption { + ScalarValue::from_bytes(&bytes).map(Self).into() } fn to_repr(&self) -> FieldBytes { self.0.to_bytes() } - fn is_odd(&self) -> Choice { - self.0.is_odd() + fn is_odd(&self) -> subtle::Choice { + self.0.is_odd().into() } } @@ -190,27 +189,27 @@ impl AsRef for Scalar { } } -impl ConditionallySelectable for Scalar { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Self(ScalarValue::conditional_select(&a.0, &b.0, choice)) +impl CtEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) } } -impl ConstantTimeEq for Scalar { - fn ct_eq(&self, other: &Self) -> Choice { - self.0.ct_eq(&other.0) +impl CtSelect for Scalar { + fn ct_select(&self, other: &Self, choice: Choice) -> Self { + Self(self.0.ct_select(&other.0, choice)) } } -impl ctutils::CtEq for Scalar { - fn ct_eq(&self, other: &Self) -> ctutils::Choice { - ctutils::CtEq::ct_eq(&self.0, &other.0) +impl subtle::ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> subtle::Choice { + CtEq::ct_eq(&self.0, &other.0).into() } } -impl ctutils::CtSelect for Scalar { - fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self { - Self(self.0.ct_select(&other.0, choice)) +impl subtle::ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + a.ct_select(b, choice.into()) } } @@ -382,7 +381,7 @@ impl Reduce for Scalar { fn reduce(w: &U256) -> Self { let (r, underflow) = w.borrowing_sub(&MockCurve::ORDER, Limb::ZERO); let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); - let reduced = U256::conditional_select(w, &r, !underflow); + let reduced = w.ct_select(&r, !underflow); Self(ScalarValue::new(reduced).unwrap()) } } @@ -516,7 +515,7 @@ impl AffineCoordinates for AffinePoint { } } -impl ConstantTimeEq for AffinePoint { +impl CtEq for AffinePoint { fn ct_eq(&self, other: &Self) -> Choice { match (self, other) { (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { @@ -529,22 +528,22 @@ impl ConstantTimeEq for AffinePoint { } } -impl ConditionallySelectable for AffinePoint { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - ctutils::CtSelect::ct_select(a, b, choice.into()) +impl CtSelect for AffinePoint { + fn ct_select(&self, other: &Self, choice: Choice) -> Self { + // Not really constant time, but this is dev code + if choice.to_bool() { *other } else { *self } } } -impl ctutils::CtEq for AffinePoint { - fn ct_eq(&self, other: &Self) -> ctutils::Choice { - ConstantTimeEq::ct_eq(self, other).into() +impl subtle::ConstantTimeEq for AffinePoint { + fn ct_eq(&self, other: &Self) -> subtle::Choice { + CtEq::ct_eq(self, other).into() } } -impl ctutils::CtSelect for AffinePoint { - fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self { - // Not really constant time, but this is dev code - if choice.to_bool() { *other } else { *self } +impl subtle::ConditionallySelectable for AffinePoint { + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + CtSelect::ct_select(a, b, choice.into()) } } @@ -565,14 +564,14 @@ impl Generate for AffinePoint { } impl FromSec1Point for AffinePoint { - fn from_sec1_point(encoded_point: &Sec1Point) -> ctutils::CtOption { + fn from_sec1_point(encoded_point: &Sec1Point) -> CtOption { let point = if encoded_point.is_identity() { Self::Identity } else { Self::Other(*encoded_point) }; - ctutils::CtOption::new(point, ctutils::Choice::TRUE) + CtOption::new(point, Choice::TRUE) } } @@ -646,7 +645,7 @@ impl BatchNormalize<[ProjectivePoint]> for ProjectivePoint { } } -impl ConstantTimeEq for ProjectivePoint { +impl CtEq for ProjectivePoint { fn ct_eq(&self, other: &Self) -> Choice { match (self, other) { (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { @@ -659,21 +658,21 @@ impl ConstantTimeEq for ProjectivePoint { } } -impl ConditionallySelectable for ProjectivePoint { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - ctutils::CtSelect::ct_select(a, b, choice.into()) +impl CtSelect for ProjectivePoint { + fn ct_select(&self, other: &Self, choice: Choice) -> Self { + if choice.to_bool() { *other } else { *self } } } -impl ctutils::CtEq for ProjectivePoint { - fn ct_eq(&self, other: &Self) -> ctutils::Choice { - ConstantTimeEq::ct_eq(self, other).into() +impl subtle::ConditionallySelectable for ProjectivePoint { + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + CtSelect::ct_select(a, b, choice.into()) } } -impl ctutils::CtSelect for ProjectivePoint { - fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self { - if choice.to_bool() { *other } else { *self } +impl subtle::ConstantTimeEq for ProjectivePoint { + fn ct_eq(&self, other: &Self) -> subtle::Choice { + CtEq::ct_eq(self, other).into() } } @@ -711,7 +710,7 @@ impl Generate for ProjectivePoint { } impl FromSec1Point for ProjectivePoint { - fn from_sec1_point(_point: &Sec1Point) -> ctutils::CtOption { + fn from_sec1_point(_point: &Sec1Point) -> CtOption { unimplemented!(); } } @@ -745,8 +744,9 @@ impl group::Group for ProjectivePoint { Self::Generator } - fn is_identity(&self) -> Choice { - Choice::from(u8::from(self == &Self::Identity)) + fn is_identity(&self) -> subtle::Choice { + // WARNING: variable-time! This is for mock/testing purposes only! + subtle::Choice::from(u8::from(self == &Self::Identity)) } fn double(&self) -> Self { @@ -758,19 +758,18 @@ impl group::GroupEncoding for AffinePoint { type Repr = CompressedPoint; #[allow(clippy::map_unwrap_or)] - fn from_bytes(bytes: &Self::Repr) -> CtOption { + fn from_bytes(bytes: &Self::Repr) -> subtle::CtOption { Sec1Point::from_bytes(bytes) - .map(|point| ctutils::CtOption::new(point, ctutils::Choice::TRUE)) + .map(|point| CtOption::new(point, Choice::TRUE)) .unwrap_or_else(|_| { - let is_identity = - ctutils::CtEq::ct_eq(bytes.as_slice(), Self::Repr::default().as_slice()); - ctutils::CtOption::new(Sec1Point::identity(), is_identity) + let is_identity = CtEq::ct_eq(bytes.as_slice(), Self::Repr::default().as_slice()); + CtOption::new(Sec1Point::identity(), is_identity) }) .and_then(|point| Self::from_sec1_point(&point)) .into() } - fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + fn from_bytes_unchecked(bytes: &Self::Repr) -> subtle::CtOption { Self::from_bytes(bytes) } @@ -785,11 +784,11 @@ impl group::GroupEncoding for AffinePoint { impl group::GroupEncoding for ProjectivePoint { type Repr = CompressedPoint; - fn from_bytes(bytes: &Self::Repr) -> CtOption { + fn from_bytes(bytes: &Self::Repr) -> subtle::CtOption { ::from_bytes(bytes).map(Into::into) } - fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + fn from_bytes_unchecked(bytes: &Self::Repr) -> subtle::CtOption { Self::from_bytes(bytes) } diff --git a/elliptic-curve/src/lib.rs b/elliptic-curve/src/lib.rs index e2f3c3a12..0aa639b6f 100644 --- a/elliptic-curve/src/lib.rs +++ b/elliptic-curve/src/lib.rs @@ -95,11 +95,10 @@ pub use crate::{ pub use array; pub use array::typenum::consts; pub use bigint; -pub use bigint::ctutils; pub use common; pub use common::Generate; +pub use ctutils; pub use rand_core; -pub use subtle; pub use zeroize; #[cfg(feature = "arithmetic")] diff --git a/elliptic-curve/src/ops.rs b/elliptic-curve/src/ops.rs index 84dddd60d..695581f09 100644 --- a/elliptic-curve/src/ops.rs +++ b/elliptic-curve/src/ops.rs @@ -3,10 +3,12 @@ pub use bigint::{Invert, Reduce}; pub use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign}; -use crate::CurveGroup; +use crate::{ + CurveGroup, + ctutils::{Choice, CtOption}, +}; use core::iter; use ff::Field; -use subtle::{Choice, CtOption}; #[cfg(feature = "alloc")] use alloc::{borrow::ToOwned, vec::Vec}; @@ -90,7 +92,7 @@ fn invert(scalar: T) -> (T, Choice) { let choice = scalar.is_some(); let scalar = scalar.unwrap_or(T::default()); - (scalar, choice) + (scalar, choice.into()) } /// Implements "Montgomery's trick", a trick for computing many modular inverses at once. diff --git a/elliptic-curve/src/point.rs b/elliptic-curve/src/point.rs index e3153cf2f..771b0f37f 100644 --- a/elliptic-curve/src/point.rs +++ b/elliptic-curve/src/point.rs @@ -10,8 +10,10 @@ pub use {self::non_identity::NonIdentity, lookup_table::LookupTable}; #[cfg(feature = "basepoint-table")] pub use self::basepoint_table::BasepointTable; -use crate::{Curve, FieldBytes}; -use subtle::{Choice, CtOption}; +use crate::{ + Curve, FieldBytes, + ctutils::{Choice, CtOption}, +}; #[cfg(feature = "arithmetic")] use crate::CurveArithmetic; diff --git a/elliptic-curve/src/point/basepoint_table.rs b/elliptic-curve/src/point/basepoint_table.rs index df218f72c..76261cf26 100644 --- a/elliptic-curve/src/point/basepoint_table.rs +++ b/elliptic-curve/src/point/basepoint_table.rs @@ -6,9 +6,8 @@ #[cfg(not(any(feature = "critical-section", feature = "std")))] compile_error!("`basepoint-table` feature requires either `critical-section` or `std`"); -use crate::point::LookupTable; +use crate::{ctutils::CtAssign, point::LookupTable}; use group::Group; -use subtle::ConditionallySelectable; use {core::ops::Deref, ff::PrimeField}; #[cfg(feature = "critical-section")] @@ -30,7 +29,7 @@ pub struct BasepointTable { impl BasepointTable where - Point: ConditionallySelectable + Default + Group, + Point: CtAssign + Default + Group, { /// Create a new [`BasepointTable`] which is lazily initialized on first use and can be bound /// to a constant. @@ -40,7 +39,7 @@ where /// Inner function to initialize the table. fn init_table() -> [LookupTable; N] where - Point: ConditionallySelectable + Default + Group, + Point: CtAssign + Default + Group, { // Ensure basepoint table contains the expected number of entries for the scalar's size const { @@ -73,7 +72,7 @@ where impl Default for BasepointTable where - Point: ConditionallySelectable + Default + Group, + Point: CtAssign + Default + Group, { fn default() -> Self { Self::new() diff --git a/elliptic-curve/src/point/lookup_table.rs b/elliptic-curve/src/point/lookup_table.rs index 9e13daa6d..2c16f88e5 100644 --- a/elliptic-curve/src/point/lookup_table.rs +++ b/elliptic-curve/src/point/lookup_table.rs @@ -3,8 +3,8 @@ #![cfg(feature = "arithmetic")] +use ctutils::{Choice, CtAssign, CtEq}; use group::Group; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; /// Internal constant for the number of entries in a [`LookupTable`]. /// @@ -13,6 +13,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; const LUT_SIZE: usize = 8; /// Lookup table containing precomputed values `[p, 2p, 3p, ..., 8p]` +// TODO(tarcieri): impl `ctutils::CtLookup` #[derive(Clone, Copy, Debug, Default)] pub struct LookupTable { points: [Point; LUT_SIZE], @@ -20,7 +21,7 @@ pub struct LookupTable { impl LookupTable where - Point: ConditionallySelectable + Group, + Point: CtAssign + Group, { /// Number of entries in the lookup table. pub const SIZE: usize = LUT_SIZE; @@ -53,12 +54,12 @@ where #[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); + t.ct_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); + t.ct_assign(&-t, neg_mask); // Now t == x * p. t diff --git a/elliptic-curve/src/point/non_identity.rs b/elliptic-curve/src/point/non_identity.rs index f6fee940d..9ea636be6 100644 --- a/elliptic-curve/src/point/non_identity.rs +++ b/elliptic-curve/src/point/non_identity.rs @@ -4,15 +4,15 @@ use common::Generate; use core::ops::{Deref, Mul}; +use ctutils::{Choice, CtEq, CtOption, CtSelect}; use group::{Group, GroupEncoding, prime::PrimeCurveAffine}; use rand_core::{CryptoRng, TryCryptoRng}; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::Zeroize; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[cfg(feature = "serde")] use serdect::serde::{Deserialize, Serialize, de, ser}; -use zeroize::Zeroize; use crate::{BatchNormalize, CurveArithmetic, CurveGroup, NonZeroScalar, Scalar}; @@ -22,7 +22,7 @@ use crate::{BatchNormalize, CurveArithmetic, CurveGroup, NonZeroScalar, Scalar}; /// /// In the context of ECC, it's useful for ensuring that certain arithmetic /// cannot result in the identity point. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] // `repr` is needed for `unsafe` safety invariants below #[repr(transparent)] pub struct NonIdentity

{ @@ -31,11 +31,12 @@ pub struct NonIdentity

{ impl

NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + Default, + P: CtSelect + CtEq + Default, { /// Create a [`NonIdentity`] from a point. pub fn new(point: P) -> CtOption { - CtOption::new(Self { point }, !point.ct_eq(&P::default())) + let is_identity = point.ct_eq(&P::default()); + CtOption::new(Self { point }, !is_identity) } pub(crate) fn new_unchecked(point: P) -> Self { @@ -45,11 +46,11 @@ where impl

NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, + P: CtEq + CtSelect + Default + GroupEncoding + subtle::ConditionallySelectable, { /// Decode a [`NonIdentity`] from its encoding. pub fn from_repr(repr: &P::Repr) -> CtOption { - Self::from_bytes(repr) + Self::from_bytes(repr).into() } } @@ -98,7 +99,7 @@ impl NonIdentity

{ impl

NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + CurveGroup + Default, + P: CtSelect + CtEq + CurveGroup + Default, { /// Generate a random `NonIdentity`. #[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")] @@ -176,23 +177,34 @@ where } } -impl

ConditionallySelectable for NonIdentity

+impl

CtEq for NonIdentity

where - P: ConditionallySelectable, + P: CtEq, { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + fn ct_eq(&self, other: &Self) -> Choice { + self.point.ct_eq(&other.point) + } +} + +impl

CtSelect for NonIdentity

+where + P: CtSelect, +{ + fn ct_select(&self, other: &Self, choice: Choice) -> Self { Self { - point: P::conditional_select(&a.point, &b.point, choice), + point: self.point.ct_select(&other.point, choice), } } } -impl

ConstantTimeEq for NonIdentity

+impl

subtle::ConditionallySelectable for NonIdentity

where - P: ConstantTimeEq, + P: Copy + CtSelect, { - fn ct_eq(&self, other: &Self) -> Choice { - self.point.ct_eq(&other.point) + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + Self { + point: a.point.ct_select(&b.point, choice.into()), + } } } @@ -206,7 +218,7 @@ impl

Deref for NonIdentity

{ impl

Generate for NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + Default + Generate, + P: CtSelect + CtEq + Default + Generate, { fn try_generate_from_rng(rng: &mut R) -> Result { loop { @@ -219,16 +231,18 @@ where impl

GroupEncoding for NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, + P: CtEq + Default + GroupEncoding + subtle::ConditionallySelectable, { type Repr = P::Repr; - fn from_bytes(bytes: &Self::Repr) -> CtOption { - let point = P::from_bytes(bytes); - point.and_then(|point| CtOption::new(Self { point }, !point.ct_eq(&P::default()))) + fn from_bytes(bytes: &Self::Repr) -> subtle::CtOption { + // TODO(tarcieri): convert to `ctutils`, use `CtOption::filter_by` + P::from_bytes(bytes).and_then(|point| { + subtle::CtOption::new(Self { point }, (!point.ct_eq(&P::default())).into()) + }) } - fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + fn from_bytes_unchecked(bytes: &Self::Repr) -> subtle::CtOption { P::from_bytes_unchecked(bytes).map(|point| Self { point }) } @@ -303,7 +317,7 @@ where #[cfg(feature = "serde")] impl<'de, P> Deserialize<'de> for NonIdentity

where - P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding, + P: CtSelect + CtEq + Default + Deserialize<'de> + GroupEncoding, { fn deserialize(deserializer: D) -> Result where diff --git a/elliptic-curve/src/public_key.rs b/elliptic-curve/src/public_key.rs index 2cb0706e7..d3fb3d180 100644 --- a/elliptic-curve/src/public_key.rs +++ b/elliptic-curve/src/public_key.rs @@ -20,11 +20,11 @@ use { use { crate::{ FieldBytesSize, - ctutils::{Choice, CtOption}, point::PointCompression, sec1::{CompressedPoint, FromSec1Point, ModulusSize, Sec1Point, ToSec1Point}, }, core::cmp::Ordering, + ctutils::{CtEq, CtOption}, }; #[cfg(feature = "serde")] @@ -187,9 +187,10 @@ where /// Initialize [`PublicKey`] from an [`Sec1Point`] fn from_sec1_point(encoded_point: &Sec1Point) -> CtOption { AffinePoint::::from_sec1_point(encoded_point).and_then(|point| { - // Defeating the point of `subtle`, but the use case is specifically a public key - let is_identity = Choice::from_u8_lsb(u8::from(encoded_point.is_identity())); - CtOption::new(PublicKey { point }, !is_identity) + CtOption::new( + PublicKey { point }, + !encoded_point.ct_eq(&Sec1Point::::identity()), + ) }) } } diff --git a/elliptic-curve/src/scalar.rs b/elliptic-curve/src/scalar.rs index b98fba8e5..f35aa9059 100644 --- a/elliptic-curve/src/scalar.rs +++ b/elliptic-curve/src/scalar.rs @@ -12,7 +12,7 @@ pub use self::value::ScalarValue; pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar}; use bigint::Integer; -use subtle::Choice; +use ctutils::Choice; #[cfg(feature = "arithmetic")] use crate::CurveArithmetic; diff --git a/elliptic-curve/src/scalar/blinded.rs b/elliptic-curve/src/scalar/blinded.rs index f98f0cae5..5ce18557c 100644 --- a/elliptic-curve/src/scalar/blinded.rs +++ b/elliptic-curve/src/scalar/blinded.rs @@ -1,11 +1,10 @@ //! Random blinding support for [`Scalar`] use super::Scalar; -use crate::{CurveArithmetic, ops::Invert}; +use crate::{CurveArithmetic, ctutils::CtOption, ops::Invert}; use common::Generate; use core::fmt; use rand_core::{CryptoRng, TryCryptoRng}; -use subtle::CtOption; use zeroize::Zeroize; #[cfg(feature = "getrandom")] diff --git a/elliptic-curve/src/scalar/nonzero.rs b/elliptic-curve/src/scalar/nonzero.rs index d61065be8..ef14a7e86 100644 --- a/elliptic-curve/src/scalar/nonzero.rs +++ b/elliptic-curve/src/scalar/nonzero.rs @@ -2,6 +2,7 @@ use crate::{ CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarValue, SecretKey, + ctutils::{Choice, CtEq, CtOption, CtSelect}, ops::{self, BatchInvert, Invert, Reduce, ReduceNonZero}, point::NonIdentity, scalar::IsHigh, @@ -15,7 +16,6 @@ use core::{ }; use ff::{Field, PrimeField}; use rand_core::{CryptoRng, TryCryptoRng}; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::Zeroize; #[cfg(feature = "alloc")] @@ -28,7 +28,7 @@ use serdect::serde::{Deserialize, Serialize, de, ser}; /// /// This type ensures that its value is not zero, ala `core::num::NonZero*`. /// To do this, the generic `S` type must impl both `Default` and -/// `ConstantTimeEq`, with the requirement that `S::default()` returns 0. +/// `CtEq`, with the requirement that `S::default()` returns 0. /// /// In the context of ECC, it's useful for ensuring that scalar multiplication /// cannot result in the point at infinity. @@ -54,12 +54,12 @@ where { /// Create a [`NonZeroScalar`] from a scalar. pub fn new(scalar: Scalar) -> CtOption { - CtOption::new(Self { scalar }, !scalar.is_zero()) + CtOption::new(Self { scalar }, (!scalar.is_zero()).into()) } /// Decode a [`NonZeroScalar`] from a big endian-serialized field element. pub fn from_repr(repr: FieldBytes) -> CtOption { - Scalar::::from_repr(repr).and_then(Self::new) + CtOption::from(Scalar::::from_repr(repr)).and_then(Self::new) } /// Create a [`NonZeroScalar`] from a `C::Uint`. @@ -145,18 +145,18 @@ where } } -impl ConditionallySelectable for NonZeroScalar +impl CtSelect for NonZeroScalar where C: CurveArithmetic, { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + fn ct_select(&self, other: &Self, choice: Choice) -> Self { Self { - scalar: Scalar::::conditional_select(&a.scalar, &b.scalar, choice), + scalar: self.scalar.ct_select(&other.scalar, choice), } } } -impl ConstantTimeEq for NonZeroScalar +impl CtEq for NonZeroScalar where C: CurveArithmetic, { diff --git a/elliptic-curve/src/scalar/value.rs b/elliptic-curve/src/scalar/value.rs index 1a986c658..7156b3759 100644 --- a/elliptic-curve/src/scalar/value.rs +++ b/elliptic-curve/src/scalar/value.rs @@ -4,7 +4,7 @@ use crate::{ Curve, Error, FieldBytes, FieldBytesEncoding, Result, array::Array, bigint::{AddMod, ConstOne, ConstZero, Integer, Limb, NegMod, Odd, RandomMod, SubMod, Zero}, - ctutils::{self, CtEq, CtGt, CtLt, CtSelect}, + ctutils::{Choice, CtEq, CtGt, CtLt, CtOption, CtSelect}, scalar::{FromUintUnchecked, IsHigh}, }; use base16ct::HexDisplay; @@ -16,10 +16,6 @@ use core::{ str, }; use rand_core::{CryptoRng, TryCryptoRng}; -use subtle::{ - Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, - CtOption, -}; use zeroize::DefaultIsZeroes; #[cfg(feature = "arithmetic")] @@ -66,10 +62,7 @@ where /// Create a new scalar from [`Curve::Uint`]. pub fn new(uint: C::Uint) -> CtOption { - CtOption::new( - Self { inner: uint }, - CtLt::ct_lt(&uint, &Self::MODULUS).into(), - ) + CtOption::new(Self { inner: uint }, CtLt::ct_lt(&uint, &Self::MODULUS)) } /// Decode [`ScalarValue`] from a serialized field element @@ -99,17 +92,17 @@ where /// Is this [`ScalarValue`] value equal to zero? pub fn is_zero(&self) -> Choice { - self.inner.is_zero().into() + self.inner.is_zero() } /// Is this [`ScalarValue`] value even? pub fn is_even(&self) -> Choice { - self.inner.is_even().into() + self.inner.is_even() } /// Is this [`ScalarValue`] value odd? pub fn is_odd(&self) -> Choice { - self.inner.is_odd().into() + self.inner.is_odd() } /// Encode [`ScalarValue`] as a serialized field element. @@ -185,41 +178,30 @@ where } } -impl ConditionallySelectable for ScalarValue -where - C: Curve, -{ - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Self { - inner: C::Uint::ct_select(&a.inner, &b.inner, choice.into()), - } - } -} - -impl ConstantTimeEq for ScalarValue +impl CtEq for ScalarValue where C: Curve, { fn ct_eq(&self, other: &Self) -> Choice { - self.inner.ct_eq(&other.inner).into() + self.inner.ct_eq(&other.inner) } } -impl ConstantTimeLess for ScalarValue +impl CtLt for ScalarValue where C: Curve, { fn ct_lt(&self, other: &Self) -> Choice { - self.inner.ct_lt(&other.inner).into() + self.inner.ct_lt(&other.inner) } } -impl ConstantTimeGreater for ScalarValue +impl CtGt for ScalarValue where C: Curve, { fn ct_gt(&self, other: &Self) -> Choice { - self.inner.ct_gt(&other.inner).into() + self.inner.ct_gt(&other.inner) } } @@ -227,37 +209,48 @@ impl CtSelect for ScalarValue where C: Curve, { - fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self { + fn ct_select(&self, other: &Self, choice: Choice) -> Self { Self { inner: C::Uint::ct_select(&self.inner, &other.inner, choice), } } } -impl CtEq for ScalarValue +impl subtle::ConstantTimeEq for ScalarValue where C: Curve, { - fn ct_eq(&self, other: &Self) -> ctutils::Choice { - self.inner.ct_eq(&other.inner) + fn ct_eq(&self, other: &Self) -> subtle::Choice { + self.inner.ct_eq(&other.inner).into() } } -impl CtGt for ScalarValue +impl subtle::ConstantTimeGreater for ScalarValue where C: Curve, { - fn ct_gt(&self, other: &Self) -> ctutils::Choice { - self.inner.ct_gt(&other.inner) + fn ct_gt(&self, other: &Self) -> subtle::Choice { + self.inner.ct_gt(&other.inner).into() } } -impl CtLt for ScalarValue +impl subtle::ConstantTimeLess for ScalarValue where C: Curve, { - fn ct_lt(&self, other: &Self) -> ctutils::Choice { - self.inner.ct_lt(&other.inner) + fn ct_lt(&self, other: &Self) -> subtle::Choice { + self.inner.ct_lt(&other.inner).into() + } +} + +impl subtle::ConditionallySelectable for ScalarValue +where + C: Curve, +{ + fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self { + Self { + inner: C::Uint::ct_select(&a.inner, &b.inner, choice.into()), + } } } @@ -415,7 +408,7 @@ where { fn is_high(&self) -> Choice { let n_2 = Self::MODULUS.get() >> 1u32; - self.inner.ct_gt(&n_2).into() + self.inner.ct_gt(&n_2) } } diff --git a/elliptic-curve/src/secret_key.rs b/elliptic-curve/src/secret_key.rs index 989e219af..d05246aa5 100644 --- a/elliptic-curve/src/secret_key.rs +++ b/elliptic-curve/src/secret_key.rs @@ -8,12 +8,14 @@ #[cfg(all(feature = "pkcs8", feature = "sec1"))] mod pkcs8; -use crate::{Curve, Error, FieldBytes, Result, ScalarValue}; +use crate::{ + Curve, Error, FieldBytes, Result, ScalarValue, + ctutils::{Choice, CtEq, CtOption}, +}; use array::typenum::Unsigned; use common::{Generate, InvalidKey, KeySizeUser, TryKeyInit}; use core::fmt::{self, Debug}; use rand_core::{CryptoRng, TryCryptoRng}; -use subtle::{Choice, ConstantTimeEq, CtOption}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; #[cfg(feature = "arithmetic")] @@ -293,7 +295,7 @@ where } } -impl ConstantTimeEq for SecretKey +impl CtEq for SecretKey where C: Curve, {