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 #[allow(deprecated)]
113 let secret = Scalar::from_bits(secret.to_bytes());
114 let shared_point = public * secret;
115 let shared_point_compressed = shared_point.compress();
116
117 let output = shared_point_compressed.as_bytes().to_owned();
118
119 output
120}
121
122fn encapsulate(emphemeral_sk: &SecretKey, peer_pk: &PublicKey) -> AesKey {
123 let shared_point = generate_shared(emphemeral_sk, peer_pk);
124
125 let emphemeral_pk = PublicKey::from_secret(emphemeral_sk);
126
127 let mut master = [0u8; 32 * 2];
128 master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
129 master[32..].clone_from_slice(&shared_point);
130
131 hkdf_sha3(&master)
132}
133
134fn decapsulate(sk: &SecretKey, emphemeral_pk: &PublicKey) -> AesKey {
135 let shared_point = generate_shared(sk, emphemeral_pk);
136
137 let mut master = [0u8; 32 * 2];
138 master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
139 master[32..].clone_from_slice(&shared_point);
140
141 hkdf_sha3(&master)
142}
143
144use thiserror::Error;
146
147#[derive(Debug, Error)]
148pub enum Error {
149 #[error("ecies-rd25519: encryption failed")]
151 EncryptionFailed,
152
153 #[error("ecies-rd25519: encryption failed - RNG error")]
155 EncryptionFailedRng,
156
157 #[error("ecies-rd25519: decryption failed")]
159 DecryptionFailed,
160
161 #[error("ecies-rd25519: decryption failed - ciphertext too short")]
163 DecryptionFailedCiphertextShort,
164
165 #[error("ecies-rd25519: invalid public key bytes")]
167 InvalidPublicKeyBytes,
168
169 #[error("ecies-rd25519: invalid secret key bytes")]
171 InvalidSecretKeyBytes,
172}
173
174#[cfg(test)]
175pub mod tests {
176 use super::*;
177
178 use rand::thread_rng;
179 use rand::SeedableRng;
180
181 #[test]
182 fn test_shared() {
183 let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
184 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
185
186 assert_eq!(
187 generate_shared(&emphemeral_sk, &peer_pk),
188 generate_shared(&peer_sk, &emphemeral_pk)
189 );
190
191 assert_ne!(
193 generate_shared(&emphemeral_sk, &emphemeral_pk),
194 generate_shared(&peer_sk, &peer_pk)
195 )
196 }
197
198 #[test]
199 fn test_encapsulation() {
200 let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
201 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
202
203 assert_eq!(
204 encapsulate(&emphemeral_sk, &peer_pk),
205 decapsulate(&peer_sk, &emphemeral_pk)
206 )
207 }
208
209 #[test]
210 fn test_aes() {
211 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
212 let mut key = [0u8; 32];
213 test_rng.fill_bytes(&mut key);
214
215 let plaintext = b"ABC";
216 let encrypted = aes_encrypt(&key, plaintext, &mut test_rng).unwrap();
217 let decrypted = aes_decrypt(&key, &encrypted).unwrap();
218
219 assert_eq!(plaintext, decrypted.as_slice());
220
221 assert!(aes_decrypt(&key, &[0u8; 16]).is_err());
223
224 let bad_secret = SecretKey::generate(&mut thread_rng());
226 assert!(aes_decrypt(bad_secret.as_bytes(), &encrypted).is_err());
227 }
228
229 #[test]
230 fn test_ecies_ed25519() {
231 let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
232
233 let plaintext = b"ABOLISH ICE";
234
235 let encrypted = encrypt(&peer_pk, plaintext, &mut thread_rng()).unwrap();
236 let decrypted = decrypt(&peer_sk, &encrypted).unwrap();
237
238 assert_eq!(plaintext, decrypted.as_slice());
239
240 assert!(decrypt(&peer_sk, &[0u8; 16]).is_err());
242
243 let bad_secret = SecretKey::generate(&mut thread_rng());
245 assert!(decrypt(&bad_secret, &encrypted).is_err());
246 }
247
248 #[test]
249 fn test_hkdf_sha256_interop() {
250 let known_key: Vec<u8> = vec![
251 204, 68, 78, 7, 8, 70, 53, 136, 56, 115, 129, 183, 226, 82, 147, 253, 62, 59, 170, 188,
252 131, 119, 31, 21, 249, 255, 19, 103, 230, 24, 213, 204,
253 ];
254 let key = hkdf_sha3(b"ABC123");
255
256 assert_eq!(key.to_vec(), known_key);
257 }
258
259 #[test]
260 fn test_aes_interop() {
261 let key = [
262 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
263 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
264 ];
265
266 let plaintext = b"ABC";
267
268 let known_encrypted: Vec<u8> = vec![
269 218, 65, 89, 124, 81, 87, 72, 141, 119, 36, 224, 63, 149, 218, 64, 106, 159, 178, 238,
270 212, 36, 223, 93, 107, 19, 211, 62, 75, 195, 46, 177,
271 ];
272
273 let decrypted = aes_decrypt(&key, &known_encrypted).unwrap();
274 assert_eq!(plaintext, decrypted.as_slice());
275 }
276
277 #[test]
278 fn test_ecies_ed25519_interop() {
279 let peer_sk = SecretKey([
280 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
281 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
282 ]);
283
284 let plaintext = b"ABC";
285 let known_encrypted: Vec<u8> = vec![
286 235, 249, 207, 231, 91, 38, 106, 202, 22, 34, 114, 191, 107, 122, 99, 157, 43, 210, 46,
287 229, 219, 208, 111, 176, 98, 154, 42, 250, 114, 233, 68, 8, 159, 7, 231, 190, 85, 81,
288 56, 122, 152, 186, 151, 124, 246, 147, 163, 153, 29, 85, 248, 238, 194, 15, 180, 98,
289 163, 36, 49, 191, 133, 242, 186,
290 ];
291
292 let decrypted = decrypt(&peer_sk, &known_encrypted).unwrap();
293
294 assert_eq!(plaintext, decrypted.as_slice());
295 }
296
297 #[test]
298 fn test_public_key_extract() {
299 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
300
301 let secret = SecretKey::generate(&mut test_rng);
302 let public = PublicKey::from_secret(&secret);
303
304 PublicKey::from_bytes(public.as_bytes()).unwrap();
305
306 assert!(PublicKey::from_bytes(&[0u8; 16]).is_err());
308 assert!(SecretKey::from_bytes(&[0u8; 16]).is_err());
309 }
310
311 #[cfg(feature = "serde")]
312 #[test]
313 fn test_hex() {
314 use hex::{FromHex, ToHex};
315
316 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
317 let (secret, public) = generate_keypair(&mut test_rng);
318
319 let serialized_secret: String = secret.encode_hex();
321 let serialized_public: String = public.encode_hex();
322
323 let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
324 let deserialized_public = PublicKey::from_hex(&serialized_public).unwrap();
325
326 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
327 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
328
329 let serialized_secret: String = secret.encode_hex_upper();
331 let serialized_public: String = public.encode_hex_upper();
332
333 let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
334 let deserialized_public = PublicKey::from_hex(serialized_public).unwrap();
335
336 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
337 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
338 }
339
340 #[cfg(feature = "serde")]
341 #[test]
342 fn test_serde_json() {
343 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
344 let (secret, public) = generate_keypair(&mut test_rng);
345
346 let serialized_secret = serde_json::to_string(&secret).unwrap();
348 let serialized_public = serde_json::to_string(&public).unwrap();
349
350 let deserialized_secret: SecretKey = serde_json::from_str(&serialized_secret).unwrap();
351 let deserialized_public: PublicKey = serde_json::from_str(&serialized_public).unwrap();
352
353 assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
354 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
355
356 let deserialized_secret: SecretKey =
358 serde_json::from_slice(serialized_secret.as_bytes()).unwrap();
359 let deserialized_public: PublicKey =
360 serde_json::from_slice(serialized_public.as_bytes()).unwrap();
361
362 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
363 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
364
365 let serialized_secret = serde_json::to_vec(&secret).unwrap();
367 let serialized_public = serde_json::to_vec(&public).unwrap();
368
369 let deserialized_secret: SecretKey = serde_json::from_slice(&serialized_secret).unwrap();
370 let deserialized_public: PublicKey = serde_json::from_slice(&serialized_public).unwrap();
371
372 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
373 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
374
375 let mut serialized_public = serde_json::to_vec(&public).unwrap();
377 serialized_public[0] = 50;
378 assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
379
380 let mut serialized_public = serde_json::to_vec(&public).unwrap();
381 serialized_public.push(48);
382 serialized_public.push(49);
383 assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
384 }
385
386 #[cfg(feature = "serde")]
387 #[test]
388 fn test_serde_cbor() {
389 let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
390 let (secret, public) = generate_keypair(&mut test_rng);
391
392 let serialized_secret = serde_cbor::to_vec(&secret).unwrap();
393 let serialized_public = serde_cbor::to_vec(&public).unwrap();
394
395 let deserialized_secret: SecretKey = serde_cbor::from_slice(&serialized_secret).unwrap();
396 let deserialized_public: PublicKey = serde_cbor::from_slice(&serialized_public).unwrap();
397
398 assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
399 assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
400
401 let mut serialized_public = serialized_public;
403 serialized_public[6] ^= 0xFF;
404 assert!(serde_cbor::from_slice::<PublicKey>(&serialized_public).is_err());
405 }
406}