p256/arithmetic/scalar/
blinded.rs

1//! Random blinding support for [`Scalar`]
2
3// TODO(tarcieri): make this generic (along with `Scalar::invert_vartime`)
4// and extract it into the `elliptic-curve` crate so it can be reused across curves
5
6use super::Scalar;
7use core::borrow::Borrow;
8use elliptic_curve::{
9    group::ff::Field,
10    ops::Invert,
11    rand_core::{CryptoRng, RngCore},
12    subtle::CtOption,
13    zeroize::Zeroize,
14};
15
16/// Scalar blinded with a randomly generated masking value.
17///
18/// This provides a randomly blinded impl of [`Invert`] which is useful for
19/// ECDSA ephemeral (`k`) scalars.
20#[derive(Clone)]
21#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
22pub struct BlindedScalar {
23    /// Actual scalar value
24    scalar: Scalar,
25
26    /// Mask value
27    mask: Scalar,
28}
29
30impl BlindedScalar {
31    /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRng`]
32    pub fn new(scalar: Scalar, rng: impl CryptoRng + RngCore) -> Self {
33        Self {
34            scalar,
35            mask: Scalar::random(rng),
36        }
37    }
38}
39
40impl Borrow<Scalar> for BlindedScalar {
41    fn borrow(&self) -> &Scalar {
42        &self.scalar
43    }
44}
45
46impl Invert for BlindedScalar {
47    type Output = CtOption<Scalar>;
48
49    fn invert(&self) -> CtOption<Scalar> {
50        // prevent side channel analysis of scalar inversion by pre-and-post-multiplying
51        // with the random masking scalar
52        (self.scalar * self.mask)
53            .invert_vartime()
54            .map(|s| s * self.mask)
55    }
56}
57
58impl Zeroize for BlindedScalar {
59    fn zeroize(&mut self) {
60        self.scalar.zeroize();
61        self.mask.zeroize();
62    }
63}
64
65impl Drop for BlindedScalar {
66    fn drop(&mut self) {
67        self.zeroize();
68    }
69}