1use crate::{
83 bls12381::primitives::{
84 group::{Scalar, DST, GT},
85 ops::{hash_message, hash_message_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;
97
98const DST: DST = b"TLE_BLS12381_XMD:SHA-256_SSWU_RO_H3_";
100
101const BLOCK_SIZE: usize = Digest::SIZE;
103
104pub type Block = FixedBytes<BLOCK_SIZE>;
106
107impl From<Digest> for Block {
108 fn from(digest: Digest) -> Self {
109 Block::new(digest.0)
110 }
111}
112
113#[derive(Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
115pub struct Ciphertext<V: Variant> {
116 pub u: V::Public,
118 pub v: Block,
120 pub w: Block,
122}
123
124impl<V: Variant> Write for Ciphertext<V> {
125 fn write(&self, buf: &mut impl BufMut) {
126 self.u.write(buf);
127 buf.put_slice(self.v.as_ref());
128 buf.put_slice(self.w.as_ref());
129 }
130}
131
132impl<V: Variant> Read for Ciphertext<V> {
133 type Cfg = ();
134
135 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
136 let u = V::Public::read(buf)?;
137 let v = Block::read(buf)?;
138 let w = Block::read(buf)?;
139 Ok(Self { u, v, w })
140 }
141}
142
143impl<V: Variant> EncodeSize for Ciphertext<V> {
144 fn encode_size(&self) -> usize {
145 self.u.encode_size() + self.v.encode_size() + self.w.encode_size()
146 }
147}
148
149#[cfg(feature = "arbitrary")]
150impl<V: Variant> arbitrary::Arbitrary<'_> for Ciphertext<V>
151where
152 V::Public: for<'a> arbitrary::Arbitrary<'a>,
153{
154 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
155 let ge = u.arbitrary()?;
156 let v = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
157 let w = FixedBytes::new(<[u8; BLOCK_SIZE]>::arbitrary(u)?);
158 Ok(Self { u: ge, v, w })
159 }
160}
161
162mod hash {
164 use super::*;
165 use crate::{Hasher, Sha256};
166
167 pub fn h2(gt: >) -> Block {
171 let mut hasher = Sha256::new();
172 hasher.update(b"h2");
173 hasher.update(>.as_slice());
174 hasher.finalize().into()
175 }
176
177 pub fn h3(sigma: &Block, message: &[u8]) -> Scalar {
181 let mut combined = Vec::with_capacity(sigma.len() + message.len());
183 combined.extend_from_slice(sigma.as_ref());
184 combined.extend_from_slice(message);
185
186 Scalar::map(DST, &combined)
191 }
192
193 pub fn h4(sigma: &Block) -> Block {
197 let mut hasher = Sha256::new();
198 hasher.update(b"h4");
199 hasher.update(sigma.as_ref());
200 hasher.finalize().into()
201 }
202}
203
204#[inline]
210fn xor(a: &Block, b: &Block) -> Block {
211 let a_bytes = a.as_ref();
212 let b_bytes = b.as_ref();
213
214 Block::new([
217 a_bytes[0] ^ b_bytes[0],
218 a_bytes[1] ^ b_bytes[1],
219 a_bytes[2] ^ b_bytes[2],
220 a_bytes[3] ^ b_bytes[3],
221 a_bytes[4] ^ b_bytes[4],
222 a_bytes[5] ^ b_bytes[5],
223 a_bytes[6] ^ b_bytes[6],
224 a_bytes[7] ^ b_bytes[7],
225 a_bytes[8] ^ b_bytes[8],
226 a_bytes[9] ^ b_bytes[9],
227 a_bytes[10] ^ b_bytes[10],
228 a_bytes[11] ^ b_bytes[11],
229 a_bytes[12] ^ b_bytes[12],
230 a_bytes[13] ^ b_bytes[13],
231 a_bytes[14] ^ b_bytes[14],
232 a_bytes[15] ^ b_bytes[15],
233 a_bytes[16] ^ b_bytes[16],
234 a_bytes[17] ^ b_bytes[17],
235 a_bytes[18] ^ b_bytes[18],
236 a_bytes[19] ^ b_bytes[19],
237 a_bytes[20] ^ b_bytes[20],
238 a_bytes[21] ^ b_bytes[21],
239 a_bytes[22] ^ b_bytes[22],
240 a_bytes[23] ^ b_bytes[23],
241 a_bytes[24] ^ b_bytes[24],
242 a_bytes[25] ^ b_bytes[25],
243 a_bytes[26] ^ b_bytes[26],
244 a_bytes[27] ^ b_bytes[27],
245 a_bytes[28] ^ b_bytes[28],
246 a_bytes[29] ^ b_bytes[29],
247 a_bytes[30] ^ b_bytes[30],
248 a_bytes[31] ^ b_bytes[31],
249 ])
250}
251
252pub fn encrypt<R: CryptoRngCore, V: Variant>(
270 rng: &mut R,
271 public: V::Public,
272 target: (Option<&[u8]>, &[u8]),
273 message: &Block,
274) -> Ciphertext<V> {
275 let q_id = match target {
277 (None, target) => hash_message::<V>(V::MESSAGE, target),
278 (Some(namespace), target) => hash_message_namespace::<V>(V::MESSAGE, namespace, target),
279 };
280
281 let mut sigma_array = [0u8; BLOCK_SIZE];
283 rng.fill_bytes(&mut sigma_array);
284 let sigma = 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 = hash::h2(>);
302 let v = xor(&sigma, &h2_value);
303
304 let h4_value = 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::{keypair, sign_message},
354 variant::{MinPk, MinSig},
355 };
356 use commonware_math::algebra::Random as _;
357 use rand::thread_rng;
358
359 #[test]
360 fn test_encrypt_decrypt_minpk() {
361 let mut rng = thread_rng();
362
363 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
365
366 let target = 10u64.to_be_bytes();
368 let message = b"Hello, IBE! This is exactly 32b!"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
372
373 let ciphertext = encrypt::<_, MinPk>(
375 &mut rng,
376 master_public,
377 (None, &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 = thread_rng();
391
392 let (master_secret, master_public) = 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 = sign_message::<MinSig>(&master_secret, None, &target);
401
402 let ciphertext = encrypt::<_, MinSig>(
404 &mut rng,
405 master_public,
406 (None, &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 = thread_rng();
420
421 let (_, master_public1) = keypair::<_, MinPk>(&mut rng);
423 let (master_secret2, _) = 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 (None, &target),
433 &Block::new(*message),
434 );
435
436 let wrong_signature = sign_message::<MinPk>(&master_secret2, None, &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 = thread_rng();
446
447 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
448 let target = 40u64.to_be_bytes();
449 let message = b"Tamper test padded to 32 bytes.."; let signature = sign_message::<MinPk>(&master_secret, None, &target);
453
454 let ciphertext = encrypt::<_, MinPk>(
456 &mut rng,
457 master_public,
458 (None, &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 = thread_rng();
480
481 let (master_secret, master_public) = 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 = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
491
492 let ciphertext = encrypt::<_, MinPk>(
494 &mut rng,
495 master_public,
496 (Some(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 = thread_rng();
510
511 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
513
514 let namespace = b"example.org";
515 let target = 100u64.to_be_bytes();
516 let message = b"Namespace vs no namespace - 32by"; let signature_no_ns = sign_message::<MinPk>(&master_secret, None, &target);
520
521 let signature_ns = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
523
524 let ciphertext_ns = encrypt::<_, MinPk>(
526 &mut rng,
527 master_public,
528 (Some(namespace), &target),
529 &Block::new(*message),
530 );
531
532 let ciphertext_no_ns = encrypt::<_, MinPk>(
534 &mut rng,
535 master_public,
536 (None, &target),
537 &Block::new(*message),
538 );
539
540 let result1 = decrypt::<MinPk>(&signature_no_ns, &ciphertext_ns);
542 assert!(result1.is_none());
543
544 let result2 = decrypt::<MinPk>(&signature_ns, &ciphertext_no_ns);
546 assert!(result2.is_none());
547
548 let decrypted_ns = decrypt::<MinPk>(&signature_ns, &ciphertext_ns)
550 .expect("Decryption with matching namespace should succeed");
551 let decrypted_no_ns = decrypt::<MinPk>(&signature_no_ns, &ciphertext_no_ns)
552 .expect("Decryption without namespace should succeed");
553
554 assert_eq!(message.as_ref(), decrypted_ns.as_ref());
555 assert_eq!(message.as_ref(), decrypted_no_ns.as_ref());
556 }
557
558 #[test]
559 fn test_cca_modified_v() {
560 let mut rng = thread_rng();
561
562 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
563 let target = 110u64.to_be_bytes();
564 let message = b"Another CCA test message 32bytes"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
568
569 let ciphertext = encrypt::<_, MinPk>(
571 &mut rng,
572 master_public,
573 (None, &target),
574 &Block::new(*message),
575 );
576
577 let mut v_bytes = [0u8; BLOCK_SIZE];
579 v_bytes.copy_from_slice(ciphertext.v.as_ref());
580 v_bytes[0] ^= 0x01;
581 let tampered_ciphertext = Ciphertext {
582 u: ciphertext.u,
583 v: Block::new(v_bytes),
584 w: ciphertext.w,
585 };
586
587 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
589 assert!(result.is_none());
590 }
591
592 #[test]
593 fn test_cca_modified_u() {
594 let mut rng = thread_rng();
595
596 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
597 let target = 70u64.to_be_bytes();
598 let message = b"CCA security test message 32 byt"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
602
603 let mut ciphertext = encrypt::<_, MinPk>(
605 &mut rng,
606 master_public,
607 (None, &target),
608 &Block::new(*message),
609 );
610
611 let mut modified_u = ciphertext.u;
613 modified_u *= &Scalar::random(&mut rng);
614 ciphertext.u = modified_u;
615
616 let result = decrypt::<MinPk>(&signature, &ciphertext);
618 assert!(result.is_none());
619 }
620
621 #[cfg(feature = "arbitrary")]
622 mod conformance {
623 use super::*;
624 use commonware_codec::conformance::CodecConformance;
625
626 commonware_conformance::conformance_tests! {
627 CodecConformance<Ciphertext<MinPk>>,
628 }
629 }
630}