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
142impl Serializable for EphemeralPublicKey {
143 fn write_into<W: ByteWriter>(&self, target: &mut W) {
144 let encoded = self.inner.to_sec1_point(true);
146
147 target.write_bytes(encoded.as_bytes());
148 }
149}
150
151impl Deserializable for EphemeralPublicKey {
152 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
153 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
154
155 let inner = k256::PublicKey::from_sec1_bytes(&bytes)
156 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
157
158 Ok(Self { inner })
159 }
160}
161
162pub struct K256;
166
167impl KeyAgreementScheme for K256 {
168 type EphemeralSecretKey = EphemeralSecretKey;
169 type EphemeralPublicKey = EphemeralPublicKey;
170
171 type SecretKey = KeyExchangeKey;
172 type PublicKey = PublicKey;
173
174 type SharedSecret = SharedSecret;
175
176 fn generate_ephemeral_keypair<R: CryptoRng>(
177 rng: &mut R,
178 ) -> (Self::EphemeralSecretKey, Self::EphemeralPublicKey) {
179 let sk = EphemeralSecretKey::with_rng(rng);
180 let pk = sk.public_key();
181
182 (sk, pk)
183 }
184
185 fn exchange_ephemeral_static(
186 ephemeral_sk: Self::EphemeralSecretKey,
187 static_pk: &Self::PublicKey,
188 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
189 Ok(ephemeral_sk.diffie_hellman(static_pk.clone()))
190 }
191
192 fn exchange_static_ephemeral(
193 static_sk: &Self::SecretKey,
194 ephemeral_pk: &Self::EphemeralPublicKey,
195 ) -> Result<Self::SharedSecret, super::KeyAgreementError> {
196 Ok(static_sk.get_shared_secret(ephemeral_pk.clone()))
197 }
198
199 fn extract_key_material(
200 shared_secret: &Self::SharedSecret,
201 length: usize,
202 info: &[u8],
203 ) -> Result<Vec<u8>, super::KeyAgreementError> {
204 super::extract_key_material(shared_secret.as_ref(), None, length, info)
205 }
206}
207
208#[cfg(test)]
212mod test {
213 use super::{EphemeralPublicKey, EphemeralSecretKey};
214 use crate::{
215 dsa::ecdsa_k256_keccak::KeyExchangeKey,
216 rand::test_utils::seeded_rng,
217 utils::{Deserializable, Serializable},
218 };
219
220 #[test]
221 fn key_agreement() {
222 let mut rng = seeded_rng([0u8; 32]);
223
224 let sk = KeyExchangeKey::with_rng(&mut rng);
226 let pk = sk.public_key();
227
228 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
230 let pk_e = sk_e.public_key();
231
232 let shared_secret_key_1 = sk_e.diffie_hellman(pk);
235
236 let shared_secret_key_2 = sk.get_shared_secret(pk_e);
240
241 assert_eq!(shared_secret_key_1.as_ref(), shared_secret_key_2.as_ref());
243 }
244
245 #[test]
246 fn test_serialization_round_trip() {
247 let mut rng = seeded_rng([1u8; 32]);
248
249 let sk_e = EphemeralSecretKey::with_rng(&mut rng);
250 let pk_e = sk_e.public_key();
251
252 let pk_e_bytes = pk_e.to_bytes();
253 let pk_e_serialized = EphemeralPublicKey::read_from_bytes(&pk_e_bytes)
254 .expect("failed to desrialize ephemeral public key");
255 assert_eq!(pk_e_serialized, pk_e);
256 }
257}