ecies_ed25519_morus/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
70#![forbid(unsafe_code)]
71#![deny(warnings)]
72
73pub mod errors;
74pub mod morus;
75
76pub(crate) mod helper;
77
78pub type DecryptTag = morus::Tag;
79pub type Nonce = morus::Nonce;
80
81pub const KDF_CONTEXT: &str = "ecies-ed25519-morus/kdf";
82
83#[doc(inline)]
84pub use ed25519_dalek::{SecretKey, SigningKey, VerifyingKey};
85pub use errors::Error;
86
87#[derive(Clone, Copy, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
89pub struct DecryptionMaterials {
90 pub nonce: Nonce,
91 pub tag: DecryptTag,
92}
93
94pub fn encrypt_into<RNG: rand_core::CryptoRng + rand_core::RngCore>(
109 rng: &mut RNG,
110 sender_keypair: &SigningKey,
111 receiver_public_key: &VerifyingKey,
112 associated_data: &[u8],
113 message: &[u8],
114 ciphertext: &mut [u8],
115) -> Result<DecryptionMaterials, Error> {
116 let cipher_key = CipherKey::sender_generate(sender_keypair, receiver_public_key)?;
117
118 helper::morus_encrypt(rng, &cipher_key, associated_data, message, ciphertext)
119}
120
121pub fn decrypt_into(
132 decryption_materials: &DecryptionMaterials,
133 receiver_keypair: &SigningKey,
134 sender_public_key: &VerifyingKey,
135 associated_data: &[u8],
136 ciphertext: &[u8],
137 decrypted_message: &mut [u8],
138) -> Result<(), Error> {
139 let cipher_key = CipherKey::receiver_generate(receiver_keypair, sender_public_key)?;
140
141 helper::morus_decrypt(
142 decryption_materials,
143 &cipher_key,
144 associated_data,
145 ciphertext,
146 decrypted_message,
147 )
148}
149
150#[derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)]
151pub(crate) struct CipherKey {
152 pub(crate) inner: morus::Key,
153}
154
155impl CipherKey {
156 fn sender_generate(
157 sender_keypair: &SigningKey,
158 receiver_public_key: &VerifyingKey,
159 ) -> Result<Self, Error> {
160 let shared_secret = Self::generate_shared_secret(sender_keypair, receiver_public_key)?;
161 let mut master_key = [0u8; 64];
162 master_key[..32].copy_from_slice(&sender_keypair.verifying_key().as_bytes()[..]);
163 master_key[32..].copy_from_slice(&shared_secret[..]);
164 let inner = helper::derive_key(&master_key);
165
166 Ok(Self { inner })
167 }
168
169 fn receiver_generate(
170 receiver_keypair: &SigningKey,
171 sender_public_key: &VerifyingKey,
172 ) -> Result<Self, Error> {
173 let shared_secret = Self::generate_shared_secret(receiver_keypair, sender_public_key)?;
174 let mut master_key = [0u8; 64];
175 master_key[..32].copy_from_slice(&sender_public_key.as_bytes()[..]);
176 master_key[32..].copy_from_slice(&shared_secret[..]);
177 let inner = helper::derive_key(&master_key);
178
179 Ok(Self { inner })
180 }
181
182 fn generate_shared_secret(
183 keypair_alice: &SigningKey,
184 public_bob: &VerifyingKey,
185 ) -> Result<[u8; 32], Error> {
186 let pk_compressed = curve25519_dalek::edwards::CompressedEdwardsY(public_bob.to_bytes());
187 let pk_point = pk_compressed
188 .decompress()
189 .ok_or(Error::EdwardsPointDecompressionFailure)?;
190 let sk_scalar = curve25519_dalek::Scalar::from_bytes_mod_order(
191 curve25519_dalek::scalar::clamp_integer(keypair_alice.to_scalar_bytes()),
192 );
193 let shared_point = pk_point * sk_scalar;
194 let shared_point_compressed = shared_point.compress();
195
196 Ok(shared_point_compressed.to_bytes())
197 }
198}
199
200#[cfg(test)]
201mod unit_tests {
202 use super::*;
203 use rand_core::RngCore;
204
205 const REPETITION: usize = 32;
206 const BUFFER_SIZE: usize = 512 * 1024; #[test]
209 fn test_encrypt_decrypt_always_successful() {
210 for _ in 0..REPETITION {
211 let mut rng = rand_core::OsRng::default();
212 let sender_keypair = ed25519_dalek::SigningKey::generate(&mut rng);
213 let receiver_keypair = ed25519_dalek::SigningKey::generate(&mut rng);
214 let sender_public = sender_keypair.verifying_key();
215 let receiver_public = receiver_keypair.verifying_key();
216 let mut random_message = [0u8; BUFFER_SIZE];
217 let mut decrypted_message = [0u8; BUFFER_SIZE];
218 let mut ciphertext = [0u8; BUFFER_SIZE];
219 rng.fill_bytes(&mut random_message);
220
221 let decrypt_materials = encrypt_into(
222 &mut rng,
223 &sender_keypair,
224 &receiver_public,
225 &[],
226 &random_message[..],
227 &mut ciphertext[..],
228 )
229 .unwrap();
230 decrypt_into(
231 &decrypt_materials,
232 &receiver_keypair,
233 &sender_public,
234 &[],
235 &ciphertext[..],
236 &mut decrypted_message[..],
237 )
238 .unwrap();
239
240 assert_eq!(random_message, decrypted_message);
241 assert_ne!(sender_public, receiver_public);
242 }
243 }
244
245 #[test]
246 fn test_idempotent_keys_yield_different() {
247 for _ in 0..REPETITION {
248 let mut rng = rand_core::OsRng::default();
249 let sender_keypair = ed25519_dalek::SigningKey::generate(&mut rng);
250 let receiver_keypair = ed25519_dalek::SigningKey::generate(&mut rng);
251 let receiver_public = receiver_keypair.verifying_key();
252 let mut random_message = [0u8; BUFFER_SIZE];
253 let mut ciphertext_0 = [0u8; BUFFER_SIZE];
254 let mut ciphertext_1 = [0u8; BUFFER_SIZE];
255 rng.fill_bytes(&mut random_message);
256
257 let _ = encrypt_into(
258 &mut rng,
259 &sender_keypair,
260 &receiver_public,
261 &[],
262 &random_message[..],
263 &mut ciphertext_0[..],
264 )
265 .unwrap();
266 let _ = encrypt_into(
267 &mut rng,
268 &sender_keypair,
269 &receiver_public,
270 &[],
271 &random_message[..],
272 &mut ciphertext_1[..],
273 )
274 .unwrap();
275
276 assert_ne!(ciphertext_0, ciphertext_1);
277 }
278 }
279}