miden_crypto/ecdh/
k256.rs1use alloc::{string::ToString, vec::Vec};
16
17use hkdf::{Hkdf, hmac::SimpleHmac};
18use k256::{AffinePoint, elliptic_curve::sec1::ToEncodedPoint, sha2::Sha256};
19use rand::{CryptoRng, RngCore};
20
21use crate::{
22 dsa::ecdsa_k256_keccak::{KeyExchangeKey, PUBLIC_KEY_BYTES, PublicKey},
23 ecdh::KeyAgreementScheme,
24 utils::{
25 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
26 zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing},
27 },
28};
29pub struct SharedSecret {
37 pub(crate) inner: k256::ecdh::SharedSecret,
38}
39
40impl SharedSecret {
41 pub(crate) fn new(inner: k256::ecdh::SharedSecret) -> SharedSecret {
42 Self { inner }
43 }
44
45 pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf<Sha256, SimpleHmac<Sha256>> {
51 self.inner.extract(salt)
52 }
53}
54
55impl AsRef<[u8]> for SharedSecret {
56 fn as_ref(&self) -> &[u8] {
57 self.inner.raw_secret_bytes()
58 }
59}
60
61impl Zeroize for SharedSecret {
62 fn zeroize(&mut self) {
75 let bytes = self.inner.raw_secret_bytes();
76 for byte in
77 unsafe { core::slice::from_raw_parts_mut(bytes.as_ptr() as *mut u8, bytes.len()) }
78 {
79 unsafe {
80 core::ptr::write_volatile(byte, 0u8);
81 }
82 }
83 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
84 }
85}
86
87impl ZeroizeOnDrop for SharedSecret {}
89
90pub struct EphemeralSecretKey {
98 inner: k256::ecdh::EphemeralSecret,
99}
100
101impl EphemeralSecretKey {
102 #[cfg(feature = "std")]
104 #[allow(clippy::new_without_default)]
105 pub fn new() -> Self {
106 let mut rng = rand::rng();
107
108 Self::with_rng(&mut rng)
109 }
110
111 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
113 use k256::elliptic_curve::rand_core::SeedableRng;
118 let mut seed = Zeroizing::new([0_u8; 32]);
119 RngCore::fill_bytes(rng, &mut *seed);
120 let mut rng = rand_hc::Hc128Rng::from_seed(*seed);
121
122 let sk_e = k256::ecdh::EphemeralSecret::random(&mut rng);
123 Self { inner: sk_e }
124 }
125
126 pub fn public_key(&self) -> EphemeralPublicKey {
128 let pk = self.inner.public_key();
129 EphemeralPublicKey { inner: pk }
130 }
131
132 pub fn diffie_hellman(&self, pk_other: PublicKey) -> SharedSecret {
135 let shared_secret_inner = self.inner.diffie_hellman(&pk_other.inner.into());
136
137 SharedSecret { inner: shared_secret_inner }
138 }
139}
140
141impl ZeroizeOnDrop for EphemeralSecretKey {}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct EphemeralPublicKey {
149 pub(crate) inner: k256::PublicKey,
150}
151
152impl EphemeralPublicKey {
153 pub fn as_affine(&self) -> &AffinePoint {
156 self.inner.as_affine()
157 }
158}
159
160impl Serializable for EphemeralPublicKey {
161 fn write_into<W: ByteWriter>(&self, target: &mut W) {
162 let encoded = self.inner.to_encoded_point(true);
164
165 target.write_bytes(encoded.as_bytes());
166 }
167}
168
169impl Deserializable for EphemeralPublicKey {
170 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
171 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
172
173 let inner = k256::PublicKey::from_sec1_bytes(&bytes)
174 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
175
176 Ok(Self { inner })
177 }
178}
179
180pub struct K256;
184
185impl KeyAgreementScheme for K256 {
186 type EphemeralSecretKey = EphemeralSecretKey;
187 type EphemeralPublicKey = EphemeralPublicKey;
188
189 type SecretKey = KeyExchangeKey;
190 type PublicKey = PublicKey;
191
192 type SharedSecret = SharedSecret;
193
194 fn generate_ephemeral_keypair<R: CryptoRng + RngCore>(
195 rng: &mut R,
196 ) -> (Self::EphemeralSecretKey, Self::EphemeralPublicKey) {
197 let sk = EphemeralSecretKey::with_rng(rng);
198 let pk = sk.public_key();
199
200 (sk, pk)
201 }
202
203 fn exchange_ephemeral_static(
204 ephemeral_sk: Self::EphemeralSecretKey,
205 static_pk: &Self::PublicKey,
206 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
207 Ok(ephemeral_sk.diffie_hellman(static_pk.clone()))
208 }
209
210 fn exchange_static_ephemeral(
211 static_sk: &Self::SecretKey,
212 ephemeral_pk: &Self::EphemeralPublicKey,
213 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
214 Ok(static_sk.get_shared_secret(ephemeral_pk.clone()))
215 }
216
217 fn extract_key_material(
218 shared_secret: &Self::SharedSecret,
219 length: usize,
220 info: &[u8],
221 ) -> Result<Vec<u8>, super::KeyAgreementError> {
222 let hkdf = shared_secret.extract(None);
223 let mut buf = vec![0_u8; length];
224 hkdf.expand(info, &mut buf)
225 .map_err(|_| super::KeyAgreementError::HkdfExpansionFailed)?;
226 Ok(buf)
227 }
228}
229
230#[cfg(test)]
234mod test {
235 use super::{EphemeralPublicKey, EphemeralSecretKey};
236 use crate::{
237 dsa::ecdsa_k256_keccak::KeyExchangeKey,
238 rand::test_utils::seeded_rng,
239 utils::{Deserializable, Serializable},
240 };
241
242 #[test]
243 fn key_agreement() {
244 let mut rng = seeded_rng([0u8; 32]);
245
246 let sk = KeyExchangeKey::with_rng(&mut rng);
248 let pk = sk.public_key();
249
250 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
252 let pk_e = sk_e.public_key();
253
254 let shared_secret_key_1 = sk_e.diffie_hellman(pk);
257
258 let shared_secret_key_2 = sk.get_shared_secret(pk_e);
262
263 assert_eq!(
265 shared_secret_key_1.inner.raw_secret_bytes(),
266 shared_secret_key_2.inner.raw_secret_bytes()
267 );
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}