├── requirements.txt ├── FABEO ├── __init__.py ├── gpsw06kp │ └── __init__.py ├── fabeo22kp │ └── __init__.py ├── bsw07cp │ └── __init__.py ├── waters12dfa │ └── __init__.py ├── waters11cp │ └── __init__.py ├── fabeo22dfa │ └── __init__.py ├── fabeo22cp │ └── __init__.py ├── abgw17kp │ └── __init__.py ├── abgw17cp │ └── __init__.py ├── msp │ └── __init__.py ├── ac17kp │ └── __init__.py ├── cgw15kp │ └── __init__.py ├── ac17cp │ └── __init__.py └── cgw15cp │ └── __init__.py ├── makefile ├── setup.py ├── LICENSE ├── samples ├── run_dfa_schemes.py ├── run_kp_schemes.py ├── run_cp_schemes.py ├── measurements_dfa.py ├── measurements_kp.py └── measurements_cp.py ├── Dockerfile └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | charm-crypto==0.43 2 | -------------------------------------------------------------------------------- /FABEO/__init__.py: -------------------------------------------------------------------------------- 1 | # This is needed for module distinction 2 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: clean setup 2 | 3 | clean: 4 | $(RM) -r pox3.egg-info/ dist/ build/ 5 | 6 | setup: 7 | python setup.py sdist bdist_wheel 8 | 9 | upload: 10 | twine upload --repository pypi dist/* 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | LONG_DESCRIPTION = fh.read() 5 | 6 | setuptools.setup( 7 | name="FABEO", 8 | version="0.1.0", 9 | author="anonymous contributer", 10 | description="Attribute-based Encryption", 11 | long_description=LONG_DESCRIPTION, 12 | long_description_content_type="text/markdown", 13 | url="https://github.com/DoreenRiepel/FABEO.git", 14 | packages=setuptools.find_packages(), 15 | classifiers=[ 16 | "Programming Language :: Python :: 2", 17 | "License :: OSI Approved :: MIT License", 18 | "Operating System :: OS Independent", 19 | ], 20 | python_requires='>=2.7', 21 | include_package_data=True, 22 | ) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Shashank Agrawal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/run_dfa_schemes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from charm.toolbox.DFA import DFA 7 | from FABEO.fabeo22dfa import FABEO22DFA 8 | from FABEO.waters12dfa import WATERS12DFA 9 | 10 | def run_dfa(fe, alphabet, dfaM, x, msg): 11 | 12 | (mpk, msk) = fe.setup(alphabet) 13 | sk = fe.keygen(mpk, msk, dfaM) 14 | ct = fe.encrypt(mpk, x, msg) 15 | rec_msg = fe.decrypt(sk, ct) 16 | 17 | if debug: 18 | if rec_msg == msg: 19 | print("Successful decryption for {}.".format(fe.name)) 20 | else: 21 | print("Decryption failed for {}.".format(fe.name)) 22 | 23 | def main(): 24 | # instantiate a bilinear pairing map 25 | pairing_group = PairingGroup('MNT224') 26 | 27 | alphabet = {'a', 'b'} 28 | 29 | regex = "ab*a" 30 | x_string = "abba" 31 | 32 | dfa = DFA(regex, alphabet) 33 | dfaM = dfa.constructDFA() 34 | x = dfa.getSymbols(x_string) 35 | 36 | # choose a random message 37 | msg = pairing_group.random(GT) 38 | 39 | waters = WATERS12DFA(pairing_group, dfa) 40 | run_dfa(waters, alphabet, dfaM, x, msg) 41 | 42 | fabeo = FABEO22DFA(pairing_group, dfa) 43 | run_dfa(fabeo, alphabet, dfaM, x, msg) 44 | 45 | if __name__ == "__main__": 46 | debug = True 47 | main() 48 | -------------------------------------------------------------------------------- /samples/run_kp_schemes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from FABEO.abgw17kp import ABGW17KPABE 7 | from FABEO.ac17kp import AC17KPABE 8 | from FABEO.cgw15kp import CGW15KPABE 9 | from FABEO.fabeo22kp import FABEO22KPABE 10 | from FABEO.gpsw06kp import GPSW06KPABE 11 | 12 | 13 | def run_kpabe(abe, attr_list, policy_str, msg): 14 | (mpk, msk) = abe.setup() 15 | key = abe.keygen(mpk, msk, policy_str) 16 | ctxt = abe.encrypt(mpk, msg, attr_list) 17 | rec_msg = abe.decrypt(mpk, ctxt, key) 18 | 19 | if debug: 20 | if rec_msg == msg: 21 | print("Successful decryption for {}.".format(abe.name)) 22 | else: 23 | print("Decryption failed for {}.".format(abe.name)) 24 | 25 | def main(): 26 | # instantiate a bilinear pairing map 27 | pairing_group = PairingGroup('MNT224') 28 | 29 | attr_list = ['1', '2', '3'] 30 | policy_str = '((1 and 3) and (2 OR 4))' 31 | 32 | # choose a random message 33 | msg = pairing_group.random(GT) 34 | 35 | gpsw06_kp = GPSW06KPABE(pairing_group, 10) 36 | run_kpabe(gpsw06_kp, attr_list, policy_str, msg) 37 | 38 | cgw15_kp = CGW15KPABE(pairing_group, 2, 10) 39 | run_kpabe(cgw15_kp, attr_list, policy_str, msg) 40 | 41 | abgw17_kp = ABGW17KPABE(pairing_group) 42 | run_kpabe(abgw17_kp, attr_list, policy_str, msg) 43 | 44 | ac17_kp = AC17KPABE(pairing_group, 2) 45 | run_kpabe(ac17_kp, attr_list, policy_str, msg) 46 | 47 | fabeo22_kp = FABEO22KPABE(pairing_group) 48 | run_kpabe(fabeo22_kp, attr_list, policy_str, msg) 49 | 50 | if __name__ == "__main__": 51 | debug = True 52 | main() 53 | -------------------------------------------------------------------------------- /samples/run_cp_schemes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from FABEO.abgw17cp import ABGW17CPABE 7 | from FABEO.ac17cp import AC17CPABE 8 | from FABEO.bsw07cp import BSW07CPABE 9 | from FABEO.cgw15cp import CGW15CPABE 10 | from FABEO.waters11cp import Waters11CPABE 11 | from FABEO.fabeo22cp import FABEO22CPABE 12 | 13 | def run_cpabe(abe, attr_list, policy_str, msg): 14 | (mpk, msk) = abe.setup() 15 | key = abe.keygen(mpk, msk, attr_list) 16 | ctxt = abe.encrypt(mpk, msg, policy_str) 17 | rec_msg = abe.decrypt(mpk, ctxt, key) 18 | 19 | if debug: 20 | if rec_msg == msg: 21 | print("Successful decryption for {}.".format(abe.name)) 22 | else: 23 | print("Decryption failed for {}.".format(abe.name)) 24 | 25 | def main(): 26 | # instantiate a bilinear pairing map 27 | pairing_group = PairingGroup('MNT224') 28 | 29 | attr_list = ['1', '2', '3'] 30 | policy_str = '((1 and 3) and (2 OR 4))' 31 | 32 | # choose a random message 33 | msg = pairing_group.random(GT) 34 | 35 | bsw07_cp = BSW07CPABE(pairing_group) 36 | run_cpabe(bsw07_cp, attr_list, policy_str, msg) 37 | 38 | waters11_cp = Waters11CPABE(pairing_group, 10) 39 | run_cpabe(waters11_cp, attr_list, policy_str, msg) 40 | 41 | cgw15_cp = CGW15CPABE(pairing_group, 2, 10) 42 | run_cpabe(cgw15_cp, attr_list, policy_str, msg) 43 | 44 | abgw17_cp = ABGW17CPABE(pairing_group) 45 | run_cpabe(abgw17_cp, attr_list, policy_str, msg) 46 | 47 | ac17_cp = AC17CPABE(pairing_group, 2) 48 | run_cpabe(ac17_cp, attr_list, policy_str, msg) 49 | 50 | fabeo22_cp = FABEO22CPABE(pairing_group) 51 | run_cpabe(fabeo22_cp, attr_list, policy_str, msg) 52 | 53 | 54 | if __name__ == "__main__": 55 | debug = True 56 | main() 57 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | ENV LANG C.UTF-8 4 | ENV LC_ALL C.UTF-8 5 | 6 | ENV LIBRARY_PATH /usr/local/lib 7 | ENV LD_LIBRARY_PATH /usr/local/lib 8 | 9 | RUN apt update \ 10 | && apt upgrade -y \ 11 | && apt install -y locales 12 | 13 | WORKDIR /root 14 | 15 | RUN apt install -y wget python python-pip 16 | RUN apt install -y gcc flex bison build-essential 17 | 18 | # download and set up gmp and pbc 19 | RUN wget https://ftp.gnu.org/gnu/gmp/gmp-5.1.3.tar.gz 20 | RUN wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz 21 | RUN tar -xf gmp-5.1.3.tar.gz 22 | RUN tar -xf pbc-0.5.14.tar.gz 23 | RUN cd gmp-5.1.3 \ 24 | && ./configure \ 25 | && make \ 26 | && make install 27 | RUN cd pbc-0.5.14 \ 28 | && ./configure \ 29 | && make \ 30 | && make install 31 | 32 | # install packages 33 | RUN apt install -y libssl-dev 34 | RUN pip install setuptools==0.6c11 35 | RUN pip install pyparsing==1.5.6 36 | RUN pip install py==1.4.5 37 | RUN pip install pytest==2.2.0 38 | RUN pip install numpy==1.6.2 39 | 40 | # download and set up charm 41 | RUN wget https://github.com/JHUISI/charm/releases/download/v0.43/Charm-Crypto-0.43_Python2.7.tar.gz 42 | RUN tar -xf Charm-Crypto-0.43_Python2.7.tar.gz 43 | RUN cd Charm-Crypto-0.43 \ 44 | && ./configure.sh \ 45 | # need https here 46 | && sed -i "s|http|https|g" distribute_setup.py \ 47 | && make \ 48 | && make install \ 49 | && ldconfig \ 50 | && make test 51 | 52 | # clean-up 53 | RUN rm gmp-5.1.3.tar.gz \ 54 | && rm pbc-0.5.14.tar.gz \ 55 | && rm Charm-Crypto-0.43_Python2.7.tar.gz \ 56 | && rm -r gmp-5.1.3 \ 57 | && rm -r pbc-0.5.14 \ 58 | && rm -r Charm-Crypto-0.43 59 | 60 | RUN apt install -y git 61 | RUN rm /usr/local/lib/libgmp.so* 62 | 63 | RUN git clone https://github.com/DoreenRiepel/FABEO.git 64 | 65 | 66 | RUN cd FABEO \ 67 | && make \ 68 | && pip install . 69 | 70 | # clean-up 71 | RUN cd FABEO \ 72 | && rm -r FABEO.egg-info \ 73 | && rm -r dist \ 74 | && rm -r build 75 | 76 | RUN python FABEO/samples/run_cp_schemes.py 77 | RUN python FABEO/samples/run_kp_schemes.py 78 | RUN python FABEO/samples/run_dfa_schemes.py 79 | -------------------------------------------------------------------------------- /samples/measurements_dfa.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from charm.toolbox.DFA import DFA 7 | from FABEO.fabeo22dfa import FABEO22DFA 8 | from FABEO.waters12dfa import WATERS12DFA 9 | import time 10 | 11 | def measure_average_times(fe, alphabet, dfaM, x, msg,N=5): 12 | 13 | sum_setup=0 14 | sum_enc=0 15 | sum_keygen=0 16 | sum_dec=0 17 | 18 | for i in range(N): 19 | # setup time 20 | start_setup = time.time() 21 | (mpk, msk) = fe.setup(alphabet) 22 | end_setup = time.time() 23 | time_setup = end_setup-start_setup 24 | sum_setup += time_setup 25 | 26 | # encryption time 27 | start_enc = time.time() 28 | ctxt = fe.encrypt(mpk, x, msg) 29 | end_enc = time.time() 30 | time_enc = end_enc - start_enc 31 | sum_enc += time_enc 32 | 33 | # keygen time 34 | start_keygen = time.time() 35 | key = fe.keygen(mpk, msk, dfaM) 36 | end_keygen = time.time() 37 | time_keygen = end_keygen - start_keygen 38 | sum_keygen += time_keygen 39 | 40 | # decryption time 41 | start_dec = time.time() 42 | rec_msg = fe.decrypt(key, ctxt) 43 | end_dec = time.time() 44 | time_dec = end_dec - start_dec 45 | sum_dec += time_dec 46 | 47 | # sanity check 48 | if rec_msg!= msg: 49 | print ("Decryption failed.") 50 | 51 | # compute average time 52 | time_setup = sum_setup/N 53 | time_enc = sum_enc/N 54 | time_keygen = sum_keygen/N 55 | time_dec = sum_dec/N 56 | 57 | return [time_setup, time_keygen, time_enc, time_dec] 58 | 59 | def print_running_time(scheme_name,times): 60 | print('{:<20}'.format(scheme_name) + format(times[0]*1000, '7.2f') + ' ' + format(times[1]*1000, '7.2f') + ' ' + format(times[2]*1000, '7.2f') + ' ' + format(times[3]*1000, '7.2f')) 61 | 62 | def run_all(pairing_group, alphabet, regex, x_string, msg): 63 | dfa = DFA(regex, alphabet) 64 | dfaM = dfa.constructDFA() 65 | x = dfa.getSymbols(x_string) 66 | q, t, f, ell = get_par(dfaM, x) 67 | 68 | algos = ['Setup', 'KeyGen', 'Enc', 'Dec'] 69 | 70 | print('Running times (ms) curve MNT224: |Q|={} |T|={} |F|={} |x|={}'.format(q,t,f,ell)) 71 | print(' - alphabet={} regex={} x={}'.format("(" + ", ".join(alphabet) + ")",regex,x_string)) 72 | algo_string = 'Scheme {:<13}'.format('') + ' ' + algos[0] + ' ' + algos[1] + ' ' + algos[2] + ' ' + algos[3] 73 | print('-'*56) 74 | print(algo_string) 75 | print('-'*56) 76 | 77 | waters_dfa = WATERS12DFA(pairing_group, dfa) 78 | waters_dfa_times = measure_average_times(waters_dfa,alphabet,dfaM,x,msg) 79 | print_running_time(waters_dfa.name,waters_dfa_times) 80 | 81 | fabeo_dfa = FABEO22DFA(pairing_group, dfa) 82 | fabeo_dfa_times = measure_average_times(fabeo_dfa,alphabet,dfaM,x,msg) 83 | print_running_time(fabeo_dfa.name,fabeo_dfa_times) 84 | 85 | print('-'*56) 86 | print 87 | 88 | def get_par(dfaM, x): 89 | Q, S, T, q0, F = dfaM 90 | q = len(Q) 91 | t = len(T) 92 | f = len(F) 93 | ell = len(x) 94 | return q,t,f,ell 95 | 96 | def main(): 97 | # instantiate a bilinear pairing map 98 | pairing_group = PairingGroup('MNT224') 99 | 100 | msg = pairing_group.random(GT) 101 | 102 | alphabet = {'a', 'b'} 103 | regex = "ab*a" 104 | x_string = "abba" 105 | 106 | run_all(pairing_group, alphabet, regex ,x_string, msg) 107 | 108 | if __name__ == "__main__": 109 | debug = True 110 | main() 111 | -------------------------------------------------------------------------------- /FABEO/gpsw06kp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Vipul Goyal, Omkant Pandey, Amit Sahai, Brent Waters 3 | 4 | | From: "Attribute-Based Encryption for Fine-Grained Access Control of Encrypted Data" 5 | | Published in: 2006 6 | | Available from: https://eprint.iacr.org/2006/309.pdf 7 | | Notes: Implemented the scheme in Appendix A.1 8 | | 9 | | type: key-policy attribute-based encryption 10 | | setting: Pairing 11 | 12 | :Authors: Doreen Riepel 13 | :Date: 04/2022 14 | ''' 15 | 16 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 17 | from charm.toolbox.ABEnc import ABEnc 18 | from ..msp import MSP 19 | 20 | debug = False 21 | 22 | 23 | class GPSW06KPABE(ABEnc): 24 | 25 | def __init__(self, group_obj, uni_size, verbose=False): 26 | ABEnc.__init__(self) 27 | self.name = "GPSW06 KP-ABE" 28 | self.group = group_obj 29 | self.uni_size = uni_size # bound on the size of the universe of attributes 30 | self.util = MSP(self.group, verbose) 31 | 32 | def setup(self): 33 | """ 34 | Generates public key and master secret key. 35 | """ 36 | 37 | if debug: 38 | print('Setup algorithm:\n') 39 | 40 | # pick a random element each from two source groups and pair them 41 | g1 = self.group.random(G1) 42 | g2 = self.group.random(G2) 43 | alpha = self.group.random(ZR) 44 | e_gg_alpha = pair(g1, g2) ** alpha 45 | 46 | g_t = [1] 47 | t = [0] 48 | for i in range(self.uni_size): 49 | ti = self.group.random(ZR) 50 | t.append(ti) 51 | g_ti = g1 ** ti 52 | g_t.append(g_ti) 53 | 54 | pk = {'g_t': g_t, 'e_gg_alpha': e_gg_alpha} 55 | msk = {'g2': g2, 't': t, 'alpha': alpha} 56 | return pk, msk 57 | 58 | def encrypt(self, pk, msg, attr_list): 59 | """ 60 | Encrypt a message M under a set of attributes. 61 | """ 62 | 63 | if debug: 64 | print('Encryption algorithm:\n') 65 | 66 | s = self.group.random(ZR) 67 | c0 = pk['e_gg_alpha'] ** s * msg 68 | 69 | 70 | cy = {} 71 | for attr in attr_list: 72 | cy[attr] = pk['g_t'][int(attr)] ** s 73 | 74 | return {'attr_list': attr_list, 'c0': c0, 'cy': cy} 75 | 76 | def keygen(self, pk, msk, policy_str): 77 | """ 78 | Generate a key for a monotone span program. 79 | """ 80 | 81 | if debug: 82 | print('Key generation algorithm:\n') 83 | 84 | policy = self.util.createPolicy(policy_str) 85 | mono_span_prog = self.util.convert_policy_to_msp(policy) 86 | num_cols = self.util.len_longest_row 87 | 88 | # pick randomness 89 | u = [msk['alpha']] 90 | for i in range(num_cols-1): 91 | rand = self.group.random(ZR) 92 | u.append(rand) 93 | 94 | k = {} 95 | for attr, row in mono_span_prog.items(): 96 | cols = len(row) 97 | sum = 0 98 | for i in range(cols): 99 | sum += row[i] * u[i] 100 | attr_stripped = self.util.strip_index(attr) 101 | di = msk['g2'] ** (sum/msk['t'][int(attr_stripped)]) 102 | k[attr] = di 103 | 104 | return {'policy': policy, 'k': k} 105 | 106 | def decrypt(self, pk, ctxt, key): 107 | """ 108 | Decrypt ciphertext ctxt with key key. 109 | """ 110 | 111 | if debug: 112 | print('Decryption algorithm:\n') 113 | 114 | nodes = self.util.prune(key['policy'], ctxt['attr_list']) 115 | if not nodes: 116 | print ("Policy not satisfied.") 117 | return None 118 | 119 | prodGT = 1 120 | 121 | for node in nodes: 122 | attr = node.getAttributeAndIndex() 123 | attr_stripped = self.util.strip_index(attr) 124 | prodGT *= pair(ctxt['cy'][attr_stripped],key['k'][attr]) 125 | 126 | return (ctxt['c0'] / prodGT) 127 | -------------------------------------------------------------------------------- /FABEO/fabeo22kp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Doreen Riepel, Hoeteck Wee 3 | 4 | | From: "FABEO: Fast Attribute-Based Encryption with Optimal Security" 5 | | Published in: 2022 6 | | Notes: Implemented the scheme in Figure 1 (right) 7 | | 8 | | type: key-policy attribute-based encryption 9 | | setting: Pairing 10 | 11 | :Authors: Doreen Riepel 12 | :Date: 06/2023 13 | ''' 14 | 15 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 16 | from charm.toolbox.ABEnc import ABEnc 17 | from ..msp import MSP 18 | 19 | debug = False 20 | 21 | 22 | class FABEO22KPABE(ABEnc): 23 | def __init__(self, group_obj, verbose=False): 24 | ABEnc.__init__(self) 25 | self.name = "FABEO KP-ABE" 26 | self.group = group_obj 27 | self.util = MSP(self.group, verbose) 28 | 29 | def setup(self): 30 | """ 31 | Generates public key and master secret key. 32 | """ 33 | 34 | if debug: 35 | print('\nSetup algorithm:\n') 36 | 37 | # pick a random element from the two source groups and pair them 38 | g1 = self.group.random(G1) 39 | g2 = self.group.random(G2) 40 | e_g1g2 = pair(g1, g2) 41 | 42 | alpha = self.group.random(ZR) 43 | 44 | # now compute various parts of the public parameters 45 | e_g1g2_alpha = e_g1g2 ** alpha 46 | 47 | # the master secret and public key 48 | msk = {'alpha': alpha} 49 | pk = {'g1': g1, 'g2': g2, 'e_g1g2_alpha': e_g1g2_alpha} 50 | 51 | return pk, msk 52 | 53 | def encrypt(self, pk, msg, attr_list): 54 | """ 55 | Encrypt a message msg under a policy string. 56 | """ 57 | 58 | if debug: 59 | print('\nEncryption algorithm:\n') 60 | 61 | s = self.group.random(ZR) 62 | g2_s = pk['g2'] ** s 63 | 64 | ct = {} 65 | for attr in attr_list: 66 | attrHash = self.group.hash(attr, G1) 67 | ct[attr] = attrHash ** s 68 | 69 | # compute the e(g, h)^(As) * m term 70 | Cp = pk['e_g1g2_alpha'] ** s 71 | Cp = Cp * msg 72 | 73 | return {'attr_list': attr_list, 'g2_s': g2_s, 'ct': ct, 'Cp': Cp} 74 | 75 | def keygen(self, pk, msk, policy_str): 76 | """ 77 | Generate a key for a list of attributes. 78 | """ 79 | 80 | if debug: 81 | print('\nKey generation algorithm:\n') 82 | 83 | policy = self.util.createPolicy(policy_str) 84 | mono_span_prog = self.util.convert_policy_to_msp(policy) 85 | num_cols = self.util.len_longest_row 86 | 87 | # pick randomness 88 | r = self.group.random(ZR) 89 | 90 | g2_r = pk['g2'] ** r 91 | 92 | # pick random shares 93 | v = [msk['alpha']] 94 | for i in range(num_cols-1): 95 | rand = self.group.random(ZR) 96 | v.append(rand) 97 | 98 | sk = {} 99 | for attr, row in mono_span_prog.items(): 100 | attr_stripped = self.util.strip_index(attr) 101 | attrHash = self.group.hash(attr_stripped, G1) 102 | len_row = len(row) 103 | Mivtop = sum(i[0] * i[1] for i in zip(row, v[:len_row])) 104 | sk[attr] = pk['g1'] ** Mivtop * attrHash ** r 105 | 106 | return {'policy': policy, 'g2_r': g2_r, 'sk': sk} 107 | 108 | def decrypt(self, pk, ctxt, key): 109 | """ 110 | Decrypt ciphertext ctxt with key key. 111 | """ 112 | 113 | if debug: 114 | print('\nDecryption algorithm:\n') 115 | 116 | nodes = self.util.prune(key['policy'], ctxt['attr_list']) 117 | 118 | if not nodes: 119 | print ("Policy not satisfied.") 120 | return None 121 | 122 | prod_sk = 1 123 | prod_ct = 1 124 | for node in nodes: 125 | attr = node.getAttributeAndIndex() 126 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 127 | 128 | prod_sk *= key['sk'][attr] 129 | prod_ct *= ctxt['ct'][attr_stripped] 130 | 131 | e1 = pair(prod_sk, ctxt['g2_s']) 132 | e2 = pair(prod_ct, key['g2_r']) 133 | 134 | kem = e1/e2 135 | 136 | return ctxt['Cp'] / kem -------------------------------------------------------------------------------- /FABEO/bsw07cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | John Bethencourt, Amit Sahai, Brent Waters 3 | 4 | | From: "Ciphertext-Policy Attribute-Based Encryption" 5 | | Published in: 2007 6 | | Available from: https://doi.org/10.1109/SP.2007.11 7 | | Notes: Implemented an asymmetric version of the scheme in Section 4.2 8 | | Security Assumption: Generic group model 9 | | 10 | | type: ciphertext-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Shashank Agrawal 14 | :Date: 05/2016 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class BSW07CPABE(ABEnc): 25 | 26 | def __init__(self, group_obj, verbose=False): 27 | ABEnc.__init__(self) 28 | self.name = "BSW07 CP-ABE" 29 | self.group = group_obj 30 | self.util = MSP(self.group, verbose) 31 | 32 | def setup(self): 33 | """ 34 | Generates public key and master secret key. 35 | """ 36 | 37 | if debug: 38 | print('Setup algorithm:\n') 39 | 40 | # pick a random element each from two source groups 41 | g1 = self.group.random(G1) 42 | g2 = self.group.random(G2) 43 | 44 | beta = self.group.random(ZR) 45 | h = g2 ** beta 46 | f = g2 ** (1/beta) 47 | 48 | alpha = self.group.random(ZR) 49 | g1_alpha = g1 ** alpha 50 | e_gg_alpha = pair (g1_alpha, g2) 51 | 52 | pk = {'g1': g1, 'g2': g2, 'h': h, 'f': f, 'e_gg_alpha': e_gg_alpha} 53 | msk = {'beta': beta, 'g1_alpha': g1_alpha} 54 | return pk, msk 55 | 56 | def keygen(self, pk, msk, attr_list): 57 | """ 58 | Generate a key for a set of attributes. 59 | """ 60 | 61 | if debug: 62 | print('Key generation algorithm:\n') 63 | 64 | r = self.group.random(ZR) 65 | g1_r = pk['g1'] ** r 66 | beta_inverse = 1 / msk['beta'] 67 | k0 = (msk['g1_alpha'] * g1_r) ** beta_inverse 68 | 69 | K = {} 70 | for attr in attr_list: 71 | r_attr = self.group.random(ZR) 72 | k_attr1 = g1_r * (self.group.hash(str(attr), G1) ** r_attr) 73 | k_attr2 = pk['g2'] ** r_attr 74 | K[attr] = (k_attr1, k_attr2) 75 | 76 | return {'attr_list': attr_list, 'k0': k0, 'K': K} 77 | 78 | def encrypt(self, pk, msg, policy_str): 79 | """ 80 | Encrypt a message M under a policy string. 81 | """ 82 | 83 | if debug: 84 | print('Encryption algorithm:\n') 85 | 86 | policy = self.util.createPolicy(policy_str) 87 | mono_span_prog = self.util.convert_policy_to_msp(policy) 88 | num_cols = self.util.len_longest_row 89 | 90 | # pick randomness 91 | u = [] 92 | for i in range(num_cols): 93 | rand = self.group.random(ZR) 94 | u.append(rand) 95 | s = u[0] # shared secret 96 | 97 | c0 = pk['h'] ** s 98 | 99 | C = {} 100 | for attr, row in mono_span_prog.items(): 101 | cols = len(row) 102 | sum = 0 103 | for i in range(cols): 104 | sum += row[i] * u[i] 105 | attr_stripped = self.util.strip_index(attr) 106 | c_i1 = pk['g2'] ** sum 107 | c_i2 = self.group.hash(str(attr_stripped), G1) ** sum 108 | C[attr] = (c_i1, c_i2) 109 | 110 | c_m = (pk['e_gg_alpha'] ** s) * msg 111 | 112 | return {'policy': policy, 'c0': c0, 'C': C, 'c_m': c_m} 113 | 114 | def decrypt(self, pk, ctxt, key): 115 | """ 116 | Decrypt ciphertext ctxt with key key. 117 | """ 118 | 119 | if debug: 120 | print('Decryption algorithm:\n') 121 | 122 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 123 | if not nodes: 124 | print ("Policy not satisfied.") 125 | return None 126 | 127 | prod = 1 128 | 129 | for node in nodes: 130 | attr = node.getAttributeAndIndex() 131 | attr_stripped = self.util.strip_index(attr) 132 | (c_attr1, c_attr2) = ctxt['C'][attr] 133 | (k_attr1, k_attr2) = key['K'][attr_stripped] 134 | prod *= (pair(k_attr1, c_attr1) / pair(c_attr2, k_attr2)) 135 | 136 | return (ctxt['c_m'] * prod) / (pair(key['k0'], ctxt['c0'])) 137 | -------------------------------------------------------------------------------- /FABEO/waters12dfa/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Brent Waters 3 | 4 | | From: "Functional Encryption for Regular Languages". 5 | | Published in: 2012 6 | | Available from: http://eprint.iacr.org/2012/384 7 | | Notes: transferred to asymmetric pairing group setting 8 | | original code: https://jhuisi.github.io/charm/_modules/dfa_fe12.html#FE_DFA 9 | | 10 | | type: functional encryption ("public index") 11 | | setting: Pairing 12 | 13 | :Authors: Doreen Riepel 14 | :Date: 04/2022 15 | ''' 16 | from charm.toolbox.pairinggroup import PairingGroup,ZR,G1,G2,GT,pair 17 | from charm.toolbox.DFA import DFA 18 | 19 | debug = False 20 | 21 | class WATERS12DFA: 22 | def __init__(self, groupObj, dfaObj): 23 | # global group, dfaObj 24 | self.name = "Waters DFA" 25 | self.group = groupObj 26 | self.dfaObj = dfaObj 27 | 28 | def setup(self, alphabet): 29 | # pick a random element from the two source groups and pair them 30 | g = self.group.random(G1) 31 | h = self.group.random(G2) 32 | e_gh = pair(g, h) 33 | 34 | w_start, w_end, z = self.group.random(ZR,3) 35 | 36 | w = {'start':w_start, 'end':w_end } 37 | for sigma in alphabet: 38 | w[str(sigma)] = self.group.random(ZR) 39 | 40 | g_w = {} 41 | for label, w_i in w.items(): 42 | g_w[label] = g ** w_i 43 | g_z = g ** z 44 | 45 | alpha = self.group.random(ZR) 46 | 47 | msk = {'h': h, 'z': z, 'w':w, 'alpha': alpha} 48 | mpk = {'g': g, 'g_z':g_z, 'g_w':g_w, 'e_gh_alpha':e_gh ** alpha } 49 | return (mpk, msk) 50 | 51 | def keygen(self, mpk, msk, dfaM): 52 | Q, S, T, q0, F = dfaM 53 | q = len(Q) 54 | # associate D_i with each state q_i in Q 55 | d = self.group.random(ZR, q+1) # [0, q] including q-th index 56 | r_start = self.group.random(ZR) 57 | K = {} 58 | K['start1'] = msk['h'] ** (d[0] + msk['w']['start'] * r_start) 59 | K['start2'] = msk['h'] ** r_start 60 | 61 | for t in T: # for each tuple, t in transition list 62 | rx = self.group.random(ZR) 63 | (x, y, sigma) = t 64 | K[str(t)] = {} 65 | K[str(t)][1] = msk['h'] ** (-d[x] + msk['z'] * rx) 66 | K[str(t)][2] = msk['h'] ** rx 67 | K[str(t)][3] = msk['h'] ** (d[y] + msk['w'][str(sigma)] * rx) 68 | 69 | # for each accept state in the set of all accept states 70 | K['end'] = {} 71 | for x in F: 72 | rx = self.group.random(ZR) 73 | K['end'][str(x)] = {} 74 | K['end'][str(x)][1] = msk['h'] ** (msk['alpha'] - d[x] + msk['w']['end'] * rx) 75 | K['end'][str(x)][2] = msk['h'] ** rx 76 | 77 | sk = {'K':K, 'dfaM':dfaM } 78 | return sk 79 | 80 | def encrypt(self, mpk, x, M): 81 | l = len(x) # symbols of string 82 | s = self.group.random(ZR, l+1) # l+1 b/c it includes 'l'-th index 83 | C = {} 84 | C['m'] = M * (mpk['e_gh_alpha'] ** s[l]) 85 | 86 | C[0] = {} 87 | C[0][1] = mpk['g'] ** s[0] 88 | C[0][2] = mpk['g_w']['start'] ** s[0] 89 | 90 | for i in range(1, l+1): 91 | C[i] = {} 92 | C[i][1] = mpk['g'] ** s[i] 93 | C[i][2] = (mpk['g_z'] ** s[i-1]) * (mpk['g_w'][str(x[i])] ** s[i]) 94 | 95 | C['end'] = mpk['g_w']['end'] ** s[l] 96 | ct = {'C':C, 'x':x} 97 | return ct 98 | 99 | def decrypt(self, sk, ct): 100 | K, dfaM = sk['K'], sk['dfaM'] 101 | C, x = ct['C'], ct['x'] 102 | l = len(x) 103 | B = {} 104 | # if DFA does not accept string, return immediately 105 | if not self.dfaObj.accept(dfaM, x): 106 | print("DFA rejects: ", x) 107 | return False 108 | 109 | Ti = self.dfaObj.getTransitions(dfaM, x) # returns a tuple of transitions 110 | B[0] = pair(C[0][1], K['start1']) / pair(C[0][2], K['start2']) 111 | for i in range(1, l+1): 112 | ti = Ti[i] 113 | if debug: print("transition: ", ti) 114 | B[i] = B[i-1] * ( pair(C[i-1][1], K[str(ti)][1]) / pair(C[i][2], K[str(ti)][2]) ) * pair(C[i][1], K[str(ti)][3]) 115 | 116 | x = self.dfaObj.getAcceptState(Ti) # retrieve accept state 117 | Bend = B[l] * pair(C[l][1], K['end'][str(x)][1]) / pair(C['end'], K['end'][str(x)][2]) 118 | M = C['m'] / Bend 119 | return M -------------------------------------------------------------------------------- /FABEO/waters11cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Brent Waters 3 | 4 | | From: "Ciphertext-Policy Attribute-Based Encryption: An Expressive, Efficient, and Provably Secure Realization" 5 | | Published in: 2011 6 | | Available from: https://doi.org/10.1007/978-3-642-19379-8_4 7 | | Notes: Implemented an asymmetric version of the scheme in Section 3 8 | | Security Assumption: Decisional Parallel Bilinear Diffie-Hellman Exponent 9 | | 10 | | type: ciphertext-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Shashank Agrawal 14 | :Date: 05/2016 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class Waters11CPABE(ABEnc): 25 | 26 | def __init__(self, group_obj, uni_size, verbose=False): 27 | ABEnc.__init__(self) 28 | self.name = "Waters11 CP-ABE" 29 | self.group = group_obj 30 | self.uni_size = uni_size # bound on the size of the universe of attributes 31 | self.util = MSP(self.group, verbose) 32 | 33 | def setup(self): 34 | """ 35 | Generates public key and master secret key. 36 | """ 37 | 38 | if debug: 39 | print('Setup algorithm:\n') 40 | 41 | # pick a random element each from two source groups and pair them 42 | g1 = self.group.random(G1) 43 | g2 = self.group.random(G2) 44 | alpha = self.group.random(ZR) 45 | g1_alpha = g1 ** alpha 46 | e_gg_alpha = pair(g1_alpha, g2) 47 | 48 | a = self.group.random(ZR) 49 | g1_a = g1 ** a 50 | 51 | h = [0] 52 | for i in range(self.uni_size): 53 | h.append(self.group.random(G1)) 54 | 55 | pk = {'g1': g1, 'g2': g2, 'g1_a': g1_a, 'h': h, 'e_gg_alpha': e_gg_alpha} 56 | msk = {'g1_alpha': g1_alpha} 57 | return pk, msk 58 | 59 | def keygen(self, pk, msk, attr_list): 60 | """ 61 | Generate a key for a set of attributes. 62 | """ 63 | 64 | if debug: 65 | print('Key generation algorithm:\n') 66 | 67 | t = self.group.random(ZR) 68 | k0 = msk['g1_alpha'] * (pk['g1_a'] ** t) 69 | L = pk['g2'] ** t 70 | 71 | K = {} 72 | for attr in attr_list: 73 | K[attr] = pk['h'][int(attr)] ** t 74 | 75 | return {'attr_list': attr_list, 'k0': k0, 'L': L, 'K': K} 76 | 77 | def encrypt(self, pk, msg, policy_str): 78 | """ 79 | Encrypt a message M under a monotone span program. 80 | """ 81 | 82 | if debug: 83 | print('Encryption algorithm:\n') 84 | 85 | policy = self.util.createPolicy(policy_str) 86 | mono_span_prog = self.util.convert_policy_to_msp(policy) 87 | num_cols = self.util.len_longest_row 88 | 89 | # pick randomness 90 | u = [] 91 | for i in range(num_cols): 92 | rand = self.group.random(ZR) 93 | u.append(rand) 94 | s = u[0] # shared secret 95 | 96 | c0 = pk['g2'] ** s 97 | 98 | C = {} 99 | D = {} 100 | for attr, row in mono_span_prog.items(): 101 | cols = len(row) 102 | sum = 0 103 | for i in range(cols): 104 | sum += row[i] * u[i] 105 | attr_stripped = self.util.strip_index(attr) 106 | r_attr = self.group.random(ZR) 107 | c_attr = (pk['g1_a'] ** sum) / (pk['h'][int(attr_stripped)] ** r_attr) 108 | d_attr = pk['g2'] ** r_attr 109 | C[attr] = c_attr 110 | D[attr] = d_attr 111 | 112 | c_m = (pk['e_gg_alpha'] ** s) * msg 113 | 114 | return {'policy': policy, 'c0': c0, 'C': C, 'D': D, 'c_m': c_m} 115 | 116 | def decrypt(self, pk, ctxt, key): 117 | """ 118 | Decrypt ciphertext ctxt with key key. 119 | """ 120 | 121 | if debug: 122 | print('Decryption algorithm:\n') 123 | 124 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 125 | if not nodes: 126 | print ("Policy not satisfied.") 127 | return None 128 | 129 | prodG = 1 130 | prodGT = 1 131 | 132 | for node in nodes: 133 | attr = node.getAttributeAndIndex() 134 | attr_stripped = self.util.strip_index(attr) 135 | prodG *= ctxt['C'][attr] 136 | prodGT *= pair(key['K'][attr_stripped], ctxt['D'][attr]) 137 | 138 | return (ctxt['c_m'] * pair(prodG, key['L']) * prodGT) / (pair(key['k0'], ctxt['c0'])) 139 | -------------------------------------------------------------------------------- /FABEO/fabeo22dfa/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Doreen Riepel, Hoeteck Wee 3 | 4 | | From: "FABEO: Fast Attribute-Based Encryption with Optimal Security" 5 | | Published in: 2022 6 | | Notes: Implemented the scheme in Section 8.2 7 | | 8 | | type: functional encryption ("public index") 9 | | setting: Pairing 10 | 11 | :Authors: Doreen Riepel 12 | :Date: 06/2023 13 | ''' 14 | 15 | from charm.toolbox.pairinggroup import PairingGroup,ZR,G1,G2,GT,pair 16 | from charm.toolbox.DFA import DFA 17 | 18 | debug = False 19 | 20 | class FABEO22DFA: 21 | def __init__(self, groupObj, dfaObj): 22 | # global group, dfaObj 23 | self.name = "FABEO DFA" 24 | self.group = groupObj 25 | self.dfaObj = dfaObj 26 | 27 | def setup(self, alphabet): 28 | 29 | # pick a random element from the two source groups and pair them 30 | g1 = self.group.random(G1) 31 | g2 = self.group.random(G2) 32 | e_g1g2 = pair(g1, g2) 33 | 34 | w_start, w_end, z = self.group.random(ZR,3) 35 | 36 | w = {'start':w_start, 'end':w_end } 37 | for sigma in alphabet: 38 | w[str(sigma)] = self.group.random(ZR) 39 | 40 | g1_w = {} 41 | for label, w_i in w.items(): 42 | g1_w[label] = g1 ** w_i 43 | g1_z = g1 ** z 44 | 45 | alpha = self.group.random(ZR) 46 | 47 | msk = {'g2': g2, 'z': z, 'w':w, 'alpha': alpha} 48 | mpk = {'g1': g1, 'g1_z':g1_z, 'g1_w':g1_w, 'e_g1g2_alpha':e_g1g2 ** alpha } 49 | return (mpk, msk) 50 | 51 | def keygen(self, mpk, msk, dfaM): 52 | Q, S, T, q0, F = dfaM 53 | q = len(Q) 54 | # associate D_i with each state q_i in Q 55 | 56 | d = {} 57 | r = {} 58 | g2_r = {} 59 | 60 | for u in Q: 61 | d_u = self.group.random(ZR) 62 | d[str(u)] = d_u 63 | r_u = self.group.random(ZR) 64 | r[str(u)] = r_u 65 | g2_r[str(u)] = msk['g2'] ** r_u 66 | 67 | K = {} 68 | K['start1'] = msk['g2'] ** (d[str(Q[0])] + msk['w']['start'] * r[str(Q[0])]) 69 | K['start2'] = msk['g2'] ** r[str(Q[0])] 70 | 71 | 72 | for t in T: # for each tuple, t in transition list 73 | (x, y, sigma) = t 74 | K[str(t)] = {} 75 | K[str(t)][1] = msk['g2'] ** (-d[str(x)] + msk['z'] * r[str(x)]) 76 | # K[str(t)][2] = msk['h'] ** r[str(x)] 77 | K[str(t)][3] = msk['g2'] ** (d[str(y)] + msk['w'][str(sigma)] * r[str(x)]) 78 | 79 | # for each accept state in the set of all accept states 80 | K['end'] = {} 81 | for x in F: 82 | K['end'][str(x)] = {} 83 | K['end'][str(x)][1] = msk['g2'] ** (msk['alpha'] - d[str(x)] + msk['w']['end'] * r[str(x)]) 84 | # K['end'][str(x)][2] = msk['h'] ** r[str(x)] 85 | 86 | sk = {'K':K, 'g2_r':g2_r, 'dfaM':dfaM } 87 | return sk 88 | 89 | def encrypt(self, mpk, x, M): 90 | l = len(x) # symbols of string 91 | s = self.group.random(ZR, l+1) # l+1 b/c it includes 'l'-th index 92 | C = {} 93 | C['m'] = M * (mpk['e_g1g2_alpha'] ** s[l]) 94 | 95 | C[0] = {} 96 | C[0][1] = mpk['g1'] ** s[0] 97 | C[0][2] = mpk['g1_w']['start'] ** s[0] 98 | 99 | for i in range(1, l+1): 100 | C[i] = {} 101 | C[i][1] = mpk['g1'] ** s[i] 102 | C[i][2] = (mpk['g1_z'] ** s[i-1]) * (mpk['g1_w'][str(x[i])] ** s[i]) 103 | 104 | C['end'] = mpk['g1_w']['end'] ** s[l] 105 | ct = {'C':C, 'x':x} 106 | return ct 107 | 108 | def decrypt(self, sk, ct): 109 | K, h_r, dfaM = sk['K'], sk['g2_r'], sk['dfaM'] 110 | C, x = ct['C'], ct['x'] 111 | l = len(x) 112 | B = {} 113 | # if DFA does not accept string, return immediately 114 | if not self.dfaObj.accept(dfaM, x): 115 | print("DFA rejects: ", x) 116 | return False 117 | 118 | Ti = self.dfaObj.getTransitions(dfaM, x) # returns a tuple of transitions 119 | B[0] = pair(C[0][1], K['start1']) / pair(C[0][2], K['start2']) 120 | 121 | for i in range(1, l+1): 122 | ti = Ti[i] 123 | if debug: print("transition: ", ti) 124 | B[i] = B[i-1] * ( pair(C[i-1][1], K[str(ti)][1]) / pair(C[i][2], h_r[str(ti[0])]) ) * pair(C[i][1], K[str(ti)][3]) 125 | 126 | x = self.dfaObj.getAcceptState(Ti) # retrieve accept state 127 | Bend = B[l] * pair(C[l][1], K['end'][str(x)][1]) / pair(C['end'], h_r[str(x)]) 128 | M = C['m'] / Bend 129 | return M -------------------------------------------------------------------------------- /FABEO/fabeo22cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Doreen Riepel, Hoeteck Wee 3 | 4 | | From: "FABEO: Fast Attribute-Based Encryption with Optimal Security" 5 | | Published in: 2022 6 | | Notes: Implemented the scheme in Figure 1 (left) 7 | | 8 | | type: ciphertext-policy attribute-based encryption 9 | | setting: Pairing 10 | 11 | :Authors: Doreen Riepel 12 | :Date: 06/2023 13 | ''' 14 | 15 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 16 | from charm.toolbox.ABEnc import ABEnc 17 | from ..msp import MSP 18 | 19 | debug = False 20 | 21 | class FABEO22CPABE(ABEnc): 22 | def __init__(self, group_obj, verbose=False): 23 | ABEnc.__init__(self) 24 | self.name = "FABEO CP-ABE" 25 | self.group = group_obj 26 | self.util = MSP(self.group, verbose) 27 | 28 | def setup(self): 29 | """ 30 | Generates public key and master secret key. 31 | """ 32 | 33 | if debug: 34 | print('\nSetup algorithm:\n') 35 | 36 | # pick a random element from the two source groups and pair them 37 | g1 = self.group.random(G1) 38 | g2 = self.group.random(G2) 39 | e_g1g2 = pair(g1, g2) 40 | 41 | alpha = self.group.random(ZR) 42 | 43 | # now compute various parts of the public parameters 44 | e_g1g2_alpha = e_g1g2 ** alpha 45 | 46 | # the master secret and public key 47 | msk = {'alpha': alpha} 48 | pk = {'g1': g1, 'g2': g2, 'e_g1g2_alpha': e_g1g2_alpha} 49 | 50 | return pk, msk 51 | 52 | def keygen(self, pk, msk, attr_list): 53 | """ 54 | Generate a key for a list of attributes. 55 | """ 56 | 57 | if debug: 58 | print('\nKey generation algorithm:\n') 59 | 60 | r = self.group.random(ZR) 61 | g2_r = pk['g2'] ** r 62 | 63 | sk1 = {} 64 | for attr in attr_list: 65 | attrHash = self.group.hash(attr, G1) 66 | sk1[attr] = attrHash ** r 67 | 68 | bHash = self.group.hash(str(self.group.order()+1), G1) # ZR+1 69 | 70 | sk2 = pk['g1'] ** msk['alpha'] * bHash ** r 71 | 72 | return {'attr_list': attr_list, 'g2_r': g2_r, 'sk1': sk1, 'sk2': sk2} 73 | 74 | def encrypt(self, pk, msg, policy_str): 75 | """ 76 | Encrypt a message msg under a policy string. 77 | """ 78 | 79 | if debug: 80 | print('\nEncryption algorithm:\n') 81 | 82 | policy = self.util.createPolicy(policy_str) 83 | mono_span_prog = self.util.convert_policy_to_msp(policy) 84 | num_cols = self.util.len_longest_row 85 | 86 | # pick randomness 87 | s1 = self.group.random(ZR) 88 | sprime = self.group.random(ZR) 89 | 90 | g2_s1 = pk['g2'] ** s1 91 | g2_sprime = pk['g2'] ** sprime 92 | 93 | # pick random shares 94 | v = [s1] 95 | for i in range(num_cols-1): 96 | rand = self.group.random(ZR) 97 | v.append(rand) 98 | 99 | bHash = self.group.hash(str(self.group.order()+1), G1) # ZR+1 100 | 101 | ct = {} 102 | for attr, row in mono_span_prog.items(): 103 | attr_stripped = self.util.strip_index(attr) 104 | attrHash = self.group.hash(attr_stripped, G1) 105 | len_row = len(row) 106 | Mivtop = sum(i[0] * i[1] for i in zip(row, v[:len_row])) 107 | ct[attr] = bHash ** Mivtop * attrHash ** sprime 108 | 109 | # compute the e(g, h)^(As) * m term 110 | Cp = pk['e_g1g2_alpha'] ** s1 111 | Cp = Cp * msg 112 | 113 | return {'policy': policy, 'g2_s1': g2_s1, 'g2_sprime': g2_sprime, 'ct': ct, 'Cp': Cp} 114 | 115 | def decrypt(self, pk, ctxt, key): 116 | """ 117 | Decrypt ciphertext ctxt with key key. 118 | """ 119 | 120 | if debug: 121 | print('\nDecryption algorithm:\n') 122 | 123 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 124 | # print(nodes) 125 | if not nodes: 126 | print ("Policy not satisfied.") 127 | return None 128 | 129 | prod_sk = 1 130 | prod_ct = 1 131 | for node in nodes: 132 | attr = node.getAttributeAndIndex() 133 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 134 | 135 | prod_sk *= key['sk1'][attr_stripped] 136 | prod_ct *= ctxt['ct'][attr] 137 | 138 | e0 = pair(key['sk2'], ctxt['g2_s1']) 139 | e1 = pair(prod_sk, ctxt['g2_sprime']) 140 | e2 = pair(prod_ct, key['g2_r']) 141 | 142 | kem = e0 * (e1/e2) 143 | 144 | return ctxt['Cp'] / kem -------------------------------------------------------------------------------- /FABEO/abgw17kp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Miguel Ambrona, Gilles Barthe, Romain Gay, and Hoeteck Wee 3 | 4 | | From: "Attribute-Based Encryption in the Generic Group Model: Automated Proofs and New Constructions 5 | | Published in: 2017 6 | | Available from: https://dl.acm.org/doi/pdf/10.1145/3133956.3134088 7 | | Notes: Implemented the unbounded KP-ABE scheme in Section 5.3 8 | | 9 | | type: key-policy attribute-based encryption 10 | | setting: Pairing 11 | 12 | :Authors: Doreen Riepel 13 | :Date: 4/2022 14 | ''' 15 | 16 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 17 | from charm.toolbox.ABEnc import ABEnc 18 | from ..msp import MSP 19 | 20 | debug = False 21 | 22 | 23 | class ABGW17KPABE(ABEnc): 24 | def __init__(self, groupObj, verbose=False): 25 | ABEnc.__init__(self) 26 | self.name = "ABGW17 KP-ABE" 27 | self.group = groupObj 28 | self.util = MSP(self.group, verbose) 29 | 30 | def setup(self): 31 | """ 32 | Generates public key and master secret key. 33 | """ 34 | 35 | if debug: 36 | print('Setup algorithm:\n') 37 | 38 | # pick a random element from the two source groups and pair them 39 | g = self.group.random(G1) 40 | h = self.group.random(G2) 41 | e_gh = pair(g, h) 42 | 43 | # pick vector B 44 | b1 = self.group.random(ZR) 45 | b2 = self.group.random(ZR) 46 | 47 | B1 = g ** b1 48 | B2 = g ** b2 49 | 50 | alpha = self.group.random(ZR) 51 | e_gh_A = e_gh ** alpha 52 | 53 | # the public key 54 | pk = {'g': g, 'B1': B1, 'B2': B2, 'e_gh_A': e_gh_A} 55 | 56 | # the master secret key 57 | msk = {'h': h, 'b1': b1, 'b2': b2, 'alpha': alpha} 58 | 59 | return pk, msk 60 | 61 | def keygen(self, pk, msk, policy_str): 62 | """ 63 | Generate a key for a policy string. 64 | """ 65 | 66 | if debug: 67 | print('Key generation algorithm:\n') 68 | 69 | policy = self.util.createPolicy(policy_str) 70 | mono_span_prog = self.util.convert_policy_to_msp(policy) 71 | num_cols = self.util.len_longest_row 72 | 73 | # pick randomness 74 | R = [msk['alpha']] 75 | for i in range(num_cols-1): 76 | rand = self.group.random(ZR) 77 | R.append(rand) 78 | 79 | K_0 = {} 80 | K_1 = {} 81 | for attr, row in mono_span_prog.items(): 82 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 83 | cols = len(row) 84 | 85 | # compute the [M^T_j (a,r)]_2 term 86 | exp = sum(i[0] * i[1] for i in zip(row, R[:cols])) 87 | K_0[attr] = msk['h'] ** exp 88 | 89 | # compute the [M^T_j (a,r) / (b1+rho(j)b2)]_2 term 90 | exp2 = msk['b1'] + int(attr_stripped)*msk['b2'] 91 | K_1[attr] = msk['h'] ** (exp/exp2) 92 | 93 | return {'policy': policy, 'K_0': K_0, 'K_1': K_1} 94 | 95 | def encrypt(self, pk, msg, attr_list): 96 | """ 97 | Encrypt a message M under a set of attributes. 98 | """ 99 | 100 | if debug: 101 | print('Encryption algorithm:\n') 102 | 103 | # pick randomness 104 | s0 = self.group.random(ZR) 105 | S = {} 106 | for attr in attr_list: 107 | rand = self.group.random(ZR) 108 | S[attr] = rand 109 | 110 | C_0 = {} 111 | C_1 = {} 112 | for attr in attr_list: 113 | # compute the [s-si]_1 terms 114 | C_0[attr] = pk['g'] ** (s0 - S[attr]) 115 | 116 | # compute the [si(b1+ib2)]_1 terms 117 | C_1[attr] = (pk['B1'] * (pk['B2'] ** int(attr))) ** S[attr] 118 | 119 | # compute the e(g, h)^(as0) term 120 | Cx = pk['e_gh_A'] ** s0 * msg 121 | 122 | return {'attr_list': attr_list, 'C_0': C_0, 'C_1': C_1, 'Cx': Cx} 123 | 124 | def decrypt(self, pk, ctxt, key): 125 | """ 126 | Decrypt ciphertext ctxt with key key. 127 | """ 128 | 129 | if debug: 130 | print('Decryption algorithm:\n') 131 | 132 | nodes = self.util.prune(key['policy'], ctxt['attr_list']) 133 | if not nodes: 134 | print ("Policy not satisfied.") 135 | return None 136 | 137 | prod1 = 1 138 | prod2 = 1 139 | 140 | for node in nodes: 141 | attr = node.getAttributeAndIndex() 142 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 143 | prod1 *= pair(ctxt['C_0'][attr_stripped], key['K_0'][attr]) 144 | prod2 *= pair(ctxt['C_1'][attr_stripped], key['K_1'][attr]) 145 | 146 | return ctxt['Cx'] / (prod1 * prod2) 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FABEO: Fast Attribute-based Encryption with Optimal Security 2 | 3 | This is the code repository accompanying our CCS '22 paper "FABEO: Fast Attribute-based Encryption with Optimal Security" by Doreen Riepel and Hoeteck Wee. 4 | 5 | 6 | > Attribute-based encryption (ABE) enables fine-grained access control on encrypted data and has a large number of practical applications. This paper presents FABEO: fasterpairing-based ciphertext-policy and key-policy ABE schemes that support expressive policies and put no restriction on policy type or attributes, and the first to achieve optimal, adaptive security with multiple challenge ciphertexts. We implement our schemes and demonstrate that they perform better than the state-of-the-art (Bethencourt et al. S&P 2007, Agrawal et al., CCS 2017 and Ambrona et al., CCS 2017) on all parameters of practical interest. 7 | 8 | 9 | ## Schemes 10 | 11 | The code uses the Charm library and Python and builds upon the code of [FAME](https://github.com/sagrawal87/ABE), which provides implementations of their CP-ABE scheme FAME [1, Section 3] as well as those by BSW [3, Section 4.2], CGW [4, Appendix B.2] and Waters [6, Section 3]. We extend this code by our FABEO CP-ABE and KP-ABE schemes as well as the extention to DFA. For our benchmarks, we also implemented the following schemes: 12 | 13 | - ABGW CP-ABE [2, Section 5.3] 14 | - ABGW KP-ABE [2, Section 5.3] 15 | - CGW KP-ABE [x, Appendix B.1] 16 | - FAME KP-ABE [1, Appendix B] 17 | - GPSW KP-ABE [5, Appendix A.1] 18 | - Waters ABE for DFA [7, Section 3] 19 | 20 | All schemes are implemented using asymmetric pairing groups. For the Waters DFA scheme we transfer the existing code from [here](https://jhuisi.github.io/charm/_modules/dfa_fe12.html#FE_DFA) to this setting. 21 | 22 | Some of the schemes are bounded universe, i.e. they support an a-priori bounded number of attributes. To initialize such schemes, an additional parameter `uni_size` needs to be specified. Some schemes are secure under the k-linear family of assumptions, so k must be set properly during initialization through the parameter `assump_size`. 23 | 24 | ## Quick Install & Test 25 | 26 | The schemes have been tested with Charm 0.43 and Python 2.7.12 on Ubuntu 16.04. (Note that Charm may not compile on newer Linux systems due to the incompatibility of OpenSSL versions 1.0 and 1.1.). 27 | 28 | We provide a Dockerfile that installs all necessary libraries and packages. Docker can be installed from [here](https://docs.docker.com/get-docker/). On Linux, the container can be built using the command 29 | ```sh 30 | docker build -t fabeo . 31 | ``` 32 | which will also run all the implemented schemes. To run our test files individually, run the Docker container in interactive mode using 33 | ```sh 34 | docker run -it fabeo 35 | ``` 36 | To run one instance of each CP-ABE scheme use 37 | 38 | ```sh 39 | cd FABEO && python samples/run_cp_schemes.py 40 | ``` 41 | Replace `cp` by `kp` or `dfa` to run the other schemes. We also provide the code we used for the benchmarks in our submission. They can be run using `python samples/measurements_xx` for `xx={cp,kp}` and will print the running times in milliseconds. In our paper, we compute the average running time for 20 executions. This parameter can be specified as input to the `measure_average_times` function. 42 | 43 | 44 | ## Manual Installation 45 | 46 | Charm 0.43 can also be installed directly from [this](https://github.com/JHUISI/charm/releases) page, or by running 47 | 48 | ```sh 49 | pip install -r requirements.txt 50 | ``` 51 | Once you have Charm, run 52 | ```sh 53 | make && pip install . && python samples/run_cp_schemes.py 54 | ``` 55 | 56 | ## References 57 | 58 | [1] S. Agrawal and M. Chase. FAME: Fast attribute-based message encryption. In B. M. Thuraisingham, D. Evans, T. Malkin, and D. Xu, editors, ACM CCS 2017, pages 665–682. ACM Press, Oct. / Nov. 2017. 59 | 60 | [2] M. Ambrona, G. Barthe, R. Gay, and H. Wee. Attribute-based encryption in the generic group model: Automated proofs and new constructions. In B. M. Thuraisingham, D. Evans, T. Malkin, and D. Xu, editors, ACM CCS 2017, pages 647–664. ACM Press, Oct. / Nov. 2017. 61 | 62 | [3] J. Bethencourt, A. Sahai, and B.Waters. Ciphertext-policy attribute-based encryption. In 2007 IEEE Symposium on Security and Privacy, pages 321–334. IEEE Computer Society Press, May 2007. 63 | 64 | [4] J. Chen, J. Gong, and J. Weng. Tightly secure IBE under constant-size master public key. In S. Fehr, editor, PKC 2017, Part I, volume 10174 of LNCS, pages 207–231. Springer, Heidelberg, Mar. 2017. 65 | 66 | [5] V. Goyal, O. Pandey, A. Sahai, and B. Waters. Attribute-based encryption for fine-grained access control of encrypted data. In A. Juels, R. N. Wright, and S. De Capitani di Vimercati, editors, ACM CCS 2006, pages 89–98. ACM Press, Oct. / Nov. 2006. Available as Cryptology ePrint Archive Report 2006/309. 67 | 68 | [6] B. Waters. Ciphertext-policy attribute-based encryption: An expressive, efficient, and provably secure realization. In D. Catalano, N. Fazio, R. Gennaro, and A. Nicolosi, editors, PKC 2011, volume 6571 of LNCS, pages 53–70. Springer, Heidelberg, Mar. 2011. 69 | 70 | [7] B. Waters. Functional encryption for regular languages. In R. Safavi-Naini and R. Canetti, editors, CRYPTO 2012, volume 7417 of LNCS, pages 218–235. Springer, Heidelberg, Aug. 2012. -------------------------------------------------------------------------------- /FABEO/abgw17cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Miguel Ambrona, Gilles Barthe, Romain Gay, and Hoeteck Wee 3 | 4 | | From: "Attribute-Based Encryption in the Generic Group Model: Automated Proofs and New Constructions 5 | | Published in: 2017 6 | | Available from: https://dl.acm.org/doi/pdf/10.1145/3133956.3134088 7 | | Notes: Implemented the unbounded CP-ABE scheme in Section 5.3 8 | | 9 | | type: ciphertext-policy attribute-based encryption 10 | | setting: Pairing 11 | 12 | :Authors: Doreen Riepel 13 | :Date: 4/2022 14 | ''' 15 | 16 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 17 | from charm.toolbox.ABEnc import ABEnc 18 | from ..msp import MSP 19 | 20 | debug = False 21 | 22 | class ABGW17CPABE(ABEnc): 23 | def __init__(self, groupObj, verbose=False): 24 | ABEnc.__init__(self) 25 | self.name = "ABGW17 CP-ABE" 26 | self.group = groupObj 27 | self.util = MSP(self.group, verbose) 28 | 29 | def setup(self): 30 | """ 31 | Generates public key and master secret key. 32 | """ 33 | 34 | if debug: 35 | print('Setup algorithm:\n') 36 | 37 | # pick a random element from the two source groups and pair them 38 | g = self.group.random(G1) 39 | h = self.group.random(G2) 40 | e_gh = pair(g, h) 41 | 42 | # pick vector B 43 | b1 = self.group.random(ZR) 44 | b2 = self.group.random(ZR) 45 | v = self.group.random(ZR) 46 | w = self.group.random(ZR) 47 | 48 | B1 = g ** b1 49 | B2 = g ** b2 50 | V = g ** v 51 | W = g ** w 52 | 53 | alpha = self.group.random(ZR) 54 | e_gh_A = e_gh ** alpha 55 | 56 | # the public key 57 | pk = {'g': g, 'B1': B1, 'B2': B2, 'V': V, 'W': W, 'e_gh_A': e_gh_A} 58 | 59 | # the master secret key 60 | msk = {'h': h, 'b1': b1, 'b2': b2, 'v': v, 'w': w, 'alpha': alpha} 61 | 62 | return pk, msk 63 | 64 | def keygen(self, pk, msk, attr_list): 65 | """ 66 | Generate a key for a set of attributes. 67 | """ 68 | 69 | if debug: 70 | print('Key generation algorithm:\n') 71 | 72 | # pick randomness 73 | r = self.group.random(ZR) 74 | 75 | # compute the [r]_2, [a-wr]_2 terms 76 | K_0 = msk['h'] ** r 77 | K_1 = msk['h'] ** (msk['alpha'] - msk['w']*r) 78 | 79 | K = {} 80 | # compute the [rv / (b1+yb2)]_2 term 81 | for attr in attr_list: 82 | K[attr] = msk['h'] ** (r*msk['v'] / (msk['b1'] + int(attr)* msk['b2'])) 83 | 84 | return {'attr_list': attr_list, 'K_0': K_0, 'K_1': K_1, 'K': K } 85 | 86 | def encrypt(self, pk, msg, policy_str): 87 | """ 88 | Encrypt a message M under a policy string. 89 | """ 90 | 91 | if debug: 92 | print('Encryption algorithm:\n') 93 | 94 | policy = self.util.createPolicy(policy_str) 95 | mono_span_prog = self.util.convert_policy_to_msp(policy) 96 | num_cols = self.util.len_longest_row 97 | 98 | # pick randomness 99 | s0 = self.group.random(ZR) 100 | U = [s0] 101 | for i in range(num_cols-1): 102 | rand = self.group.random(ZR) 103 | U.append(rand) 104 | 105 | C_0 = {} 106 | C_1 = {} 107 | C_2 = {} 108 | for attr, row in mono_span_prog.items(): 109 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 110 | cols = len(row) 111 | 112 | # compute the [si(b1+xb2)]_1 term 113 | si = self.group.random(ZR) 114 | C_0[attr] = (pk['B1'] * (pk['B2'] ** int(attr_stripped))) ** si 115 | 116 | # compute the [M^T_i (s,u)]_1 term 117 | MuT = sum(i[0] * i[1] for i in zip(row, U[:cols])) 118 | C_1[attr] = pk['g'] ** MuT 119 | 120 | # compute the [-vsi + w M^T_i (s,u)]_1 term 121 | C_2[attr] = pk['V']**(-si) * pk['W'] ** MuT 122 | 123 | # compute the e(g,h)^(as0) term 124 | Cx = pk['e_gh_A'] ** s0 * msg 125 | 126 | return {'policy': policy, 'C_0': C_0, 'C_1': C_1, 'C_2': C_2, 'Cx': Cx} 127 | 128 | def decrypt(self, pk, ctxt, key): 129 | """ 130 | Decrypt ciphertext ctxt with key key. 131 | """ 132 | 133 | if debug: 134 | print('Decryption algorithm:\n') 135 | 136 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 137 | if not nodes: 138 | print ("Policy not satisfied.") 139 | return None 140 | 141 | prod1 = 1 142 | prodC1 = 1 143 | prodC2 = 1 144 | 145 | for node in nodes: 146 | attr = node.getAttributeAndIndex() 147 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 148 | prod1 *= pair(ctxt['C_0'][attr], key['K'][attr_stripped]) 149 | prodC1 *= ctxt['C_1'][attr] 150 | prodC2 *= ctxt['C_2'][attr] 151 | 152 | kem = prod1 * pair(prodC1, key['K_1']) * pair(prodC2, key['K_0']) 153 | 154 | return ctxt['Cx'] / kem 155 | -------------------------------------------------------------------------------- /samples/measurements_kp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from FABEO.abgw17kp import ABGW17KPABE 7 | from FABEO.ac17kp import AC17KPABE 8 | from FABEO.cgw15kp import CGW15KPABE 9 | from FABEO.fabeo22kp import FABEO22KPABE 10 | from FABEO.gpsw06kp import GPSW06KPABE 11 | from FABEO.msp import MSP 12 | 13 | import time 14 | 15 | def measure_average_times(abe,attr_list,policy_str,msg,N=5): 16 | 17 | sum_setup=0 18 | sum_enc=0 19 | sum_keygen=0 20 | sum_dec=0 21 | 22 | for i in range(N): 23 | # setup time 24 | start_setup = time.time() 25 | (pk, msk) = abe.setup() 26 | end_setup = time.time() 27 | time_setup = end_setup-start_setup 28 | sum_setup += time_setup 29 | 30 | # encryption time 31 | start_enc = time.time() 32 | ctxt = abe.encrypt(pk, msg, attr_list) 33 | end_enc = time.time() 34 | time_enc = end_enc - start_enc 35 | sum_enc += time_enc 36 | 37 | # keygen time 38 | start_keygen = time.time() 39 | key = abe.keygen(pk, msk, policy_str) 40 | end_keygen = time.time() 41 | time_keygen = end_keygen - start_keygen 42 | sum_keygen += time_keygen 43 | 44 | # decryption time 45 | start_dec = time.time() 46 | rec_msg = abe.decrypt(pk, ctxt, key) 47 | end_dec = time.time() 48 | time_dec = end_dec - start_dec 49 | sum_dec += time_dec 50 | 51 | # sanity check 52 | if rec_msg!= msg: 53 | print ("Decryption failed.") 54 | 55 | # compute average time 56 | time_setup = sum_setup/N 57 | time_enc = sum_enc/N 58 | time_keygen = sum_keygen/N 59 | time_dec = sum_dec/N 60 | 61 | return [time_setup, time_keygen, time_enc, time_dec] 62 | 63 | def print_running_time(scheme_name,times): 64 | print('{:<20}'.format(scheme_name) + format(times[0]*1000, '7.2f') + ' ' + format(times[1]*1000, '7.2f') + ' ' + format(times[2]*1000, '7.2f') + ' ' + format(times[3]*1000, '7.2f')) 65 | 66 | def run_all(pairing_group, policy_size, policy_str, attr_list,msg): 67 | 68 | algos = ['Setup', 'KeyGen', 'Enc', 'Dec'] 69 | 70 | n1,n2,m,i = get_par(pairing_group, policy_str, attr_list) 71 | 72 | print('Running times (ms) curve MNT224: n1={} n2={} m={} I={}'.format(n1,n2,m,i)) 73 | algo_string = 'KP-ABE {:<13}'.format('') + ' ' + algos[0] + ' ' + algos[1] + ' ' + algos[2] + ' ' + algos[3] 74 | print('-'*56) 75 | print(algo_string) 76 | print('-'*56) 77 | 78 | gpsw06_kp = GPSW06KPABE(pairing_group,policy_size) 79 | gpsw06_kp_times = measure_average_times(gpsw06_kp,attr_list,policy_str,msg) 80 | print_running_time(gpsw06_kp.name,gpsw06_kp_times) 81 | 82 | cgw15_kp_1 = CGW15KPABE(pairing_group, 1, policy_size) 83 | cgw15_kp_1_times = measure_average_times(cgw15_kp_1,attr_list,policy_str,msg) 84 | print_running_time(cgw15_kp_1.name,cgw15_kp_1_times) 85 | 86 | cgw15_kp_2 = CGW15KPABE(pairing_group, 2, policy_size) 87 | cgw15_kp_2_times = measure_average_times(cgw15_kp_2,attr_list,policy_str,msg) 88 | print_running_time(cgw15_kp_2.name,cgw15_kp_2_times) 89 | 90 | abgw17_kp = ABGW17KPABE(pairing_group) 91 | abgw17_kp_times = measure_average_times(abgw17_kp,attr_list,policy_str,msg) 92 | print_running_time(abgw17_kp.name,abgw17_kp_times) 93 | 94 | ac17_kp = AC17KPABE(pairing_group, 2) 95 | ac17_kp_times = measure_average_times(ac17_kp,attr_list,policy_str,msg) 96 | print_running_time(ac17_kp.name,ac17_kp_times) 97 | 98 | fabeo22_kp = FABEO22KPABE(pairing_group) 99 | fabeo22_kp_times = measure_average_times(fabeo22_kp,attr_list,policy_str,msg) 100 | print_running_time(fabeo22_kp.name,fabeo22_kp_times) 101 | 102 | print('-'*56) 103 | print 104 | 105 | # get parameters of the monotone span program 106 | def get_par(pairing_group, policy_str, attr_list): 107 | msp_obj = MSP(pairing_group) 108 | policy = msp_obj.createPolicy(policy_str) 109 | mono_span_prog = msp_obj.convert_policy_to_msp(policy) 110 | nodes = msp_obj.prune(policy, attr_list) 111 | 112 | n1 = len(mono_span_prog) # number of rows 113 | n2 = msp_obj.len_longest_row # number of columns 114 | m = len(attr_list) # number of attributes 115 | i = len(nodes) # number of attributes in decryption 116 | 117 | return n1,n2,m,i 118 | 119 | # create policy string and attribute list for a boolean formula of the form "1 and 2 and 3" 120 | def create_policy_string_and_attribute_list(n): 121 | policy_string = '(1' 122 | attr_list = ['1'] 123 | for i in range(2,n+1): 124 | policy_string += ' and ' + str(i) 125 | attr1 = str(i) 126 | attr_list.append(attr1) 127 | policy_string += ')' 128 | return policy_string, attr_list 129 | 130 | def main(): 131 | # instantiate a bilinear pairing map 132 | pairing_group = PairingGroup('MNT224') 133 | 134 | msg = pairing_group.random(GT) 135 | 136 | policy_sizes = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] 137 | 138 | for policy_size in policy_sizes: 139 | policy_str, attr_list = create_policy_string_and_attribute_list(policy_size) 140 | run_all(pairing_group, policy_size, policy_str, attr_list, msg) 141 | 142 | if __name__ == "__main__": 143 | debug = True 144 | main() 145 | -------------------------------------------------------------------------------- /samples/measurements_cp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | :Date: 4/2022 3 | ''' 4 | 5 | from charm.toolbox.pairinggroup import PairingGroup, GT 6 | from FABEO.abgw17cp import ABGW17CPABE 7 | from FABEO.ac17cp import AC17CPABE 8 | from FABEO.bsw07cp import BSW07CPABE 9 | from FABEO.cgw15cp import CGW15CPABE 10 | from FABEO.fabeo22cp import FABEO22CPABE 11 | from FABEO.waters11cp import Waters11CPABE 12 | from FABEO.msp import MSP 13 | 14 | import time 15 | 16 | def measure_average_times(abe,attr_list,policy_str,msg,N=5): 17 | 18 | sum_setup=0 19 | sum_enc=0 20 | sum_keygen=0 21 | sum_dec=0 22 | 23 | for i in range(N): 24 | # setup time 25 | start_setup = time.time() 26 | (pk, msk) = abe.setup() 27 | end_setup = time.time() 28 | time_setup = end_setup-start_setup 29 | sum_setup += time_setup 30 | 31 | # encryption time 32 | start_enc = time.time() 33 | ctxt = abe.encrypt(pk, msg, policy_str) 34 | end_enc = time.time() 35 | time_enc = end_enc - start_enc 36 | sum_enc += time_enc 37 | 38 | # keygen time 39 | start_keygen = time.time() 40 | key = abe.keygen(pk, msk, attr_list) 41 | end_keygen = time.time() 42 | time_keygen = end_keygen - start_keygen 43 | sum_keygen += time_keygen 44 | 45 | # decryption time 46 | start_dec = time.time() 47 | rec_msg = abe.decrypt(pk, ctxt, key) 48 | end_dec = time.time() 49 | time_dec = end_dec - start_dec 50 | sum_dec += time_dec 51 | 52 | # sanity check 53 | if rec_msg!= msg: 54 | print ("Decryption failed.") 55 | 56 | # compute average time 57 | time_setup = sum_setup/N 58 | time_enc = sum_enc/N 59 | time_keygen = sum_keygen/N 60 | time_dec = sum_dec/N 61 | 62 | return [time_setup, time_keygen, time_enc, time_dec] 63 | 64 | def print_running_time(scheme_name,times): 65 | print('{:<20}'.format(scheme_name) + format(times[0]*1000, '7.2f') + ' ' + format(times[1]*1000, '7.2f') + ' ' + format(times[2]*1000, '7.2f') + ' ' + format(times[3]*1000, '7.2f')) 66 | 67 | def run_all(pairing_group, policy_size, policy_str, attr_list, msg): 68 | 69 | algos = ['Setup', 'KeyGen', 'Enc', 'Dec'] 70 | 71 | n1,n2,m,i = get_par(pairing_group, policy_str, attr_list) 72 | 73 | print('Running times (ms) curve MNT224: n1={} n2={} m={} I={}'.format(n1,n2,m,i)) 74 | algo_string = 'CP-ABE {:<13}'.format('') + ' ' + algos[0] + ' ' + algos[1] + ' ' + algos[2] + ' ' + algos[3] 75 | print('-'*56) 76 | print(algo_string) 77 | print('-'*56) 78 | 79 | bsw07_cp = BSW07CPABE(pairing_group) 80 | bsw07_cp_times = measure_average_times(bsw07_cp,attr_list,policy_str,msg) 81 | print_running_time(bsw07_cp.name,bsw07_cp_times) 82 | 83 | waters11_cp = Waters11CPABE(pairing_group, policy_size) 84 | waters11_cp_times = measure_average_times(waters11_cp,attr_list,policy_str,msg) 85 | print_running_time(waters11_cp.name,waters11_cp_times) 86 | 87 | cgw15_cp_1 = CGW15CPABE(pairing_group, 1, policy_size) 88 | cgw15_cp_1_times = measure_average_times(cgw15_cp_1,attr_list,policy_str,msg) 89 | print_running_time(cgw15_cp_1.name,cgw15_cp_1_times) 90 | 91 | cgw15_cp_2 = CGW15CPABE(pairing_group, 2, policy_size) 92 | cgw15_cp_2_times = measure_average_times(cgw15_cp_2,attr_list,policy_str,msg) 93 | print_running_time(cgw15_cp_2.name,cgw15_cp_2_times) 94 | 95 | abgw17_cp = ABGW17CPABE(pairing_group) 96 | abgw17_cp_times = measure_average_times(abgw17_cp,attr_list,policy_str,msg) 97 | print_running_time(abgw17_cp.name,abgw17_cp_times) 98 | 99 | ac17_cp = AC17CPABE(pairing_group, 2) 100 | ac17_cp_times = measure_average_times(ac17_cp,attr_list,policy_str,msg) 101 | print_running_time(ac17_cp.name,ac17_cp_times) 102 | 103 | fabeo22_cp = FABEO22CPABE(pairing_group) 104 | fabeo22_cp_times = measure_average_times(fabeo22_cp,attr_list,policy_str,msg) 105 | print_running_time(fabeo22_cp.name,fabeo22_cp_times) 106 | 107 | print('-'*56) 108 | print 109 | 110 | # get parameters of the monotone span program 111 | def get_par(pairing_group, policy_str, attr_list): 112 | msp_obj = MSP(pairing_group) 113 | policy = msp_obj.createPolicy(policy_str) 114 | mono_span_prog = msp_obj.convert_policy_to_msp(policy) 115 | nodes = msp_obj.prune(policy, attr_list) 116 | 117 | n1 = len(mono_span_prog) # number of rows 118 | n2 = msp_obj.len_longest_row # number of columns 119 | m = len(attr_list) # number of attributes 120 | i = len(nodes) # number of attributes in decryption 121 | 122 | return n1,n2,m,i 123 | 124 | # create policy string and attribute list for a boolean formula of the form "1 and 2 and 3" 125 | def create_policy_string_and_attribute_list(n): 126 | policy_string = '(1' 127 | attr_list = ['1'] 128 | for i in range(2,n+1): 129 | policy_string += ' and ' + str(i) 130 | attr1 = str(i) 131 | attr_list.append(attr1) 132 | policy_string += ')' 133 | 134 | return policy_string, attr_list 135 | 136 | def main(): 137 | # instantiate a bilinear pairing map 138 | pairing_group = PairingGroup('MNT224') 139 | 140 | msg = pairing_group.random(GT) 141 | 142 | policy_sizes = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] 143 | for policy_size in policy_sizes: 144 | policy_str, attr_list = create_policy_string_and_attribute_list(policy_size) 145 | run_all(pairing_group, policy_size,policy_str,attr_list,msg) 146 | 147 | if __name__ == "__main__": 148 | debug = True 149 | main() 150 | -------------------------------------------------------------------------------- /FABEO/msp/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This class is adapted from the SecretUtil class in charm/toolbox/secretutil.py. 3 | It provides the following methods: 4 | - createPolicy: convert a Boolean formula encoded as a string into a policy represented like a tree; 5 | - convertPolicyToMSP: convert a policy into a monotone span program (MSP); 6 | - getCoefficients: given a policy, returns a coefficient for every attribute; 7 | - strip_index: remove the index from an attribute (i.e., x_y -> x); 8 | - prune: determine whether a given set of attributes satisfies the policy 9 | (returns false if it doesn't, otherwise a good enough subset of attributes); 10 | - getAttributeList: retrieve the attributes that occur in a policy tree in order (left to right). 11 | """ 12 | 13 | from charm.core.math.pairing import ZR 14 | from charm.toolbox.policytree import * 15 | 16 | 17 | class MSP: 18 | 19 | def __init__(self, groupObj, verbose=True): 20 | self.len_longest_row = 1 21 | self.group = groupObj 22 | 23 | def createPolicy(self, policy_string): 24 | """ 25 | Convert a Boolean formula represented as a string into a policy represented like a tree. 26 | """ 27 | 28 | assert type(policy_string) is str, "invalid type for policy_string" 29 | policy_string = unicode(policy_string) 30 | parser = PolicyParser() 31 | policy_obj = parser.parse(policy_string) 32 | _dictCount, _dictLabel = {}, {} 33 | parser.findDuplicates(policy_obj, _dictCount) 34 | for i in _dictCount.keys(): 35 | if _dictCount[i] > 1: _dictLabel[i] = 0 36 | parser.labelDuplicates(policy_obj, _dictLabel) 37 | return policy_obj 38 | 39 | def convert_policy_to_msp(self, tree): 40 | """ 41 | Convert a policy into a monotone span program (MSP) 42 | represented by a dictionary with (attribute, row) pairs 43 | """ 44 | 45 | root_vector = [1] 46 | # listOfAttributeRowPairs = {} 47 | self.len_longest_row = 1 48 | return self._convert_policy_to_msp(tree, root_vector) 49 | 50 | def _convert_policy_to_msp(self, subtree, curr_vector): 51 | """ 52 | Given a vector for the current node, 53 | returns the vectors for its children in the form of a dictionary 54 | """ 55 | 56 | if subtree is None: 57 | return None 58 | 59 | type = subtree.getNodeType() 60 | 61 | if type == OpType.ATTR: 62 | # print ('ATTR: ', subtree, subtree.getAttributeAndIndex(), currVector) 63 | return {subtree.getAttributeAndIndex(): curr_vector} 64 | 65 | if type == OpType.OR: 66 | left_list = self._convert_policy_to_msp(subtree.getLeft(), curr_vector) 67 | right_list = self._convert_policy_to_msp(subtree.getRight(), curr_vector) 68 | # print ('OR l: ', leftList, 'r: ', rightList) 69 | left_list.update(right_list) 70 | return left_list 71 | 72 | if type == OpType.AND: 73 | length = len(curr_vector) 74 | left_vector = curr_vector + [0] * (self.len_longest_row - length) + [1] 75 | right_vector = [0] * self.len_longest_row + [-1] # [0]*k creates a vector of k zeroes 76 | # extendedVector = currVector + [0]*(self.lengthOfLongestRow-length) 77 | # leftVector = extendedVector + [1] 78 | # rightVector = extendedVector + [2] # [0]*k creates a vector of k zeroes 79 | self.len_longest_row += 1 80 | left_list = self._convert_policy_to_msp(subtree.getLeft(), left_vector) 81 | right_list = self._convert_policy_to_msp(subtree.getRight(), right_vector) 82 | # print ('AND l: ', leftList, 'r: ', rightList) 83 | left_list.update(right_list) 84 | return left_list 85 | 86 | return None 87 | 88 | def getCoefficients(self, tree): 89 | """ 90 | Given a policy, returns a coefficient for every attribute. 91 | """ 92 | 93 | coeffs = {} 94 | self._getCoefficientsDict(tree, coeffs) 95 | return coeffs 96 | 97 | def recoverCoefficients(self, list): 98 | """ 99 | recovers the coefficients over a binary tree. 100 | """ 101 | 102 | coeff = {} 103 | list2 = [self.group.init(ZR, i) for i in list] 104 | for i in list2: 105 | result = 1 106 | for j in list2: 107 | if not (i == j): 108 | # lagrange basis poly 109 | result *= (0 - j) / (i - j) 110 | # print("coeff '%d' => '%s'" % (i, result)) 111 | coeff[int(i)] = result 112 | return coeff 113 | 114 | def _getCoefficientsDict(self, tree, coeff_list, coeff=1): 115 | """ 116 | recover coefficient over a binary tree where possible node types are OR = (1 of 2) 117 | and AND = (2 of 2) secret sharing. The leaf nodes are attributes and the coefficients are 118 | recorded in a coeff-list dictionary. 119 | """ 120 | 121 | if tree: 122 | node = tree.getNodeType() 123 | if (node == OpType.AND): 124 | this_coeff = self.recoverCoefficients([1, 2]) 125 | # left child => coeff[1], right child => coeff[2] 126 | self._getCoefficientsDict(tree.getLeft(), coeff_list, coeff * this_coeff[1]) 127 | self._getCoefficientsDict(tree.getRight(), coeff_list, coeff * this_coeff[2]) 128 | elif (node == OpType.OR): 129 | this_coeff = self.recoverCoefficients([1]) 130 | self._getCoefficientsDict(tree.getLeft(), coeff_list, coeff * this_coeff[1]) 131 | self._getCoefficientsDict(tree.getRight(), coeff_list, coeff * this_coeff[1]) 132 | elif (node == OpType.ATTR): 133 | attr = tree.getAttributeAndIndex() 134 | coeff_list[attr] = coeff 135 | else: 136 | return None 137 | 138 | def strip_index(self, node_str): 139 | """ 140 | Remove the index from an attribute (i.e., x_y -> x). 141 | """ 142 | 143 | if node_str.find('_') != -1: 144 | return node_str.split('_')[0] 145 | return node_str 146 | 147 | def prune(self, policy, attributes): 148 | """ 149 | Determine whether a given set of attributes satisfies the policy 150 | (returns false if it doesn't, otherwise a good enough subset of attributes). 151 | """ 152 | 153 | parser = PolicyParser() 154 | return parser.prune(policy, attributes) 155 | 156 | def getAttributeList(self, Node): 157 | """ 158 | Retrieve the attributes that occur in a policy tree in order (left to right). 159 | """ 160 | 161 | aList = [] 162 | self._getAttributeList(Node, aList) 163 | return aList 164 | 165 | def _getAttributeList(self, Node, List): 166 | if (Node == None): 167 | return None 168 | # V, L, R 169 | if (Node.getNodeType() == OpType.ATTR): 170 | List.append(Node.getAttributeAndIndex()) # .getAttribute() 171 | else: 172 | self._getAttributeList(Node.getLeft(), List) 173 | self._getAttributeList(Node.getRight(), List) 174 | return None 175 | -------------------------------------------------------------------------------- /FABEO/ac17kp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Shashank Agrawal, Melissa Chase 3 | 4 | | From: "FAME: Fast Attribute-based Message Encryption" 5 | | Published in: 2017 6 | | Available from: https://eprint.iacr.org/2017/807 7 | | Notes: Implemented the scheme in Appendix B 8 | | Security Assumption: a variant of k-linear, k>=2 9 | | 10 | | type: key-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Doreen Riepel 14 | :Date: 04/2022 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class AC17KPABE(ABEnc): 25 | def __init__(self, group_obj, assump_size, verbose=False): 26 | ABEnc.__init__(self) 27 | self.name = "AC17 KP-ABE k=" + str(assump_size) 28 | self.group = group_obj 29 | self.assump_size = assump_size # size of linear assumption, at least 2 30 | self.util = MSP(self.group, verbose) 31 | 32 | def setup(self): 33 | """ 34 | Generates public key and master secret key. 35 | """ 36 | 37 | if debug: 38 | print('\nSetup algorithm:\n') 39 | 40 | # generate two instances of the k-linear assumption 41 | A = [] 42 | B = [] 43 | for i in range(self.assump_size): 44 | A.append(self.group.random(ZR)) 45 | B.append(self.group.random(ZR)) # note that A, B are vectors here 46 | 47 | # vector 48 | k = [] 49 | for i in range(self.assump_size + 1): 50 | k.append(self.group.random(ZR)) 51 | 52 | # pick a random element from the two source groups and pair them 53 | g = self.group.random(G1) 54 | h = self.group.random(G2) 55 | e_gh = pair(g, h) 56 | 57 | # now compute various parts of the public parameters 58 | 59 | # compute the [A]_2 term 60 | h_A = [] 61 | for i in range(self.assump_size): 62 | h_A.append(h ** A[i]) 63 | h_A.append(h) 64 | 65 | # compute the e([k]_1, [A]_2) term 66 | g_k = [] 67 | for i in range(self.assump_size + 1): 68 | g_k.append(g ** k[i]) 69 | 70 | e_gh_kA = [] 71 | for i in range(self.assump_size): 72 | e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size])) 73 | 74 | # the public key 75 | pk = {'h_A': h_A, 'e_gh_kA': e_gh_kA} 76 | 77 | # the master secret key 78 | msk = {'g': g, 'h': h, 'g_k': g_k, 'A': A, 'B': B} 79 | 80 | return pk, msk 81 | 82 | def encrypt(self, pk, msg, attr_list): 83 | """ 84 | Encrypt a message M under a set of attributes. 85 | """ 86 | 87 | if debug: 88 | print('Encryption algorithm:\n') 89 | 90 | # pick randomness 91 | s = [] 92 | sum = 0 93 | for i in range(self.assump_size): 94 | rand = self.group.random(ZR) 95 | s.append(rand) 96 | sum += rand 97 | 98 | # compute the [As]_2 term 99 | C_0 = [] 100 | h_A = pk['h_A'] 101 | for i in range(self.assump_size): 102 | C_0.append(h_A[i] ** s[i]) 103 | C_0.append(h_A[self.assump_size] ** sum) 104 | 105 | C = {} 106 | for attr in attr_list: 107 | ct = [] 108 | for l in range(self.assump_size+1): 109 | prod = 1 110 | for t in range(self.assump_size): 111 | input_for_hash = attr + str(l) + str(t) 112 | prod *= (self.group.hash(input_for_hash, G1) ** (s[t])) 113 | ct.append(prod) 114 | C[attr] = ct 115 | 116 | # compute the e(g, h)^(k^T As) . m term 117 | Cp = 1 118 | for i in range(self.assump_size): 119 | Cp = Cp * (pk['e_gh_kA'][i] ** s[i]) 120 | Cp = Cp * msg 121 | 122 | return {'attr_list': attr_list, 'C_0': C_0, 'C': C, 'Cp': Cp } 123 | 124 | 125 | def keygen(self, pk, msk, policy_str): 126 | """ 127 | Generate a key for a monotone span program. 128 | """ 129 | 130 | if debug: 131 | print('Key generation algorithm:\n') 132 | 133 | policy = self.util.createPolicy(policy_str) 134 | mono_span_prog = self.util.convert_policy_to_msp(policy) 135 | num_cols = self.util.len_longest_row 136 | 137 | # pick randomness 138 | r = [] 139 | sum = 0 140 | for i in range(self.assump_size): 141 | rand = self.group.random(ZR) 142 | r.append(rand) 143 | sum += rand 144 | 145 | Br = [] 146 | for i in range(self.assump_size): 147 | Br.append(msk['B'][i] * r[i]) 148 | Br.append(sum) 149 | 150 | # compute the [As]_2 term 151 | K_0 = [] 152 | for br in Br: 153 | K_0.append(msk['h'] ** br) 154 | 155 | # compute the [(V^T As||U^T_2 As||...) M^T_i + W^T_i As]_1 terms 156 | 157 | # pre-compute hashes 158 | hash_table = [] 159 | for j in range(num_cols): 160 | x = [] 161 | input_for_hash1 = '0' + str(j + 1) 162 | for l in range(self.assump_size + 1): 163 | y = [] 164 | input_for_hash2 = input_for_hash1 + str(l) 165 | for t in range(self.assump_size): 166 | input_for_hash3 = input_for_hash2 + str(t) 167 | hashed_value = self.group.hash(input_for_hash3, G1) 168 | y.append(hashed_value) 169 | # if debug: print ('Hash of', i+2, ',', j2, ',', j1, 'is', hashed_value) 170 | x.append(y) 171 | hash_table.append(x) 172 | 173 | # pick sigma' 174 | sigmaCol = [0] 175 | for i in range(num_cols-1): 176 | rand = self.group.random(ZR) 177 | sigmaCol.append(rand) 178 | 179 | K = {} 180 | for attr, row in mono_span_prog.items(): 181 | sk = [] 182 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 183 | cols = len(row) 184 | sigma_attr = self.group.random(ZR) 185 | for t in range(self.assump_size): 186 | prod = msk['g'] ** (sigma_attr/msk['A'][t]) 187 | prod *= (msk['g_k'][t] ** row[0]) 188 | for l in range(self.assump_size+1): 189 | input_for_hash = attr_stripped + str(l) + str(t) 190 | prod1 = self.group.hash(input_for_hash, G1) 191 | for j in range(2,cols): 192 | # input_for_hash = '0' + str(j+1) + str(l) + str(t) 193 | prod1 *= (hash_table[j][l][t] ** row[j]) 194 | prod *= (prod1 ** (Br[l]/msk['A'][t])) 195 | exp = 0 196 | for j in range(2,cols): 197 | # compute exponent for sigma' 198 | exp += (sigmaCol[j]/msk['A'][t]) * row[j] 199 | prod *= msk['g'] ** exp 200 | sk.append(prod) 201 | sk3 = msk['g'] ** (-sigma_attr) * msk['g_k'][self.assump_size] ** row[0] 202 | for j in range(2,cols): 203 | sk3 *= msk['g'] ** (sigmaCol[j]*row[j]) 204 | sk.append(sk3) 205 | K[attr] = sk 206 | 207 | return {'policy': policy, 'K_0': K_0, 'K': K} 208 | 209 | def decrypt(self, pk, ctxt, key): 210 | """ 211 | Decrypt ciphertext ctxt with key key. 212 | """ 213 | 214 | if debug: 215 | print('\nDecryption algorithm:\n') 216 | 217 | nodes = self.util.prune(key['policy'], ctxt['attr_list']) 218 | if not nodes: 219 | print ("Policy not satisfied.") 220 | return None 221 | 222 | prod1_GT = 1 223 | prod2_GT = 1 224 | for i in range(self.assump_size + 1): 225 | prod_H = 1 226 | prod_G = 1 227 | for node in nodes: 228 | attr = node.getAttributeAndIndex() 229 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 230 | prod_H *= key['K'][attr][i] 231 | prod_G *= ctxt['C'][attr_stripped][i] 232 | prod1_GT *= pair(prod_H, ctxt['C_0'][i]) 233 | prod2_GT *= pair(prod_G, key['K_0'][i]) 234 | 235 | return ctxt['Cp'] * prod2_GT / prod1_GT 236 | -------------------------------------------------------------------------------- /FABEO/cgw15kp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Jie Chen, Romain Gay, and Hoeteck Wee 3 | 4 | | From: "Improved Dual System ABE in Prime-Order Groups via Predicate Encodings" 5 | | Published in: 2015 6 | | Available from: http://eprint.iacr.org/2015/409 7 | | Notes: Implemented the scheme in Appendix B.1 8 | | Security Assumption: k-linear 9 | | 10 | | type: key-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Doreen Riepel 14 | :Date: 04/2022 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class CGW15KPABE(ABEnc): 25 | def __init__(self, groupObj, assump_size, uni_size, verbose=False): 26 | ABEnc.__init__(self) 27 | self.name = "CGW15 KP-ABE k=" + str(assump_size) 28 | self.group = groupObj 29 | self.assump_size = assump_size # size of the linear assumption 30 | self.uni_size = uni_size # bound on the size of the universe of attributes 31 | self.util = MSP(self.group, verbose) 32 | 33 | def setup(self): 34 | """ 35 | Generates public key and master secret key. 36 | """ 37 | 38 | if debug: 39 | print('Setup algorithm:\n') 40 | 41 | # generate two instances of the k-linear assumption 42 | A = [] 43 | B = [] 44 | for i in range(self.assump_size): 45 | A.append(self.group.random(ZR)) 46 | B.append(self.group.random(ZR)) # note that A, B are vectors here 47 | 48 | # pick matrices that help to randomize basis 49 | W = {} 50 | for i in range(self.uni_size): 51 | x = [] 52 | for j1 in range(self.assump_size + 1): 53 | y = [] 54 | for j2 in range(self.assump_size + 1): 55 | y.append(self.group.random(ZR)) 56 | x.append(y) 57 | W[i + 1] = x 58 | 59 | U = {} 60 | for i in range(self.uni_size): 61 | x = [] 62 | for j1 in range(self.assump_size + 1): 63 | y = [] 64 | for j2 in range(self.assump_size + 1): 65 | y.append(self.group.random(ZR)) 66 | x.append(y) 67 | U[i + 1] = x 68 | 69 | # vector 70 | k = [] 71 | for i in range(self.assump_size + 1): 72 | k.append(self.group.random(ZR)) 73 | 74 | # pick a random element from the two source groups and pair them 75 | g = self.group.random(G1) 76 | h = self.group.random(G2) 77 | e_gh = pair(g, h) 78 | 79 | # now compute various parts of the public parameters 80 | 81 | # compute the [A]_1 term 82 | g_A = [] 83 | for i in range(self.assump_size): 84 | g_A.append(g ** A[i]) 85 | g_A.append(g) 86 | 87 | # compute the [W_1^T A]_1, [W_2^T A]_1, ... terms 88 | g_WA = {} 89 | for i in range(self.uni_size): 90 | x = [] 91 | for j1 in range(self.assump_size + 1): 92 | y = [] 93 | for j2 in range(self.assump_size): 94 | prod = (A[j2] * W[i + 1][j2][j1]) + W[i + 1][self.assump_size][j1] 95 | y.append(g ** prod) 96 | x.append(y) 97 | g_WA[i + 1] = x 98 | 99 | # compute the e([A]_1, [k]_2) term 100 | h_k = [] 101 | for i in range(self.assump_size + 1): 102 | h_k.append(h ** k[i]) 103 | 104 | e_gh_kA = [] 105 | for i in range(self.assump_size): 106 | e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size])) 107 | 108 | # the public key 109 | pk = {'g_A': g_A, 'g_WA': g_WA, 'e_gh_kA': e_gh_kA} 110 | 111 | # the master secret key 112 | msk = {'h': h, 'k': k, 'B': B, 'W': W, 'U': U} 113 | 114 | return pk, msk 115 | 116 | def encrypt(self, pk, msg, attr_list): 117 | """ 118 | Encrypt a message M under a set of attributes. 119 | """ 120 | 121 | if debug: 122 | print('Encryption algorithm:\n') 123 | 124 | # pick randomness 125 | s = [] 126 | sum = 0 127 | for i in range(self.assump_size): 128 | rand = self.group.random(ZR) 129 | s.append(rand) 130 | sum += rand 131 | s.append(sum) 132 | 133 | # compute the [As]_1 term 134 | C_0 = [] 135 | g_A = pk['g_A'] 136 | for i in range(self.assump_size + 1): 137 | C_0.append(g_A[i] ** s[i]) 138 | 139 | 140 | # compute the [W_i^T Br]_2 terms 141 | C = {} 142 | for attr in attr_list: 143 | ct = [] 144 | W_attr = pk['g_WA'][int(attr)] 145 | for j1 in range(self.assump_size + 1): 146 | prod = 1 147 | for j2 in range(self.assump_size): 148 | prod *= W_attr[j1][j2] ** s[j2] 149 | ct.append(prod) 150 | C[attr] = ct 151 | 152 | # compute the e(g, h)^(k^T As) . m term 153 | Cx = 1 154 | for i in range(self.assump_size): 155 | Cx = Cx * (pk['e_gh_kA'][i] ** s[i]) 156 | Cx = Cx * msg 157 | 158 | return {'attr_list': attr_list, 'C_0': C_0, 'C': C, 'Cx': Cx} 159 | 160 | def keygen(self, pk, msk, policy_str): 161 | """ 162 | Generate a key for a policy string. 163 | """ 164 | 165 | if debug: 166 | print('Key generation algorithm:\n') 167 | 168 | policy = self.util.createPolicy(policy_str) 169 | mono_span_prog = self.util.convert_policy_to_msp(policy) 170 | num_cols = self.util.len_longest_row 171 | 172 | # pick randomness 173 | r = [] 174 | sum = 0 175 | for i in range(self.assump_size): 176 | rand = self.group.random(ZR) 177 | r.append(rand) 178 | sum += rand 179 | 180 | # compute the [Br]_2 term 181 | K_0 = [] 182 | Br = [] 183 | h = msk['h'] 184 | for i in range(self.assump_size): 185 | prod = msk['B'][i] * r[i] 186 | Br.append(prod) 187 | K_0.append(h ** prod) 188 | Br.append(sum) 189 | K_0.append(h ** sum) 190 | 191 | # compute the U_2 Br, ..., U_col Br terms 192 | UBr = {} 193 | for i in range(1,num_cols): 194 | x = [] 195 | for j1 in range(self.assump_size + 1): 196 | sum = 0 197 | for j2 in range(self.assump_size + 1): 198 | sum += Br[j2] * msk['U'][i][j1][j2] 199 | x.append(sum) 200 | UBr[i] = x 201 | 202 | # compute the [(k||U_2 Br||...||U_cols Br) M^T_i + W_i Br]_1 terms 203 | K = {} 204 | for attr, row in mono_span_prog.items(): 205 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 206 | num_cols = len(row) 207 | key = [] 208 | for j1 in range(self.assump_size + 1): 209 | sum1 = msk['k'][j1] * row[0] 210 | for i in range(1,num_cols): 211 | sum1 += UBr[i][j1] * row[i] 212 | for j2 in range(self.assump_size + 1): 213 | sum1 += msk['W'][int(attr_stripped)][j1][j2] * Br[j2] 214 | key.append(h ** sum1) 215 | K[attr] = key 216 | 217 | return {'policy': policy, 'K_0': K_0, 'K': K} 218 | 219 | def decrypt(self, pk, ctxt, key): 220 | """ 221 | Decrypt ciphertext ctxt with key key. 222 | """ 223 | 224 | if debug: 225 | print('Decryption algorithm:\n') 226 | 227 | nodes = self.util.prune(key['policy'], ctxt['attr_list']) 228 | if not nodes: 229 | print ("Policy not satisfied.") 230 | return None 231 | 232 | prod1_GT = 1 233 | prod2_GT = 1 234 | for i in range(self.assump_size + 1): 235 | prod_H = 1 236 | prod_G = 1 237 | for node in nodes: 238 | attr = node.getAttributeAndIndex() 239 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 240 | prod_H *= key['K'][attr][i] 241 | prod_G *= ctxt['C'][attr_stripped][i] 242 | prod1_GT *= pair(ctxt['C_0'][i], prod_H) 243 | prod2_GT *= pair(prod_G, key['K_0'][i]) 244 | 245 | return ctxt['Cx'] * prod2_GT / prod1_GT 246 | -------------------------------------------------------------------------------- /FABEO/ac17cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Shashank Agrawal, Melissa Chase 3 | 4 | | From: "FAME: Fast Attribute-based Message Encryption" 5 | | Published in: 2017 6 | | Available from: https://eprint.iacr.org/2017/807 7 | | Notes: Implemented the scheme in Section 3 8 | | Security Assumption: a variant of k-linear, k>=2 9 | | 10 | | type: ciphertext-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Shashank Agrawal 14 | :Date: 05/2016 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class AC17CPABE(ABEnc): 25 | def __init__(self, group_obj, assump_size, verbose=False): 26 | ABEnc.__init__(self) 27 | self.name = "AC17 CP-ABE k=" + str(assump_size) 28 | self.group = group_obj 29 | self.assump_size = assump_size # size of linear assumption, at least 2 30 | self.util = MSP(self.group, verbose) 31 | 32 | def setup(self): 33 | """ 34 | Generates public key and master secret key. 35 | """ 36 | 37 | if debug: 38 | print('\nSetup algorithm:\n') 39 | 40 | # generate two instances of the k-linear assumption 41 | A = [] 42 | B = [] 43 | for i in range(self.assump_size): 44 | A.append(self.group.random(ZR)) 45 | B.append(self.group.random(ZR)) # note that A, B are vectors here 46 | 47 | # vector 48 | k = [] 49 | for i in range(self.assump_size + 1): 50 | k.append(self.group.random(ZR)) 51 | 52 | # pick a random element from the two source groups and pair them 53 | g = self.group.random(G1) 54 | h = self.group.random(G2) 55 | e_gh = pair(g, h) 56 | 57 | # now compute various parts of the public parameters 58 | 59 | # compute the [A]_2 term 60 | h_A = [] 61 | for i in range(self.assump_size): 62 | h_A.append(h ** A[i]) 63 | h_A.append(h) 64 | 65 | # compute the e([k]_1, [A]_2) term 66 | g_k = [] 67 | for i in range(self.assump_size + 1): 68 | g_k.append(g ** k[i]) 69 | 70 | e_gh_kA = [] 71 | for i in range(self.assump_size): 72 | e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size])) 73 | 74 | # the public key 75 | pk = {'h_A': h_A, 'e_gh_kA': e_gh_kA} 76 | 77 | # the master secret key 78 | msk = {'g': g, 'h': h, 'g_k': g_k, 'A': A, 'B': B} 79 | 80 | return pk, msk 81 | 82 | def keygen(self, pk, msk, attr_list): 83 | """ 84 | Generate a key for a list of attributes. 85 | """ 86 | 87 | if debug: 88 | print('\nKey generation algorithm:\n') 89 | 90 | # pick randomness 91 | r = [] 92 | sum = 0 93 | for i in range(self.assump_size): 94 | rand = self.group.random(ZR) 95 | r.append(rand) 96 | sum += rand 97 | 98 | # compute the [Br]_2 term 99 | 100 | # first compute just Br as it will be used later too 101 | Br = [] 102 | for i in range(self.assump_size): 103 | Br.append(msk['B'][i] * r[i]) 104 | Br.append(sum) 105 | 106 | # now compute [Br]_2 107 | K_0 = [] 108 | for i in range(self.assump_size + 1): 109 | K_0.append(msk['h'] ** Br[i]) 110 | 111 | # compute [W_1 Br]_1, ... 112 | K = {} 113 | A = msk['A'] 114 | g = msk['g'] 115 | for attr in attr_list: 116 | key = [] 117 | sigma_attr = self.group.random(ZR) 118 | for t in range(self.assump_size): 119 | prod = 1 120 | a_t = A[t] 121 | for l in range(self.assump_size + 1): 122 | input_for_hash = attr + str(l) + str(t) 123 | prod *= (self.group.hash(input_for_hash, G1) ** (Br[l]/a_t)) 124 | prod *= (g ** (sigma_attr/a_t)) 125 | key.append(prod) 126 | key.append(g ** (-sigma_attr)) 127 | K[attr] = key 128 | 129 | # compute [k + VBr]_1 130 | Kp = [] 131 | g_k = msk['g_k'] 132 | sigma = self.group.random(ZR) 133 | for t in range(self.assump_size): 134 | prod = g_k[t] 135 | a_t = A[t] 136 | for l in range(self.assump_size + 1): 137 | input_for_hash = '01' + str(l) + str(t) 138 | prod *= (self.group.hash(input_for_hash, G1) ** (Br[l] / a_t)) 139 | prod *= (g ** (sigma / a_t)) 140 | Kp.append(prod) 141 | Kp.append(g_k[self.assump_size] * (g ** (-sigma))) 142 | 143 | return {'attr_list': attr_list, 'K_0': K_0, 'K': K, 'Kp': Kp} 144 | 145 | def encrypt(self, pk, msg, policy_str): 146 | """ 147 | Encrypt a message msg under a policy string. 148 | """ 149 | 150 | if debug: 151 | print('\nEncryption algorithm:\n') 152 | 153 | policy = self.util.createPolicy(policy_str) 154 | mono_span_prog = self.util.convert_policy_to_msp(policy) 155 | num_cols = self.util.len_longest_row 156 | 157 | # pick randomness 158 | s = [] 159 | sum = 0 160 | for i in range(self.assump_size): 161 | rand = self.group.random(ZR) 162 | s.append(rand) 163 | sum += rand 164 | 165 | # compute the [As]_2 term 166 | C_0 = [] 167 | h_A = pk['h_A'] 168 | for i in range(self.assump_size): 169 | C_0.append(h_A[i] ** s[i]) 170 | C_0.append(h_A[self.assump_size] ** sum) 171 | 172 | # compute the [(V^T As||U^T_2 As||...) M^T_i + W^T_i As]_1 terms 173 | 174 | # pre-compute hashes 175 | hash_table = [] 176 | for j in range(num_cols): 177 | x = [] 178 | input_for_hash1 = '0' + str(j + 1) 179 | for l in range(self.assump_size + 1): 180 | y = [] 181 | input_for_hash2 = input_for_hash1 + str(l) 182 | for t in range(self.assump_size): 183 | input_for_hash3 = input_for_hash2 + str(t) 184 | hashed_value = self.group.hash(input_for_hash3, G1) 185 | y.append(hashed_value) 186 | # if debug: print ('Hash of', i+2, ',', j2, ',', j1, 'is', hashed_value) 187 | x.append(y) 188 | hash_table.append(x) 189 | 190 | C = {} 191 | for attr, row in mono_span_prog.items(): 192 | ct = [] 193 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 194 | for l in range(self.assump_size + 1): 195 | prod = 1 196 | cols = len(row) 197 | for t in range(self.assump_size): 198 | input_for_hash = attr_stripped + str(l) + str(t) 199 | prod1 = self.group.hash(input_for_hash, G1) 200 | for j in range(cols): 201 | # input_for_hash = '0' + str(j+1) + str(l) + str(t) 202 | prod1 *= (hash_table[j][l][t] ** row[j]) 203 | prod *= (prod1 ** s[t]) 204 | ct.append(prod) 205 | C[attr] = ct 206 | 207 | # compute the e(g, h)^(k^T As) . m term 208 | Cp = 1 209 | for i in range(self.assump_size): 210 | Cp = Cp * (pk['e_gh_kA'][i] ** s[i]) 211 | Cp = Cp * msg 212 | 213 | return {'policy': policy, 'C_0': C_0, 'C': C, 'Cp': Cp} 214 | 215 | def decrypt(self, pk, ctxt, key): 216 | """ 217 | Decrypt ciphertext ctxt with key key. 218 | """ 219 | 220 | if debug: 221 | print('\nDecryption algorithm:\n') 222 | 223 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 224 | if not nodes: 225 | print ("Policy not satisfied.") 226 | return None 227 | 228 | prod1_GT = 1 229 | prod2_GT = 1 230 | for i in range(self.assump_size + 1): 231 | prod_H = 1 232 | prod_G = 1 233 | for node in nodes: 234 | attr = node.getAttributeAndIndex() 235 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 236 | # prod_H *= key['K'][attr_stripped][i] ** coeff[attr] 237 | # prod_G *= ctxt['C'][attr][i] ** coeff[attr] 238 | prod_H *= key['K'][attr_stripped][i] 239 | prod_G *= ctxt['C'][attr][i] 240 | prod1_GT *= pair(key['Kp'][i] * prod_H, ctxt['C_0'][i]) 241 | prod2_GT *= pair(prod_G, key['K_0'][i]) 242 | 243 | return ctxt['Cp'] * prod2_GT / prod1_GT 244 | -------------------------------------------------------------------------------- /FABEO/cgw15cp/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Jie Chen, Romain Gay, and Hoeteck Wee 3 | 4 | | From: "Improved Dual System ABE in Prime-Order Groups via Predicate Encodings" 5 | | Published in: 2015 6 | | Available from: http://eprint.iacr.org/2015/409 7 | | Notes: Implemented the scheme in Appendix B.2 8 | | Security Assumption: k-linear 9 | | 10 | | type: ciphertext-policy attribute-based encryption 11 | | setting: Pairing 12 | 13 | :Authors: Shashank Agrawal 14 | :Date: 5/2016 15 | ''' 16 | 17 | from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair 18 | from charm.toolbox.ABEnc import ABEnc 19 | from ..msp import MSP 20 | 21 | debug = False 22 | 23 | 24 | class CGW15CPABE(ABEnc): 25 | def __init__(self, groupObj, assump_size, uni_size, verbose=False): 26 | ABEnc.__init__(self) 27 | self.name = "CGW15 CP-ABE k=" + str(assump_size) 28 | self.group = groupObj 29 | self.assump_size = assump_size # size of the linear assumption 30 | self.uni_size = uni_size # bound on the size of the universe of attributes 31 | self.util = MSP(self.group, verbose) 32 | 33 | def setup(self): 34 | """ 35 | Generates public key and master secret key. 36 | """ 37 | 38 | if debug: 39 | print('Setup algorithm:\n') 40 | 41 | # generate two instances of the k-linear assumption 42 | A = [] 43 | B = [] 44 | for i in range(self.assump_size): 45 | A.append(self.group.random(ZR)) 46 | B.append(self.group.random(ZR)) # note that A, B are vectors here 47 | 48 | # pick matrices that help to randomize basis 49 | W = {} 50 | for i in range(self.uni_size): 51 | x = [] 52 | for j1 in range(self.assump_size + 1): 53 | y = [] 54 | for j2 in range(self.assump_size + 1): 55 | y.append(self.group.random(ZR)) 56 | x.append(y) 57 | W[i + 1] = x 58 | 59 | V = [] 60 | for j1 in range(self.assump_size + 1): 61 | y = [] 62 | for j2 in range(self.assump_size + 1): 63 | y.append(self.group.random(ZR)) 64 | V.append(y) 65 | 66 | # vector 67 | k = [] 68 | for i in range(self.assump_size + 1): 69 | k.append(self.group.random(ZR)) 70 | 71 | # pick a random element from the two source groups and pair them 72 | g = self.group.random(G1) 73 | h = self.group.random(G2) 74 | e_gh = pair(g, h) 75 | 76 | # now compute various parts of the public parameters 77 | 78 | # compute the [A]_1 term 79 | g_A = [] 80 | for i in range(self.assump_size): 81 | g_A.append(g ** A[i]) 82 | g_A.append(g) 83 | 84 | # compute the [W_1^T A]_1, [W_2^T A]_1, ... terms 85 | g_WA = {} 86 | for i in range(self.uni_size): 87 | x = [] 88 | for j1 in range(self.assump_size + 1): 89 | y = [] 90 | for j2 in range(self.assump_size): 91 | prod = (A[j2] * W[i + 1][j2][j1]) + W[i + 1][self.assump_size][j1] 92 | y.append(g ** prod) 93 | x.append(y) 94 | g_WA[i + 1] = x 95 | 96 | g_VA = [] 97 | for j1 in range(self.assump_size + 1): 98 | y = [] 99 | for j2 in range(self.assump_size): 100 | prod = (A[j2] * V[j2][j1]) + V[self.assump_size][j1] 101 | y.append(g ** prod) 102 | g_VA.append(y) 103 | 104 | # compute the e([A]_1, [k]_2) term 105 | h_k = [] 106 | for i in range(self.assump_size + 1): 107 | h_k.append(h ** k[i]) 108 | 109 | e_gh_kA = [] 110 | for i in range(self.assump_size): 111 | e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size])) 112 | 113 | # the public key 114 | pk = {'g_A': g_A, 'g_WA': g_WA, 'g_VA': g_VA, 'e_gh_kA': e_gh_kA} 115 | 116 | # the master secret key 117 | msk = {'h': h, 'k': k, 'B': B, 'W': W, 'V': V} 118 | 119 | return pk, msk 120 | 121 | def keygen(self, pk, msk, attr_list): 122 | """ 123 | Generate a key for a set of attributes. 124 | """ 125 | 126 | if debug: 127 | print('Key generation algorithm:\n') 128 | 129 | # pick randomness 130 | r = [] 131 | sum = 0 132 | for i in range(self.assump_size): 133 | rand = self.group.random(ZR) 134 | r.append(rand) 135 | sum += rand 136 | 137 | # compute the [Br]_2 term 138 | K_0 = [] 139 | Br = [] 140 | h = msk['h'] 141 | for i in range(self.assump_size): 142 | prod = msk['B'][i] * r[i] 143 | Br.append(prod) 144 | K_0.append(h ** prod) 145 | Br.append(sum) 146 | K_0.append(h ** sum) 147 | 148 | # compute the [W_i^T Br]_2 terms 149 | K = {} 150 | for attr in attr_list: 151 | key = [] 152 | W_attr = msk['W'][int(attr)] 153 | for j1 in range(self.assump_size + 1): 154 | sum = 0 155 | for j2 in range(self.assump_size + 1): 156 | sum += W_attr[j1][j2] * Br[j2] 157 | key.append(h ** sum) 158 | K[attr] = key 159 | 160 | # compute the [k + VBr]_2 term 161 | Kp = [] 162 | V = msk['V'] 163 | k = msk['k'] 164 | for j1 in range(self.assump_size + 1): 165 | sum = 0 166 | for j2 in range(self.assump_size + 1): 167 | sum += V[j1][j2] * Br[j2] 168 | Kp.append(h ** (k[j1] + sum)) 169 | 170 | return {'attr_list': attr_list, 'K_0': K_0, 'K': K, 'Kp': Kp} 171 | 172 | def encrypt(self, pk, msg, policy_str): 173 | """ 174 | Encrypt a message M under a policy string. 175 | """ 176 | 177 | if debug: 178 | print('Encryption algorithm:\n') 179 | 180 | policy = self.util.createPolicy(policy_str) 181 | mono_span_prog = self.util.convert_policy_to_msp(policy) 182 | num_cols = self.util.len_longest_row 183 | 184 | # pick randomness 185 | s = [] 186 | sum = 0 187 | for i in range(self.assump_size): 188 | rand = self.group.random(ZR) 189 | s.append(rand) 190 | sum += rand 191 | s.append(sum) 192 | 193 | # compute the [As]_1 term 194 | g_As = [] 195 | g_A = pk['g_A'] 196 | for i in range(self.assump_size + 1): 197 | g_As.append(g_A[i] ** s[i]) 198 | 199 | # compute U^T_2 As, U^T_3 As by picking random matrices U_2, U_3 ... 200 | UAs = {} 201 | for i in range(num_cols - 1): 202 | x = [] 203 | for j1 in range(self.assump_size + 1): 204 | prod = 1 205 | for j2 in range(self.assump_size + 1): 206 | prod *= g_As[j2] ** (self.group.random(ZR)) 207 | x.append(prod) 208 | UAs[i+1] = x 209 | 210 | # compute V^T As using VA from public key 211 | VAs = [] 212 | g_VA = pk['g_VA'] 213 | for j1 in range(self.assump_size + 1): 214 | prod = 1 215 | for j2 in range(self.assump_size): 216 | prod *= g_VA[j1][j2] ** s[j2] 217 | VAs.append(prod) 218 | 219 | # compute the [(V^T As||U^T_2 As||...||U^T_cols As) M^T_i + W^T_i As]_1 terms 220 | C = {} 221 | g_WA = pk['g_WA'] 222 | for attr, row in mono_span_prog.items(): 223 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 224 | ct = [] 225 | for j1 in range(self.assump_size + 1): 226 | cols = len(row) 227 | prod1 = VAs[j1] ** row[0] 228 | for j2 in range(1, cols): 229 | prod1 *= UAs[j2][j1] ** row[j2] 230 | prod2 = 1 231 | for j2 in range(self.assump_size): 232 | prod2 *= g_WA[int(attr_stripped)][j1][j2] ** s[j2] 233 | ct.append(prod1 * prod2) 234 | C[attr] = ct 235 | 236 | # compute the e(g, h)^(k^T As) . m term 237 | Cx = 1 238 | for i in range(self.assump_size): 239 | Cx = Cx * (pk['e_gh_kA'][i] ** s[i]) 240 | Cx = Cx * msg 241 | 242 | return {'policy': policy, 'C_0': g_As, 'C': C, 'Cx': Cx} 243 | 244 | def decrypt(self, pk, ctxt, key): 245 | """ 246 | Decrypt ciphertext ctxt with key key. 247 | """ 248 | 249 | if debug: 250 | print('Decryption algorithm:\n') 251 | 252 | nodes = self.util.prune(ctxt['policy'], key['attr_list']) 253 | if not nodes: 254 | print ("Policy not satisfied.") 255 | return None 256 | 257 | prod1_GT = 1 258 | prod2_GT = 1 259 | for i in range(self.assump_size + 1): 260 | prod_H = 1 261 | prod_G = 1 262 | for node in nodes: 263 | attr = node.getAttributeAndIndex() 264 | attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed 265 | # prod_H *= D['K'][attr_stripped][i] ** coeff[attr] 266 | # prod_G *= E['C'][attr][i] ** coeff[attr] 267 | prod_H *= key['K'][attr_stripped][i] 268 | prod_G *= ctxt['C'][attr][i] 269 | prod1_GT *= pair(ctxt['C_0'][i], key['Kp'][i] * prod_H) 270 | prod2_GT *= pair(prod_G, key['K_0'][i]) 271 | 272 | return ctxt['Cx'] * prod2_GT / prod1_GT 273 | --------------------------------------------------------------------------------