Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion elliptic-curve/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub trait CurveArithmetic: Curve {
/// - [`Default`]
/// - [`Send`]
/// - [`Sync`]
type Scalar: DefaultIsZeroes
type Scalar: AsRef<Self::Scalar>
+ DefaultIsZeroes
+ From<ScalarPrimitive<Self>>
+ FromUintUnchecked<Uint = Self::Uint>
+ Into<FieldBytes<Self>>
Expand Down
6 changes: 6 additions & 0 deletions elliptic-curve/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ impl PrimeFieldBits for Scalar {
}
}

impl AsRef<Scalar> 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))
Expand Down
4 changes: 3 additions & 1 deletion elliptic-curve/src/scalar.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Scalar types.

#[cfg(feature = "arithmetic")]
mod blinded;
#[cfg(feature = "arithmetic")]
mod invert;
#[cfg(feature = "arithmetic")]
Expand All @@ -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;
Expand Down
73 changes: 73 additions & 0 deletions elliptic-curve/src/scalar/blinded.rs
Original file line number Diff line number Diff line change
@@ -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<C>
where
C: CurveArithmetic,
{
/// Actual scalar value.
scalar: Scalar<C>,

/// Mask value.
mask: Scalar<C>,
}

impl<C> BlindedScalar<C>
where
C: CurveArithmetic,
{
/// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`].
pub fn new(scalar: Scalar<C>, rng: &mut impl CryptoRngCore) -> Self {
Self {
scalar,
mask: Scalar::<C>::random(rng),
}
}
}

impl<C> AsRef<Scalar<C>> for BlindedScalar<C>
where
C: CurveArithmetic,
{
fn as_ref(&self) -> &Scalar<C> {
&self.scalar
}
}

impl<C> Invert for BlindedScalar<C>
where
C: CurveArithmetic,
{
type Output = CtOption<Scalar<C>>;

fn invert(&self) -> CtOption<Scalar<C>> {
// 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::<C>(&masked_scalar).map(|s| s * self.mask)
}
}

impl<C> Drop for BlindedScalar<C>
where
C: CurveArithmetic,
{
fn drop(&mut self) {
self.scalar.zeroize();
self.mask.zeroize();
}
}
11 changes: 4 additions & 7 deletions elliptic-curve/src/scalar/invert.rs
Original file line number Diff line number Diff line change
@@ -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.
///
/// <https://link.springer.com/article/10.1007/s13389-016-0135-4>
#[allow(non_snake_case)]
pub fn invert_vartime<C>(scalar: &Scalar<C>) -> Option<Scalar<C>>
pub fn invert_vartime<C>(scalar: &Scalar<C>) -> CtOption<Scalar<C>>
where
C: CurveArithmetic,
{
if scalar.is_zero().into() {
return None;
}

let order_div_2 = Scalar::<C>::from_uint_unchecked(C::ORDER >> 1);

let mut u = *scalar;
Expand Down Expand Up @@ -60,5 +57,5 @@ where
}
}

Some(C)
CtOption::new(C, !scalar.is_zero())
}
2 changes: 1 addition & 1 deletion elliptic-curve/src/scalar/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ where
/// sidechannels.
pub fn invert_vartime(&self) -> Self {
Self {
scalar: super::invert_vartime::<C>(&self.scalar).expect("nonzero input"),
scalar: super::invert_vartime::<C>(&self.scalar).unwrap(),
}
}
}
Expand Down