diff --git a/elliptic-curve/src/arithmetic.rs b/elliptic-curve/src/arithmetic.rs index 8113f5763..8153fb011 100644 --- a/elliptic-curve/src/arithmetic.rs +++ b/elliptic-curve/src/arithmetic.rs @@ -61,7 +61,8 @@ pub trait CurveArithmetic: Curve { /// - [`Default`] /// - [`Send`] /// - [`Sync`] - type Scalar: DefaultIsZeroes + type Scalar: AsRef + + DefaultIsZeroes + From> + FromUintUnchecked + Into> diff --git a/elliptic-curve/src/dev.rs b/elliptic-curve/src/dev.rs index c60d38b0e..ded320769 100644 --- a/elliptic-curve/src/dev.rs +++ b/elliptic-curve/src/dev.rs @@ -179,6 +179,12 @@ impl PrimeFieldBits for Scalar { } } +impl AsRef for Scalar { + fn as_ref(&self) -> &Scalar { + self + } +} + impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice)) diff --git a/elliptic-curve/src/scalar.rs b/elliptic-curve/src/scalar.rs index d4d344423..6ffd63bea 100644 --- a/elliptic-curve/src/scalar.rs +++ b/elliptic-curve/src/scalar.rs @@ -1,5 +1,7 @@ //! Scalar types. +#[cfg(feature = "arithmetic")] +mod blinded; #[cfg(feature = "arithmetic")] mod invert; #[cfg(feature = "arithmetic")] @@ -8,7 +10,7 @@ mod primitive; pub use self::primitive::ScalarPrimitive; #[cfg(feature = "arithmetic")] -pub use self::{invert::invert_vartime, nonzero::NonZeroScalar}; +pub use self::{blinded::BlindedScalar, invert::invert_vartime, nonzero::NonZeroScalar}; use crypto_bigint::Integer; use subtle::Choice; diff --git a/elliptic-curve/src/scalar/blinded.rs b/elliptic-curve/src/scalar/blinded.rs new file mode 100644 index 000000000..33303aef1 --- /dev/null +++ b/elliptic-curve/src/scalar/blinded.rs @@ -0,0 +1,73 @@ +//! Random blinding support for [`Scalar`] + +use super::{invert_vartime, Scalar}; +use crate::{ops::Invert, CurveArithmetic}; +use group::ff::Field; +use rand_core::CryptoRngCore; +use subtle::CtOption; +use zeroize::Zeroize; + +/// Scalar blinded with a randomly generated masking value. +/// +/// This provides a randomly blinded impl of [`Invert`] which is useful for +/// e.g. ECDSA ephemeral (`k`) scalars. +/// +/// It implements masked variable-time inversions using Stein's algorithm, which +/// may be helpful for performance on embedded platforms. +#[derive(Clone)] +pub struct BlindedScalar +where + C: CurveArithmetic, +{ + /// Actual scalar value. + scalar: Scalar, + + /// Mask value. + mask: Scalar, +} + +impl BlindedScalar +where + C: CurveArithmetic, +{ + /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`]. + pub fn new(scalar: Scalar, rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar, + mask: Scalar::::random(rng), + } + } +} + +impl AsRef> for BlindedScalar +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar { + &self.scalar + } +} + +impl Invert for BlindedScalar +where + C: CurveArithmetic, +{ + type Output = CtOption>; + + fn invert(&self) -> CtOption> { + // prevent side channel analysis of scalar inversion by pre-and-post-multiplying + // with the random masking scalar + let masked_scalar = self.scalar * self.mask; + invert_vartime::(&masked_scalar).map(|s| s * self.mask) + } +} + +impl Drop for BlindedScalar +where + C: CurveArithmetic, +{ + fn drop(&mut self) { + self.scalar.zeroize(); + self.mask.zeroize(); + } +} diff --git a/elliptic-curve/src/scalar/invert.rs b/elliptic-curve/src/scalar/invert.rs index d0b2bbedd..0b949718e 100644 --- a/elliptic-curve/src/scalar/invert.rs +++ b/elliptic-curve/src/scalar/invert.rs @@ -1,21 +1,18 @@ use super::FromUintUnchecked; use crate::{ops::Shr1, CurveArithmetic, Scalar}; use ff::{Field, PrimeField}; +use subtle::CtOption; /// Fast variable-time inversion using Stein's algorithm. /// -/// Returns `None` if the scalar is zero. +/// Returns none if the scalar is zero. /// /// #[allow(non_snake_case)] -pub fn invert_vartime(scalar: &Scalar) -> Option> +pub fn invert_vartime(scalar: &Scalar) -> CtOption> where C: CurveArithmetic, { - if scalar.is_zero().into() { - return None; - } - let order_div_2 = Scalar::::from_uint_unchecked(C::ORDER >> 1); let mut u = *scalar; @@ -60,5 +57,5 @@ where } } - Some(C) + CtOption::new(C, !scalar.is_zero()) } diff --git a/elliptic-curve/src/scalar/nonzero.rs b/elliptic-curve/src/scalar/nonzero.rs index c9bb6ff68..1d2a7fdae 100644 --- a/elliptic-curve/src/scalar/nonzero.rs +++ b/elliptic-curve/src/scalar/nonzero.rs @@ -76,7 +76,7 @@ where /// sidechannels. pub fn invert_vartime(&self) -> Self { Self { - scalar: super::invert_vartime::(&self.scalar).expect("nonzero input"), + scalar: super::invert_vartime::(&self.scalar).unwrap(), } } }