Example #1
0
class Waters11(ABEnc):
    def __init__(self, group_obj, uni_size, verbose=False):
        ABEnc.__init__(self)
        self.group = group_obj
        self.uni_size = uni_size  # bound on the size of the universe of attributes
        self.util = MSP(self.group, verbose)

    def setup(self):
        """
        Generates public key and master secret key.
        """

        if debug:
            print('Setup algorithm:\n')

        # pick a random element each from two source groups and pair them
        g1 = self.group.random(G1)
        g2 = self.group.random(G2)
        alpha = self.group.random(ZR)
        g1_alpha = g1**alpha
        e_gg_alpha = pair(g1_alpha, g2)

        a = self.group.random(ZR)
        g1_a = g1**a

        h = [0]
        for i in range(self.uni_size):
            h.append(self.group.random(G1))

        pk = {
            'g1': g1,
            'g2': g2,
            'g1_a': g1_a,
            'h': h,
            'e_gg_alpha': e_gg_alpha
        }
        msk = {'g1_alpha': g1_alpha}
        return pk, msk

    def keygen(self, pk, msk, attr_list):
        """
        Generate a key for a set of attributes.
        """

        if debug:
            print('Key generation algorithm:\n')

        t = self.group.random(ZR)
        k0 = msk['g1_alpha'] * (pk['g1_a']**t)
        L = pk['g2']**t

        K = {}
        for attr in attr_list:
            K[attr] = pk['h'][int(attr)]**t

        return {'attr_list': attr_list, 'k0': k0, 'L': L, 'K': K}

    def encrypt(self, pk, msg, policy_str):
        """
         Encrypt a message M under a monotone span program.
        """

        if debug:
            print('Encryption algorithm:\n')

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # pick randomness
        u = []
        for i in range(num_cols):
            rand = self.group.random(ZR)
            u.append(rand)
        s = u[0]  # shared secret

        c0 = pk['g2']**s

        C = {}
        D = {}
        for attr, row in mono_span_prog.items():
            cols = len(row)
            sum = 0
            for i in range(cols):
                sum += row[i] * u[i]
            attr_stripped = self.util.strip_index(attr)
            r_attr = self.group.random(ZR)
            c_attr = (pk['g1_a']**sum) / (pk['h'][int(attr_stripped)]**r_attr)
            d_attr = pk['g2']**r_attr
            C[attr] = c_attr
            D[attr] = d_attr

        c_m = (pk['e_gg_alpha']**s) * msg

        return {'policy': policy, 'c0': c0, 'C': C, 'D': D, 'c_m': c_m}

    def decrypt(self, pk, ctxt, key):
        """
         Decrypt ciphertext ctxt with key key.
        """

        if debug:
            print('Decryption algorithm:\n')

        nodes = self.util.prune(ctxt['policy'], key['attr_list'])
        if not nodes:
            print("Policy not satisfied.")
            return None

        prodG = 1
        prodGT = 1

        for node in nodes:
            attr = node.getAttributeAndIndex()
            attr_stripped = self.util.strip_index(attr)
            prodG *= ctxt['C'][attr]
            prodGT *= pair(key['K'][attr_stripped], ctxt['D'][attr])

        return (ctxt['c_m'] * pair(prodG, key['L']) * prodGT) / (pair(
            key['k0'], ctxt['c0']))
Example #2
0
class AGGABE(ABEnc):

    def __init__(self, group_obj, verbose=False):
        ABEnc.__init__(self)
        self.group = group_obj
        self.util = MSP(self.group, verbose)

    def agg_setup(self, n):

        g = self.group.random(G1)
        beta_2 = self.group.random(ZR)
        alpha = self.group.random(ZR)
        a = self.group.random(ZR)
        b = self.group.random(ZR)
        c = self.group.random(ZR)
        v = g ** beta_2
        g_a = g ** a
        g_b = g ** b
        g_c = g ** c

        dic_g_i = {}
        for i in range(1, 2*n + 1):
            g_i = g ** (alpha ** i)
            dic_g_i[i] = g_i
            # print(i, dic_g_i[i])

        pk = {'g': g, 'v': v, 'n': n, 'g_i': dic_g_i, 'g_a': g_a, 'g_b': g_b, 'g_c': g_c}
        msk = {'a': a, 'b': b, 'c': c, 'beta_2': beta_2}
        return pk, msk

    def agg_keygen(self, pk, msk, attr_list, S):
        g = pk['g']
        # generate key for cs
        beta_1 = self.group.random(ZR)
        u = g ** beta_1
        # key_cs = {'pk_cs': u, 'sk_cs': beta_1}

        # generate key for dta owners
        dic_g_i = pk['g_i']
        # print(len(dic_g_i))
        n = pk['n']
        h_i_1 = {}  # n * n
        h_i_2 = {}  # n * 2n
        sk_i = {}
        for i in range(1, n+1):
            gama_i_1 = self.group.random(ZR)
            gama_i_2 = self.group.random(ZR)

            # print(i, dic_g_i[i])
            # h_i_1[i] = dic_g_i[i] ** gama_i_1
            # print('h_i_1', h_i_1)
            dic_h_1 = {}
            for j in range(1, n+1):
                temp_1 = dic_g_i[j] ** gama_i_1
                dic_h_1[j] = temp_1
            h_i_1[i] = dic_h_1

            ek_i_1 = u ** gama_i_1
            ek_i_2 = pk['v'] ** gama_i_1
            sk_i[i] = (ek_i_1, ek_i_2)
            # print('sk_i', sk_i)

            # h_i_2 = list_g_i[i] ** gama_i_2
            # iteration with 2n
            dic_h_2 = {}
            for j in range(1, 2*n + 1):
                # print(j)
                temp_2 = dic_g_i[j] ** gama_i_2
                # h_i_2[i][j] = h_j_2
                dic_h_2[j] = temp_2
            h_i_2[i] = dic_h_2
            # print('h_i_2', h_i_2)
            # pk_i[i] = (h_i_1, h_i_2)

        # generate key for users
        r = self.group.random(ZR)
        g_r = g ** r
        a = msk['a']
        b = msk['b']
        b_inverse = 1 / b
        c = msk['c']
        A_d = (a * c - r) * b_inverse
        A = g ** A_d

        A_B = {}
        for attr_j in attr_list:
            r_j = self.group.random(ZR)
            A_j = g_r * (self.group.hash(str(attr_j), G1) ** r_j)
            B_j = g ** r_j
            A_B[attr_j] = (A_j, B_j)

        # authorize user with DOs
        beta_2 = msk['beta_2']
        k_agg = 1
        for k in S:
            k_agg *= (dic_g_i[n + 1 - k] ** beta_2)
            # print('k_agg', k_agg)
        return {'attr_list': attr_list, 'pk_cs': u, 'sk_cs': beta_1, 'h_i_1': h_i_1, 'h_i_2': h_i_2, 'sk_i': sk_i, 'A': A, 'A_B': A_B, 'k_agg': k_agg}

    def agg_index(self, pk, key_gen, w_l, policy_list):
        n = pk['n']
        g = pk['g']
        v = pk['v']
        # pk_i = key['pk_i']
        # h_i_1 = key_gen['h_i_1']
        h_i_2 = key_gen['h_i_2']
        sk_i = key_gen['sk_i']

        # for each DO
        C_agg = {}
        W_all = {}
        W_agg = {}

        policy = {}
        for i in range(1, n + 1):
            r_i_l = self.group.random(ZR)
            # (h_i_1, h_i_2) = pk_i[i]
            # print(i, sk_i[i])
            (ek_i_1, ek_i_2) = sk_i[i]
            c_i_l_1 = ek_i_1 ** r_i_l
            c_i_l_2 = ek_i_2 ** r_i_l
            c_i_l_3 = (v * h_i_2[i][i]) ** r_i_l
            C_agg[i] = (c_i_l_1, c_i_l_2, c_i_l_3)

            # perform attribute based encryption
            policy[i] = self.util.createPolicy(policy_list[i])
            mono_span_prog = self.util.convert_policy_to_msp(policy[i])
            num_cols = self.util.len_longest_row

            u_bsw = []
            for j in range(num_cols):
                rand = self.group.random(ZR)
                u_bsw.append(rand)

            r_i_1 = self.group.random(ZR)
            r_i_2 = u_bsw[0]  # shared secret
            g_a = pk['g_a']
            g_b = pk['g_b']
            g_c = pk['g_c']
            W = g_c ** r_i_1
            W_0 = (g_a ** (r_i_1 + r_i_2)) * ((g_b ** (self.group.hash(str(w_l), ZR))) ** r_i_1)
            W_bar = g_b ** r_i_2
            W_all[i] = (W, W_0, W_bar)

            W_agg_i = {}
            for attr, row in mono_span_prog.items():
                cols = len(row)
                sum = 0
                for l in range(cols):
                    sum += row[l] * u_bsw[l]
                attr_stripped = self.util.strip_index(attr)
                W_f = g ** sum
                D_f = self.group.hash(str(attr_stripped), G1) ** sum
                W_agg_i[attr] = (W_f, D_f)
                W_agg[i] = W_agg_i
        return {'policy': policy, 'C_agg': C_agg, 'W_all': W_all, 'W_agg': W_agg}

    def agg_trap(self, pk, key_gen, w_l):
        x = self.group.random(ZR)
        s = self.group.random(ZR)

        Tr_1 = key_gen['k_agg'] * (pk['v'] ** x)
        Tr_2 = key_gen['pk_cs'] ** x
        tok_1 = (pk['g_a'] * (pk['g_b'] ** (self.group.hash(str(w_l), ZR)))) ** s
        tok_2 = pk['g_c'] ** s
        tok_3 = key_gen['A'] ** s

        A_B_bar = {}
        for attr_j in key_gen['attr_list']:
            (A_j, B_j) = key_gen['A_B'][attr_j]
            A_j_bar = A_j ** s
            B_j_bar = B_j ** s
            A_B_bar[attr_j] = (A_j_bar, B_j_bar)
        return {'Tr_1': Tr_1, 'Tr_2': Tr_2, 'tok_1': tok_1, 'tok_2': tok_2, 'tok_3': tok_3, 'A_B_bar': A_B_bar}

    def agg_search(self, pk, key_gen, S, I, Trap):
        h_i_2 = key_gen['h_i_2']  # dic
        # print(type(h_i_2))
        # print('n', pk['n'])
        flag1 = {}
        flag2 = {}
        for i in range(1, pk['n'] + 1):
            print('i', i)
            prod_pub = 1
            prod_k = 1
            dic_h_i_2 = h_i_2[i]  # dic
            # print(type(dic_h_i_2))
            for k in S:
                # (pub_1, pub_2) = key_gen['pk_i'][pk['n'] + 1 - k]
                # prod_pub *= pub_1
                h_i_1_k = key_gen['h_i_1'][i][pk['n'] + 1 - k]
                prod_pub *= h_i_1_k

                if k != i:
                    # (pk_1, pk_2) = key_gen['pk_i'][pk['n'] + 1 - k + i]
                    # prod_k *= pk_2
                    # h_i_2_k = h_i_2[[pk['n'] - 1 - k + i]][[pk['n'] - 1 - k + i]]
                    h_i_2_k = dic_h_i_2[pk['n'] + 1 - k + i]
                    prod_k *= h_i_2_k

            Tr_i_1 = Trap['Tr_1'] * prod_k

            # verify the eq.1
            (c_i_l_1, c_i_l_2, c_i_l_3) = I['C_agg'][i]
            # (h_1, h_2) = key_gen['pk_i'][pk['n'] + 1]
            h_2 = dic_h_i_2[pk['n'] + 1]
            left_1 = ((pair(prod_pub, c_i_l_3) ** key_gen['sk_cs']) * pair(c_i_l_2, Trap['Tr_2'])) / pair(Tr_i_1, c_i_l_1)
            right_1 = pair(h_2, c_i_l_1)

            if left_1 == right_1:
                flag1[i] = True
                print("The first layer satisfied.")

                nodes = self.util.prune(I['policy'][i], key_gen['attr_list'])
                if not nodes:
                    print("Policy not satisfied.")
                    # return None

                E_root = 1
                for node in nodes:
                    attr = node.getAttributeAndIndex()
                    attr_stripped = self.util.strip_index(attr)  # satisfied attributes
                    (A_j_bar, B_j_bar) = Trap['A_B_bar'][attr_stripped]
                    (W_f, D_f) = I['W_agg'][i][attr]
                    E_f = pair(A_j_bar, W_f) / pair(B_j_bar, D_f)
                    E_root *= E_f

                (W, W_0, W_bar) = I['W_all'][i]
                left_2 = pair(W_0, Trap['tok_2'])
                right_2 = pair(W, Trap['tok_1']) * E_root * pair(Trap['tok_3'], W_bar)

                if left_2 == right_2:
                    # return True
                    flag2[i] = True
                    print("The second layer satisfied.")
                else:
                    flag2[i] = False
                    print("The second layer not satisfied.")
                    # return False
            else:
                flag1[i] = False
                print("The first layer not satisfied.")
                # return False
        return {'flag1': flag1, 'flag2': flag2}
Example #3
0
class AC17CPABE(ABEnc):
    def __init__(self, group_obj, assump_size, verbose=False):
        ABEnc.__init__(self)
        self.group = group_obj
        self.assump_size = assump_size  # size of linear assumption, at least 2
        self.util = MSP(self.group, verbose)

    def setup(self):
        """
        Generates public key and master secret key.
        """

        if debug:
            print('\nSetup algorithm:\n')

        # generate two instances of the k-linear assumption
        A = []
        B = []
        for i in range(self.assump_size):
            A.append(self.group.random(ZR))
            B.append(self.group.random(ZR))  # note that A, B are vectors here

        # vector
        k = []
        for i in range(self.assump_size + 1):
            k.append(self.group.random(ZR))

        # pick a random element from the two source groups and pair them
        g = self.group.random(G1)
        h = self.group.random(G2)
        e_gh = pair(g, h)

        # now compute various parts of the public parameters

        # compute the [A]_2 term
        h_A = []
        for i in range(self.assump_size):
            h_A.append(h**A[i])
        h_A.append(h)

        # compute the e([k]_1, [A]_2) term
        g_k = []
        for i in range(self.assump_size + 1):
            g_k.append(g**k[i])

        e_gh_kA = []
        for i in range(self.assump_size):
            e_gh_kA.append(e_gh**(k[i] * A[i] + k[self.assump_size]))

        # the public key
        pk = {'h_A': h_A, 'e_gh_kA': e_gh_kA}

        # the master secret key
        msk = {'g': g, 'h': h, 'g_k': g_k, 'A': A, 'B': B}

        return pk, msk

    def keygen(self, pk, msk, attr_list):
        """
        Generate a key for a list of attributes.
        """

        if debug:
            print('\nKey generation algorithm:\n')

        # pick randomness
        r = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            r.append(rand)
            sum += rand

        # compute the [Br]_2 term

        # first compute just Br as it will be used later too
        Br = []
        for i in range(self.assump_size):
            Br.append(msk['B'][i] * r[i])
        Br.append(sum)

        # now compute [Br]_2
        K_0 = []
        for i in range(self.assump_size + 1):
            K_0.append(msk['h']**Br[i])

        # compute [W_1 Br]_1, ...
        K = {}
        A = msk['A']
        g = msk['g']
        for attr in attr_list:
            key = []
            sigma_attr = self.group.random(ZR)
            for t in range(self.assump_size):
                prod = 1
                a_t = A[t]
                for l in range(self.assump_size + 1):
                    input_for_hash = attr + str(l) + str(t)
                    prod *= (self.group.hash(input_for_hash,
                                             G1)**(Br[l] / a_t))
                prod *= (g**(sigma_attr / a_t))
                key.append(prod)
            key.append(g**(-sigma_attr))
            K[attr] = key

        # compute [k + VBr]_1
        Kp = []
        g_k = msk['g_k']
        sigma = self.group.random(ZR)
        for t in range(self.assump_size):
            prod = g_k[t]
            a_t = A[t]
            for l in range(self.assump_size + 1):
                input_for_hash = '01' + str(l) + str(t)
                prod *= (self.group.hash(input_for_hash, G1)**(Br[l] / a_t))
            prod *= (g**(sigma / a_t))
            Kp.append(prod)
        Kp.append(g_k[self.assump_size] * (g**(-sigma)))

        return {'attr_list': attr_list, 'K_0': K_0, 'K': K, 'Kp': Kp}

    def encrypt(self, pk, msg, policy_str):
        """
        Encrypt a message msg under a policy string.
        """

        if debug:
            print('\nEncryption algorithm:\n')

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # pick randomness
        s = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            s.append(rand)
            sum += rand

        # compute the [As]_2 term
        C_0 = []
        h_A = pk['h_A']
        for i in range(self.assump_size):
            C_0.append(h_A[i]**s[i])
        C_0.append(h_A[self.assump_size]**sum)

        # compute the [(V^T As||U^T_2 As||...) M^T_i + W^T_i As]_1 terms

        # pre-compute hashes
        hash_table = []
        for j in range(num_cols):
            x = []
            input_for_hash1 = '0' + str(j + 1)
            for l in range(self.assump_size + 1):
                y = []
                input_for_hash2 = input_for_hash1 + str(l)
                for t in range(self.assump_size):
                    input_for_hash3 = input_for_hash2 + str(t)
                    hashed_value = self.group.hash(input_for_hash3, G1)
                    y.append(hashed_value)
                    # if debug: print ('Hash of', i+2, ',', j2, ',', j1, 'is', hashed_value)
                x.append(y)
            hash_table.append(x)

        C = {}
        for attr, row in mono_span_prog.items():
            ct = []
            attr_stripped = self.util.strip_index(
                attr)  # no need, re-use not allowed
            for l in range(self.assump_size + 1):
                prod = 1
                cols = len(row)
                for t in range(self.assump_size):
                    input_for_hash = attr_stripped + str(l) + str(t)
                    prod1 = self.group.hash(input_for_hash, G1)
                    for j in range(cols):
                        # input_for_hash = '0' + str(j+1) + str(l) + str(t)
                        prod1 *= (hash_table[j][l][t]**row[j])
                    prod *= (prod1**s[t])
                ct.append(prod)
            C[attr] = ct

        # compute the e(g, h)^(k^T As) . m term
        Cp = 1
        for i in range(self.assump_size):
            Cp = Cp * (pk['e_gh_kA'][i]**s[i])
        Cp = Cp * msg

        return {'policy': policy, 'C_0': C_0, 'C': C, 'Cp': Cp}

    def decrypt(self, pk, ctxt, key):
        """
        Decrypt ciphertext ctxt with key key.
        """

        if debug:
            print('\nDecryption algorithm:\n')

        nodes = self.util.prune(ctxt['policy'], key['attr_list'])
        if not nodes:
            print("Policy not satisfied.")
            return None

        prod1_GT = 1
        prod2_GT = 1
        for i in range(self.assump_size + 1):
            prod_H = 1
            prod_G = 1
            for node in nodes:
                attr = node.getAttributeAndIndex()
                attr_stripped = self.util.strip_index(
                    attr)  # no need, re-use not allowed
                # prod_H *= key['K'][attr_stripped][i] ** coeff[attr]
                # prod_G *= ctxt['C'][attr][i] ** coeff[attr]
                prod_H *= key['K'][attr_stripped][i]
                prod_G *= ctxt['C'][attr][i]
            prod1_GT *= pair(key['Kp'][i] * prod_H, ctxt['C_0'][i])
            prod2_GT *= pair(prod_G, key['K_0'][i])

        return ctxt['Cp'] * prod2_GT / prod1_GT
Example #4
0
class CGW15CPABE(ABEnc):
    def __init__(self, groupObj, assump_size, uni_size, verbose=False):
        ABEnc.__init__(self)
        self.group = groupObj
        self.assump_size = assump_size  # size of the linear assumption
        self.uni_size = uni_size  # bound on the size of the universe of attributes
        self.util = MSP(self.group, verbose)  

    def setup(self):
        """
        Generates public key and master secret key.
        """

        if debug:
            print('Setup algorithm:\n')

        # generate two instances of the k-linear assumption
        A = []
        B = []
        for i in range(self.assump_size):
            A.append(self.group.random(ZR))
            B.append(self.group.random(ZR))  # note that A, B are vectors here

        # pick matrices that help to randomize basis
        W = {}
        for i in range(self.uni_size):
            x = []
            for j1 in range(self.assump_size + 1):
                y = []
                for j2 in range(self.assump_size + 1):
                    y.append(self.group.random(ZR))
                x.append(y)
            W[i + 1] = x

        V = []
        for j1 in range(self.assump_size + 1):
            y = []
            for j2 in range(self.assump_size + 1):
                y.append(self.group.random(ZR))
            V.append(y)

        # vector
        k = []
        for i in range(self.assump_size + 1):
            k.append(self.group.random(ZR))

        # pick a random element from the two source groups and pair them
        g = self.group.random(G1)
        h = self.group.random(G2)
        e_gh = pair(g, h)

        # now compute various parts of the public parameters

        # compute the [A]_1 term
        g_A = []
        for i in range(self.assump_size):
            g_A.append(g ** A[i])
        g_A.append(g)

        # compute the [W_1^T A]_1, [W_2^T A]_1, ...  terms
        g_WA = {}
        for i in range(self.uni_size):
            x = []
            for j1 in range(self.assump_size + 1):
                y = []
                for j2 in range(self.assump_size):
                    prod = (A[j2] * W[i + 1][j2][j1]) + W[i + 1][self.assump_size][j1]
                    y.append(g ** prod)
                x.append(y)
            g_WA[i + 1] = x

        g_VA = []
        for j1 in range(self.assump_size + 1):
            y = []
            for j2 in range(self.assump_size):
                prod = (A[j2] * V[j2][j1]) + V[self.assump_size][j1]
                y.append(g ** prod)
            g_VA.append(y)

        # compute the e([A]_1, [k]_2) term
        h_k = []
        for i in range(self.assump_size + 1):
            h_k.append(h ** k[i])

        e_gh_kA = []
        for i in range(self.assump_size):
            e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size]))

        # the public key
        pk = {'g_A': g_A, 'g_WA': g_WA, 'g_VA': g_VA, 'e_gh_kA': e_gh_kA}

        # the master secret key
        msk = {'h': h, 'k': k, 'B': B, 'W': W, 'V': V}

        return pk, msk

    def keygen(self, pk, msk, attr_list):
        """
        Generate a key for a set of attributes.
        """

        if debug:
            print('Key generation algorithm:\n')

        # pick randomness
        r = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            r.append(rand)
            sum += rand

        # compute the [Br]_2 term
        K_0 = []
        Br = []
        h = msk['h']
        for i in range(self.assump_size):
            prod = msk['B'][i] * r[i]
            Br.append(prod)
            K_0.append(h ** prod)
        Br.append(sum)
        K_0.append(h ** sum)

        # compute the [W_i^T Br]_2 terms
        K = {}
        for attr in attr_list:
            key = []
            W_attr = msk['W'][int(attr)]
            for j1 in range(self.assump_size + 1):
                sum = 0
                for j2 in range(self.assump_size + 1):
                    sum += W_attr[j1][j2] * Br[j2]
                key.append(h ** sum)
            K[attr] = key

        # compute the [k + VBr]_2 term
        Kp = []
        V = msk['V']
        k = msk['k']
        for j1 in range(self.assump_size + 1):
            sum = 0
            for j2 in range(self.assump_size + 1):
                sum += V[j1][j2] * Br[j2]
            Kp.append(h ** (k[j1] + sum))

        return {'attr_list': attr_list, 'K_0': K_0, 'K': K, 'Kp': Kp}

    def encrypt(self, pk, msg, policy_str):
        """
        Encrypt a message M under a policy string.
        """

        if debug:
            print('Encryption algorithm:\n')

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # pick randomness
        s = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            s.append(rand)
            sum += rand
        s.append(sum)

        # compute the [As]_1 term
        g_As = []
        g_A = pk['g_A']
        for i in range(self.assump_size + 1):
            g_As.append(g_A[i] ** s[i])

        # compute U^T_2 As, U^T_3 As by picking random matrices U_2, U_3 ...
        UAs = {}
        for i in range(num_cols - 1):
            x = []
            for j1 in range(self.assump_size + 1):
                prod = 1
                for j2 in range(self.assump_size + 1):
                    prod *= g_As[j2] ** (self.group.random(ZR))
                x.append(prod)
            UAs[i+1] = x

        # compute V^T As using VA from public key
        VAs = []
        g_VA = pk['g_VA']
        for j1 in range(self.assump_size + 1):
            prod = 1
            for j2 in range(self.assump_size):
                prod *= g_VA[j1][j2] ** s[j2]
            VAs.append(prod)

        # compute the [(V^T As||U^T_2 As||...||U^T_cols As) M^T_i + W^T_i As]_1 terms
        C = {}
        g_WA = pk['g_WA']
        for attr, row in mono_span_prog.items():
            attr_stripped = self.util.strip_index(attr)  # no need, re-use not allowed
            ct = []
            for j1 in range(self.assump_size + 1):
                cols = len(row)
                prod1 = VAs[j1] ** row[0]
                for j2 in range(1, cols):
                    prod1 *= UAs[j2][j1] ** row[j2]
                prod2 = 1
                for j2 in range(self.assump_size):
                    prod2 *= g_WA[int(attr_stripped)][j1][j2] ** s[j2]
                ct.append(prod1 * prod2)
            C[attr] = ct

        # compute the e(g, h)^(k^T As) . m term
        Cx = 1
        for i in range(self.assump_size):
            Cx = Cx * (pk['e_gh_kA'][i] ** s[i])
        Cx = Cx * msg

        return {'policy': policy, 'C_0': g_As, 'C': C, 'Cx': Cx}

    def decrypt(self, pk, ctxt, key):
        """
        Decrypt ciphertext ctxt with key key.
        """

        if debug:
            print('Decryption algorithm:\n')

        nodes = self.util.prune(ctxt['policy'], key['attr_list'])
        if not nodes:
            print ("Policy not satisfied.")
            return None

        prod1_GT = 1
        prod2_GT = 1
        for i in range(self.assump_size + 1):
            prod_H = 1
            prod_G = 1
            for node in nodes:
                attr = node.getAttributeAndIndex()
                attr_stripped = self.util.strip_index(attr)  # no need, re-use not allowed
                # prod_H *= D['K'][attr_stripped][i] ** coeff[attr]
                # prod_G *= E['C'][attr][i] ** coeff[attr]
                prod_H *= key['K'][attr_stripped][i]
                prod_G *= ctxt['C'][attr][i]
            prod1_GT *= pair(ctxt['C_0'][i], key['Kp'][i] * prod_H)
            prod2_GT *= pair(prod_G, key['K_0'][i])

        return ctxt['Cx'] * prod2_GT / prod1_GT
Example #5
0
class BSW07(ABEnc):
    def __init__(self, group_obj, verbose=False):
        ABEnc.__init__(self)
        self.group = group_obj
        self.util = MSP(self.group, verbose)

    def setup(self):
        """
        Generates public key and master secret key.
        """

        if debug:
            print('Setup algorithm:\n')

        # pick a random element each from two source groups
        g1 = self.group.random(G1)
        g2 = self.group.random(G2)

        beta = self.group.random(ZR)
        h = g2**beta
        f = g2**(1 / beta)

        alpha = self.group.random(ZR)
        g1_alpha = g1**alpha
        e_gg_alpha = pair(g1_alpha, g2)

        pk = {'g1': g1, 'g2': g2, 'h': h, 'f': f, 'e_gg_alpha': e_gg_alpha}
        msk = {'beta': beta, 'g1_alpha': g1_alpha}
        return pk, msk

    def keygen(self, pk, msk, attr_list):
        """
        Generate a key for a set of attributes.
        """

        if debug:
            print('Key generation algorithm:\n')

        r = self.group.random(ZR)
        g1_r = pk['g1']**r
        beta_inverse = 1 / msk['beta']
        k0 = (msk['g1_alpha'] * g1_r)**beta_inverse

        K = {}
        for attr in attr_list:
            r_attr = self.group.random(ZR)
            k_attr1 = g1_r * (self.group.hash(str(attr), G1)**r_attr)
            k_attr2 = pk['g2']**r_attr
            K[attr] = (k_attr1, k_attr2)

        return {'attr_list': attr_list, 'k0': k0, 'K': K}

    def encrypt(self, pk, msg, policy_str):
        """
         Encrypt a message M under a policy string.
        """

        if debug:
            print('Encryption algorithm:\n')

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # pick randomness
        u = []
        for i in range(num_cols):
            rand = self.group.random(ZR)
            u.append(rand)
        s = u[0]  # shared secret

        c0 = pk['h']**s

        C = {}
        for attr, row in mono_span_prog.items():
            cols = len(row)
            sum = 0
            for i in range(cols):
                sum += row[i] * u[i]
            attr_stripped = self.util.strip_index(attr)
            c_i1 = pk['g2']**sum
            c_i2 = self.group.hash(str(attr_stripped), G1)**sum
            C[attr] = (c_i1, c_i2)

        c_m = (pk['e_gg_alpha']**s) * msg

        return {'policy': policy, 'c0': c0, 'C': C, 'c_m': c_m}

    def decrypt(self, pk, ctxt, key):
        """
         Decrypt ciphertext ctxt with key key.
        """

        if debug:
            print('Decryption algorithm:\n')

        nodes = self.util.prune(ctxt['policy'], key['attr_list'])
        if not nodes:
            print("Policy not satisfied.")
            return None

        prod = 1

        for node in nodes:
            attr = node.getAttributeAndIndex()
            attr_stripped = self.util.strip_index(attr)
            (c_attr1, c_attr2) = ctxt['C'][attr]
            (k_attr1, k_attr2) = key['K'][attr_stripped]
            prod *= (pair(k_attr1, c_attr1) / pair(c_attr2, k_attr2))

        return (ctxt['c_m'] * prod) / (pair(key['k0'], ctxt['c0']))
Example #6
0
class PCHBA(ABEnc):
    def __init__(self, group_obj, assump_size, k, verbose=False):
        ABEnc.__init__(self)
        self.group = group_obj
        self.assump_size = assump_size  # size of linear assumption, at least 2
        self.util = MSP(self.group, verbose)
        self.k = k
        self.index = k
        self.i = 5
        self.j = 5  # we assume i = j, equals to identity-based encryption.
        self.msk = {}
        self.mpk = {}
        self.pk = None
        self.sk = None
        self.sk_delta = None
        self.ID_i = None
        self.ID_j = None
        self.I = []
        for i in range(self.k):
            self.I.append(self.group.random(ZR))

    def setup(self):
        """
        Generates public key and master secret key.
        """

        if debug:
            print('\nSetup algorithm:\n')

# (sk, pk)
        h = self.group.random(G2)
        self.sk = self.group.random(ZR)
        self.pk = h**self.sk

        # (msk, mpk)
        g = self.group.random(G1)
        a0 = self.group.random(ZR)
        a1 = self.group.random(ZR)
        b0 = self.group.random(ZR)
        b1 = self.group.random(ZR)
        alpha = self.group.random(ZR)
        beta = self.group.random(ZR)
        d0 = self.group.random(ZR)
        d1 = self.group.random(ZR)
        d2 = self.group.random(ZR)
        g_d1 = g**d0
        g_d2 = g**d1
        g_d3 = g**d2
        Z = []  # {z1,...,zk}
        G = []  # {g1,...,gk}
        H = []  # {h1,...,hk}
        GZ = []  # {g_z1,...,g_zk}
        HZ = []  # {h_z1,...,h_zk}
        for i in range(self.k):
            Z.append(self.group.random(ZR))
            G.append(self.group.random(G1))
            H.append(self.group.random(G2))
            GZ.append(g**Z[i])
            HZ.append(h**Z[i])

        e_gh = pair(g, h)
        H1 = h**a0
        H2 = h**a1
        T1 = e_gh**(d0 * a0 + d2 / alpha)
        T2 = e_gh**(d1 * a1 + d2 / alpha)
        g_alpha = g**alpha
        d = d0 + d1 + d2
        h_d_alpha = h**(d / alpha)
        h_1_alpha = h**(1 / alpha)
        h_beta_alpha = h**(beta / alpha)

        self.ID_i = 1
        for i in range(self.i):
            g_k = GZ[self.k - i - 1]
            self.ID_i *= g_k**self.I[i]
        self.ID_i *= g
        self.ID_j = 1
        for j in range(self.j):
            h_k = HZ[self.k - j - 1]
            self.ID_j *= h_k**self.I[j]
        self.ID_j *= h

        self.msk = {
            'a0': a0,
            'a1': a1,
            'b0': b0,
            'b1': b1,
            'alpha': alpha,
            'beta': beta,
            'd0': d0,
            'd1': d1,
            'd2': d2,
            'g_d1': g_d1,
            'g_d2': g_d2,
            'g_d3': g_d3,
            'Z': Z
        }
        self.mpk = {
            'g': g,
            'h': h,
            'H1': H1,
            'H2': H2,
            'T1': T1,
            'T2': T2,
            'GZ': GZ,
            'HZ': HZ,
            'g_alpha': g_alpha,
            'h_d_alpha': h_d_alpha,
            'h_1_alpha': h_1_alpha,
            'h_beta_alpha': h_beta_alpha
        }

        return self.sk, self.pk, self.msk, self.mpk

    def keygen(self, sk, pk, msk, mpk, attr_list):
        """
        Generate a key for a list of attributes.
        """

        if debug:
            print('\nKey generation algorithm:\n')

        msk = self.msk
        mpk = self.mpk
        sk = self.sk
        pk = self.pk
        g = mpk['g']
        h = mpk['h']
        alpha = msk['alpha']
        x = sk
        d = msk['d0'] + msk['d1'] + msk['d2']
        R = self.group.random(ZR)
        r1 = self.group.random(ZR)
        r2 = self.group.random(ZR)
        r = r1 + r2
        h_b1_r1 = h**(msk['b0'] * r1)
        h_b2_r2 = h**(msk['b1'] * r2)
        h_r1_r2_alpha = h**((r1 + r2) / alpha)
        g_1_alpha = g**(1 / alpha)
        g_r_alpha = g**(r / alpha)
        g_R = g**R
        sk0 = {
            'h_b1_r1': h_b1_r1,
            'h_b2_r2': h_b2_r2,
            'h_r1_r2_alpha': h_r1_r2_alpha,
            'g_1_alpha': g_1_alpha,
            'g_r_alpha': g_r_alpha,
            'g_R': g_R
        }
        SK = {}  # SK = {[sk_y_1, sk_y_2]} sk_y_t
        sk_prime = []

        for attr in attr_list:
            sigma_y = self.group.random(ZR)
            key = []
            for t in range(self.assump_size):
                input_for_hash1 = attr + str(0) + str(t)
                input_for_hash2 = attr + str(1) + str(t)
                input_for_hash3 = attr + str(2) + str(t)
                a_t = 'a' + str(t)
                sk_y_t = self.group.hash(input_for_hash1, G1)**(
                    msk['b0'] * r1 / msk[a_t]) * self.group.hash(
                        input_for_hash2,
                        G1)**(msk['b1'] * r2 / msk[a_t]) * self.group.hash(
                            input_for_hash3, G1)**(
                                (r1 + r2) /
                                (alpha * msk[a_t])) * g**(sigma_y /
                                                          (alpha * msk[a_t]))
                key.append(sk_y_t)
            key.append(g**(-sigma_y))
            SK[attr] = key

        sigma_prime = self.group.random(ZR)
        for t in range(self.assump_size):
            input_for_hash1 = "010" + str(t)
            input_for_hash2 = "011" + str(t)
            input_for_hash3 = "012" + str(t)
            a_t = 'a' + str(t)
            d_t = 'd' + str(t)
            sk_t = g**msk[d_t] * self.group.hash(input_for_hash1, G1)**(
                msk['b0'] * r1 / msk[a_t]) * self.group.hash(
                    input_for_hash2,
                    G1)**(msk['b1'] * r2 / msk[a_t]) * self.group.hash(
                        input_for_hash3, G1)**(
                            (r1 + r2) /
                            (alpha * msk[a_t])) * g**(sigma_prime /
                                                      (alpha * msk[a_t]))
            sk_prime.append(sk_t)
        sk_prime.append(g**msk['d2'] * g**(-sigma_prime))

        sk1 = g**d * self.ID_i**(alpha * r) * g**(msk['beta'] * R)

        sk2 = [None] * ((self.i - 1) * 2)
        for i in range(self.i - 1):
            g_k = mpk['GZ'][self.i - 1 - i]
            sk2[i] = g_k**(alpha * r)
            sk2[self.i + i - 1] = g_k**alpha

        ssk = {
            'sk0': sk0,
            'sk_y_t': SK,
            'sk_prime': sk_prime,
            'sk1': sk1,
            'sk2': sk2
        }
        self.sk_delta = {'x': x, 'ssk': ssk, 'attr_list': attr_list}

        return self.sk_delta

    def hash(self, m, policy_str):
        msk = self.msk
        mpk = self.mpk
        pk = self.pk
        h = mpk['h']
        g = mpk['g']
        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # step 1
        r = self.group.random(ZR)
        p = pk**r

        # step 2
        R = self.group.random(ZR)
        sha256 = hashlib.new('sha256')
        sha256.update(self.group.serialize(R))
        hd = sha256.hexdigest()
        seed = str(hd)
        e = self.group.hash(seed, ZR)
        h_prime = h**e

        # step 3
        m = self.group.random(ZR)
        b = p * h_prime**m

        # step 4
        s = []
        sum = 0  # sum = s1 + s2
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            s.append(rand)
            sum += rand
        _sk = sum
        _vk = self.ID_j**(msk['alpha'] * sum)

        # step 5
        ct0 = []
        H1 = mpk['H1']
        H2 = mpk['H2']
        ct0.append(H1**s[0])
        ct0.append(H2**s[1])
        ct0.append(h**(sum / msk['alpha']))
        ct0.append(mpk['h_beta_alpha']**sum)

        # pre-compute hashes
        hash_table = []
        for j in range(num_cols):
            x = []
            input_for_hash1 = '0' + str(j + 1)
            for l in range(self.assump_size + 1):
                y = []
                input_for_hash2 = input_for_hash1 + str(l)
                for t in range(self.assump_size):
                    input_for_hash3 = input_for_hash2 + str(t)
                    hashed_value = self.group.hash(input_for_hash3, G1)
                    y.append(hashed_value)
                x.append(y)
            hash_table.append(x)

        # compute C = ct_u_l
        C = {}
        for attr, row in mono_span_prog.items():
            ct = []
            attr_stripped = self.util.strip_index(
                attr)  # no need, re-use not allowed
            for l in range(self.assump_size + 1):
                prod = 1
                cols = len(row)
                for t in range(self.assump_size):
                    input_for_hash = attr_stripped + str(l) + str(t)
                    prod1 = self.group.hash(input_for_hash, G1)
                    for j in range(cols):
                        prod1 *= (hash_table[j][l][t]**row[j])
                    prod *= (prod1**s[t])
                ct.append(prod)
            C[attr] = ct

        sha256 = hashlib.new('sha256')
        msg = mpk['T1']**s[0] * mpk['T2']**s[1]
        sha256.update(self.group.serialize(msg))
        hd = sha256.hexdigest()
        seed = str(hd)
        _ct = r * self.group.hash(seed, ZR)
        d = msk['d0'] + msk['d1'] + msk['d2']

        cpp = pair(g, h**(d / msk['alpha']))**_sk
        seed = str(cpp)
        _ctp = R * self.group.hash(seed, ZR)
        _ct2p = _vk
        _ct3p = self.ID_j**(sum)
        _ct4p = _vk**(sum)
        _C = [ct0, C, _ct, _ctp, _ct2p, _ct3p, policy, _ct4p]

        # step 6
        c = h**(_sk + R)
        esk = self.group.random(ZR)
        epk = pair(g, _vk)**esk
        sigma = esk + _sk * self.group.hash(str(epk) + str(c))

        # step 7
        return m, p, h_prime, b, _C, c, epk, sigma

    def verify(self, m, p, h_prime, b, C, c, epk, sigma):
        vk = C[4]  # get vk
        vk_s = C[7]  # get vk_s
        b_prime = p * h_prime**m
        base = pair(self.mpk['g'], vk)
        base_sigma_prime = epk * pair(
            self.mpk['g'], vk_s)**self.group.hash(str(epk) + str(c))

        if (b == b_prime and base**sigma == base_sigma_prime):
            return 0
        else:
            return 1

    def adapt(self, sk_delta, m, m_prime, p, h_prime, b, C, c, epk, sigma,
              ID_i, policy_str):
        m_prime = self.group.random(ZR)
        _m = self.group.random(ZR)
        g = self.mpk['g']
        h = self.mpk['h']
        d = self.msk['d0'] + self.msk['d1'] + self.msk['d2']
        alpha = self.msk['alpha']
        mpk = self.mpk
        msk = self.msk
        sk_delta = self.sk_delta
        sk_prime = self.sk_delta['ssk']['sk_prime']
        ID_i = self.ID_i

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row

        # step 2.(b)
        ctp = C[3]
        pair1 = pair(sk_delta['ssk']['sk1'], C[0][2])  # C[0][2] = ct0,3
        pair2 = pair(sk_delta['ssk']['sk0']['g_r_alpha'], C[4])  # C[4] = ct2p
        pair3 = pair(sk_delta['ssk']['sk0']['g_R'],
                     C[0][3])  # C[0][3] = mpk['h_beta_alpha'] ** sum
        cpp = pair1 / (pair2 * pair3)
        seed = str(cpp)
        R = ctp / self.group.hash(seed, ZR)

        # step 3
        nodes = self.util.prune(
            C[6], self.sk_delta['attr_list']
        )  # C[6] = ctxt['policy'] get ciphertext policy
        if not nodes:
            print("Policy is not satisfied.")
            return None

        sk0_tmp = []
        sk0_tmp.append(sk_delta['ssk']['sk0']['h_b1_r1'])
        sk0_tmp.append(sk_delta['ssk']['sk0']['h_b2_r2'])
        sk0_tmp.append(sk_delta['ssk']['sk0']['h_r1_r2_alpha'])

        prod1_GT = 1
        prod2_GT = 1
        for i in range(self.assump_size + 1):
            prod_H = 1
            prod_G = 1
            for node in nodes:
                attr = node.getAttributeAndIndex()
                attr_stripped = self.util.strip_index(
                    attr)  # no need, re-use not allowed
                prod_H *= sk_delta['ssk']['sk_y_t'][attr_stripped][i]
                prod_G *= C[1][attr][i]  # C[1] = _C
            prod1_GT *= pair(sk_prime[i] * prod_H, C[0][i])
            prod2_GT *= pair(prod_G, sk0_tmp[i])
        Cp = -(prod2_GT / prod1_GT)

        sha256 = hashlib.new('sha256')
        sha256.update(self.group.serialize(Cp))
        x = sha256.hexdigest()
        seed = str(x)
        r_tmp = C[2] / self.group.hash(seed, ZR)  # C[2] = _ct

        # step 4
        s_prime = []
        sum_prime = 0  # sum = s1 + s2
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            s_prime.append(rand)
            sum_prime += rand

        _sk_prime = sum_prime
        _vk_prime = self.ID_j**(msk['alpha'] * sum_prime
                                )  # TODO add comment for ID_j

        # step 5
        sha256 = hashlib.new('sha256')
        sha256.update(self.group.serialize(R))
        hd = sha256.hexdigest()
        seed = str(hd)
        e = self.group.hash(seed, ZR)
        r_prime = r_tmp + (m - m_prime) * e / self.sk
        p_prime = self.pk**r_prime

        # step 6
        ct0 = []
        H1 = mpk['H1']
        H2 = mpk['H2']
        ct0.append(H1**s_prime[0])
        ct0.append(H2**s_prime[1])
        ct0.append(h**(sum_prime / msk['alpha']))
        ct0.append(mpk['h_beta_alpha']**sum_prime)

        # pre-compute hashes
        hash_table = []
        for j in range(num_cols):
            x = []
            input_for_hash1 = '0' + str(j + 1)
            for l in range(self.assump_size + 1):
                y = []
                input_for_hash2 = input_for_hash1 + str(l)
                for t in range(self.assump_size):
                    input_for_hash3 = input_for_hash2 + str(t)
                    hashed_value = self.group.hash(input_for_hash3, G1)
                    y.append(hashed_value)
                x.append(y)
            hash_table.append(x)

        # compute C = ct_u_l
        C = {}
        for attr, row in mono_span_prog.items():
            ct = []
            attr_stripped = self.util.strip_index(
                attr)  # no need, re-use not allowed
            for l in range(self.assump_size + 1):
                prod = 1
                cols = len(row)
                for t in range(self.assump_size):
                    input_for_hash = attr_stripped + str(l) + str(t)
                    prod1 = self.group.hash(input_for_hash, G1)
                    for j in range(cols):
                        prod1 *= (hash_table[j][l][t]**row[j])
                    prod *= (prod1**s_prime[t])
                ct.append(prod)
            C[attr] = ct

        # step 7
        sha256 = hashlib.new('sha256')
        msg = mpk['T1']**s_prime[0] * mpk['T2']**s_prime[1]
        sha256.update(self.group.serialize(msg))
        hd = sha256.hexdigest()
        seed = str(hd)
        _ct = r_prime * self.group.hash(seed, ZR)
        d = msk['d0'] + msk['d1'] + msk['d2']

        cpp = pair(g, h**(d / msk['alpha']))**_sk_prime
        seed = str(cpp)
        _ctp = R * self.group.hash(seed, ZR)
        _ct2p = _vk_prime
        _ct3p = self.ID_j**(sum_prime)
        _ct4p = _vk_prime**(sum_prime)
        _C = [ct0, C, _ct, _ctp, _ct2p, _ct3p, policy, _ct4p]
        C_prime = _C

        c_prime = h**(_sk_prime + R)
        esk_prime = self.group.random(ZR)
        epk_prime = pair(g, _vk_prime)**esk_prime
        sigma_prime = esk_prime + _sk_prime * self.group.hash(
            str(epk_prime) + str(c_prime))

        return m_prime, p_prime, h_prime, b, C_prime, c_prime, epk_prime, sigma_prime

    def judge(self, m, p, h_prime, b, C, c, epk, sigma, m_prime, p_prime,
              C_prime, c_prime, epk_prime, sigma_prime):
        rs = 0
        alpha = self.msk['alpha']
        h = self.mpk['h']
        g = self.mpk['g']
        vk = C[4]
        vk_prime = C_prime[4]

        # step 1
        b0 = p * h_prime**m
        b1 = p_prime * h_prime**m_prime

        if (b == b0 and b == b1):
            rs = 0
        else:
            rs = 1

        # step 2
        vk_s = C[7]
        vk_s_prime = C_prime[7]
        base = pair(g, vk)
        base_prime = pair(g, vk_prime)
        base_sigma0 = epk * pair(g, vk_s)**self.group.hash(str(epk) + str(c))
        base_sigma1 = epk_prime * pair(
            g, vk_s_prime)**self.group.hash(str(epk_prime) + str(c_prime))
        if (base**sigma == base_sigma0
                and base_prime**sigma_prime == base_sigma1):
            rs = 0
        else:
            rs = 1

        # step 3
        delta_sk = c_prime / c
        ct_0_3 = C[0][2]
        ct_0_3_prime = C_prime[0][2]
        if (ct_0_3_prime == ct_0_3 * delta_sk):
            rs = 0
        else:
            rs = 1

        # step 4
        pair1 = pair(g, vk**(1 / (alpha * alpha)))
        pair2 = pair(self.ID_i, C[0][2])  # C[0][2] = ct_(0,3)
        if (pair1 == pair2):
            rs = 0
        else:
            rs = 1

        return rs

    def TestExp(self):
        self.mpk['g']**self.msk['a0']
class ABE(ABEnc):
    def __init__(self, group_obj, assump_size, verbose=False, htype='sha256'):
        ABEnc.__init__(self)
        self.group = group_obj
        self.assump_size = assump_size  # size of linear assumption, at least 2
        self.util = MSP(self.group, verbose)
	self.hash_type = htype

    def setup(self):
        """
        Generates master public key and master secret key.
        """

        # generate two instances of the k-linear assumption
        A = []
        B = []
        for i in range(self.assump_size):
            A.append(self.group.random(ZR))
            B.append(self.group.random(ZR))  # note that A, B are vectors here

        # vector includes d_1, d_2, d_3
        k = []
        for i in range(self.assump_size + 1):
            k.append(self.group.random(ZR))

        # pick a random element from the two source groups and pair them
        g = self.group.random(G1)
        h = self.group.random(G2)
        e_gh = pair(g, h)


        # compute the [A]_2 term includes h^{a_1}, h^{a_2}, h
        h_A = []
        for i in range(self.assump_size):
            h_A.append(h ** A[i])
        h_A.append(h)

        # compute the e([k]_1, [A]_2) term, g_k includes g^{d_1}, g^{d_2}, g^{d_3}
        g_k = []
        for i in range(self.assump_size + 1):
            g_k.append(g ** k[i])

        e_gh_kA = []
        for i in range(self.assump_size):
            e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size]))

        # the public key
        mpk = {'h_A': h_A, 'e_gh_kA': e_gh_kA}

        # the master secret key
        msk = {'g': g, 'h': h, 'g_k': g_k, 'A': A, 'B': B}

        return mpk, msk

    def keygen(self, mpk, msk, policy_str):
        """
        Generate a key under a policy string.
        """

        policy = self.util.createPolicy(policy_str)
        mono_span_prog = self.util.convert_policy_to_msp(policy)
        num_cols = self.util.len_longest_row # max col = 3 in this example

        # pick randomness
        r = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            r.append(rand)
            sum += rand

        # first compute Br, which includes b_1 * r_1, b_2 * r_2, r_1 + r_2
        Br = []
        for i in range(self.assump_size):
            Br.append(msk['B'][i] * r[i])
        Br.append(sum)

        # compute the [Br]_2 term, which includes h^{b_1 * r_1], h^{b_2 * r_2}, h^{r_1 + r_2}
        K_0 = []
        for i in range(self.assump_size + 1):
            K_0.append(msk['h'] ** Br[i])

	# compute keys
        K = {}
        A = msk['A']
        g = msk['g']
    	g_k = msk['g_k']
 	
	# len(sigma_col) = 2
        sigma_col = [] 
        for j in range(num_cols-1):
            rand = self.group.random(ZR)
    	    sigma_col.append(rand)
	
        # The we compute the [ attribute y in S ]_1 terms	
	for attr, row in mono_span_prog.items():
            k = []
	    sigma_attr = self.group.random(ZR)
            cols = len(row)
            attr_stripped = self.util.strip_index(attr)  # no need, re-use not allowed

	    #sk_i_1/2
	    for t in range(self.assump_size):
		a_t = A[t]
		prod1 = 1
		for j in range(1, cols): # j = [1, 2]
		    prodt1 = 1	
	
		    for l in range(self.assump_size + 1):
			input_for_hash_1 = '0' + str(j+1) + str(l) + str(t) # l = [0, 1, 2], t = [0, 1]		
			prodt2 = self.group.hash(input_for_hash_1, G1)
			prodt2 = prodt2 ** (Br[l] / a_t)
			prodt1 *= prodt2
		    # g^(sig_p_j/a_t)
		    prodt2 = g ** (sigma_col[j-1] / a_t )
		    prodt1 *= prodt2
		    prodt1 = prodt1 ** (row[j])		
		    #print(prodt1)    
		    prod1 *= prodt1
 
		for l in range(self.assump_size + 1):
		    input_for_hash_2 = attr_stripped + str(l) + str(t)  # l = [0, 1, 2], t = [0, 1]	
		    prodt1 = self.group.hash(input_for_hash_2, G1) ** (Br[l] / a_t)
		    prod1 *= prodt1

		prodt1 = g ** (sigma_attr/a_t)
		prod1 *= prodt1
		prodt1 = (g_k[t]) ** (row[0])
		prod1 *= prodt1
		k.append(prod1) # sk_i1, sk_i2

	    prod1 = 1	    
	    for j in range(1, cols):	# j = [1, 2]
		prod1 *= (g ** (-sigma_col[j-1]) ) ** (row[j])
	    prod1 *= g ** (-sigma_attr)
	    prod1 *= (g_k[self.assump_size]) ** (row[0]) #sk_i3
	    k.append(prod1)
            K[attr] = k

        return {'policy': policy, 'K_0': K_0, 'K': K}

    def encrypt(self, mpk, msg, attr_list):
        """
        Encrypt a message msg for a list of attributes.
        """

        # pick randomness
        s = []
        sum = 0
        for i in range(self.assump_size):
            rand = self.group.random(ZR)
            s.append(rand)
            sum += rand

        # compute the [As]_2 term, h^{a_1 * s_1}, h^{a_2 * s_2}, h^{s_1 * s_2}
        C_0 = []
        h_A = mpk['h_A'] 
        for i in range(self.assump_size):
            C_0.append(h_A[i] ** s[i]) 
        C_0.append(h_A[self.assump_size] ** sum) 

        # compute the [Ws]_1 terms

        C = {}
        for attr in attr_list:
            ct = []
            for l in range(self.assump_size + 1):
                prod = 1
                for t in range(self.assump_size):
                    input_for_hash = attr + str(l) + str(t) # l = [0,1,2], t= [0,1]
                    prod *= (self.group.hash(input_for_hash, G1) ** s[t])
                ct.append(prod)
            C[attr] = ct

        # compute the e(g, h)^(k^T As) . msg term
        Cp = 1
        for i in range(self.assump_size):
            Cp = Cp * (mpk['e_gh_kA'][i] ** s[i])	 
	
	sha256 = hashlib.new(self.hash_type)
	sha256.update(self.group.serialize(Cp))
	x = sha256.hexdigest() 
	Cp = msg^(int(x,16))

        return {'attr_list': attr_list, 'C_0': C_0, 'C': C, 'Cp': Cp}

    def decrypt(self, mpk, key, ctxt):
        """
        Decrypt ciphertext ctxt with decryption key.
        """

        nodes = self.util.prune(key['policy'], ctxt['attr_list'])
        if not nodes:
            print ("Policy is not satisfied.")
            return None

        prod1_GT = 1
        prod2_GT = 1
        for i in range(self.assump_size + 1):
            prod_H = 1
            prod_G = 1
            for node in nodes:
                attr = node.getAttributeAndIndex()
                attr_stripped = self.util.strip_index(attr)  # no need, re-use not allowed
		prod_H *= key['K'][attr][i]
		prod_G *= ctxt['C'][attr_stripped][i]
	    prod1_GT *= pair(prod_H, ctxt['C_0'][i])
            prod2_GT *= pair(prod_G, key['K_0'][i])
	    #Cp = prod2_GT / prod1_GT
	    Cp = prod1_GT / prod2_GT

	sha256 = hashlib.new(self.hash_type)
	sha256.update(self.group.serialize(Cp))
	x = sha256.hexdigest()

        return ctxt['Cp']^(int(x,16))