etf_crypto_primitives/client/
etf_client.rs

1/// ETF CLIENT
2use 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};
9// use aes_gcm::aead::OsRng;
10use 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
58/// a clent to setup and perform IBE functions
59/// uses known generator of G2 and other ranomd generator point
60impl<I: Ibe> EtfClient<I> for DefaultEtfClient<I> {
61
62    /// Encrypts a message using AES-GCM, with the secret key having been generated via SSS
63    /// Then, encrypt each share for the input ids (assumes sequential)
64    /// 
65    /// * `ibe_pp`: the public paramter of the BF IBE, in G2
66    /// * `p_pub`: ibe_pp * msk
67    /// * `message`: The message to encrypt
68    /// * `ids`: The ids to encrypt the message for
69    /// * `t`: The threshold (when splitting the secret)
70    ///
71    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        // todo: verify: t < |ids|
80        // todo: verify public params, error handling
81        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        // if there is only one id, then shares = [msk]
86        // and when we loop over the shares and encrypt w/ IBE
87        // then we encrypt the msk directly instead
88        let (msk, shares) = generate_secrets(ids.len() as u8, t, &mut rng);
89        let msk_bytes = convert_to_bytes::<Fr, 32>(msk);
90        // Q: will this error ever occur?
91        // not sure how to test for it
92        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            // TODO: handle errors
109            ct.serialize_compressed(&mut o).unwrap();
110            out.push(o);
111        }
112        Ok(AesIbeCt{ aes_ct: ct_aes, etf_ct: out })
113    }
114
115    /// decrypt a ct blob 
116    ///
117    /// * `ibe_pp`: the public paramter of the BF IBE, in G2
118    /// * `ciphertext`: The (AES encrypted) ciphertext to decrypt
119    /// * `nonce`: The AES nonce
120    /// * `capsule`: A vec of ciphertexts encrypted with IBE
121    /// * `secrets`: an ordered list of secrets, the order should match the order
122    ///
123    /// used when generating the ciphertext
124    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            // convert bytes to Fr
136            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            // Q: The error probably should never happen...
142            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                // calculate secret keys: Q = H1(id), d = sQ
194                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                // calculate secret keys: Q = H1(id), d = sQ
241                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        // bad 'p'
270        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        // bad 'q' 
284        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        // bad 'p'
301        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        // bad capsule
319        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                // calculate secret keys: Q = H1(id), d = sQ
356                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                // calculate secret keys: Q = H1(id), d = sQ
403                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                // calculate secret keys: Q = H1(id), d = sQ
453                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}