1use crate::{
83 bls12381::primitives::{
84 group::{Element, Scalar, DST, GT},
85 ops::{hash_message, hash_message_namespace},
86 variant::Variant,
87 },
88 sha256::Digest,
89};
90use bytes::{Buf, BufMut};
91use commonware_codec::{EncodeSize, FixedSize, Read, ReadExt, Write};
92use commonware_utils::sequence::FixedBytes;
93use rand::{CryptoRng, Rng};
94
95const DST: DST = b"TLE_BLS12381_XMD:SHA-256_SSWU_RO_H3_";
97
98const BLOCK_SIZE: usize = Digest::SIZE;
100
101pub type Block = FixedBytes<BLOCK_SIZE>;
103
104impl From<Digest> for Block {
105 fn from(digest: Digest) -> Self {
106 Block::new(digest.0)
107 }
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct Ciphertext<V: Variant> {
113 pub u: V::Public,
115 pub v: Block,
117 pub w: Block,
119}
120
121impl<V: Variant> Write for Ciphertext<V> {
122 fn write(&self, buf: &mut impl BufMut) {
123 self.u.write(buf);
124 buf.put_slice(self.v.as_ref());
125 buf.put_slice(self.w.as_ref());
126 }
127}
128
129impl<V: Variant> Read for Ciphertext<V> {
130 type Cfg = ();
131
132 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
133 let u = V::Public::read(buf)?;
134 let v = Block::read(buf)?;
135 let w = Block::read(buf)?;
136 Ok(Self { u, v, w })
137 }
138}
139
140impl<V: Variant> EncodeSize for Ciphertext<V> {
141 fn encode_size(&self) -> usize {
142 self.u.encode_size() + self.v.encode_size() + self.w.encode_size()
143 }
144}
145
146mod hash {
148 use super::*;
149 use crate::{Hasher, Sha256};
150
151 pub fn h2(gt: >) -> Block {
155 let mut hasher = Sha256::new();
156 hasher.update(b"h2");
157 hasher.update(>.as_slice());
158 hasher.finalize().into()
159 }
160
161 pub fn h3(sigma: &Block, message: &[u8]) -> Scalar {
165 let mut combined = Vec::with_capacity(sigma.len() + message.len());
167 combined.extend_from_slice(sigma.as_ref());
168 combined.extend_from_slice(message);
169
170 Scalar::map(DST, &combined)
172 }
173
174 pub fn h4(sigma: &Block) -> Block {
178 let mut hasher = Sha256::new();
179 hasher.update(b"h4");
180 hasher.update(sigma.as_ref());
181 hasher.finalize().into()
182 }
183}
184
185#[inline]
191fn xor(a: &Block, b: &Block) -> Block {
192 let a_bytes = a.as_ref();
193 let b_bytes = b.as_ref();
194
195 Block::new([
198 a_bytes[0] ^ b_bytes[0],
199 a_bytes[1] ^ b_bytes[1],
200 a_bytes[2] ^ b_bytes[2],
201 a_bytes[3] ^ b_bytes[3],
202 a_bytes[4] ^ b_bytes[4],
203 a_bytes[5] ^ b_bytes[5],
204 a_bytes[6] ^ b_bytes[6],
205 a_bytes[7] ^ b_bytes[7],
206 a_bytes[8] ^ b_bytes[8],
207 a_bytes[9] ^ b_bytes[9],
208 a_bytes[10] ^ b_bytes[10],
209 a_bytes[11] ^ b_bytes[11],
210 a_bytes[12] ^ b_bytes[12],
211 a_bytes[13] ^ b_bytes[13],
212 a_bytes[14] ^ b_bytes[14],
213 a_bytes[15] ^ b_bytes[15],
214 a_bytes[16] ^ b_bytes[16],
215 a_bytes[17] ^ b_bytes[17],
216 a_bytes[18] ^ b_bytes[18],
217 a_bytes[19] ^ b_bytes[19],
218 a_bytes[20] ^ b_bytes[20],
219 a_bytes[21] ^ b_bytes[21],
220 a_bytes[22] ^ b_bytes[22],
221 a_bytes[23] ^ b_bytes[23],
222 a_bytes[24] ^ b_bytes[24],
223 a_bytes[25] ^ b_bytes[25],
224 a_bytes[26] ^ b_bytes[26],
225 a_bytes[27] ^ b_bytes[27],
226 a_bytes[28] ^ b_bytes[28],
227 a_bytes[29] ^ b_bytes[29],
228 a_bytes[30] ^ b_bytes[30],
229 a_bytes[31] ^ b_bytes[31],
230 ])
231}
232
233pub fn encrypt<R: Rng + CryptoRng, V: Variant>(
251 rng: &mut R,
252 public: V::Public,
253 target: (Option<&[u8]>, &[u8]),
254 message: &Block,
255) -> Ciphertext<V> {
256 let q_id = match target {
258 (None, target) => hash_message::<V>(V::MESSAGE, target),
259 (Some(namespace), target) => hash_message_namespace::<V>(V::MESSAGE, namespace, target),
260 };
261
262 let mut sigma_array = [0u8; BLOCK_SIZE];
264 rng.fill_bytes(&mut sigma_array);
265 let sigma = Block::new(sigma_array);
266
267 let r = hash::h3(&sigma, message.as_ref());
269
270 let mut u = V::Public::one();
272 u.mul(&r);
273
274 let mut r_pub = public;
276 r_pub.mul(&r);
277 let gt = V::pairing(&r_pub, &q_id);
278
279 let h2_value = hash::h2(>);
281 let v = xor(&sigma, &h2_value);
282
283 let h4_value = hash::h4(&sigma);
285 let w = xor(message, &h4_value);
286
287 Ciphertext { u, v, w }
288}
289
290pub fn decrypt<V: Variant>(signature: &V::Signature, ciphertext: &Ciphertext<V>) -> Option<Block> {
306 let gt = V::pairing(&ciphertext.u, signature);
308
309 let h2_value = hash::h2(>);
311 let sigma = xor(&ciphertext.v, &h2_value);
312
313 let h4_value = hash::h4(&sigma);
315 let message = xor(&ciphertext.w, &h4_value);
316
317 let r = hash::h3(&sigma, &message);
319 let mut expected_u = V::Public::one();
320 expected_u.mul(&r);
321 if ciphertext.u != expected_u {
322 return None;
323 }
324
325 Some(message)
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 use crate::bls12381::primitives::{
332 ops::{keypair, sign_message},
333 variant::{MinPk, MinSig},
334 };
335 use rand::thread_rng;
336
337 #[test]
338 fn test_encrypt_decrypt_minpk() {
339 let mut rng = thread_rng();
340
341 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
343
344 let target = 10u64.to_be_bytes();
346 let message = b"Hello, IBE! This is exactly 32b!"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
350
351 let ciphertext = encrypt::<_, MinPk>(
353 &mut rng,
354 master_public,
355 (None, &target),
356 &Block::new(*message),
357 );
358
359 let decrypted =
361 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
362
363 assert_eq!(message.as_ref(), decrypted.as_ref());
364 }
365
366 #[test]
367 fn test_encrypt_decrypt_minsig() {
368 let mut rng = thread_rng();
369
370 let (master_secret, master_public) = keypair::<_, MinSig>(&mut rng);
372
373 let target = 20u64.to_be_bytes();
375 let message = b"Testing MinSig variant - 32 byte";
376
377 let signature = sign_message::<MinSig>(&master_secret, None, &target);
379
380 let ciphertext = encrypt::<_, MinSig>(
382 &mut rng,
383 master_public,
384 (None, &target),
385 &Block::new(*message),
386 );
387
388 let decrypted =
390 decrypt::<MinSig>(&signature, &ciphertext).expect("Decryption should succeed");
391
392 assert_eq!(message.as_ref(), decrypted.as_ref());
393 }
394
395 #[test]
396 fn test_wrong_private_key() {
397 let mut rng = thread_rng();
398
399 let (_, master_public1) = keypair::<_, MinPk>(&mut rng);
401 let (master_secret2, _) = keypair::<_, MinPk>(&mut rng);
402
403 let target = 30u64.to_be_bytes();
404 let message = b"Secret message padded to 32bytes";
405
406 let ciphertext = encrypt::<_, MinPk>(
408 &mut rng,
409 master_public1,
410 (None, &target),
411 &Block::new(*message),
412 );
413
414 let wrong_signature = sign_message::<MinPk>(&master_secret2, None, &target);
416 let result = decrypt::<MinPk>(&wrong_signature, &ciphertext);
417
418 assert!(result.is_none());
419 }
420
421 #[test]
422 fn test_tampered_ciphertext() {
423 let mut rng = thread_rng();
424
425 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
426 let target = 40u64.to_be_bytes();
427 let message = b"Tamper test padded to 32 bytes.."; let signature = sign_message::<MinPk>(&master_secret, None, &target);
431
432 let ciphertext = encrypt::<_, MinPk>(
434 &mut rng,
435 master_public,
436 (None, &target),
437 &Block::new(*message),
438 );
439
440 let mut w_bytes = [0u8; BLOCK_SIZE];
442 w_bytes.copy_from_slice(ciphertext.w.as_ref());
443 w_bytes[0] ^= 0xFF;
444 let tampered_ciphertext = Ciphertext {
445 u: ciphertext.u,
446 v: ciphertext.v,
447 w: Block::new(w_bytes),
448 };
449
450 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
452 assert!(result.is_none());
453 }
454
455 #[test]
456 fn test_encrypt_decrypt_with_namespace() {
457 let mut rng = thread_rng();
458
459 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
461
462 let namespace = b"example.org";
464 let target = 80u64.to_be_bytes();
465 let message = b"Message with namespace - 32 byte"; let signature = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
469
470 let ciphertext = encrypt::<_, MinPk>(
472 &mut rng,
473 master_public,
474 (Some(namespace), &target),
475 &Block::new(*message),
476 );
477
478 let decrypted =
480 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
481
482 assert_eq!(message.as_ref(), decrypted.as_ref());
483 }
484
485 #[test]
486 fn test_namespace_variance() {
487 let mut rng = thread_rng();
488
489 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
491
492 let namespace = b"example.org";
493 let target = 100u64.to_be_bytes();
494 let message = b"Namespace vs no namespace - 32by"; let signature_no_ns = sign_message::<MinPk>(&master_secret, None, &target);
498
499 let signature_ns = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
501
502 let ciphertext_ns = encrypt::<_, MinPk>(
504 &mut rng,
505 master_public,
506 (Some(namespace), &target),
507 &Block::new(*message),
508 );
509
510 let ciphertext_no_ns = encrypt::<_, MinPk>(
512 &mut rng,
513 master_public,
514 (None, &target),
515 &Block::new(*message),
516 );
517
518 let result1 = decrypt::<MinPk>(&signature_no_ns, &ciphertext_ns);
520 assert!(result1.is_none());
521
522 let result2 = decrypt::<MinPk>(&signature_ns, &ciphertext_no_ns);
524 assert!(result2.is_none());
525
526 let decrypted_ns = decrypt::<MinPk>(&signature_ns, &ciphertext_ns)
528 .expect("Decryption with matching namespace should succeed");
529 let decrypted_no_ns = decrypt::<MinPk>(&signature_no_ns, &ciphertext_no_ns)
530 .expect("Decryption without namespace should succeed");
531
532 assert_eq!(message.as_ref(), decrypted_ns.as_ref());
533 assert_eq!(message.as_ref(), decrypted_no_ns.as_ref());
534 }
535
536 #[test]
537 fn test_cca_modified_v() {
538 let mut rng = thread_rng();
539
540 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
541 let target = 110u64.to_be_bytes();
542 let message = b"Another CCA test message 32bytes"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
546
547 let ciphertext = encrypt::<_, MinPk>(
549 &mut rng,
550 master_public,
551 (None, &target),
552 &Block::new(*message),
553 );
554
555 let mut v_bytes = [0u8; BLOCK_SIZE];
557 v_bytes.copy_from_slice(ciphertext.v.as_ref());
558 v_bytes[0] ^= 0x01;
559 let tampered_ciphertext = Ciphertext {
560 u: ciphertext.u,
561 v: Block::new(v_bytes),
562 w: ciphertext.w,
563 };
564
565 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
567 assert!(result.is_none());
568 }
569
570 #[test]
571 fn test_cca_modified_u() {
572 let mut rng = thread_rng();
573
574 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
575 let target = 70u64.to_be_bytes();
576 let message = b"CCA security test message 32 byt"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
580
581 let mut ciphertext = encrypt::<_, MinPk>(
583 &mut rng,
584 master_public,
585 (None, &target),
586 &Block::new(*message),
587 );
588
589 let mut modified_u = ciphertext.u;
591 modified_u.mul(&Scalar::from_rand(&mut rng));
592 ciphertext.u = modified_u;
593
594 let result = decrypt::<MinPk>(&signature, &ciphertext);
596 assert!(result.is_none());
597 }
598}