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};
90#[cfg(not(feature = "std"))]
91use alloc::vec::Vec;
92use bytes::{Buf, BufMut};
93use commonware_codec::{EncodeSize, FixedSize, Read, ReadExt, Write};
94use commonware_utils::sequence::FixedBytes;
95use rand_core::CryptoRngCore;
96
97const DST: DST = b"TLE_BLS12381_XMD:SHA-256_SSWU_RO_H3_";
99
100const BLOCK_SIZE: usize = Digest::SIZE;
102
103pub type Block = FixedBytes<BLOCK_SIZE>;
105
106impl From<Digest> for Block {
107 fn from(digest: Digest) -> Self {
108 Block::new(digest.0)
109 }
110}
111
112#[derive(Hash, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
114pub struct Ciphertext<V: Variant> {
115 pub u: V::Public,
117 pub v: Block,
119 pub w: Block,
121}
122
123impl<V: Variant> Write for Ciphertext<V> {
124 fn write(&self, buf: &mut impl BufMut) {
125 self.u.write(buf);
126 buf.put_slice(self.v.as_ref());
127 buf.put_slice(self.w.as_ref());
128 }
129}
130
131impl<V: Variant> Read for Ciphertext<V> {
132 type Cfg = ();
133
134 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, commonware_codec::Error> {
135 let u = V::Public::read(buf)?;
136 let v = Block::read(buf)?;
137 let w = Block::read(buf)?;
138 Ok(Self { u, v, w })
139 }
140}
141
142impl<V: Variant> EncodeSize for Ciphertext<V> {
143 fn encode_size(&self) -> usize {
144 self.u.encode_size() + self.v.encode_size() + self.w.encode_size()
145 }
146}
147
148mod hash {
150 use super::*;
151 use crate::{Hasher, Sha256};
152
153 pub fn h2(gt: >) -> Block {
157 let mut hasher = Sha256::new();
158 hasher.update(b"h2");
159 hasher.update(>.as_slice());
160 hasher.finalize().into()
161 }
162
163 pub fn h3(sigma: &Block, message: &[u8]) -> Scalar {
167 let mut combined = Vec::with_capacity(sigma.len() + message.len());
169 combined.extend_from_slice(sigma.as_ref());
170 combined.extend_from_slice(message);
171
172 Scalar::map(DST, &combined)
174 }
175
176 pub fn h4(sigma: &Block) -> Block {
180 let mut hasher = Sha256::new();
181 hasher.update(b"h4");
182 hasher.update(sigma.as_ref());
183 hasher.finalize().into()
184 }
185}
186
187#[inline]
193fn xor(a: &Block, b: &Block) -> Block {
194 let a_bytes = a.as_ref();
195 let b_bytes = b.as_ref();
196
197 Block::new([
200 a_bytes[0] ^ b_bytes[0],
201 a_bytes[1] ^ b_bytes[1],
202 a_bytes[2] ^ b_bytes[2],
203 a_bytes[3] ^ b_bytes[3],
204 a_bytes[4] ^ b_bytes[4],
205 a_bytes[5] ^ b_bytes[5],
206 a_bytes[6] ^ b_bytes[6],
207 a_bytes[7] ^ b_bytes[7],
208 a_bytes[8] ^ b_bytes[8],
209 a_bytes[9] ^ b_bytes[9],
210 a_bytes[10] ^ b_bytes[10],
211 a_bytes[11] ^ b_bytes[11],
212 a_bytes[12] ^ b_bytes[12],
213 a_bytes[13] ^ b_bytes[13],
214 a_bytes[14] ^ b_bytes[14],
215 a_bytes[15] ^ b_bytes[15],
216 a_bytes[16] ^ b_bytes[16],
217 a_bytes[17] ^ b_bytes[17],
218 a_bytes[18] ^ b_bytes[18],
219 a_bytes[19] ^ b_bytes[19],
220 a_bytes[20] ^ b_bytes[20],
221 a_bytes[21] ^ b_bytes[21],
222 a_bytes[22] ^ b_bytes[22],
223 a_bytes[23] ^ b_bytes[23],
224 a_bytes[24] ^ b_bytes[24],
225 a_bytes[25] ^ b_bytes[25],
226 a_bytes[26] ^ b_bytes[26],
227 a_bytes[27] ^ b_bytes[27],
228 a_bytes[28] ^ b_bytes[28],
229 a_bytes[29] ^ b_bytes[29],
230 a_bytes[30] ^ b_bytes[30],
231 a_bytes[31] ^ b_bytes[31],
232 ])
233}
234
235pub fn encrypt<R: CryptoRngCore, V: Variant>(
253 rng: &mut R,
254 public: V::Public,
255 target: (Option<&[u8]>, &[u8]),
256 message: &Block,
257) -> Ciphertext<V> {
258 let q_id = match target {
260 (None, target) => hash_message::<V>(V::MESSAGE, target),
261 (Some(namespace), target) => hash_message_namespace::<V>(V::MESSAGE, namespace, target),
262 };
263
264 let mut sigma_array = [0u8; BLOCK_SIZE];
266 rng.fill_bytes(&mut sigma_array);
267 let sigma = Block::new(sigma_array);
268
269 let r = hash::h3(&sigma, message.as_ref());
271
272 let mut u = V::Public::one();
274 u.mul(&r);
275
276 let mut r_pub = public;
278 r_pub.mul(&r);
279 let gt = V::pairing(&r_pub, &q_id);
280
281 let h2_value = hash::h2(>);
283 let v = xor(&sigma, &h2_value);
284
285 let h4_value = hash::h4(&sigma);
287 let w = xor(message, &h4_value);
288
289 Ciphertext { u, v, w }
290}
291
292pub fn decrypt<V: Variant>(signature: &V::Signature, ciphertext: &Ciphertext<V>) -> Option<Block> {
308 let gt = V::pairing(&ciphertext.u, signature);
310
311 let h2_value = hash::h2(>);
313 let sigma = xor(&ciphertext.v, &h2_value);
314
315 let h4_value = hash::h4(&sigma);
317 let message = xor(&ciphertext.w, &h4_value);
318
319 let r = hash::h3(&sigma, &message);
321 let mut expected_u = V::Public::one();
322 expected_u.mul(&r);
323 if ciphertext.u != expected_u {
324 return None;
325 }
326
327 Some(message)
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333 use crate::bls12381::primitives::{
334 ops::{keypair, sign_message},
335 variant::{MinPk, MinSig},
336 };
337 use rand::thread_rng;
338
339 #[test]
340 fn test_encrypt_decrypt_minpk() {
341 let mut rng = thread_rng();
342
343 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
345
346 let target = 10u64.to_be_bytes();
348 let message = b"Hello, IBE! This is exactly 32b!"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
352
353 let ciphertext = encrypt::<_, MinPk>(
355 &mut rng,
356 master_public,
357 (None, &target),
358 &Block::new(*message),
359 );
360
361 let decrypted =
363 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
364
365 assert_eq!(message.as_ref(), decrypted.as_ref());
366 }
367
368 #[test]
369 fn test_encrypt_decrypt_minsig() {
370 let mut rng = thread_rng();
371
372 let (master_secret, master_public) = keypair::<_, MinSig>(&mut rng);
374
375 let target = 20u64.to_be_bytes();
377 let message = b"Testing MinSig variant - 32 byte";
378
379 let signature = sign_message::<MinSig>(&master_secret, None, &target);
381
382 let ciphertext = encrypt::<_, MinSig>(
384 &mut rng,
385 master_public,
386 (None, &target),
387 &Block::new(*message),
388 );
389
390 let decrypted =
392 decrypt::<MinSig>(&signature, &ciphertext).expect("Decryption should succeed");
393
394 assert_eq!(message.as_ref(), decrypted.as_ref());
395 }
396
397 #[test]
398 fn test_wrong_private_key() {
399 let mut rng = thread_rng();
400
401 let (_, master_public1) = keypair::<_, MinPk>(&mut rng);
403 let (master_secret2, _) = keypair::<_, MinPk>(&mut rng);
404
405 let target = 30u64.to_be_bytes();
406 let message = b"Secret message padded to 32bytes";
407
408 let ciphertext = encrypt::<_, MinPk>(
410 &mut rng,
411 master_public1,
412 (None, &target),
413 &Block::new(*message),
414 );
415
416 let wrong_signature = sign_message::<MinPk>(&master_secret2, None, &target);
418 let result = decrypt::<MinPk>(&wrong_signature, &ciphertext);
419
420 assert!(result.is_none());
421 }
422
423 #[test]
424 fn test_tampered_ciphertext() {
425 let mut rng = thread_rng();
426
427 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
428 let target = 40u64.to_be_bytes();
429 let message = b"Tamper test padded to 32 bytes.."; let signature = sign_message::<MinPk>(&master_secret, None, &target);
433
434 let ciphertext = encrypt::<_, MinPk>(
436 &mut rng,
437 master_public,
438 (None, &target),
439 &Block::new(*message),
440 );
441
442 let mut w_bytes = [0u8; BLOCK_SIZE];
444 w_bytes.copy_from_slice(ciphertext.w.as_ref());
445 w_bytes[0] ^= 0xFF;
446 let tampered_ciphertext = Ciphertext {
447 u: ciphertext.u,
448 v: ciphertext.v,
449 w: Block::new(w_bytes),
450 };
451
452 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
454 assert!(result.is_none());
455 }
456
457 #[test]
458 fn test_encrypt_decrypt_with_namespace() {
459 let mut rng = thread_rng();
460
461 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
463
464 let namespace = b"example.org";
466 let target = 80u64.to_be_bytes();
467 let message = b"Message with namespace - 32 byte"; let signature = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
471
472 let ciphertext = encrypt::<_, MinPk>(
474 &mut rng,
475 master_public,
476 (Some(namespace), &target),
477 &Block::new(*message),
478 );
479
480 let decrypted =
482 decrypt::<MinPk>(&signature, &ciphertext).expect("Decryption should succeed");
483
484 assert_eq!(message.as_ref(), decrypted.as_ref());
485 }
486
487 #[test]
488 fn test_namespace_variance() {
489 let mut rng = thread_rng();
490
491 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
493
494 let namespace = b"example.org";
495 let target = 100u64.to_be_bytes();
496 let message = b"Namespace vs no namespace - 32by"; let signature_no_ns = sign_message::<MinPk>(&master_secret, None, &target);
500
501 let signature_ns = sign_message::<MinPk>(&master_secret, Some(namespace), &target);
503
504 let ciphertext_ns = encrypt::<_, MinPk>(
506 &mut rng,
507 master_public,
508 (Some(namespace), &target),
509 &Block::new(*message),
510 );
511
512 let ciphertext_no_ns = encrypt::<_, MinPk>(
514 &mut rng,
515 master_public,
516 (None, &target),
517 &Block::new(*message),
518 );
519
520 let result1 = decrypt::<MinPk>(&signature_no_ns, &ciphertext_ns);
522 assert!(result1.is_none());
523
524 let result2 = decrypt::<MinPk>(&signature_ns, &ciphertext_no_ns);
526 assert!(result2.is_none());
527
528 let decrypted_ns = decrypt::<MinPk>(&signature_ns, &ciphertext_ns)
530 .expect("Decryption with matching namespace should succeed");
531 let decrypted_no_ns = decrypt::<MinPk>(&signature_no_ns, &ciphertext_no_ns)
532 .expect("Decryption without namespace should succeed");
533
534 assert_eq!(message.as_ref(), decrypted_ns.as_ref());
535 assert_eq!(message.as_ref(), decrypted_no_ns.as_ref());
536 }
537
538 #[test]
539 fn test_cca_modified_v() {
540 let mut rng = thread_rng();
541
542 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
543 let target = 110u64.to_be_bytes();
544 let message = b"Another CCA test message 32bytes"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
548
549 let ciphertext = encrypt::<_, MinPk>(
551 &mut rng,
552 master_public,
553 (None, &target),
554 &Block::new(*message),
555 );
556
557 let mut v_bytes = [0u8; BLOCK_SIZE];
559 v_bytes.copy_from_slice(ciphertext.v.as_ref());
560 v_bytes[0] ^= 0x01;
561 let tampered_ciphertext = Ciphertext {
562 u: ciphertext.u,
563 v: Block::new(v_bytes),
564 w: ciphertext.w,
565 };
566
567 let result = decrypt::<MinPk>(&signature, &tampered_ciphertext);
569 assert!(result.is_none());
570 }
571
572 #[test]
573 fn test_cca_modified_u() {
574 let mut rng = thread_rng();
575
576 let (master_secret, master_public) = keypair::<_, MinPk>(&mut rng);
577 let target = 70u64.to_be_bytes();
578 let message = b"CCA security test message 32 byt"; let signature = sign_message::<MinPk>(&master_secret, None, &target);
582
583 let mut ciphertext = encrypt::<_, MinPk>(
585 &mut rng,
586 master_public,
587 (None, &target),
588 &Block::new(*message),
589 );
590
591 let mut modified_u = ciphertext.u;
593 modified_u.mul(&Scalar::from_rand(&mut rng));
594 ciphertext.u = modified_u;
595
596 let result = decrypt::<MinPk>(&signature, &ciphertext);
598 assert!(result.is_none());
599 }
600}