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#[derive(Debug)]
12pub struct PublicKey(pub [u8; 64]);
13
14pub struct SharedSecret(pub [u8; 64]);
20
21impl From<&[u8; 64]> for PublicKey {
22 fn from(value: &[u8; 64]) -> Self {
23 Self(*value)
24 }
25}
26
27impl TryFrom<&[u8]> for PublicKey {
28 type Error = Error;
29
30 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
31 Ok(Self(value.try_into().map_err(|_| Error::InvalidPoint)?))
32 }
33}
34
35impl From<&[u8; 32]> for PrivateKey {
36 fn from(value: &[u8; 32]) -> Self {
37 Self(*value)
38 }
39}
40
41impl TryFrom<&[u8]> for PrivateKey {
42 type Error = Error;
43
44 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
45 Ok(Self(value.try_into().map_err(|_| Error::InvalidScalar)?))
46 }
47}
48
49impl From<&[u8; 64]> for SharedSecret {
50 fn from(value: &[u8; 64]) -> Self {
51 Self(*value)
52 }
53}
54
55impl TryFrom<&[u8]> for SharedSecret {
56 type Error = Error;
57
58 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
59 Ok(Self(value.try_into().map_err(|_| Error::InvalidScalar)?))
60 }
61}
62
63impl AsRef<[u8]> for PrivateKey {
64 fn as_ref(&self) -> &[u8] {
65 &self.0
66 }
67}
68
69impl AsRef<[u8]> for PublicKey {
70 fn as_ref(&self) -> &[u8] {
71 &self.0
72 }
73}
74
75impl AsRef<[u8]> for SharedSecret {
76 fn as_ref(&self) -> &[u8] {
77 &self.0
78 }
79}
80
81impl AsRef<[u8; 32]> for PrivateKey {
82 fn as_ref(&self) -> &[u8; 32] {
83 &self.0
84 }
85}
86
87impl AsRef<[u8; 64]> for PublicKey {
88 fn as_ref(&self) -> &[u8; 64] {
89 &self.0
90 }
91}
92
93impl AsRef<[u8; 64]> for SharedSecret {
94 fn as_ref(&self) -> &[u8; 64] {
95 &self.0
96 }
97}
98
99pub(super) fn derive(p: &PublicKey, s: &PrivateKey) -> Result<SharedSecret, Error> {
100 p256::ecdh(s, p)
102 .map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))
103 .map(SharedSecret)
104}
105
106pub(super) fn secret_to_public(s: &PrivateKey) -> Result<PublicKey, Error> {
107 p256::validate_scalar(s).map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))?;
108 p256::secret_to_public(s)
109 .map_err(|e| Error::Custom(format!("HACL Error {:?}", e)))
110 .map(PublicKey)
111}
112
113pub fn validate_scalar(s: &PrivateKey) -> Result<(), Error> {
114 p256::validate_scalar(s).map_err(|e| e.into())
115}
116
117#[allow(unused)]
118pub fn validate_point(p: &PublicKey) -> Result<(), Error> {
119 p256::validate_point(p).map_err(|e| e.into())
120}
121
122pub(crate) fn prepare_public_key(public_key: &[u8]) -> Result<PublicKey, Error> {
123 if public_key.is_empty() {
124 return Err(Error::InvalidPoint);
125 }
126
127 let pk = if let Ok(pk) = p256::uncompressed_to_coordinates(public_key) {
129 pk
130 } else {
131 if public_key.len() == 33 {
133 p256::compressed_to_coordinates(public_key).map_err(|_| Error::InvalidPoint)?
134 } else {
135 public_key.try_into().map_err(|_| Error::InvalidPoint)?
137 }
138 };
139 let pk = PublicKey(pk);
140
141 p256::validate_point(&pk)
142 .map(|()| pk)
143 .map_err(|_| Error::InvalidPoint)
144}
145
146pub fn generate_secret(rng: &mut (impl CryptoRng + Rng)) -> Result<PrivateKey, Error> {
148 const LIMIT: usize = 100;
149 for _ in 0..LIMIT {
150 let mut out = [0u8; 32];
151 rng.try_fill_bytes(&mut out)
152 .map_err(|_| Error::KeyGenError)?;
153
154 let out = PrivateKey(out);
155 if validate_scalar(&out).is_ok() {
156 return Ok(out);
157 }
158 }
159 Err(Error::KeyGenError)
160}
161
162pub fn key_gen(rng: &mut (impl CryptoRng + Rng)) -> Result<(PrivateKey, PublicKey), Error> {
164 let sk = generate_secret(rng)?;
165 let pk = secret_to_public(&sk)?;
166 Ok((sk, pk))
167}