rabe 0.4.2

ABE Schemes implemented in rust.
Documentation
//! `LSW` scheme by Allison Lewko, Amit Sahai and Brent Waters.
//!
//! * Developped by Allison Lewko, Amit Sahai and Brent Waters, "Revocation Systems with Very Small Private Keys"
//! * Published in Security and Privacy, 2010. SP'10. IEEE Symposium on. IEEE
//! * Available from <http://eprint.iacr.org/2008/309.pdf>
//! * Type: encryption (key-policy attribute-based)
//! * Setting: bilinear groups (asymmetric)
//! * Authors: Georg Bramm
//! * Date:	04/2018
//!
//! # Examples
//!
//! ```
//!use rabe::schemes::lsw::*;
//! use rabe::utils::policy::pest::PolicyLanguage;
//! let (pk, msk) = setup();
//! let plaintext = String::from("our plaintext!").into_bytes();
//! let policy = String::from(r#""B" or "C""#);
//! let ct_kp: KpAbeCiphertext = encrypt(&pk, &vec!["A", "B"], &plaintext).unwrap();
//! let sk: KpAbeSecretKey = keygen(&pk, &msk, &policy, PolicyLanguage::HumanPolicy).unwrap();
//! assert_eq!(decrypt(&sk, &ct_kp).unwrap(), plaintext);
//! ```
use rabe_bn::{Group, Fr, G1, G2, Gt, pairing};
use std::ops::Neg;
use utils::{
    tools::*,
    secretsharing::{gen_shares_policy, calc_coefficients, calc_pruned},
    aes::*,
    hash::{sha3_hash_fr, sha3_hash}
};
use rand::Rng;
use utils::policy::pest::{PolicyLanguage, parse};
use crate::error::RabeError;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "borsh")]
use borsh::{BorshSerialize, BorshDeserialize};
use utils::secretsharing::remove_index;

/// A LSW Public Key (PK)
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KpAbePublicKey {
    g1: G1,
    g2: G2,
    g1_b: G1,
    g1_b2: G1,
    h_b: G1,
    e_gg_alpha: Gt,
}

/// A LSW Master Key (MSK)
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KpAbeMasterKey {
    alpha1: Fr,
    alpha2: Fr,
    b: Fr,
    h_g1: G1,
    h_g2: G2,
}

/// A LSW Secret User Key (SK)
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KpAbeSecretKey {
    policy: (String, PolicyLanguage),
    dj: Vec<(String, G1, G2, G1, G1, G1)>,
}

/// A LSW Ciphertext (CT)
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KpAbeCiphertext {
    e1: Gt,
    e2: G2,
    ej: Vec<(String, G1, G1, G1)>,
    ct: Vec<u8>,
}

/// The setup algorithm of LSW KP-ABE. Generates a new KpAbePublicKey and a new KpAbeMasterKey.
pub fn setup() -> (KpAbePublicKey, KpAbeMasterKey) {
    // random number generator
    let mut rng = rand::thread_rng();
    // generate random alpha1, alpha2 and b
    let alpha1:Fr = rng.gen();
    let alpha2:Fr = rng.gen();
    let b:Fr = rng.gen();

    let alpha = alpha1 * alpha2;
    let g1:G1 = rng.gen();
    let g2:G2 = rng.gen();
    let h_g1:G1 = rng.gen();
    let h_g2:G2 = rng.gen();
    let g1_b = g1 * b;
    let g1_b2 = g1_b * b;
    let h_b = h_g1 * b;
    // calculate the pairing between g1 and g2^alpha
    let e_gg_alpha = pairing(g1, g2).pow(alpha);
    // return PK and MSK
    return (
        KpAbePublicKey { g1, g2, g1_b, g1_b2, h_b, e_gg_alpha },
        KpAbeMasterKey { alpha1, alpha2, b, h_g1, h_g2 }
    );
}

/// The key generation algorithm of LSW KP-ABE.
/// Generates a KpAbeSecretKey using a KpAbePublicKey, a KpAbeMasterKey and a policy given as JSON String.
///
/// # Arguments
///
///	* `pk` - A Public Key (PK), generated by the function setup()
///	* `msk` - A Master Key (MSK), generated by the function setup()
///	* `policy` - An access policy given as JSON String
///	* `language` - The policy language
///
pub fn keygen(
    pk: &KpAbePublicKey,
    msk: &KpAbeMasterKey,
    policy: &str,
    language: PolicyLanguage,
) -> Result<KpAbeSecretKey, RabeError> {
    // random number generator
    let mut rng = rand::thread_rng();
    match parse(policy, language) {
        Ok(policy_value) => {
            match gen_shares_policy(msk.alpha1, &policy_value, None) {
                Some(shares) => {
                    let mut dj: Vec<(String, G1, G2, G1, G1, G1)> = Vec::new();
                    for (share_str, share_value) in shares.into_iter() {
                        let striped = remove_index(&share_str);
                        let random:Fr = rng.gen();
                        if is_negative(&striped) {
                            let share_hash = sha3_hash_fr(&striped).expect("could not hash _share_str");
                            dj.push((
                                striped,
                                G1::zero(),
                                G2::zero(),
                                (pk.g1 * share_value) + (pk.g1_b2 * random),
                                pk.g1_b * (share_hash * random) + (msk.h_g1 * random),
                                pk.g1 * random.neg(),
                            ));
                        } else {
                            let share_hash = sha3_hash(pk.g1, &striped).expect("could not hash _share_str");
                            dj.push((
                                striped,
                                (pk.g1 * (msk.alpha2 * share_value))
                                    + (share_hash * random),
                                pk.g2 * random,
                                G1::zero(),
                                G1::zero(),
                                G1::zero(),
                            ));
                        }
                    }
                    return Ok(KpAbeSecretKey {
                        policy: (policy.to_string(), language),
                        dj,
                    });
                },
                None => Err(RabeError::new("could not share secret over policy"))
            }
        }
        Err(e) => Err(e)
    }
}

/// The encrypt algorithm of LSW KP-ABE. Generates a new KpAbeCiphertext using an KpAbePublicKey, a set of attributes given as String Vector and some plaintext data given as [u8].
///
/// # Arguments
///
///	* `pk` - A Public Key (PK), generated by the function setup()
///	* `attributes` - A set of attributes given as String Vector
///	* `plaintext` - plaintext data given as a Vector of u8
///
pub fn encrypt(
    pk: &KpAbePublicKey,
    attributes: &[&str],
    plaintext: &[u8],
) -> Result<KpAbeCiphertext, RabeError> {
    if attributes.is_empty() || plaintext.is_empty() {
        Err(RabeError::new("attributes or data empty"))
    } else {
        // random number generator
        let mut rng = rand::thread_rng();
        // attribute vector
        let mut ej: Vec<(String, G1, G1, G1)> = Vec::new();
        // random secret
        let secret:Fr = rng.gen();
        // sx vector
        let mut sx: Vec<Fr> = Vec::new();
        sx.push(secret);
        for (_i, _attr) in attributes.iter().enumerate() {
            sx.push(rng.gen());
            sx[0] = sx[0] - sx[_i];
        }
        for (_i, _attr) in attributes.into_iter().enumerate() {
            ej.push((
                _attr.to_string(),
                sha3_hash(pk.g1, &_attr).expect("could not hash _attr") * secret,
                pk.g1_b * sx[_i.clone()],
                (pk.g1_b2 * (sx[_i.clone()] * sha3_hash_fr(&_attr.to_string()).expect("could not hash _attr"))) + (pk.h_b * sx[_i]),
            ));
        }
        // random message
        let msg: Gt = rng.gen();
        let e1: Gt = pk.e_gg_alpha.pow(secret) * msg;
        let e2: G2 = pk.g2 * secret;
        //Encrypt plaintext using derived key from secret
        match encrypt_symmetric(msg, &plaintext.to_vec()) {
            Ok(ct) => Ok(KpAbeCiphertext { e1, e2, ej, ct }),
            Err(e) => Err(e)
        }
    }
}

/// The decrypt algorithm of LSW KP-ABE. Reconstructs the original plaintext data as Vec<u8>, given a KpAbeCiphertext with a matching KpAbeSecretKey.
///
/// # Arguments
///
///	* `sk` - A Secret Key (SK), generated by the function keygen()
///	* `ct` - A LSW KP-ABE Ciphertext
///
pub fn decrypt(
    sk: &KpAbeSecretKey,
    ct: &KpAbeCiphertext
) -> Result<Vec<u8>, RabeError> {
    let attr = ct
        .ej
        .iter()
        .map(|a| a.clone().0.to_string())
        .collect::<Vec<_>>();
    match parse(sk.policy.0.as_ref(), sk.policy.1) {
        Ok(policy_value) => {
            return match calc_pruned(&attr, &policy_value, None) {
                Err(e) => Err(e),
                Ok((matches, list)) => {
                    if matches {
                        let mut prod_t = Gt::one();
                        let mut _z_y = Gt::one();
                        let mut coeff_list: Vec<(String, Fr)> = Vec::new();
                        coeff_list = calc_coefficients(&policy_value, Some(Fr::one()), coeff_list, None).unwrap();
                        for attr_str in list.iter() {
                            let sk_attr = sk
                                .dj
                                .iter()
                                .filter(|_attr| { _attr.0 == attr_str.0.to_string() })
                                .nth(0)
                                .unwrap();
                            let ct_attr = ct
                                .ej
                                .iter()
                                .filter(|_attr| _attr.0 == attr_str.0.to_string())
                                .nth(0)
                                .unwrap();
                            let coeff = coeff_list
                                .iter()
                                .filter(|_attr| _attr.0 == attr_str.1.to_string())
                                .nth(0)
                                .unwrap();
                            if is_negative(&attr_str.0) {
                                // TODO !!
                                /*let _sum_e4 = G2::zero();
                                let _sum_e5 = G2::zero();
                                _prod_t = _prod_t *
                                    (pairing(sk._d_i[_i].3, ct._e2) *
                                         (pairing(sk._d_i[_i].4, _sum_e4) * pairing(sk._d_i[_i].5, _sum_e5))
                                             .inverse());
                                */
                            } else {
                                _z_y = pairing(sk_attr.1, ct.e2)
                                    * pairing(ct_attr.1, sk_attr.2).inverse();
                            }
                            prod_t = prod_t * _z_y.pow(coeff.1);
                        }
                        let msg: Gt = ct.e1 * prod_t.inverse();
                        decrypt_symmetric(msg, &ct.ct)
                    } else {
                        Err(RabeError::new("Error in lsw/decrypt: attributes do not match policy."))
                    }
                }
            }
        }
        Err(e)=> Err(e)
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn and() {
        // setup scheme
        let (pk, msk) = setup();
        // a set of two attributes matching the policy
        let att_matching: Vec<&str> = vec!["A","B","C"];
        // our plaintext
        let plaintext =
            String::from("dance like no one's watching, encrypt like everyone is!").into_bytes();
        // our policy
        let policy = String::from(r#"{"name": "and", "children": [{"name": "C"}, {"name": "B"}]}"#);
        // kp-abe ciphertext
        let ct_kp_matching: KpAbeCiphertext = encrypt(&pk, &att_matching, &plaintext).unwrap();
        // a kp-abe SK key
        let sk: KpAbeSecretKey = keygen(&pk, &msk, &policy, PolicyLanguage::JsonPolicy).unwrap();
        // and now decrypt again with matching sk
        assert_eq!(decrypt(&sk, &ct_kp_matching).unwrap(), plaintext);
    }

    #[test]
    fn or() {
        // setup scheme
        let (pk, msk) = setup();
        // a set of two attributes matching the policy
        let att_matching: Vec<&str> = vec!["A","B","C"];
        // our plaintext
        let plaintext =
            String::from("dance like no one's watching, encrypt like everyone is!").into_bytes();
        // our policy
        let policy = String::from(r#"{"name": "or", "children": [{"name": "X"}, {"name": "B"}]}"#);
        // kp-abe ciphertext
        let ct_kp_matching: KpAbeCiphertext = encrypt(&pk, &att_matching, &plaintext).unwrap();
        // a kp-abe SK key
        let sk: KpAbeSecretKey = keygen(&pk, &msk, &policy, PolicyLanguage::JsonPolicy).unwrap();
        // and now decrypt again with matching sk
        assert_eq!(decrypt(&sk, &ct_kp_matching).unwrap(), plaintext);
    }

    #[test]
    fn or_and() {
        // setup scheme
        let (pk, msk) = setup();
        // a set of two attributes matching the policy
        let att_matching: Vec<&str> = vec!["X","Y","Z"];
        // our plaintext
        let plaintext =
            String::from("dance like no one's watching, encrypt like everyone is!").into_bytes();
        // our policy
        let policy =
            String::from(r#"{"name": "or", "children": [{"name": "A"}, {"name": "and", "children": [{"name": "Y"}, {"name": "Z"}]}]}"#);
        // kp-abe ciphertext
        let ct: KpAbeCiphertext = encrypt(&pk, &att_matching, &plaintext).unwrap();
        // a kp-abe SK key
        let sk: KpAbeSecretKey = keygen(&pk, &msk, &policy, PolicyLanguage::JsonPolicy).unwrap();
        // and now decrypt again with matching sk
        assert_eq!(decrypt(&sk, &ct).unwrap(), plaintext);
    }

    #[test]
    fn not() {
        // setup scheme
        let (pk, msk) = setup();
        // a set of two attributes matching the policy
        let att_matching: Vec<&str> = vec!["A","B"];
        // our plaintext
        let plaintext =
            String::from("dance like no one's watching, encrypt like everyone is!").into_bytes();
        // our policy
        let policy = String::from(r#"{"name": "or", "children": [{"name": "X"}, {"name": "Y"}]}"#);
        // kp-abe ciphertext
        let ct_kp_matching: KpAbeCiphertext = encrypt(&pk, &att_matching, &plaintext).unwrap();
        // a kp-abe SK key
        let sk: KpAbeSecretKey = keygen(&pk, &msk, &policy, PolicyLanguage::JsonPolicy).unwrap();
        // and now decrypt again with matching sk
        let res = decrypt(&sk, &ct_kp_matching);
        assert_eq!(res.is_ok(), false);
    }
}