libcrux_ecdh/
p256_internal.rs1use alloc::format;
2use rand::{CryptoRng, Rng, TryRngCore};
3
4use crate::hacl::p256;
6
7use super::Error;
8
9pub struct PrivateKey(pub [u8; 32]);
10
11#[cfg(feature = "codec")]
12use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize};
13
14#[cfg(feature = "codec")]
15extern crate std;
16
17#[derive(Debug)]
18#[cfg_attr(feature = "codec", derive(TlsSize, TlsSerialize, TlsDeserialize))]
19pub struct PublicKey(pub [u8; 64]);
20
21#[cfg_attr(feature = "codec", derive(TlsSize, TlsSerialize, TlsDeserialize))]
27pub struct SharedSecret(pub [u8; 64]);
28
29impl From<&[u8; 64]> for PublicKey {
30 fn from(value: &[u8; 64]) -> Self {
31 Self(*value)
32 }
33}
34
35impl TryFrom<&[u8]> for PublicKey {
36 type Error = Error;
37
38 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
39 Ok(Self(value.try_into().map_err(|_| Error::InvalidPoint)?))
40 }
41}
42
43impl From<&[u8; 32]> for PrivateKey {
44 fn from(value: &[u8; 32]) -> Self {
45 Self(*value)
46 }
47}
48
49impl TryFrom<&[u8]> for PrivateKey {
50 type Error = Error;
51
52 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
53 Ok(Self(value.try_into().map_err(|_| Error::InvalidScalar)?))
54 }
55}
56
57impl From<&[u8; 64]> for SharedSecret {
58 fn from(value: &[u8; 64]) -> Self {
59 Self(*value)
60 }
61}
62
63impl TryFrom<&[u8]> for SharedSecret {
64 type Error = Error;
65
66 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
67 Ok(Self(value.try_into().map_err(|_| Error::InvalidScalar)?))
68 }
69}
70
71impl AsRef<[u8]> for PrivateKey {
72 fn as_ref(&self) -> &[u8] {
73 &self.0
74 }
75}
76
77impl AsRef<[u8]> for PublicKey {
78 fn as_ref(&self) -> &[u8] {
79 &self.0
80 }
81}
82
83impl AsRef<[u8]> for SharedSecret {
84 fn as_ref(&self) -> &[u8] {
85 &self.0
86 }
87}
88
89impl AsRef<[u8; 32]> for PrivateKey {
90 fn as_ref(&self) -> &[u8; 32] {
91 &self.0
92 }
93}
94
95impl AsRef<[u8; 64]> for PublicKey {
96 fn as_ref(&self) -> &[u8; 64] {
97 &self.0
98 }
99}
100
101impl AsRef<[u8; 64]> for SharedSecret {
102 fn as_ref(&self) -> &[u8; 64] {
103 &self.0
104 }
105}
106
107pub(super) fn derive(p: &PublicKey, s: &PrivateKey) -> Result<SharedSecret, Error> {
108 p256::ecdh(s, p)
110 .map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))
111 .map(SharedSecret)
112}
113
114pub fn secret_to_public(s: &PrivateKey) -> Result<PublicKey, Error> {
116 p256::validate_scalar(s).map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))?;
117 p256::secret_to_public(s)
118 .map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))
119 .map(PublicKey)
120}
121
122pub fn validate_scalar(s: &PrivateKey) -> Result<(), Error> {
123 p256::validate_scalar(s).map_err(|e| e.into())
124}
125
126#[allow(unused)]
127pub fn validate_point(p: &PublicKey) -> Result<(), Error> {
128 p256::validate_point(p).map_err(|e| e.into())
129}
130
131pub(crate) fn prepare_public_key(public_key: &[u8]) -> Result<PublicKey, Error> {
132 if public_key.is_empty() {
133 return Err(Error::InvalidPoint);
134 }
135
136 let pk = if let Ok(pk) = p256::uncompressed_to_coordinates(public_key) {
138 pk
139 } else {
140 if public_key.len() == 33 {
142 p256::compressed_to_coordinates(public_key).map_err(|_| Error::InvalidPoint)?
143 } else {
144 public_key.try_into().map_err(|_| Error::InvalidPoint)?
146 }
147 };
148 let pk = PublicKey(pk);
149
150 p256::validate_point(&pk)
151 .map(|()| pk)
152 .map_err(|_| Error::InvalidPoint)
153}
154
155pub fn generate_secret(rng: &mut (impl CryptoRng + Rng)) -> Result<PrivateKey, Error> {
157 const LIMIT: usize = 100;
158 for _ in 0..LIMIT {
159 let mut out = [0u8; 32];
160 rng.try_fill_bytes(&mut out)
161 .map_err(|_| Error::KeyGenError)?;
162
163 let out = PrivateKey(out);
164 if validate_scalar(&out).is_ok() {
165 return Ok(out);
166 }
167 }
168 Err(Error::KeyGenError)
169}
170
171pub fn key_gen(rng: &mut (impl CryptoRng + Rng)) -> Result<(PrivateKey, PublicKey), Error> {
173 let sk = generate_secret(rng)?;
174 let pk = secret_to_public(&sk)?;
175 Ok((sk, pk))
176}