Skip to main content

generic_ec/
secret_point.rs

1use core::fmt;
2use core::iter::Sum;
3
4use crate::{errors::InvalidPoint, secret, Curve, EncodedSecretPoint, Point};
5use subtle::{Choice, ConstantTimeEq};
6
7/// Point representing sensitive information (like a derived secret)
8///
9/// Secret point should be treated with an extra care. You shouldn't do any
10/// branching (e.g. `Eq`, `Ord`) on the secret to avoid timing side-channel
11/// attacks, so it implements only constant time traits (like [`ConstantTimeEq`]).
12///
13/// Also, when `alloc` feature is enabled, we enforce extra measures:
14///
15/// * Secret point leaves no trace in RAM after it's dropped \
16///   Memory is zeroized after use
17/// * All clones of a secret point refer to the same region in the memory \
18///   I.e. there will always be only one instance of the point in the memory
19///   no matter how many clones you make
20///
21/// All these guarantees can be bypassed by calling `.as_ref()` and obtaining
22/// `&Point<E>` that is not protected from timing attacks, leaving traces in
23/// the memory, etc.
24///
25/// [`ConstantTimeEq`]: subtle::ConstantTimeEq
26pub struct SecretPoint<E: Curve>(secret::Secret<Point<E>>);
27
28impl<E: Curve> Point<E> {
29    /// Convert this value into a [`SecretPoint`]. You should do this at the end
30    /// of computations that produce a secret, like a key exchange
31    #[inline(always)] // Prevent a byte copy in most cases
32    pub fn into_secret(mut self) -> SecretPoint<E> {
33        SecretPoint::new(&mut self)
34    }
35}
36
37impl<E: Curve> SecretPoint<E> {
38    /// Constructs a new secret point
39    ///
40    /// Takes the original point by mutable reference instead of taking by value
41    /// to avoid leaving copies of the point on stack. Point behind the
42    /// reference will be zeroized after the function has returned.
43    pub fn new(point: &mut Point<E>) -> Self {
44        Self(secret::new(point))
45    }
46
47    /// Returns the generator defined in the curve specs
48    pub fn generator() -> Self {
49        Self::new(&mut Point::generator().into())
50    }
51
52    /// Returns identity point $\O$
53    pub fn zero() -> Self {
54        Self::new(&mut Point::zero())
55    }
56
57    /// Obtain the reference to the point, which you can use for any operations
58    /// necessary. This bypasses all the secrecy guarantees, so be careful when
59    /// handling the resulting value; ideally this reference should not be held
60    /// for longer than one expression
61    ///
62    /// The [`AsRef`] impl uses this method under the hood, and is provided as a
63    /// less explicit but very convenient alternative
64    pub fn as_nonsecret(&self) -> &Point<E> {
65        secret::inner_ref(&self.0)
66    }
67
68    /// Encodes a point as bytes
69    pub fn to_bytes(&self, compressed: bool) -> EncodedSecretPoint<E> {
70        let bytes = self.as_ref().to_bytes(compressed);
71        EncodedSecretPoint::new(bytes)
72    }
73
74    /// Decodes a point from bytes
75    pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidPoint> {
76        let mut point = Point::from_bytes(bytes)?;
77        Ok(Self::new(&mut point))
78    }
79}
80
81impl<E: Curve> AsRef<Point<E>> for SecretPoint<E> {
82    fn as_ref(&self) -> &Point<E> {
83        self.as_nonsecret()
84    }
85}
86
87impl<E: Curve> Clone for SecretPoint<E> {
88    fn clone(&self) -> Self {
89        Self(self.0.clone())
90    }
91}
92
93impl<E: Curve> ConstantTimeEq for SecretPoint<E> {
94    fn ct_eq(&self, other: &Self) -> Choice {
95        self.as_ref().ct_eq(other.as_ref())
96    }
97}
98
99impl<E: Curve> Sum<SecretPoint<E>> for Point<E> {
100    fn sum<I: Iterator<Item = SecretPoint<E>>>(iter: I) -> Self {
101        iter.fold(Point::<E>::zero(), |acc, i| acc + &i)
102    }
103}
104
105impl<'s, E: Curve> Sum<&'s SecretPoint<E>> for Point<E> {
106    fn sum<I: Iterator<Item = &'s SecretPoint<E>>>(iter: I) -> Self {
107        iter.fold(Point::<E>::zero(), |acc, i| acc + i)
108    }
109}
110
111impl<E: Curve> fmt::Debug for SecretPoint<E> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.write_str("SecretPoint")
114    }
115}