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