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::{PUBLIC_KEY_BYTES, PublicKey, SecretKey},
23 ecdh::KeyAgreementScheme,
24 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
25 zeroize::{Zeroize, ZeroizeOnDrop},
26};
27
28pub struct SharedSecret {
36 pub(crate) inner: k256::ecdh::SharedSecret,
37}
38
39impl SharedSecret {
40 pub(crate) fn new(inner: k256::ecdh::SharedSecret) -> SharedSecret {
41 Self { inner }
42 }
43
44 pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf<Sha256, SimpleHmac<Sha256>> {
50 self.inner.extract(salt)
51 }
52}
53
54impl AsRef<[u8]> for SharedSecret {
55 fn as_ref(&self) -> &[u8] {
56 self.inner.raw_secret_bytes()
57 }
58}
59
60impl Zeroize for SharedSecret {
61 fn zeroize(&mut self) {
74 let bytes = self.inner.raw_secret_bytes();
75 for byte in
76 unsafe { core::slice::from_raw_parts_mut(bytes.as_ptr() as *mut u8, bytes.len()) }
77 {
78 unsafe {
79 core::ptr::write_volatile(byte, 0u8);
80 }
81 }
82 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
83 }
84}
85
86impl ZeroizeOnDrop for SharedSecret {}
88
89pub struct EphemeralSecretKey {
97 inner: k256::ecdh::EphemeralSecret,
98}
99
100impl EphemeralSecretKey {
101 #[cfg(feature = "std")]
103 #[allow(clippy::new_without_default)]
104 pub fn new() -> Self {
105 let mut rng = rand::rng();
106
107 Self::with_rng(&mut rng)
108 }
109
110 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
112 use k256::elliptic_curve::rand_core::SeedableRng;
117 let mut seed = [0_u8; 32];
118 rand::RngCore::fill_bytes(rng, &mut seed);
119 let mut rng = rand_hc::Hc128Rng::from_seed(seed);
120
121 let sk_e = k256::ecdh::EphemeralSecret::random(&mut rng);
122 Self { inner: sk_e }
123 }
124
125 pub fn public_key(&self) -> EphemeralPublicKey {
127 let pk = self.inner.public_key();
128 EphemeralPublicKey { inner: pk }
129 }
130
131 pub fn diffie_hellman(&self, pk_other: PublicKey) -> SharedSecret {
134 let shared_secret_inner = self.inner.diffie_hellman(&pk_other.inner.into());
135
136 SharedSecret { inner: shared_secret_inner }
137 }
138}
139
140impl ZeroizeOnDrop for EphemeralSecretKey {}
141
142#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct EphemeralPublicKey {
148 pub(crate) inner: k256::PublicKey,
149}
150
151impl EphemeralPublicKey {
152 pub fn as_affine(&self) -> &AffinePoint {
155 self.inner.as_affine()
156 }
157}
158
159impl Serializable for EphemeralPublicKey {
160 fn write_into<W: ByteWriter>(&self, target: &mut W) {
161 let encoded = self.inner.to_encoded_point(true);
163
164 target.write_bytes(encoded.as_bytes());
165 }
166}
167
168impl Deserializable for EphemeralPublicKey {
169 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
170 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
171
172 let inner = k256::PublicKey::from_sec1_bytes(&bytes)
173 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
174
175 Ok(Self { inner })
176 }
177}
178
179pub struct K256;
183
184impl KeyAgreementScheme for K256 {
185 type EphemeralSecretKey = EphemeralSecretKey;
186 type EphemeralPublicKey = EphemeralPublicKey;
187
188 type SecretKey = SecretKey;
189 type PublicKey = PublicKey;
190
191 type SharedSecret = SharedSecret;
192
193 fn generate_ephemeral_keypair<R: CryptoRng + RngCore>(
194 rng: &mut R,
195 ) -> (Self::EphemeralSecretKey, Self::EphemeralPublicKey) {
196 let sk = EphemeralSecretKey::with_rng(rng);
197 let pk = sk.public_key();
198
199 (sk, pk)
200 }
201
202 fn exchange_ephemeral_static(
203 ephemeral_sk: Self::EphemeralSecretKey,
204 static_pk: &Self::PublicKey,
205 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
206 Ok(ephemeral_sk.diffie_hellman(static_pk.clone()))
207 }
208
209 fn exchange_static_ephemeral(
210 static_sk: &Self::SecretKey,
211 ephemeral_pk: &Self::EphemeralPublicKey,
212 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
213 Ok(static_sk.get_shared_secret(ephemeral_pk.clone()))
214 }
215
216 fn extract_key_material(
217 shared_secret: &Self::SharedSecret,
218 length: usize,
219 ) -> Result<Vec<u8>, super::KeyAgreementError> {
220 let hkdf = shared_secret.extract(None);
221 let mut buf = vec![0_u8; length];
222 hkdf.expand(&[], &mut buf)
223 .map_err(|_| super::KeyAgreementError::HkdfExpansionFailed)?;
224 Ok(buf)
225 }
226}
227
228#[cfg(test)]
232mod test {
233
234 use rand::rng;
235 use winter_utils::{Deserializable, Serializable};
236
237 use super::{EphemeralPublicKey, EphemeralSecretKey};
238 use crate::dsa::ecdsa_k256_keccak::SecretKey;
239
240 #[test]
241 fn key_agreement() {
242 let mut rng = rng();
243
244 let sk = SecretKey::with_rng(&mut rng);
246 let pk = sk.public_key();
247
248 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
250 let pk_e = sk_e.public_key();
251
252 let shared_secret_key_1 = sk_e.diffie_hellman(pk);
255
256 let shared_secret_key_2 = sk.get_shared_secret(pk_e);
260
261 assert_eq!(
263 shared_secret_key_1.inner.raw_secret_bytes(),
264 shared_secret_key_2.inner.raw_secret_bytes()
265 );
266 }
267
268 #[test]
269 fn test_serialization_round_trip() {
270 let mut rng = rng();
271
272 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
273 let pk_e = sk_e.public_key();
274
275 let pk_e_bytes = pk_e.to_bytes();
276 let pk_e_serialized = EphemeralPublicKey::read_from_bytes(&pk_e_bytes)
277 .expect("failed to desrialize ephemeral public key");
278 assert_eq!(pk_e_serialized, pk_e);
279 }
280}