1use crate::{
3 encryption::aes::*,
4 ibe::fullident::{Ibe, IbeCiphertext},
5 utils::{convert_to_bytes, hash_to_g1},
6};
7use ark_bls12_381::{G1Affine as G1, G2Affine as G2, Fr};
8use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
9use serde::{Deserialize, Serialize};
11
12use ark_std::{
13 marker::PhantomData,
14 vec::Vec,
15 rand::{CryptoRng, Rng},
16};
17
18#[derive(Serialize, Deserialize, Debug)]
19pub struct AesIbeCt {
20 pub aes_ct: AESOutput,
21 pub etf_ct: Vec<Vec<u8>>
22}
23
24#[derive(Debug, PartialEq)]
25pub enum ClientError {
26 AesEncryptError,
27 DeserializationError,
28 DeserializationErrorG1,
29 DeserializationErrorG2,
30 DeserializationErrorFr,
31 DecryptionError,
32}
33
34pub trait EtfClient<I: Ibe> {
35
36 fn encrypt<R: Rng + CryptoRng + Sized>(
37 ibe_pp: Vec<u8>,
38 p_pub: Vec<u8>,
39 message: &[u8],
40 ids: Vec<Vec<u8>>,
41 t: u8,
42 rng: R,
43 ) -> Result<AesIbeCt, ClientError>;
44
45 fn decrypt(
46 ibe_pp: Vec<u8>,
47 ciphertext: Vec<u8>,
48 nonce: Vec<u8>,
49 capsule: Vec<Vec<u8>>,
50 secrets: Vec<Vec<u8>>,
51 ) -> Result<Vec<u8>, ClientError>;
52}
53
54pub struct DefaultEtfClient<I> {
55 _i: PhantomData<I>,
56}
57
58impl<I: Ibe> EtfClient<I> for DefaultEtfClient<I> {
61
62 fn encrypt<R: Rng + CryptoRng + Sized>(
72 ibe_pp: Vec<u8>,
73 p_pub: Vec<u8>,
74 message: &[u8],
75 ids: Vec<Vec<u8>>,
76 t: u8,
77 mut rng: R,
78 ) -> Result<AesIbeCt, ClientError> {
79 let p = G2::deserialize_compressed(&ibe_pp[..])
82 .map_err(|_| ClientError::DeserializationError)?;
83 let q = G2::deserialize_compressed(&p_pub[..])
84 .map_err(|_| ClientError::DeserializationError)?;
85 let (msk, shares) = generate_secrets(ids.len() as u8, t, &mut rng);
89 let msk_bytes = convert_to_bytes::<Fr, 32>(msk);
90 let ct_aes = encrypt(message, msk_bytes, &mut rng)
93 .map_err(|_| ClientError::AesEncryptError)?;
94
95 let mut out: Vec<Vec<u8>> = Vec::new();
96 for (idx, id) in ids.iter().enumerate() {
97 let b = convert_to_bytes::<Fr, 32>(shares[idx].1).to_vec();
98 let id_point = hash_to_g1(id);
99 let ct =
100 I::encrypt(
101 p.into(),
102 q.into(),
103 &b.try_into().unwrap(),
104 id_point.into(), &
105 mut rng,
106 );
107 let mut o = Vec::with_capacity(ct.compressed_size());
108 ct.serialize_compressed(&mut o).unwrap();
110 out.push(o);
111 }
112 Ok(AesIbeCt{ aes_ct: ct_aes, etf_ct: out })
113 }
114
115 fn decrypt(
125 ibe_pp: Vec<u8>,
126 ciphertext: Vec<u8>,
127 nonce: Vec<u8>,
128 capsule: Vec<Vec<u8>>,
129 secrets: Vec<Vec<u8>>,
130 ) -> Result<Vec<u8>, ClientError> {
131 let mut dec_secrets: Vec<(Fr, Fr)> = Vec::new();
132 let p = G2::deserialize_compressed(&ibe_pp[..])
133 .map_err(|_| ClientError::DeserializationErrorG2)?;
134 for (idx, e) in capsule.iter().enumerate() {
135 let ct = IbeCiphertext::deserialize_compressed(&e[..])
137 .map_err(|_| ClientError::DeserializationError)?;
138 let sk = G1::deserialize_compressed(&secrets[idx][..])
139 .map_err(|_| ClientError::DeserializationErrorG1)?;
140 let share_bytes = I::decrypt(p.into(), ct, sk.into());
141 let share = Fr::deserialize_compressed(&share_bytes[..])
143 .map_err(|_| ClientError::DeserializationErrorFr)?;
144 dec_secrets.push((Fr::from((idx + 1) as u8), share));
145 }
146 let secret_scalar = interpolate(dec_secrets);
147 let o = convert_to_bytes::<Fr, 32>(secret_scalar);
148 let plaintext = decrypt(ciphertext, &nonce, &o)
149 .map_err(|_| ClientError::DecryptionError)?;
150
151 Ok(plaintext)
152 }
153}
154
155
156#[cfg(test)]
157mod test {
158
159 use super::*;
160 use ark_std::{
161 rand::SeedableRng,
162 test_rng,
163 ops::Mul,
164 };
165 use ark_bls12_381::{Fr, G2Projective as G2};
166 use ark_ff::UniformRand;
167 use ark_ec::Group;
168 use rand_chacha::ChaCha20Rng;
169 use crate::ibe::fullident::BfIbe;
170 use crate::utils::hash_to_g1;
171
172 #[test]
173 pub fn client_can_encrypt_decrypt_with_single_key() {
174 let rng = ChaCha20Rng::from_seed([4;32]);
175 let message = b"this is a test";
176 let ids = vec![
177 b"id1".to_vec(),
178 ];
179 let t = 1;
180
181 let ibe_pp: G2 = G2::generator().into();
182 let s = Fr::rand(&mut test_rng());
183 let p_pub: G2 = ibe_pp.mul(s).into();
184
185 let ibe_pp_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
186 let p_pub_bytes = convert_to_bytes::<G2, 96>(p_pub);
187
188 match DefaultEtfClient::<BfIbe>::encrypt(
189 ibe_pp_bytes.to_vec(), p_pub_bytes.to_vec(),
190 message, ids.clone(), t, rng,
191 ) {
192 Ok(ct) => {
193 let secrets: Vec<Vec<u8>> = ids.iter().map(|id| {
195 let q = hash_to_g1(&id);
196 let d = q.mul(s);
197 convert_to_bytes::<G1, 48>(d.into()).to_vec()
198 }).collect::<Vec<_>>();
199 match DefaultEtfClient::<BfIbe>::decrypt(
200 ibe_pp_bytes.to_vec(), ct.aes_ct.ciphertext, ct.aes_ct.nonce, ct.etf_ct, secrets,
201 ) {
202 Ok(m) => {
203 assert_eq!(message.to_vec(), m);
204 },
205 Err(e) => {
206 panic!("Decryption should work but was: {:?}", e);
207 }
208 }
209 },
210 Err(e) => {
211 panic!("Encryption should work but was {:?}", e);
212 }
213 }
214
215 }
216
217 #[test]
218 pub fn client_can_encrypt_decrypt_with_many_keys() {
219 let rng = ChaCha20Rng::from_seed([4;32]);
220 let message = b"this is a test";
221 let ids = vec![
222 b"id1".to_vec(),
223 b"id2".to_vec(),
224 b"id3".to_vec(),
225 ];
226 let t = 2;
227
228 let ibe_pp: G2 = G2::generator().into();
229 let s = Fr::rand(&mut test_rng());
230 let p_pub: G2 = ibe_pp.mul(s).into();
231
232 let ibe_pp_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
233 let p_pub_bytes = convert_to_bytes::<G2, 96>(p_pub);
234
235 match DefaultEtfClient::<BfIbe>::encrypt(
236 ibe_pp_bytes.to_vec(), p_pub_bytes.to_vec(),
237 message, ids.clone(), t, rng
238 ) {
239 Ok(ct) => {
240 let secrets: Vec<Vec<u8>> = ids.iter().map(|id| {
242 let q = hash_to_g1(&id);
243 let d = q.mul(s);
244 convert_to_bytes::<G1, 48>(d.into()).to_vec()
245 }).collect::<Vec<_>>();
246 match DefaultEtfClient::<BfIbe>::decrypt(
247 ibe_pp_bytes.to_vec(), ct.aes_ct.ciphertext, ct.aes_ct.nonce, ct.etf_ct, secrets,
248 ) {
249 Ok(m) => {
250 assert_eq!(message.to_vec(), m);
251 },
252 Err(e) => {
253 panic!("Decryption should work but was: {:?}", e);
254 }
255 }
256 },
257 Err(e) => {
258 panic!("Encryption should work but was {:?}", e);
259 }
260 }
261 }
262
263 #[test]
264 pub fn client_encrypt_fails_with_bad_encoding() {
265 let rng = ChaCha20Rng::from_seed([4;32]);
266 let ibe_pp: G2 = G2::generator();
267 let p_pub_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
268
269 match DefaultEtfClient::<BfIbe>::encrypt(
271 vec![],
272 p_pub_bytes.to_vec(),
273 b"test", vec![], 2, rng.clone()
274 ) {
275 Ok(_) => {
276 panic!("should be an error");
277 },
278 Err(e) => {
279 assert_eq!(e, ClientError::DeserializationError);
280 }
281 }
282
283 match DefaultEtfClient::<BfIbe>::encrypt(
285 p_pub_bytes.to_vec(),
286 vec![],
287 b"test", vec![], 2, rng,
288 ) {
289 Ok(_) => {
290 panic!("should be an error");
291 },
292 Err(e) => {
293 assert_eq!(e, ClientError::DeserializationError);
294 }
295 }
296 }
297
298 #[test]
299 pub fn client_decrypt_fails_with_bad_encoding_p() {
300 match DefaultEtfClient::<BfIbe>::decrypt(
302 vec![], vec![], vec![], vec![], vec![],
303 ) {
304 Ok(_) => {
305 panic!("should be an error");
306 },
307 Err(e) => {
308 assert_eq!(e, ClientError::DeserializationErrorG2);
309 }
310 }
311 }
312
313 #[test]
314 pub fn client_decrypt_fails_with_bad_encoded_capsule_ct() {
315 let ibe_pp: G2 = G2::generator();
316 let p_pub_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
317 let cap = vec![vec![1,2,3]];
318 match DefaultEtfClient::<BfIbe>::decrypt(
320 p_pub_bytes.to_vec(), vec![], vec![], cap, vec![],
321 ) {
322 Ok(_) => {
323 panic!("should be an error");
324 },
325 Err(e) => {
326 assert_eq!(e, ClientError::DeserializationError);
327 }
328 }
329 }
330
331 #[test]
332 pub fn client_decrypt_fails_with_bad_slot_secrets() {
333 let message = b"this is a test";
334 let ids = vec![
335 b"id1".to_vec(),
336 b"id2".to_vec(),
337 b"id3".to_vec(),
338 ];
339 let t = 2;
340
341 let rng = ChaCha20Rng::from_seed([4;32]);
342
343 let ibe_pp: G2 = G2::generator().into();
344 let s = Fr::rand(&mut test_rng());
345 let p_pub: G2 = ibe_pp.mul(s).into();
346
347 let ibe_pp_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
348 let p_pub_bytes = convert_to_bytes::<G2, 96>(p_pub);
349
350 match DefaultEtfClient::<BfIbe>::encrypt(
351 ibe_pp_bytes.to_vec(), p_pub_bytes.to_vec(),
352 message, ids.clone(), t, rng,
353 ) {
354 Ok(ct) => {
355 let b = Fr::rand(&mut test_rng());
357 let secrets: Vec<Vec<u8>> = ids.iter().map(|id| {
358 let q = hash_to_g1(&id);
359 let d = q.mul(b);
360 convert_to_bytes::<G1, 48>(d.into()).to_vec()
361 }).collect::<Vec<_>>();
362 match DefaultEtfClient::<BfIbe>::decrypt(
363 ibe_pp_bytes.to_vec(), vec![],
364 ct.aes_ct.nonce, ct.etf_ct, secrets,
365 ) {
366 Ok(_) => {
367 panic!("should be an error");
368 },
369 Err(e) => {
370 assert_eq!(e, ClientError::DecryptionError);
371 }
372 }
373 },
374 Err(e) => {
375 panic!("Encryption should work but was {:?}", e);
376 }
377 }
378 }
379
380 #[test]
381 pub fn client_decrypt_fails_with_bad_nonce() {
382 let message = b"this is a test";
383 let ids = vec![
384 b"id1".to_vec(),
385 b"id2".to_vec(),
386 b"id3".to_vec(),
387 ];
388 let t = 2;
389 let rng = ChaCha20Rng::from_seed([4;32]);
390 let ibe_pp: G2 = G2::generator().into();
391 let s = Fr::rand(&mut test_rng());
392 let p_pub: G2 = ibe_pp.mul(s).into();
393
394 let ibe_pp_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
395 let p_pub_bytes = convert_to_bytes::<G2, 96>(p_pub);
396
397 match DefaultEtfClient::<BfIbe>::encrypt(
398 ibe_pp_bytes.to_vec(), p_pub_bytes.to_vec(),
399 message, ids.clone(), t, rng,
400 ) {
401 Ok(ct) => {
402 let secrets: Vec<Vec<u8>> = ids.iter().map(|id| {
404 let q = hash_to_g1(&id);
405 let d = q.mul(s);
406 convert_to_bytes::<G1, 48>(d.into()).to_vec()
407 }).collect::<Vec<_>>();
408 match DefaultEtfClient::<BfIbe>::decrypt(
409 ibe_pp_bytes.to_vec(), ct.aes_ct.ciphertext,
410 vec![0,0,0,0,0,0,0,0,0,0,0,0], ct.etf_ct, secrets,
411 ) {
412 Ok(_) => {
413 panic!("should be an error");
414 },
415 Err(e) => {
416 assert_eq!(e, ClientError::DecryptionError);
417 }
418 }
419 },
420 Err(e) => {
421 panic!("Encryption should work but was {:?}", e);
422 }
423 }
424 }
425
426 #[test]
427 pub fn client_decrypt_fails_with_bad_ciphertext() {
428 let message = b"this is a test";
429 let ids = vec![
430 b"id1".to_vec(),
431 b"id2".to_vec(),
432 b"id3".to_vec(),
433 ];
434 let t = 2;
435 let rng = ChaCha20Rng::from_seed([4;32]);
436 let ibe_pp: G2 = G2::generator().into();
437 let s = Fr::rand(&mut test_rng());
438 let p_pub: G2 = ibe_pp.mul(s).into();
439
440 let ibe_pp_bytes = convert_to_bytes::<G2, 96>(ibe_pp);
441 let p_pub_bytes = convert_to_bytes::<G2, 96>(p_pub);
442
443 match DefaultEtfClient::<BfIbe>::encrypt(
444 ibe_pp_bytes.to_vec(),
445 p_pub_bytes.to_vec(),
446 message,
447 ids.clone(),
448 t,
449 rng,
450 ) {
451 Ok(ct) => {
452 let secrets: Vec<Vec<u8>> = ids.iter().map(|id| {
454 let q = hash_to_g1(&id);
455 let d = q.mul(s);
456 convert_to_bytes::<G1, 48>(d.into()).to_vec()
457 }).collect::<Vec<_>>();
458 match DefaultEtfClient::<BfIbe>::decrypt(
459 ibe_pp_bytes.to_vec(), vec![],
460 ct.aes_ct.nonce, ct.etf_ct, secrets,
461 ) {
462 Ok(_) => {
463 panic!("should be an error");
464 },
465 Err(e) => {
466 assert_eq!(e, ClientError::DecryptionError);
467 }
468 }
469 },
470 Err(e) => {
471 panic!("Encryption should work but was {:?}", e);
472 }
473 }
474 }
475}