1use blake3::Hasher;
49use chacha20poly1305::{
50 ChaCha20Poly1305, Nonce,
51 aead::{Aead, KeyInit},
52};
53use curve25519_dalek::{
54 constants::RISTRETTO_BASEPOINT_TABLE,
55 ristretto::{CompressedRistretto, RistrettoPoint},
56 scalar::Scalar,
57};
58use rand::RngExt;
59use serde::{Deserialize, Serialize};
60
61#[derive(Debug, Clone, PartialEq, Eq)]
63pub enum ProxyReError {
64 InvalidCiphertext,
66 DecryptionFailed,
68 EncryptionFailed,
70 InvalidPublicKey,
72 InvalidReKey,
74 SerializationError,
76}
77
78impl std::fmt::Display for ProxyReError {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 match self {
81 ProxyReError::InvalidCiphertext => write!(f, "Invalid ciphertext format"),
82 ProxyReError::DecryptionFailed => write!(f, "Decryption failed"),
83 ProxyReError::EncryptionFailed => write!(f, "Encryption failed"),
84 ProxyReError::InvalidPublicKey => write!(f, "Invalid public key"),
85 ProxyReError::InvalidReKey => write!(f, "Invalid re-encryption key"),
86 ProxyReError::SerializationError => write!(f, "Serialization/deserialization error"),
87 }
88 }
89}
90
91impl std::error::Error for ProxyReError {}
92
93pub type ProxyReResult<T> = Result<T, ProxyReError>;
95
96#[derive(Clone, Serialize, Deserialize)]
98pub struct ProxyReSecretKey(Scalar);
99
100impl ProxyReSecretKey {
101 pub fn generate() -> Self {
103 let mut rng = rand::rng();
104 let mut bytes = [0u8; 32];
105 rng.fill(&mut bytes);
106 Self(Scalar::from_bytes_mod_order(bytes))
107 }
108
109 pub fn to_bytes(&self) -> [u8; 32] {
111 self.0.to_bytes()
112 }
113
114 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
116 Self(Scalar::from_bytes_mod_order(*bytes))
117 }
118}
119
120#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
122pub struct ProxyRePublicKey(RistrettoPoint);
123
124impl ProxyRePublicKey {
125 pub fn from_secret(secret: &ProxyReSecretKey) -> Self {
127 Self(&secret.0 * RISTRETTO_BASEPOINT_TABLE)
128 }
129
130 pub fn to_bytes(&self) -> [u8; 32] {
132 self.0.compress().to_bytes()
133 }
134
135 pub fn from_bytes(bytes: &[u8; 32]) -> ProxyReResult<Self> {
137 CompressedRistretto(*bytes)
138 .decompress()
139 .map(Self)
140 .ok_or(ProxyReError::InvalidPublicKey)
141 }
142}
143
144#[derive(Clone)]
146pub struct ProxyReKeypair {
147 secret: ProxyReSecretKey,
148 public: ProxyRePublicKey,
149}
150
151impl ProxyReKeypair {
152 pub fn generate() -> Self {
154 let secret = ProxyReSecretKey::generate();
155 let public = ProxyRePublicKey::from_secret(&secret);
156 Self { secret, public }
157 }
158
159 pub fn public_key(&self) -> ProxyRePublicKey {
161 self.public
162 }
163
164 pub fn secret_key(&self) -> &ProxyReSecretKey {
166 &self.secret
167 }
168
169 pub fn encrypt(&self, plaintext: &[u8]) -> ProxyReResult<ProxyReCiphertext> {
171 encrypt(&self.public, plaintext)
172 }
173
174 pub fn decrypt(&self, ciphertext: &ProxyReCiphertext) -> ProxyReResult<Vec<u8>> {
176 decrypt(&self.secret, ciphertext)
177 }
178
179 pub fn generate_re_key(&self, target_pk: &ProxyRePublicKey) -> ProxyReReKey {
181 generate_re_key(&self.secret, target_pk)
182 }
183}
184
185#[derive(Clone, Serialize, Deserialize)]
187pub struct ProxyReReKey {
188 re_key: Scalar,
190 target_pk: ProxyRePublicKey,
192}
193
194#[derive(Clone, Serialize, Deserialize)]
196pub struct ProxyReCiphertext {
197 ephemeral_pk: RistrettoPoint,
199 encrypted_key: Vec<u8>,
201 ciphertext: Vec<u8>,
203 nonce: [u8; 12],
205}
206
207impl ProxyReCiphertext {
208 pub fn to_bytes(&self) -> ProxyReResult<Vec<u8>> {
210 crate::codec::encode(self).map_err(|_| ProxyReError::SerializationError)
211 }
212
213 pub fn from_bytes(bytes: &[u8]) -> ProxyReResult<Self> {
215 crate::codec::decode(bytes).map_err(|_| ProxyReError::SerializationError)
216 }
217}
218
219pub fn encrypt(pk: &ProxyRePublicKey, plaintext: &[u8]) -> ProxyReResult<ProxyReCiphertext> {
221 let mut rng = rand::rng();
222
223 let ephemeral_sk = ProxyReSecretKey::generate();
225 let ephemeral_pk = ProxyRePublicKey::from_secret(&ephemeral_sk);
226
227 let shared_point = pk.0 * ephemeral_sk.0;
229
230 let sym_key = derive_symmetric_key(&shared_point);
232
233 let mut nonce_bytes = [0u8; 12];
235 rng.fill(&mut nonce_bytes);
236 let nonce = Nonce::from_slice(&nonce_bytes);
237
238 let cipher = ChaCha20Poly1305::new(&sym_key.into());
240 let ciphertext = cipher
241 .encrypt(nonce, plaintext)
242 .map_err(|_| ProxyReError::EncryptionFailed)?;
243
244 let encrypted_key = vec![0u8; 32];
248
249 Ok(ProxyReCiphertext {
250 ephemeral_pk: ephemeral_pk.0,
251 encrypted_key,
252 ciphertext,
253 nonce: nonce_bytes,
254 })
255}
256
257pub fn decrypt(sk: &ProxyReSecretKey, ciphertext: &ProxyReCiphertext) -> ProxyReResult<Vec<u8>> {
259 let shared_point = ciphertext.ephemeral_pk * sk.0;
261
262 let sym_key = derive_symmetric_key(&shared_point);
264
265 let cipher = ChaCha20Poly1305::new(&sym_key.into());
267 let nonce = Nonce::from_slice(&ciphertext.nonce);
268
269 cipher
270 .decrypt(nonce, ciphertext.ciphertext.as_ref())
271 .map_err(|_| ProxyReError::DecryptionFailed)
272}
273
274pub fn generate_re_key(
276 delegator_sk: &ProxyReSecretKey,
277 delegatee_pk: &ProxyRePublicKey,
278) -> ProxyReReKey {
279 let re_key = delegator_sk.0.invert();
282
283 ProxyReReKey {
284 re_key,
285 target_pk: *delegatee_pk,
286 }
287}
288
289pub fn re_encrypt(
291 ciphertext: &ProxyReCiphertext,
292 re_key: &ProxyReReKey,
293) -> ProxyReResult<ProxyReCiphertext> {
294 let mut rng = rand::rng();
312
313 let re_ephemeral_sk = ProxyReSecretKey::generate();
315 let re_ephemeral_pk = ProxyRePublicKey::from_secret(&re_ephemeral_sk);
316
317 let new_shared_point = re_key.target_pk.0 * re_ephemeral_sk.0;
319 let new_sym_key = derive_symmetric_key(&new_shared_point);
320
321 let mut nonce_bytes = [0u8; 12];
323 rng.fill(&mut nonce_bytes);
324 let nonce = Nonce::from_slice(&nonce_bytes);
325
326 let cipher = ChaCha20Poly1305::new(&new_sym_key.into());
327
328 let original_serialized =
330 crate::codec::encode(ciphertext).map_err(|_| ProxyReError::SerializationError)?;
331
332 let new_ciphertext = cipher
333 .encrypt(nonce, original_serialized.as_ref())
334 .map_err(|_| ProxyReError::EncryptionFailed)?;
335
336 Ok(ProxyReCiphertext {
337 ephemeral_pk: re_ephemeral_pk.0,
338 encrypted_key: vec![1u8; 32], ciphertext: new_ciphertext,
340 nonce: nonce_bytes,
341 })
342}
343
344fn derive_symmetric_key(point: &RistrettoPoint) -> [u8; 32] {
346 let mut hasher = Hasher::new();
347 hasher.update(b"chie-proxy-re-v1");
348 hasher.update(&point.compress().to_bytes());
349 let hash = hasher.finalize();
350 *hash.as_bytes()
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356
357 #[test]
358 fn test_keypair_generation() {
359 let keypair = ProxyReKeypair::generate();
360 let pk_derived = ProxyRePublicKey::from_secret(keypair.secret_key());
361 assert_eq!(pk_derived, keypair.public_key());
362 }
363
364 #[test]
365 fn test_basic_encryption_decryption() {
366 let keypair = ProxyReKeypair::generate();
367 let plaintext = b"Hello, proxy re-encryption!";
368
369 let ciphertext = keypair.encrypt(plaintext).unwrap();
370 let decrypted = keypair.decrypt(&ciphertext).unwrap();
371
372 assert_eq!(decrypted, plaintext);
373 }
374
375 #[test]
376 fn test_encryption_produces_different_ciphertexts() {
377 let keypair = ProxyReKeypair::generate();
378 let plaintext = b"Test message";
379
380 let ct1 = keypair.encrypt(plaintext).unwrap();
381 let ct2 = keypair.encrypt(plaintext).unwrap();
382
383 assert_ne!(ct1.ephemeral_pk.compress(), ct2.ephemeral_pk.compress());
385 assert_ne!(ct1.ciphertext, ct2.ciphertext);
386 }
387
388 #[test]
389 fn test_wrong_key_decryption_fails() {
390 let alice = ProxyReKeypair::generate();
391 let bob = ProxyReKeypair::generate();
392
393 let plaintext = b"Secret message";
394 let ciphertext = alice.encrypt(plaintext).unwrap();
395
396 assert!(bob.decrypt(&ciphertext).is_err());
398 }
399
400 #[test]
401 fn test_proxy_re_encryption() {
402 let alice = ProxyReKeypair::generate();
403 let bob = ProxyReKeypair::generate();
404
405 let plaintext = b"Delegated content";
406
407 let ciphertext = alice.encrypt(plaintext).unwrap();
409
410 let alice_decrypted = alice.decrypt(&ciphertext).unwrap();
412 assert_eq!(alice_decrypted, plaintext);
413
414 let re_key = alice.generate_re_key(&bob.public_key());
416
417 let re_encrypted = re_encrypt(&ciphertext, &re_key).unwrap();
419
420 let outer_decrypted = bob.decrypt(&re_encrypted).unwrap();
423
424 let inner_ciphertext: ProxyReCiphertext = crate::codec::decode(&outer_decrypted).unwrap();
426
427 let final_plaintext = alice.decrypt(&inner_ciphertext).unwrap();
429 assert_eq!(final_plaintext, plaintext);
430 }
431
432 #[test]
433 fn test_public_key_serialization() {
434 let keypair = ProxyReKeypair::generate();
435 let pk = keypair.public_key();
436
437 let bytes = pk.to_bytes();
438 let pk_restored = ProxyRePublicKey::from_bytes(&bytes).unwrap();
439
440 assert_eq!(pk, pk_restored);
441 }
442
443 #[test]
444 fn test_secret_key_serialization() {
445 let keypair = ProxyReKeypair::generate();
446 let sk = keypair.secret_key();
447
448 let bytes = sk.to_bytes();
449 let sk_restored = ProxyReSecretKey::from_bytes(&bytes);
450
451 let pk1 = ProxyRePublicKey::from_secret(sk);
453 let pk2 = ProxyRePublicKey::from_secret(&sk_restored);
454 assert_eq!(pk1, pk2);
455 }
456
457 #[test]
458 fn test_invalid_public_key() {
459 let invalid_bytes = [255u8; 32];
460 assert!(ProxyRePublicKey::from_bytes(&invalid_bytes).is_err());
461 }
462
463 #[test]
464 fn test_ciphertext_serialization() {
465 let keypair = ProxyReKeypair::generate();
466 let plaintext = b"Serialize this";
467
468 let ciphertext = keypair.encrypt(plaintext).unwrap();
469 let serialized = crate::codec::encode(&ciphertext).unwrap();
470 let deserialized: ProxyReCiphertext = crate::codec::decode(&serialized).unwrap();
471
472 let decrypted = keypair.decrypt(&deserialized).unwrap();
473 assert_eq!(decrypted, plaintext);
474 }
475
476 #[test]
477 fn test_empty_plaintext() {
478 let keypair = ProxyReKeypair::generate();
479 let plaintext = b"";
480
481 let ciphertext = keypair.encrypt(plaintext).unwrap();
482 let decrypted = keypair.decrypt(&ciphertext).unwrap();
483
484 assert_eq!(decrypted, plaintext);
485 }
486
487 #[test]
488 fn test_large_plaintext() {
489 let keypair = ProxyReKeypair::generate();
490 let plaintext = vec![42u8; 10_000];
491
492 let ciphertext = keypair.encrypt(&plaintext).unwrap();
493 let decrypted = keypair.decrypt(&ciphertext).unwrap();
494
495 assert_eq!(decrypted, plaintext);
496 }
497
498 #[test]
499 fn test_multiple_delegations() {
500 let alice = ProxyReKeypair::generate();
501 let bob = ProxyReKeypair::generate();
502 let carol = ProxyReKeypair::generate();
503
504 let plaintext = b"Multi-hop delegation";
505
506 let ct_alice = alice.encrypt(plaintext).unwrap();
508
509 let re_key_alice_to_bob = alice.generate_re_key(&bob.public_key());
511 let ct_bob = re_encrypt(&ct_alice, &re_key_alice_to_bob).unwrap();
512
513 let re_key_alice_to_carol = alice.generate_re_key(&carol.public_key());
515 let ct_carol = re_encrypt(&ct_alice, &re_key_alice_to_carol).unwrap();
516
517 let bob_outer = bob.decrypt(&ct_bob).unwrap();
519 let carol_outer = carol.decrypt(&ct_carol).unwrap();
520
521 assert!(crate::codec::decode::<ProxyReCiphertext>(&bob_outer).is_ok());
522 assert!(crate::codec::decode::<ProxyReCiphertext>(&carol_outer).is_ok());
523 }
524
525 #[test]
526 fn test_re_key_serialization() {
527 let alice = ProxyReKeypair::generate();
528 let bob = ProxyReKeypair::generate();
529
530 let re_key = alice.generate_re_key(&bob.public_key());
531 let serialized = crate::codec::encode(&re_key).unwrap();
532 let deserialized: ProxyReReKey = crate::codec::decode(&serialized).unwrap();
533
534 assert_eq!(re_key.target_pk, deserialized.target_pk);
535 }
536}