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 pub(crate) inner: k256::ecdh::SharedSecret,
42}
43
44impl SharedSecret {
45 pub(crate) fn new(inner: k256::ecdh::SharedSecret) -> SharedSecret {
46 Self { inner }
47 }
48
49 pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf<Sha256> {
55 self.inner.extract(salt)
56 }
57}
58
59impl AsRef<[u8]> for SharedSecret {
60 fn as_ref(&self) -> &[u8] {
61 self.inner.raw_secret_bytes()
62 }
63}
64
65impl Zeroize for SharedSecret {
66 fn zeroize(&mut self) {
79 let bytes = self.inner.raw_secret_bytes();
80 for byte in
81 unsafe { core::slice::from_raw_parts_mut(bytes.as_ptr() as *mut u8, bytes.len()) }
82 {
83 unsafe {
84 core::ptr::write_volatile(byte, 0u8);
85 }
86 }
87 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
88 }
89}
90
91impl ZeroizeOnDrop for SharedSecret {}
93
94pub struct EphemeralSecretKey {
102 inner: k256::ecdh::EphemeralSecret,
103}
104
105impl EphemeralSecretKey {
106 #[cfg(feature = "std")]
108 #[allow(clippy::new_without_default)]
109 pub fn new() -> Self {
110 let mut rng = rand::rng();
111
112 Self::with_rng(&mut rng)
113 }
114
115 pub fn with_rng<R: CryptoRng>(rng: &mut R) -> Self {
117 let sk_e = k256::ecdh::EphemeralSecret::generate_from_rng(rng);
118 Self { inner: sk_e }
119 }
120
121 pub fn public_key(&self) -> EphemeralPublicKey {
123 let pk = self.inner.public_key();
124 EphemeralPublicKey { inner: pk }
125 }
126
127 pub fn diffie_hellman(&self, pk_other: PublicKey) -> SharedSecret {
130 let shared_secret_inner = self.inner.diffie_hellman(&pk_other.inner.into());
131
132 SharedSecret { inner: shared_secret_inner }
133 }
134}
135
136impl ZeroizeOnDrop for EphemeralSecretKey {}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
143pub struct EphemeralPublicKey {
144 pub(crate) inner: k256::PublicKey,
145}
146
147impl EphemeralPublicKey {
148 pub fn as_affine(&self) -> &AffinePoint {
151 self.inner.as_affine()
152 }
153}
154
155impl Serializable for EphemeralPublicKey {
156 fn write_into<W: ByteWriter>(&self, target: &mut W) {
157 let encoded = self.inner.to_sec1_point(true);
159
160 target.write_bytes(encoded.as_bytes());
161 }
162}
163
164impl Deserializable for EphemeralPublicKey {
165 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
166 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
167
168 let inner = k256::PublicKey::from_sec1_bytes(&bytes)
169 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
170
171 Ok(Self { inner })
172 }
173}
174
175pub struct K256;
179
180impl KeyAgreementScheme for K256 {
181 type EphemeralSecretKey = EphemeralSecretKey;
182 type EphemeralPublicKey = EphemeralPublicKey;
183
184 type SecretKey = KeyExchangeKey;
185 type PublicKey = PublicKey;
186
187 type SharedSecret = SharedSecret;
188
189 fn generate_ephemeral_keypair<R: CryptoRng>(
190 rng: &mut R,
191 ) -> (Self::EphemeralSecretKey, Self::EphemeralPublicKey) {
192 let sk = EphemeralSecretKey::with_rng(rng);
193 let pk = sk.public_key();
194
195 (sk, pk)
196 }
197
198 fn exchange_ephemeral_static(
199 ephemeral_sk: Self::EphemeralSecretKey,
200 static_pk: &Self::PublicKey,
201 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
202 Ok(ephemeral_sk.diffie_hellman(static_pk.clone()))
203 }
204
205 fn exchange_static_ephemeral(
206 static_sk: &Self::SecretKey,
207 ephemeral_pk: &Self::EphemeralPublicKey,
208 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
209 Ok(static_sk.get_shared_secret(ephemeral_pk.clone()))
210 }
211
212 fn extract_key_material(
213 shared_secret: &Self::SharedSecret,
214 length: usize,
215 info: &[u8],
216 ) -> Result<Vec<u8>, super::KeyAgreementError> {
217 super::extract_key_material(shared_secret.as_ref(), None, length, info)
218 }
219}
220
221#[cfg(test)]
225mod test {
226 use super::{EphemeralPublicKey, EphemeralSecretKey};
227 use crate::{
228 dsa::ecdsa_k256_keccak::KeyExchangeKey,
229 rand::test_utils::seeded_rng,
230 utils::{Deserializable, Serializable},
231 };
232
233 #[test]
234 fn key_agreement() {
235 let mut rng = seeded_rng([0u8; 32]);
236
237 let sk = KeyExchangeKey::with_rng(&mut rng);
239 let pk = sk.public_key();
240
241 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
243 let pk_e = sk_e.public_key();
244
245 let shared_secret_key_1 = sk_e.diffie_hellman(pk);
248
249 let shared_secret_key_2 = sk.get_shared_secret(pk_e);
253
254 assert_eq!(
256 shared_secret_key_1.inner.raw_secret_bytes(),
257 shared_secret_key_2.inner.raw_secret_bytes()
258 );
259 }
260
261 #[test]
262 fn test_serialization_round_trip() {
263 let mut rng = seeded_rng([1u8; 32]);
264
265 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
266 let pk_e = sk_e.public_key();
267
268 let pk_e_bytes = pk_e.to_bytes();
269 let pk_e_serialized = EphemeralPublicKey::read_from_bytes(&pk_e_bytes)
270 .expect("failed to desrialize ephemeral public key");
271 assert_eq!(pk_e_serialized, pk_e);
272 }
273}