1use crate::{
83 bls12381::primitives::{
84 group::{Scalar, DST, GT},
85 ops::hash_with_namespace,
86 variant::Variant,
87 },
88 sha256::Digest,
89};
90#[cfg(not(feature = "std"))]
91use alloc::vec::Vec;
92use bytes::{Buf, BufMut};
93use commonware_codec::{EncodeSize, FixedSize, Read, ReadExt, Write};
94use commonware_math::algebra::CryptoGroup;
95use commonware_utils::sequence::FixedBytes;
96use rand_core::CryptoRngCore;
97use zeroize::Zeroizing;
98
99const DST: DST = b"TLE_BLS12381_XMD:SHA-256_SSWU_RO_H3_";
101
102const BLOCK_SIZE: usize = Digest::SIZE;
104
105pub type Block = FixedBytes<BLOCK_SIZE>;
107
108impl From<Digest> for Block {
109 fn from(digest: Digest) -> Self {
110 Block::new(digest.0)
111 }
112}
113
114#[derive(Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
116pub struct Ciphertext<V: Variant> {
117 pub u: V::Public,
119 pub v: Block,
121 pub w: Block,
123}
124
125impl<V: Variant> Write for Ciphertext<V> {
126 fn write(&self, buf: &mut impl BufMut) {
127 self.u.write(buf);
128 buf.put_slice(self.v.as_ref());
129 buf.put_slice(self.w.as_ref());
130 }
131}
132
133impl<V: Variant> Read for Ciphertext<V> {
134 type Cfg = ();
135
136 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
137 let u = V::Public::read(buf)?;
138 let v = Block::read(buf)?;
139 let w = Block::read(buf)?;
140 Ok(Self { u, v, w })
141 }
142}
143
144impl<V: Variant> EncodeSize for Ciphertext<V> {
145 fn encode_size(&self) -> usize {
146 self.u.encode_size() + self.v.encode_size() + self.w.encode_size()
147 }
148}
149
150#[cfg(feature = "arbitrary")]
151impl<V: Variant> arbitrary::Arbitrary<'_> for Ciphertext<V>
152where
153 V::Public: for<'a> arbitrary::Arbitrary<'a>,
154{
155 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
156 let ge = u.arbitrary()?;
157 let v = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
158 let w = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
159 Ok(Self { u: ge, v, w })
160 }
161}
162
163mod hash {
165 use super::*;
166 use crate::{Hasher, Sha256};
167
168 pub fn h2(gt: >) -> Block {
172 let mut hasher = Sha256::new();
173 hasher.update(b"h2");
174 let gt = Zeroizing::new(gt.as_slice());
175 hasher.update(gt.as_ref());
176 hasher.finalize().into()
177 }
178
179 pub fn h3(sigma: &Block, message: &[u8]) -> Scalar {
183 let mut combined = Zeroizing::new(Vec::with_capacity(sigma.len() + message.len()));
185 combined.extend_from_slice(sigma.as_ref());
186 combined.extend_from_slice(message);
187
188 Scalar::map(DST, &combined)
193 }
194
195 pub fn h4(sigma: &Block) -> Block {
199 let mut hasher = Sha256::new();
200 hasher.update(b"h4");
201 hasher.update(sigma.as_ref());
202 hasher.finalize().into()
203 }
204}
205
206#[inline]
212fn xor(a: &Block, b: &Block) -> Block {
213 let a_bytes = a.as_ref();
214 let b_bytes = b.as_ref();
215
216 Block::new([
219 a_bytes[0] ^ b_bytes[0],
220 a_bytes[1] ^ b_bytes[1],
221 a_bytes[2] ^ b_bytes[2],
222 a_bytes[3] ^ b_bytes[3],
223 a_bytes[4] ^ b_bytes[4],
224 a_bytes[5] ^ b_bytes[5],
225 a_bytes[6] ^ b_bytes[6],
226 a_bytes[7] ^ b_bytes[7],
227 a_bytes[8] ^ b_bytes[8],
228 a_bytes[9] ^ b_bytes[9],
229 a_bytes[10] ^ b_bytes[10],
230 a_bytes[11] ^ b_bytes[11],
231 a_bytes[12] ^ b_bytes[12],
232 a_bytes[13] ^ b_bytes[13],
233 a_bytes[14] ^ b_bytes[14],
234 a_bytes[15] ^ b_bytes[15],
235 a_bytes[16] ^ b_bytes[16],
236 a_bytes[17] ^ b_bytes[17],
237 a_bytes[18] ^ b_bytes[18],
238 a_bytes[19] ^ b_bytes[19],
239 a_bytes[20] ^ b_bytes[20],
240 a_bytes[21] ^ b_bytes[21],
241 a_bytes[22] ^ b_bytes[22],
242 a_bytes[23] ^ b_bytes[23],
243 a_bytes[24] ^ b_bytes[24],
244 a_bytes[25] ^ b_bytes[25],
245 a_bytes[26] ^ b_bytes[26],
246 a_bytes[27] ^ b_bytes[27],
247 a_bytes[28] ^ b_bytes[28],
248 a_bytes[29] ^ b_bytes[29],
249 a_bytes[30] ^ b_bytes[30],
250 a_bytes[31] ^ b_bytes[31],
251 ])
252}
253
254pub fn encrypt<R: CryptoRngCore, V: Variant>(
272 rng: &mut R,
273 public: V::Public,
274 target: (&[u8], &[u8]),
275 message: &Block,
276) -> Ciphertext<V> {
277 let (namespace, target) = target;
279 let q_id = hash_with_namespace::<V>(V::MESSAGE, namespace, target);
280
281 let mut sigma_array = Zeroizing::new([0u8; BLOCK_SIZE]);
283 rng.fill_bytes(sigma_array.as_mut());
284 let sigma = Zeroizing::new(Block::new(*sigma_array));
285
286 let r = hash::h3(&sigma, message.as_ref());
288
289 let mut u = V::Public::generator();
291 u *= &r;
292
293 let mut r_pub = public;
297 r_pub *= &r;
298 let gt = V::pairing(&r_pub, &q_id);
299
300 let h2_value = Zeroizing::new(hash::h2(>));
302 let v = xor(&sigma, &h2_value);
303
304 let h4_value = Zeroizing::new(hash::h4(&sigma));
306 let w = xor(message, &h4_value);
307
308 Ciphertext { u, v, w }
309}
310
311pub fn decrypt<V: Variant>(signature: &V::Signature, ciphertext: &Ciphertext<V>) -> Option<Block> {
327 let gt = V::pairing(&ciphertext.u, signature);
329
330 let h2_value = hash::h2(>);
332 let sigma = xor(&ciphertext.v, &h2_value);
333
334 let h4_value = hash::h4(&sigma);
336 let message = xor(&ciphertext.w, &h4_value);
337
338 let r = hash::h3(&sigma, &message);
340 let mut expected_u = V::Public::generator();
341 expected_u *= &r;
342 if ciphertext.u != expected_u {
343 return None;
344 }
345
346 Some(message)
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352 use crate::bls12381::primitives::{
353 ops,
354 variant::{MinPk, MinSig},
355 };
356 use commonware_math::algebra::Random as _;
357 use commonware_utils::test_rng;
358
359 #[test]
360 fn test_encrypt_decrypt_minpk() {
361 let mut rng = test_rng();
362
363 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
365
366 let target = 10u64.to_be_bytes();
368 let message = b"Hello, IBE! This is exactly 32b!"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
372
373 let ciphertext = encrypt::<_, MinPk>(
375 &mut rng,
376 master_public,
377 (b"_TLE_", &target),
378 &Block::new(*message),
379 );
380
381 let decrypted =
383 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
384
385 assert_eq!(message.as_ref(), decrypted.as_ref());
386 }
387
388 #[test]
389 fn test_encrypt_decrypt_minsig() {
390 let mut rng = test_rng();
391
392 let (master_secret, master_public) = ops::keypair::<_, MinSig>(&mut rng);
394
395 let target = 20u64.to_be_bytes();
397 let message = b"Testing MinSig variant - 32 byte";
398
399 let signature = ops::sign_message::<MinSig>(&master_secret, b"_TLE_", &target);
401
402 let ciphertext = encrypt::<_, MinSig>(
404 &mut rng,
405 master_public,
406 (b"_TLE_", &target),
407 &Block::new(*message),
408 );
409
410 let decrypted =
412 decrypt::<MinSig>(&signature, &ciphertext).expect("Decryption should succeed");
413
414 assert_eq!(message.as_ref(), decrypted.as_ref());
415 }
416
417 #[test]
418 fn test_wrong_private_key() {
419 let mut rng = test_rng();
420
421 let (_, master_public1) = ops::keypair::<_, MinPk>(&mut rng);
423 let (master_secret2, _) = ops::keypair::<_, MinPk>(&mut rng);
424
425 let target = 30u64.to_be_bytes();
426 let message = b"Secret message padded to 32bytes";
427
428 let ciphertext = encrypt::<_, MinPk>(
430 &mut rng,
431 master_public1,
432 (b"_TLE_", &target),
433 &Block::new(*message),
434 );
435
436 let wrong_signature = ops::sign_message::<MinPk>(&master_secret2, b"_TLE_", &target);
438 let result = decrypt::<MinPk>(&wrong_signature, &ciphertext);
439
440 assert!(result.is_none());
441 }
442
443 #[test]
444 fn test_tampered_ciphertext() {
445 let mut rng = test_rng();
446
447 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
448 let target = 40u64.to_be_bytes();
449 let message = b"Tamper test padded to 32 bytes.."; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
453
454 let ciphertext = encrypt::<_, MinPk>(
456 &mut rng,
457 master_public,
458 (b"_TLE_", &target),
459 &Block::new(*message),
460 );
461
462 let mut w_bytes = [0u8; BLOCK_SIZE];
464 w_bytes.copy_from_slice(ciphertext.w.as_ref());
465 w_bytes[0] ^= 0xFF;
466 let tampered_ciphertext = Ciphertext {
467 u: ciphertext.u,
468 v: ciphertext.v,
469 w: Block::new(w_bytes),
470 };
471
472 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
474 assert!(result.is_none());
475 }
476
477 #[test]
478 fn test_encrypt_decrypt_with_namespace() {
479 let mut rng = test_rng();
480
481 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
483
484 let namespace = b"example.org";
486 let target = 80u64.to_be_bytes();
487 let message = b"Message with namespace - 32 byte"; let signature = ops::sign_message::<MinPk>(&master_secret, namespace, &target);
491
492 let ciphertext = encrypt::<_, MinPk>(
494 &mut rng,
495 master_public,
496 (namespace, &target),
497 &Block::new(*message),
498 );
499
500 let decrypted =
502 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
503
504 assert_eq!(message.as_ref(), decrypted.as_ref());
505 }
506
507 #[test]
508 fn test_namespace_variance() {
509 let mut rng = test_rng();
510
511 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
513
514 let namespace1 = b"example.org";
515 let namespace2 = b"other.org";
516 let target = 100u64.to_be_bytes();
517 let message = b"Namespace vs no namespace - 32by"; let signature_ns1 = ops::sign_message::<MinPk>(&master_secret, namespace1, &target);
521
522 let signature_ns2 = ops::sign_message::<MinPk>(&master_secret, namespace2, &target);
524
525 let ciphertext_ns1 = encrypt::<_, MinPk>(
527 &mut rng,
528 master_public,
529 (namespace1, &target),
530 &Block::new(*message),
531 );
532
533 let ciphertext_ns2 = encrypt::<_, MinPk>(
535 &mut rng,
536 master_public,
537 (namespace2, &target),
538 &Block::new(*message),
539 );
540
541 let result1 = decrypt::<MinPk>(&signature_ns2, &ciphertext_ns1);
543 assert!(result1.is_none());
544
545 let result2 = decrypt::<MinPk>(&signature_ns1, &ciphertext_ns2);
547 assert!(result2.is_none());
548
549 let decrypted_ns1 = decrypt::<MinPk>(&signature_ns1, &ciphertext_ns1)
551 .expect("Decryption with matching namespace should succeed");
552 let decrypted_ns2 = decrypt::<MinPk>(&signature_ns2, &ciphertext_ns2)
553 .expect("Decryption with matching namespace should succeed");
554
555 assert_eq!(message.as_ref(), decrypted_ns1.as_ref());
556 assert_eq!(message.as_ref(), decrypted_ns2.as_ref());
557 }
558
559 #[test]
560 fn test_cca_modified_v() {
561 let mut rng = test_rng();
562
563 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
564 let target = 110u64.to_be_bytes();
565 let message = b"Another CCA test message 32bytes"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
569
570 let ciphertext = encrypt::<_, MinPk>(
572 &mut rng,
573 master_public,
574 (b"_TLE_", &target),
575 &Block::new(*message),
576 );
577
578 let mut v_bytes = [0u8; BLOCK_SIZE];
580 v_bytes.copy_from_slice(ciphertext.v.as_ref());
581 v_bytes[0] ^= 0x01;
582 let tampered_ciphertext = Ciphertext {
583 u: ciphertext.u,
584 v: Block::new(v_bytes),
585 w: ciphertext.w,
586 };
587
588 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
590 assert!(result.is_none());
591 }
592
593 #[test]
594 fn test_cca_modified_u() {
595 let mut rng = test_rng();
596
597 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
598 let target = 70u64.to_be_bytes();
599 let message = b"CCA security test message 32 byt"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
603
604 let mut ciphertext = encrypt::<_, MinPk>(
606 &mut rng,
607 master_public,
608 (b"_TLE_", &target),
609 &Block::new(*message),
610 );
611
612 let mut modified_u = ciphertext.u;
614 modified_u *= &Scalar::random(&mut rng);
615 ciphertext.u = modified_u;
616
617 let result = decrypt::<MinPk>(&signature, &ciphertext);
619 assert!(result.is_none());
620 }
621
622 #[cfg(feature = "arbitrary")]
623 mod conformance {
624 use super::*;
625 use commonware_codec::conformance::CodecConformance;
626
627 commonware_conformance::conformance_tests! {
628 CodecConformance<Ciphertext<MinPk>>,
629 }
630 }
631}