libcrux_ecdh/
x25519.rs

1// XXX: This could be simplified with the pure Rust version now.
2
3use alloc::format;
4use rand::{CryptoRng, TryRngCore};
5
6use super::Error;
7
8pub struct PrivateKey(pub [u8; 32]);
9
10#[cfg(feature = "codec")]
11use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize};
12
13#[cfg(feature = "codec")]
14extern crate std;
15
16#[derive(Debug)]
17#[cfg_attr(feature = "codec", derive(TlsSize, TlsSerialize, TlsDeserialize))]
18pub struct PublicKey(pub [u8; 32]);
19
20/// Output of a scalar multiplication between a public key and a secret key.
21///
22/// This value is NOT (!) safe for use as a key and needs to be processed in a round of key
23/// derivation, to ensure both that the output is uniformly random and that unkown key share
24/// attacks can not happen.
25#[cfg_attr(feature = "codec", derive(TlsSize, TlsSerialize, TlsDeserialize))]
26pub struct SharedSecret(pub [u8; 32]);
27
28impl From<&[u8; 32]> for PublicKey {
29    fn from(value: &[u8; 32]) -> Self {
30        Self(*value)
31    }
32}
33
34impl TryFrom<&[u8]> for PublicKey {
35    type Error = Error;
36
37    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
38        Ok(Self(value.try_into().map_err(|_| Error::InvalidPoint)?))
39    }
40}
41
42impl From<&[u8; 32]> for PrivateKey {
43    fn from(value: &[u8; 32]) -> Self {
44        let mut out = Self(*value);
45        clamp(&mut out.0);
46        out
47    }
48}
49
50impl TryFrom<&[u8]> for PrivateKey {
51    type Error = Error;
52
53    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
54        let mut out = Self(value.try_into().map_err(|_| Error::InvalidScalar)?);
55        clamp(&mut out.0);
56        Ok(out)
57    }
58}
59
60impl From<&[u8; 32]> for SharedSecret {
61    fn from(value: &[u8; 32]) -> Self {
62        Self(*value)
63    }
64}
65
66impl TryFrom<&[u8]> for SharedSecret {
67    type Error = Error;
68
69    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
70        Ok(Self(value.try_into().map_err(|_| Error::InvalidScalar)?))
71    }
72}
73
74impl AsRef<[u8]> for PrivateKey {
75    fn as_ref(&self) -> &[u8] {
76        &self.0
77    }
78}
79
80impl AsRef<[u8]> for PublicKey {
81    fn as_ref(&self) -> &[u8] {
82        &self.0
83    }
84}
85
86impl AsRef<[u8]> for SharedSecret {
87    fn as_ref(&self) -> &[u8] {
88        &self.0
89    }
90}
91
92impl AsRef<[u8; 32]> for PrivateKey {
93    fn as_ref(&self) -> &[u8; 32] {
94        &self.0
95    }
96}
97
98impl AsRef<[u8; 32]> for PublicKey {
99    fn as_ref(&self) -> &[u8; 32] {
100        &self.0
101    }
102}
103
104impl AsRef<[u8; 32]> for SharedSecret {
105    fn as_ref(&self) -> &[u8; 32] {
106        &self.0
107    }
108}
109
110pub fn derive(p: &PublicKey, s: &PrivateKey) -> Result<SharedSecret, Error> {
111    // Use the portable HACL implementation.
112    use crate::hacl::curve25519;
113
114    curve25519::ecdh(s, p)
115        .map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))
116        .map(SharedSecret)
117}
118
119/// Compute the public key, corresponding to the private key `s`.
120pub fn secret_to_public(s: &PrivateKey) -> Result<PublicKey, Error> {
121    // Use the portable HACL implementation.
122    use crate::hacl::curve25519;
123
124    Ok(PublicKey(curve25519::secret_to_public(s)))
125}
126
127/// Generate a new x25519 secret.
128pub fn generate_secret(rng: &mut impl CryptoRng) -> Result<PrivateKey, Error> {
129    const LIMIT: usize = 100;
130    for _ in 0..LIMIT {
131        let mut out = [0u8; 32];
132        rng.try_fill_bytes(&mut out)
133            .map_err(|_| Error::KeyGenError)?;
134
135        // We don't want a 0 key.
136        if out.iter().all(|&b| b == 0) {
137            continue;
138        }
139
140        clamp(&mut out);
141        return Ok(PrivateKey(out));
142    }
143
144    Err(Error::KeyGenError)
145}
146
147/// Clamp a scalar.
148fn clamp(scalar: &mut [u8; 32]) {
149    // We clamp the key already to make sure it can't be misused.
150    scalar[0] &= 248u8;
151    scalar[31] &= 127u8;
152    scalar[31] |= 64u8;
153}
154
155/// Generate a new P256 key pair
156pub fn key_gen(rng: &mut impl CryptoRng) -> Result<(PrivateKey, PublicKey), Error> {
157    let sk = generate_secret(rng)?;
158    let pk = secret_to_public(&sk)?;
159    Ok((sk, pk))
160}