1use curve25519_dalek::scalar::Scalar;
36use rand::{CryptoRng, RngCore};
37
38mod keys;
39pub use keys::*;
40
41#[cfg(feature = "ring")]
42mod ring_backend;
43
44#[cfg(feature = "ring")]
45use ring_backend::*;
46
47#[cfg(feature = "pure_rust")]
48mod pure_rust_backend;
49
50#[cfg(feature = "pure_rust")]
51use pure_rust_backend::*;
52
53#[cfg(not(any(feature = "ring", feature = "pure_rust")))]
54compile_error!(
55 "ecies-rd25519: Either feature 'ring' or 'pure_rust' must be enabled for this crate."
56);
57
58#[cfg(all(feature = "ring", feature = "pure_rust"))]
59compile_error!(
60 "ecies-rd25519: Feature 'ring' and 'pure_rust' cannot both be enabled. Please choose one."
61);
62
63const HKDF_INFO: &[u8; 13] = b"ecies-ed25519";
64
65const AES_IV_LENGTH: usize = 12;
66
67type AesKey = [u8; 32];
68type SharedSecret = [u8; 32];
69
70pub fn generate_keypair<R: CryptoRng + RngCore>(rng: &mut R) -> (SecretKey, PublicKey) {
72 let secret = SecretKey::generate(rng);
73 let public = PublicKey::from_secret(&secret);
74 (secret, public)
75}
76
77pub fn encrypt<R: CryptoRng + RngCore>(
79 receiver_pub: &PublicKey,
80 msg: &[u8],
81 rng: &mut R,
82) -> Result<Vec<u8>, Error> {
83 let (ephemeral_sk, ephemeral_pk) = generate_keypair(rng);
84
85 let aes_key = encapsulate(&ephemeral_sk, &receiver_pub);
86 let encrypted = aes_encrypt(&aes_key, msg, rng)?;
87
88 let mut cipher_text = Vec::with_capacity(PUBLIC_KEY_LENGTH + encrypted.len());
89 cipher_text.extend(ephemeral_pk.to_bytes().iter());
90 cipher_text.extend(encrypted);
91
92 Ok(cipher_text)
93}
94
95pub fn decrypt(receiver_sec: &SecretKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
97 if ciphertext.len() <= PUBLIC_KEY_LENGTH {
98 return Err(Error::DecryptionFailedCiphertextShort);
99 }
100
101 let ephemeral_pk = PublicKey::from_bytes(&ciphertext[..PUBLIC_KEY_LENGTH])?;
102 let encrypted = &ciphertext[PUBLIC_KEY_LENGTH..];
103 let aes_key = decapsulate(&receiver_sec, &ephemeral_pk);
104
105 let decrypted = aes_decrypt(&aes_key, encrypted).map_err(|_| Error::DecryptionFailed)?;
106
107 Ok(decrypted)
108}
109
110fn generate_shared(secret: &SecretKey, public: &PublicKey) -> SharedSecret {
111 let public = public.to_point();
112 let secret = Scalar::from_bits(secret.to_bytes());
113 let shared_point = public * secret;
114 let shared_point_compressed = shared_point.compress();
115
116 let output = shared_point_compressed.as_bytes().to_owned();
117
118 output
119}
120
121fn encapsulate(emphemeral_sk: &SecretKey, peer_pk: &PublicKey) -> AesKey {
122 let shared_point = generate_shared(emphemeral_sk, peer_pk);
123
124 let emphemeral_pk = PublicKey::from_secret(emphemeral_sk);
125
126 let mut master = [0u8; 32 * 2];
127 master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
128 master[32..].clone_from_slice(&shared_point);
129
130 hkdf_sha256(&master)
131}
132
133fn decapsulate(sk: &SecretKey, emphemeral_pk: &PublicKey) -> AesKey {
134 let shared_point = generate_shared(sk, emphemeral_pk);
135
136 let mut master = [0u8; 32 * 2];
137 master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
138 master[32..].clone_from_slice(&shared_point);
139
140 hkdf_sha256(&master)
141}
142
143use thiserror::Error;
145
146#[derive(Debug, Error)]
147pub enum Error {
148 #[error("ecies-rd25519: encryption failed")]
150 EncryptionFailed,
151
152 #[error("ecies-rd25519: encryption failed - RNG error")]
154 EncryptionFailedRng,
155
156 #[error("ecies-rd25519: decryption failed")]
158 DecryptionFailed,
159
160 #[error("ecies-rd25519: decryption failed - ciphertext too short")]
162 DecryptionFailedCiphertextShort,
163
164 #[error("ecies-rd25519: invalid public key bytes")]
166 InvalidPublicKeyBytes,
167
168 #[error("ecies-rd25519: invalid secret key bytes")]
170 InvalidSecretKeyBytes,
171}
172
173#[cfg(test)]
174pub mod tests {
175 use super::*;
176
177 use rand::thread_rng;
178 use rand::SeedableRng;
179
180 #[test]
181 fn test_shared() {
182 let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
183 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
184
185 assert_eq!(
186 generate_shared(&emphemeral_sk, &peer_pk),
187 generate_shared(&peer_sk, &emphemeral_pk)
188 );
189
190 assert_ne!(
192 generate_shared(&emphemeral_sk, &emphemeral_pk),
193 generate_shared(&peer_sk, &peer_pk)
194 )
195 }
196
197 #[test]
198 fn test_encapsulation() {
199 let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
200 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
201
202 assert_eq!(
203 encapsulate(&emphemeral_sk, &peer_pk),
204 decapsulate(&peer_sk, &emphemeral_pk)
205 )
206 }
207
208 #[test]
209 fn test_aes() {
210 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
211 let mut key = [0u8; 32];
212 test_rng.fill_bytes(&mut key);
213
214 let plaintext = b"ABC";
215 let encrypted = aes_encrypt(&key, plaintext, &mut test_rng).unwrap();
216 let decrypted = aes_decrypt(&key, &encrypted).unwrap();
217
218 assert_eq!(plaintext, decrypted.as_slice());
219
220 assert!(aes_decrypt(&key, &[0u8; 16]).is_err());
222
223 let bad_secret = SecretKey::generate(&mut thread_rng());
225 assert!(aes_decrypt(&bad_secret.as_bytes(), &encrypted).is_err());
226 }
227
228 #[test]
229 fn test_ecies_ed25519() {
230 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
231
232 let plaintext = b"ABOLISH ICE";
233
234 let encrypted = encrypt(&peer_pk, plaintext, &mut thread_rng()).unwrap();
235 let decrypted = decrypt(&peer_sk, &encrypted).unwrap();
236
237 assert_eq!(plaintext, decrypted.as_slice());
238
239 assert!(decrypt(&peer_sk, &[0u8; 16]).is_err());
241
242 let bad_secret = SecretKey::generate(&mut thread_rng());
244 assert!(decrypt(&bad_secret, &encrypted).is_err());
245 }
246
247 #[test]
248 fn test_hkdf_sha256_interop() {
249 let known_key: Vec<u8> = vec![
250 204, 68, 78, 7, 8, 70, 53, 136, 56, 115, 129, 183, 226, 82, 147, 253, 62, 59, 170, 188,
251 131, 119, 31, 21, 249, 255, 19, 103, 230, 24, 213, 204,
252 ];
253 let key = hkdf_sha256(b"ABC123");
254
255 assert_eq!(key.to_vec(), known_key);
256 }
257
258 #[test]
259 fn test_aes_interop() {
260 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
261
262 let mut key = [0u8; 32];
263 test_rng.fill_bytes(&mut key);
264
265 let plaintext = b"ABC";
266
267 let known_encrypted: Vec<u8> = vec![
268 218, 65, 89, 124, 81, 87, 72, 141, 119, 36, 224, 63, 149, 218, 64, 106, 159, 178, 238,
269 212, 36, 223, 93, 107, 19, 211, 62, 75, 195, 46, 177,
270 ];
271
272 let decrypted = aes_decrypt(&key, &known_encrypted).unwrap();
273 assert_eq!(plaintext, decrypted.as_slice());
274 }
275
276 #[test]
277 fn test_ecies_ed25519_interop() {
278 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
279
280 let (peer_sk, _peer_pk) = generate_keypair(&mut test_rng);
281
282 let plaintext = b"ABC";
283 let known_encrypted: Vec<u8> = vec![
284 235, 249, 207, 231, 91, 38, 106, 202, 22, 34, 114, 191, 107, 122, 99, 157, 43, 210, 46,
285 229, 219, 208, 111, 176, 98, 154, 42, 250, 114, 233, 68, 8, 159, 7, 231, 190, 85, 81,
286 56, 122, 152, 186, 151, 124, 246, 147, 163, 153, 29, 85, 248, 238, 194, 15, 180, 98,
287 163, 36, 49, 191, 133, 242, 186,
288 ];
289
290 let decrypted = decrypt(&peer_sk, &known_encrypted).unwrap();
291
292 assert_eq!(plaintext, decrypted.as_slice());
293 }
294
295 #[test]
296 fn test_public_key_extract() {
297 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
298
299 let secret = SecretKey::generate(&mut test_rng);
300 let public = PublicKey::from_secret(&secret);
301
302 PublicKey::from_bytes(public.as_bytes()).unwrap();
303
304 assert!(PublicKey::from_bytes(&[0u8; 16]).is_err());
306 assert!(SecretKey::from_bytes(&[0u8; 16]).is_err());
307 }
308
309 #[cfg(feature = "serde")]
310 #[test]
311 fn test_hex() {
312 use hex::{FromHex, ToHex};
313
314 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
315 let (secret, public) = generate_keypair(&mut test_rng);
316
317 let serialized_secret: String = secret.encode_hex();
319 let serialized_public: String = public.encode_hex();
320
321 let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
322 let deserialized_public = PublicKey::from_hex(&serialized_public).unwrap();
323
324 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
325 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
326
327 let serialized_secret: String = secret.encode_hex_upper();
329 let serialized_public: String = public.encode_hex_upper();
330
331 let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
332 let deserialized_public = PublicKey::from_hex(serialized_public).unwrap();
333
334 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
335 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
336 }
337
338 #[cfg(feature = "serde")]
339 #[test]
340 fn test_serde_json() {
341 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
342 let (secret, public) = generate_keypair(&mut test_rng);
343
344 let serialized_secret = serde_json::to_string(&secret).unwrap();
346 let serialized_public = serde_json::to_string(&public).unwrap();
347
348 let deserialized_secret: SecretKey = serde_json::from_str(&serialized_secret).unwrap();
349 let deserialized_public: PublicKey = serde_json::from_str(&serialized_public).unwrap();
350
351 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
352 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
353
354 let deserialized_secret: SecretKey =
356 serde_json::from_slice(serialized_secret.as_bytes()).unwrap();
357 let deserialized_public: PublicKey =
358 serde_json::from_slice(serialized_public.as_bytes()).unwrap();
359
360 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
361 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
362
363 let serialized_secret = serde_json::to_vec(&secret).unwrap();
365 let serialized_public = serde_json::to_vec(&public).unwrap();
366
367 let deserialized_secret: SecretKey = serde_json::from_slice(&serialized_secret).unwrap();
368 let deserialized_public: PublicKey = serde_json::from_slice(&serialized_public).unwrap();
369
370 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
371 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
372
373 let mut serialized_public = serde_json::to_vec(&public).unwrap();
375 serialized_public[0] = 50;
376 assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
377
378 let mut serialized_public = serde_json::to_vec(&public).unwrap();
379 serialized_public.push(48);
380 serialized_public.push(49);
381 assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
382 }
383
384 #[cfg(feature = "serde")]
385 #[test]
386 fn test_serde_cbor() {
387 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
388 let (secret, public) = generate_keypair(&mut test_rng);
389
390 let serialized_secret = serde_cbor::to_vec(&secret).unwrap();
391 let serialized_public = serde_cbor::to_vec(&public).unwrap();
392
393 let deserialized_secret: SecretKey = serde_cbor::from_slice(&serialized_secret).unwrap();
394 let deserialized_public: PublicKey = serde_cbor::from_slice(&serialized_public).unwrap();
395
396 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
397 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
398
399 let mut serialized_public = serde_cbor::to_vec(&public).unwrap();
401 serialized_public[6] = 120;
402 assert!(serde_cbor::from_slice::<PublicKey>(&serialized_public).is_err());
403 }
404}