1use crate::{
86 bls12381::primitives::{
87 group::{DST, GT, Scalar},
88 ops::hash_with_namespace,
89 variant::Variant,
90 },
91 sha256::Digest,
92};
93#[cfg(not(feature = "std"))]
94use alloc::vec::Vec;
95use bytes::{Buf, BufMut};
96use commonware_codec::{EncodeSize, FixedSize, Read, ReadExt, Write};
97use commonware_math::algebra::{Additive, CryptoGroup};
98use commonware_utils::sequence::FixedBytes;
99use rand_core::CryptoRng;
100use thiserror::Error;
101use zeroize::Zeroizing;
102
103const DST: DST = b"TLE_BLS12381_XMD:SHA-256_SSWU_RO_H3_";
105
106const BLOCK_SIZE: usize = Digest::SIZE;
108
109pub type Block = FixedBytes<BLOCK_SIZE>;
111
112#[derive(Debug, Error, PartialEq, Eq)]
114pub enum Error {
115 #[error("master public key is the group identity")]
117 InvalidPublicKey,
118}
119
120impl From<Digest> for Block {
121 fn from(digest: Digest) -> Self {
122 Block::new(digest.0)
123 }
124}
125
126#[derive(Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
128pub struct Ciphertext<V: Variant> {
129 pub u: V::Public,
131 pub v: Block,
133 pub w: Block,
135}
136
137impl<V: Variant> Write for Ciphertext<V> {
138 fn write(&self, buf: &mut impl BufMut) {
139 self.u.write(buf);
140 buf.put_slice(self.v.as_ref());
141 buf.put_slice(self.w.as_ref());
142 }
143}
144
145impl<V: Variant> Read for Ciphertext<V> {
146 type Cfg = ();
147
148 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
149 let u = V::Public::read(buf)?;
150 let v = Block::read(buf)?;
151 let w = Block::read(buf)?;
152 Ok(Self { u, v, w })
153 }
154}
155
156impl<V: Variant> EncodeSize for Ciphertext<V> {
157 fn encode_size(&self) -> usize {
158 self.u.encode_size() + self.v.encode_size() + self.w.encode_size()
159 }
160}
161
162#[cfg(feature = "arbitrary")]
163impl<V: Variant> arbitrary::Arbitrary<'_> for Ciphertext<V>
164where
165 V::Public: for<'a> arbitrary::Arbitrary<'a>,
166{
167 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
168 let ge = u.arbitrary()?;
169 let v = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
170 let w = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
171 Ok(Self { u: ge, v, w })
172 }
173}
174
175mod hash {
177 use super::*;
178 use crate::{Hasher, Sha256};
179
180 pub fn h2(gt: >) -> Block {
184 let gt = Zeroizing::new(gt.as_slice());
185 Sha256::hash(&[b"h2", gt.as_ref()]).into()
186 }
187
188 pub fn h3(sigma: &Block, message: &[u8]) -> Scalar {
192 let mut combined = Zeroizing::new(Vec::with_capacity(sigma.len() + message.len()));
194 combined.extend_from_slice(sigma.as_ref());
195 combined.extend_from_slice(message);
196
197 Scalar::map(DST, &combined)
199 }
200
201 pub fn h4(sigma: &Block) -> Block {
205 Sha256::hash(&[b"h4", sigma.as_ref()]).into()
206 }
207}
208
209#[inline]
211fn xor(a: &Block, b: &Block) -> Block {
212 let a = a.as_ref();
213 let b = b.as_ref();
214 Block::new(core::array::from_fn(|i| a[i] ^ b[i]))
215}
216
217pub fn encrypt<R: CryptoRng, V: Variant>(
235 rng: &mut R,
236 public: V::Public,
237 target: (&[u8], &[u8]),
238 message: &Block,
239) -> Result<Ciphertext<V>, Error> {
240 if public == V::Public::zero() {
242 return Err(Error::InvalidPublicKey);
243 }
244
245 let (namespace, target) = target;
247 let q_id = hash_with_namespace::<V>(V::MESSAGE, namespace, target);
248
249 let mut sigma_array = Zeroizing::new([0u8; BLOCK_SIZE]);
251 rng.fill_bytes(sigma_array.as_mut());
252 let sigma = Zeroizing::new(Block::new(*sigma_array));
253
254 let r = hash::h3(&sigma, message.as_ref());
256
257 let mut u = V::Public::generator();
259 u *= &r;
260
261 let mut r_pub = public;
265 r_pub *= &r;
266 let gt = V::pairing(&r_pub, &q_id);
267
268 let h2_value = Zeroizing::new(hash::h2(>));
270 let v = xor(&sigma, &h2_value);
271
272 let h4_value = Zeroizing::new(hash::h4(&sigma));
274 let w = xor(message, &h4_value);
275
276 Ok(Ciphertext { u, v, w })
277}
278
279pub fn decrypt<V: Variant>(signature: &V::Signature, ciphertext: &Ciphertext<V>) -> Option<Block> {
295 if signature == &V::Signature::zero() {
297 return None;
298 }
299
300 let gt = V::pairing(&ciphertext.u, signature);
302
303 let h2_value = hash::h2(>);
305 let sigma = xor(&ciphertext.v, &h2_value);
306
307 let h4_value = hash::h4(&sigma);
309 let message = xor(&ciphertext.w, &h4_value);
310
311 let r = hash::h3(&sigma, &message);
313 let mut expected_u = V::Public::generator();
314 expected_u *= &r;
315 if ciphertext.u != expected_u {
316 return None;
317 }
318
319 Some(message)
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use crate::bls12381::primitives::{
326 ops,
327 variant::{MinPk, MinSig},
328 };
329 use commonware_math::algebra::Random as _;
330 use commonware_utils::test_rng;
331
332 fn identity_signature_cannot_decrypt<V: Variant>() {
333 let sigma = Block::new([1; BLOCK_SIZE]);
334 let message = Block::new([2; BLOCK_SIZE]);
335 let r = hash::h3(&sigma, message.as_ref());
336
337 let mut u = V::Public::generator();
338 u *= &r;
339 let identity_pairing = V::pairing(&V::Public::zero(), &V::Signature::generator());
340 let ciphertext = Ciphertext {
341 u,
342 v: xor(&sigma, &hash::h2(&identity_pairing)),
343 w: xor(&message, &hash::h4(&sigma)),
344 };
345
346 assert!(decrypt::<V>(&V::Signature::zero(), &ciphertext).is_none());
347 }
348
349 #[test]
350 fn test_identity_signature_cannot_decrypt() {
351 identity_signature_cannot_decrypt::<MinPk>();
352 identity_signature_cannot_decrypt::<MinSig>();
353 }
354
355 fn identity_public_key_cannot_encrypt<V: Variant>() {
356 let result = encrypt::<_, V>(
357 &mut test_rng(),
358 V::Public::zero(),
359 (b"test", b"target"),
360 &Block::new([0; BLOCK_SIZE]),
361 );
362 assert_eq!(result, Err(Error::InvalidPublicKey));
363 }
364
365 #[test]
366 fn test_identity_public_key_cannot_encrypt() {
367 identity_public_key_cannot_encrypt::<MinPk>();
368 identity_public_key_cannot_encrypt::<MinSig>();
369 }
370
371 #[test]
372 fn test_encrypt_decrypt_minpk() {
373 let mut rng = test_rng();
374
375 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
377
378 let target = 10u64.to_be_bytes();
380 let message = b"Hello, IBE! This is exactly 32b!"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
384
385 let ciphertext = encrypt::<_, MinPk>(
387 &mut rng,
388 master_public,
389 (b"_TLE_", &target),
390 &Block::new(*message),
391 )
392 .expect("encryption should succeed");
393
394 let decrypted =
396 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
397
398 assert_eq!(message.as_ref(), decrypted.as_ref());
399 }
400
401 #[test]
402 fn test_encrypt_decrypt_minsig() {
403 let mut rng = test_rng();
404
405 let (master_secret, master_public) = ops::keypair::<_, MinSig>(&mut rng);
407
408 let target = 20u64.to_be_bytes();
410 let message = b"Testing MinSig variant - 32 byte";
411
412 let signature = ops::sign_message::<MinSig>(&master_secret, b"_TLE_", &target);
414
415 let ciphertext = encrypt::<_, MinSig>(
417 &mut rng,
418 master_public,
419 (b"_TLE_", &target),
420 &Block::new(*message),
421 )
422 .expect("encryption should succeed");
423
424 let decrypted =
426 decrypt::<MinSig>(&signature, &ciphertext).expect("Decryption should succeed");
427
428 assert_eq!(message.as_ref(), decrypted.as_ref());
429 }
430
431 #[test]
432 fn test_wrong_private_key() {
433 let mut rng = test_rng();
434
435 let (_, master_public1) = ops::keypair::<_, MinPk>(&mut rng);
437 let (master_secret2, _) = ops::keypair::<_, MinPk>(&mut rng);
438
439 let target = 30u64.to_be_bytes();
440 let message = b"Secret message padded to 32bytes";
441
442 let ciphertext = encrypt::<_, MinPk>(
444 &mut rng,
445 master_public1,
446 (b"_TLE_", &target),
447 &Block::new(*message),
448 )
449 .expect("encryption should succeed");
450
451 let wrong_signature = ops::sign_message::<MinPk>(&master_secret2, b"_TLE_", &target);
453 let result = decrypt::<MinPk>(&wrong_signature, &ciphertext);
454
455 assert!(result.is_none());
456 }
457
458 #[test]
459 fn test_tampered_ciphertext() {
460 let mut rng = test_rng();
461
462 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
463 let target = 40u64.to_be_bytes();
464 let message = b"Tamper test padded to 32 bytes.."; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
468
469 let ciphertext = encrypt::<_, MinPk>(
471 &mut rng,
472 master_public,
473 (b"_TLE_", &target),
474 &Block::new(*message),
475 )
476 .expect("encryption should succeed");
477
478 let mut w_bytes = [0u8; BLOCK_SIZE];
480 w_bytes.copy_from_slice(ciphertext.w.as_ref());
481 w_bytes[0] ^= 0xFF;
482 let tampered_ciphertext = Ciphertext {
483 u: ciphertext.u,
484 v: ciphertext.v,
485 w: Block::new(w_bytes),
486 };
487
488 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
490 assert!(result.is_none());
491 }
492
493 #[test]
494 fn test_encrypt_decrypt_with_namespace() {
495 let mut rng = test_rng();
496
497 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
499
500 let namespace = b"example.org";
502 let target = 80u64.to_be_bytes();
503 let message = b"Message with namespace - 32 byte"; let signature = ops::sign_message::<MinPk>(&master_secret, namespace, &target);
507
508 let ciphertext = encrypt::<_, MinPk>(
510 &mut rng,
511 master_public,
512 (namespace, &target),
513 &Block::new(*message),
514 )
515 .expect("encryption should succeed");
516
517 let decrypted =
519 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
520
521 assert_eq!(message.as_ref(), decrypted.as_ref());
522 }
523
524 #[test]
525 fn test_namespace_variance() {
526 let mut rng = test_rng();
527
528 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
530
531 let namespace1 = b"example.org";
532 let namespace2 = b"other.org";
533 let target = 100u64.to_be_bytes();
534 let message = b"Namespace vs no namespace - 32by"; let signature_ns1 = ops::sign_message::<MinPk>(&master_secret, namespace1, &target);
538
539 let signature_ns2 = ops::sign_message::<MinPk>(&master_secret, namespace2, &target);
541
542 let ciphertext_ns1 = encrypt::<_, MinPk>(
544 &mut rng,
545 master_public,
546 (namespace1, &target),
547 &Block::new(*message),
548 )
549 .expect("encryption should succeed");
550
551 let ciphertext_ns2 = encrypt::<_, MinPk>(
553 &mut rng,
554 master_public,
555 (namespace2, &target),
556 &Block::new(*message),
557 )
558 .expect("encryption should succeed");
559
560 let result1 = decrypt::<MinPk>(&signature_ns2, &ciphertext_ns1);
562 assert!(result1.is_none());
563
564 let result2 = decrypt::<MinPk>(&signature_ns1, &ciphertext_ns2);
566 assert!(result2.is_none());
567
568 let decrypted_ns1 = decrypt::<MinPk>(&signature_ns1, &ciphertext_ns1)
570 .expect("Decryption with matching namespace should succeed");
571 let decrypted_ns2 = decrypt::<MinPk>(&signature_ns2, &ciphertext_ns2)
572 .expect("Decryption with matching namespace should succeed");
573
574 assert_eq!(message.as_ref(), decrypted_ns1.as_ref());
575 assert_eq!(message.as_ref(), decrypted_ns2.as_ref());
576 }
577
578 #[test]
579 fn test_cca_modified_v() {
580 let mut rng = test_rng();
581
582 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
583 let target = 110u64.to_be_bytes();
584 let message = b"Another CCA test message 32bytes"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
588
589 let ciphertext = encrypt::<_, MinPk>(
591 &mut rng,
592 master_public,
593 (b"_TLE_", &target),
594 &Block::new(*message),
595 )
596 .expect("encryption should succeed");
597
598 let mut v_bytes = [0u8; BLOCK_SIZE];
600 v_bytes.copy_from_slice(ciphertext.v.as_ref());
601 v_bytes[0] ^= 0x01;
602 let tampered_ciphertext = Ciphertext {
603 u: ciphertext.u,
604 v: Block::new(v_bytes),
605 w: ciphertext.w,
606 };
607
608 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
610 assert!(result.is_none());
611 }
612
613 #[test]
614 fn test_cca_modified_u() {
615 let mut rng = test_rng();
616
617 let (master_secret, master_public) = ops::keypair::<_, MinPk>(&mut rng);
618 let target = 70u64.to_be_bytes();
619 let message = b"CCA security test message 32 byt"; let signature = ops::sign_message::<MinPk>(&master_secret, b"_TLE_", &target);
623
624 let mut ciphertext = encrypt::<_, MinPk>(
626 &mut rng,
627 master_public,
628 (b"_TLE_", &target),
629 &Block::new(*message),
630 )
631 .expect("encryption should succeed");
632
633 let mut modified_u = ciphertext.u;
635 modified_u *= &Scalar::random(&mut rng);
636 ciphertext.u = modified_u;
637
638 let result = decrypt::<MinPk>(&signature, &ciphertext);
640 assert!(result.is_none());
641 }
642
643 #[cfg(feature = "arbitrary")]
644 mod conformance {
645 use super::*;
646 use commonware_codec::conformance::CodecConformance;
647
648 commonware_conformance::conformance_tests! {
649 CodecConformance<Ciphertext<MinPk>>,
650 }
651 }
652}