miden_crypto/ecdh/
k256.rs1use alloc::{string::ToString, vec::Vec};
16
17use hkdf::Hkdf;
18use k256::{
19 AffinePoint,
20 elliptic_curve::{Generate, sec1::ToSec1Point},
21};
22use rand::CryptoRng;
23use sha2::Sha256;
24
25use crate::{
26 dsa::ecdsa_k256_keccak::{KeyExchangeKey, PUBLIC_KEY_BYTES, PublicKey},
27 ecdh::KeyAgreementScheme,
28 utils::{
29 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
30 zeroize::{Zeroize, ZeroizeOnDrop},
31 },
32};
33pub struct SharedSecret {
41 bytes: [u8; 32],
42}
43
44impl SharedSecret {
45 pub(crate) fn new(inner: k256::ecdh::SharedSecret) -> SharedSecret {
46 let mut bytes = [0u8; 32];
47 bytes.copy_from_slice(inner.raw_secret_bytes());
48 Self { bytes }
49 }
50
51 pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf<Sha256> {
57 Hkdf::new(salt, &self.bytes)
58 }
59}
60
61impl AsRef<[u8]> for SharedSecret {
62 fn as_ref(&self) -> &[u8] {
63 &self.bytes
64 }
65}
66
67impl Zeroize for SharedSecret {
68 fn zeroize(&mut self) {
69 self.bytes.zeroize();
70 }
71}
72
73impl Drop for SharedSecret {
74 fn drop(&mut self) {
75 self.zeroize();
76 }
77}
78
79impl ZeroizeOnDrop for SharedSecret {}
80
81pub struct EphemeralSecretKey {
89 inner: k256::ecdh::EphemeralSecret,
90}
91
92impl EphemeralSecretKey {
93 #[cfg(feature = "std")]
95 #[allow(clippy::new_without_default)]
96 pub fn new() -> Self {
97 let mut rng = rand::rng();
98
99 Self::with_rng(&mut rng)
100 }
101
102 pub fn with_rng<R: CryptoRng>(rng: &mut R) -> Self {
104 let sk_e = k256::ecdh::EphemeralSecret::generate_from_rng(rng);
105 Self { inner: sk_e }
106 }
107
108 pub fn public_key(&self) -> EphemeralPublicKey {
110 let pk = self.inner.public_key();
111 EphemeralPublicKey { inner: pk }
112 }
113
114 pub fn diffie_hellman(&self, pk_other: PublicKey) -> SharedSecret {
117 let shared_secret_inner = self.inner.diffie_hellman(&pk_other.inner.into());
118
119 SharedSecret::new(shared_secret_inner)
120 }
121}
122
123impl ZeroizeOnDrop for EphemeralSecretKey {}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct EphemeralPublicKey {
131 pub(crate) inner: k256::PublicKey,
132}
133
134impl EphemeralPublicKey {
135 pub fn as_affine(&self) -> &AffinePoint {
138 self.inner.as_affine()
139 }
140}
141
142#[cfg(any(test, feature = "arbitrary"))]
143mod ephemeral_key_arbitrary {
144 use proptest::prelude::*;
145 use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
146
147 use super::EphemeralPublicKey;
148 use crate::ecdh::k256::EphemeralSecretKey;
149
150 impl Arbitrary for EphemeralPublicKey {
151 type Parameters = ();
152 type Strategy = BoxedStrategy<Self>;
153
154 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
155 any::<[u8; 32]>()
158 .prop_map(|seed| {
159 let mut rng = ChaCha20Rng::from_seed(seed);
160 EphemeralSecretKey::with_rng(&mut rng).public_key()
161 })
162 .boxed()
163 }
164 }
165}
166
167impl Serializable for EphemeralPublicKey {
168 fn write_into<W: ByteWriter>(&self, target: &mut W) {
169 let encoded = self.inner.to_sec1_point(true);
171
172 target.write_bytes(encoded.as_bytes());
173 }
174}
175
176impl Deserializable for EphemeralPublicKey {
177 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
178 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
179
180 let inner = k256::PublicKey::from_sec1_bytes(&bytes)
181 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
182
183 Ok(Self { inner })
184 }
185}
186
187pub struct K256;
191
192impl KeyAgreementScheme for K256 {
193 type EphemeralSecretKey = EphemeralSecretKey;
194 type EphemeralPublicKey = EphemeralPublicKey;
195
196 type SecretKey = KeyExchangeKey;
197 type PublicKey = PublicKey;
198
199 type SharedSecret = SharedSecret;
200
201 fn generate_ephemeral_keypair<R: CryptoRng>(
202 rng: &mut R,
203 ) -> (Self::EphemeralSecretKey, Self::EphemeralPublicKey) {
204 let sk = EphemeralSecretKey::with_rng(rng);
205 let pk = sk.public_key();
206
207 (sk, pk)
208 }
209
210 fn exchange_ephemeral_static(
211 ephemeral_sk: Self::EphemeralSecretKey,
212 static_pk: &Self::PublicKey,
213 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
214 Ok(ephemeral_sk.diffie_hellman(static_pk.clone()))
215 }
216
217 fn exchange_static_ephemeral(
218 static_sk: &Self::SecretKey,
219 ephemeral_pk: &Self::EphemeralPublicKey,
220 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
221 Ok(static_sk.get_shared_secret(ephemeral_pk.clone()))
222 }
223
224 fn extract_key_material(
225 shared_secret: &Self::SharedSecret,
226 length: usize,
227 info: &[u8],
228 ) -> Result<Vec<u8>, super::KeyAgreementError> {
229 super::extract_key_material(shared_secret.as_ref(), None, length, info)
230 }
231}
232
233#[cfg(test)]
237mod test {
238 use super::{EphemeralPublicKey, EphemeralSecretKey};
239 use crate::{
240 dsa::ecdsa_k256_keccak::KeyExchangeKey,
241 rand::test_utils::seeded_rng,
242 utils::{Deserializable, Serializable},
243 };
244
245 #[test]
246 fn key_agreement() {
247 let mut rng = seeded_rng([0u8; 32]);
248
249 let sk = KeyExchangeKey::with_rng(&mut rng);
251 let pk = sk.public_key();
252
253 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
255 let pk_e = sk_e.public_key();
256
257 let shared_secret_key_1 = sk_e.diffie_hellman(pk);
260
261 let shared_secret_key_2 = sk.get_shared_secret(pk_e);
265
266 assert_eq!(shared_secret_key_1.as_ref(), shared_secret_key_2.as_ref());
268 }
269
270 #[test]
271 fn test_serialization_round_trip() {
272 let mut rng = seeded_rng([1u8; 32]);
273
274 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
275 let pk_e = sk_e.public_key();
276
277 let pk_e_bytes = pk_e.to_bytes();
278 let pk_e_serialized = EphemeralPublicKey::read_from_bytes(&pk_e_bytes)
279 .expect("failed to desrialize ephemeral public key");
280 assert_eq!(pk_e_serialized, pk_e);
281 }
282}