charm-crypto-framework 0.61.1__cp313-cp313-macosx_10_13_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. charm/__init__.py +5 -0
  2. charm/adapters/__init__.py +0 -0
  3. charm/adapters/abenc_adapt_hybrid.py +90 -0
  4. charm/adapters/dabenc_adapt_hybrid.py +145 -0
  5. charm/adapters/ibenc_adapt_hybrid.py +72 -0
  6. charm/adapters/ibenc_adapt_identityhash.py +80 -0
  7. charm/adapters/kpabenc_adapt_hybrid.py +91 -0
  8. charm/adapters/pkenc_adapt_bchk05.py +121 -0
  9. charm/adapters/pkenc_adapt_chk04.py +91 -0
  10. charm/adapters/pkenc_adapt_hybrid.py +98 -0
  11. charm/adapters/pksig_adapt_naor01.py +89 -0
  12. charm/config.py +7 -0
  13. charm/core/__init__.py +0 -0
  14. charm/core/benchmark/benchmark_util.c +353 -0
  15. charm/core/benchmark/benchmark_util.h +61 -0
  16. charm/core/benchmark/benchmarkmodule.c +476 -0
  17. charm/core/benchmark/benchmarkmodule.h +162 -0
  18. charm/core/benchmark.cpython-313-darwin.so +0 -0
  19. charm/core/crypto/AES/AES.c +1464 -0
  20. charm/core/crypto/AES.cpython-313-darwin.so +0 -0
  21. charm/core/crypto/DES/DES.c +113 -0
  22. charm/core/crypto/DES.cpython-313-darwin.so +0 -0
  23. charm/core/crypto/DES3/DES3.c +26 -0
  24. charm/core/crypto/DES3.cpython-313-darwin.so +0 -0
  25. charm/core/crypto/__init__.py +0 -0
  26. charm/core/crypto/cryptobase/XOR.c +80 -0
  27. charm/core/crypto/cryptobase/_counter.c +496 -0
  28. charm/core/crypto/cryptobase/_counter.h +54 -0
  29. charm/core/crypto/cryptobase/block_template.c +900 -0
  30. charm/core/crypto/cryptobase/block_template.h +69 -0
  31. charm/core/crypto/cryptobase/cryptobasemodule.c +220 -0
  32. charm/core/crypto/cryptobase/libtom/tomcrypt.h +90 -0
  33. charm/core/crypto/cryptobase/libtom/tomcrypt_argchk.h +44 -0
  34. charm/core/crypto/cryptobase/libtom/tomcrypt_cfg.h +186 -0
  35. charm/core/crypto/cryptobase/libtom/tomcrypt_cipher.h +941 -0
  36. charm/core/crypto/cryptobase/libtom/tomcrypt_custom.h +556 -0
  37. charm/core/crypto/cryptobase/libtom/tomcrypt_des.c +1912 -0
  38. charm/core/crypto/cryptobase/libtom/tomcrypt_hash.h +407 -0
  39. charm/core/crypto/cryptobase/libtom/tomcrypt_mac.h +496 -0
  40. charm/core/crypto/cryptobase/libtom/tomcrypt_macros.h +435 -0
  41. charm/core/crypto/cryptobase/libtom/tomcrypt_math.h +534 -0
  42. charm/core/crypto/cryptobase/libtom/tomcrypt_misc.h +103 -0
  43. charm/core/crypto/cryptobase/libtom/tomcrypt_pk.h +653 -0
  44. charm/core/crypto/cryptobase/libtom/tomcrypt_pkcs.h +90 -0
  45. charm/core/crypto/cryptobase/libtom/tomcrypt_prng.h +199 -0
  46. charm/core/crypto/cryptobase/stream_template.c +271 -0
  47. charm/core/crypto/cryptobase/strxor.c +229 -0
  48. charm/core/crypto/cryptobase.cpython-313-darwin.so +0 -0
  49. charm/core/engine/__init__.py +5 -0
  50. charm/core/engine/protocol.py +293 -0
  51. charm/core/engine/util.py +174 -0
  52. charm/core/math/__init__.py +0 -0
  53. charm/core/math/elliptic_curve/ecmodule.c +1986 -0
  54. charm/core/math/elliptic_curve/ecmodule.h +230 -0
  55. charm/core/math/elliptic_curve.cpython-313-darwin.so +0 -0
  56. charm/core/math/elliptic_curve.pyi +63 -0
  57. charm/core/math/integer/integermodule.c +2539 -0
  58. charm/core/math/integer/integermodule.h +145 -0
  59. charm/core/math/integer.cpython-313-darwin.so +0 -0
  60. charm/core/math/integer.pyi +76 -0
  61. charm/core/math/pairing/miracl/miracl_config.h +37 -0
  62. charm/core/math/pairing/miracl/miracl_interface.h +118 -0
  63. charm/core/math/pairing/miracl/miracl_interface2.h +126 -0
  64. charm/core/math/pairing/miracl/pairingmodule2.c +2094 -0
  65. charm/core/math/pairing/miracl/pairingmodule2.h +307 -0
  66. charm/core/math/pairing/pairingmodule.c +2230 -0
  67. charm/core/math/pairing/pairingmodule.h +241 -0
  68. charm/core/math/pairing/relic/pairingmodule3.c +1853 -0
  69. charm/core/math/pairing/relic/pairingmodule3.h +233 -0
  70. charm/core/math/pairing/relic/relic_interface.c +1337 -0
  71. charm/core/math/pairing/relic/relic_interface.h +217 -0
  72. charm/core/math/pairing/relic/test_relic.c +171 -0
  73. charm/core/math/pairing.cpython-313-darwin.so +0 -0
  74. charm/core/math/pairing.pyi +69 -0
  75. charm/core/utilities/base64.c +248 -0
  76. charm/core/utilities/base64.h +15 -0
  77. charm/schemes/__init__.py +0 -0
  78. charm/schemes/abenc/__init__.py +0 -0
  79. charm/schemes/abenc/abenc_accountability_jyjxgd20.py +647 -0
  80. charm/schemes/abenc/abenc_bsw07.py +146 -0
  81. charm/schemes/abenc/abenc_ca_cpabe_ar17.py +684 -0
  82. charm/schemes/abenc/abenc_dacmacs_yj14.py +298 -0
  83. charm/schemes/abenc/abenc_lsw08.py +159 -0
  84. charm/schemes/abenc/abenc_maabe_rw15.py +236 -0
  85. charm/schemes/abenc/abenc_maabe_yj14.py +297 -0
  86. charm/schemes/abenc/abenc_tbpre_lww14.py +309 -0
  87. charm/schemes/abenc/abenc_unmcpabe_yahk14.py +223 -0
  88. charm/schemes/abenc/abenc_waters09.py +144 -0
  89. charm/schemes/abenc/abenc_yct14.py +208 -0
  90. charm/schemes/abenc/abenc_yllc15.py +178 -0
  91. charm/schemes/abenc/ac17.py +248 -0
  92. charm/schemes/abenc/bsw07.py +141 -0
  93. charm/schemes/abenc/cgw15.py +277 -0
  94. charm/schemes/abenc/dabe_aw11.py +204 -0
  95. charm/schemes/abenc/dfa_fe12.py +144 -0
  96. charm/schemes/abenc/pk_hve08.py +179 -0
  97. charm/schemes/abenc/waters11.py +143 -0
  98. charm/schemes/aggrsign_MuSig.py +150 -0
  99. charm/schemes/aggrsign_bls.py +267 -0
  100. charm/schemes/blindsig_ps16.py +654 -0
  101. charm/schemes/chamhash_adm05.py +113 -0
  102. charm/schemes/chamhash_rsa_hw09.py +100 -0
  103. charm/schemes/commit/__init__.py +0 -0
  104. charm/schemes/commit/commit_gs08.py +77 -0
  105. charm/schemes/commit/commit_pedersen92.py +53 -0
  106. charm/schemes/encap_bchk05.py +62 -0
  107. charm/schemes/grpsig/__init__.py +0 -0
  108. charm/schemes/grpsig/groupsig_bgls04.py +114 -0
  109. charm/schemes/grpsig/groupsig_bgls04_var.py +115 -0
  110. charm/schemes/hibenc/__init__.py +0 -0
  111. charm/schemes/hibenc/hibenc_bb04.py +105 -0
  112. charm/schemes/hibenc/hibenc_lew11.py +193 -0
  113. charm/schemes/ibenc/__init__.py +0 -0
  114. charm/schemes/ibenc/clpkc_rp03.py +119 -0
  115. charm/schemes/ibenc/ibenc_CW13_z.py +168 -0
  116. charm/schemes/ibenc/ibenc_bb03.py +94 -0
  117. charm/schemes/ibenc/ibenc_bf01.py +121 -0
  118. charm/schemes/ibenc/ibenc_ckrs09.py +120 -0
  119. charm/schemes/ibenc/ibenc_cllww12_z.py +172 -0
  120. charm/schemes/ibenc/ibenc_lsw08.py +120 -0
  121. charm/schemes/ibenc/ibenc_sw05.py +238 -0
  122. charm/schemes/ibenc/ibenc_waters05.py +144 -0
  123. charm/schemes/ibenc/ibenc_waters05_z.py +164 -0
  124. charm/schemes/ibenc/ibenc_waters09.py +107 -0
  125. charm/schemes/ibenc/ibenc_waters09_z.py +147 -0
  126. charm/schemes/joye_scheme.py +106 -0
  127. charm/schemes/lem_scheme.py +207 -0
  128. charm/schemes/pk_fre_ccv11.py +107 -0
  129. charm/schemes/pk_vrf.py +127 -0
  130. charm/schemes/pkenc/__init__.py +0 -0
  131. charm/schemes/pkenc/pkenc_cs98.py +108 -0
  132. charm/schemes/pkenc/pkenc_elgamal85.py +122 -0
  133. charm/schemes/pkenc/pkenc_gm82.py +98 -0
  134. charm/schemes/pkenc/pkenc_paillier99.py +118 -0
  135. charm/schemes/pkenc/pkenc_rabin.py +254 -0
  136. charm/schemes/pkenc/pkenc_rsa.py +186 -0
  137. charm/schemes/pksig/__init__.py +0 -0
  138. charm/schemes/pksig/pksig_CW13_z.py +135 -0
  139. charm/schemes/pksig/pksig_bls04.py +87 -0
  140. charm/schemes/pksig/pksig_boyen.py +156 -0
  141. charm/schemes/pksig/pksig_chch.py +97 -0
  142. charm/schemes/pksig/pksig_chp.py +70 -0
  143. charm/schemes/pksig/pksig_cl03.py +150 -0
  144. charm/schemes/pksig/pksig_cl04.py +87 -0
  145. charm/schemes/pksig/pksig_cllww12_z.py +142 -0
  146. charm/schemes/pksig/pksig_cyh.py +132 -0
  147. charm/schemes/pksig/pksig_dsa.py +76 -0
  148. charm/schemes/pksig/pksig_ecdsa.py +71 -0
  149. charm/schemes/pksig/pksig_hess.py +104 -0
  150. charm/schemes/pksig/pksig_hw.py +110 -0
  151. charm/schemes/pksig/pksig_lamport.py +63 -0
  152. charm/schemes/pksig/pksig_ps01.py +135 -0
  153. charm/schemes/pksig/pksig_ps02.py +124 -0
  154. charm/schemes/pksig/pksig_ps03.py +119 -0
  155. charm/schemes/pksig/pksig_rsa_hw09.py +206 -0
  156. charm/schemes/pksig/pksig_schnorr91.py +77 -0
  157. charm/schemes/pksig/pksig_waters.py +115 -0
  158. charm/schemes/pksig/pksig_waters05.py +121 -0
  159. charm/schemes/pksig/pksig_waters09.py +121 -0
  160. charm/schemes/pre_mg07.py +150 -0
  161. charm/schemes/prenc/pre_afgh06.py +126 -0
  162. charm/schemes/prenc/pre_bbs98.py +123 -0
  163. charm/schemes/prenc/pre_nal16.py +216 -0
  164. charm/schemes/protocol_a01.py +272 -0
  165. charm/schemes/protocol_ao00.py +215 -0
  166. charm/schemes/protocol_cns07.py +274 -0
  167. charm/schemes/protocol_schnorr91.py +125 -0
  168. charm/schemes/sigma1.py +64 -0
  169. charm/schemes/sigma2.py +129 -0
  170. charm/schemes/sigma3.py +126 -0
  171. charm/schemes/threshold/__init__.py +59 -0
  172. charm/schemes/threshold/dkls23_dkg.py +556 -0
  173. charm/schemes/threshold/dkls23_presign.py +1089 -0
  174. charm/schemes/threshold/dkls23_sign.py +761 -0
  175. charm/schemes/threshold/xrpl_wallet.py +967 -0
  176. charm/test/__init__.py +0 -0
  177. charm/test/adapters/__init__.py +0 -0
  178. charm/test/adapters/abenc_adapt_hybrid_test.py +29 -0
  179. charm/test/adapters/dabenc_adapt_hybrid_test.py +56 -0
  180. charm/test/adapters/ibenc_adapt_hybrid_test.py +36 -0
  181. charm/test/adapters/ibenc_adapt_identityhash_test.py +32 -0
  182. charm/test/adapters/kpabenc_adapt_hybrid_test.py +30 -0
  183. charm/test/benchmark/abenc_yllc15_bench.py +92 -0
  184. charm/test/benchmark/benchmark_test.py +148 -0
  185. charm/test/benchmark_threshold.py +260 -0
  186. charm/test/conftest.py +38 -0
  187. charm/test/fuzz/__init__.py +1 -0
  188. charm/test/fuzz/conftest.py +5 -0
  189. charm/test/fuzz/fuzz_policy_parser.py +76 -0
  190. charm/test/fuzz/fuzz_serialization.py +83 -0
  191. charm/test/schemes/__init__.py +0 -0
  192. charm/test/schemes/abenc/__init__.py +0 -0
  193. charm/test/schemes/abenc/abenc_bsw07_test.py +39 -0
  194. charm/test/schemes/abenc/abenc_dacmacs_yj14_test.py +16 -0
  195. charm/test/schemes/abenc/abenc_lsw08_test.py +33 -0
  196. charm/test/schemes/abenc/abenc_maabe_yj14_test.py +16 -0
  197. charm/test/schemes/abenc/abenc_tbpre_lww14_test.py +16 -0
  198. charm/test/schemes/abenc/abenc_waters09_test.py +38 -0
  199. charm/test/schemes/abenc/abenc_yllc15_test.py +74 -0
  200. charm/test/schemes/chamhash_adm05_test.py +31 -0
  201. charm/test/schemes/chamhash_rsa_hw09_test.py +29 -0
  202. charm/test/schemes/commit/__init__.py +0 -0
  203. charm/test/schemes/commit/commit_gs08_test.py +24 -0
  204. charm/test/schemes/commit/commit_pedersen92_test.py +26 -0
  205. charm/test/schemes/dabe_aw11_test.py +45 -0
  206. charm/test/schemes/encap_bchk05_test.py +21 -0
  207. charm/test/schemes/grpsig/__init__.py +0 -0
  208. charm/test/schemes/grpsig/groupsig_bgls04_test.py +35 -0
  209. charm/test/schemes/grpsig/groupsig_bgls04_var_test.py +39 -0
  210. charm/test/schemes/hibenc/__init__.py +0 -0
  211. charm/test/schemes/hibenc/hibenc_bb04_test.py +28 -0
  212. charm/test/schemes/ibenc/__init__.py +0 -0
  213. charm/test/schemes/ibenc/ibenc_bb03_test.py +26 -0
  214. charm/test/schemes/ibenc/ibenc_bf01_test.py +24 -0
  215. charm/test/schemes/ibenc/ibenc_ckrs09_test.py +25 -0
  216. charm/test/schemes/ibenc/ibenc_lsw08_test.py +31 -0
  217. charm/test/schemes/ibenc/ibenc_sw05_test.py +32 -0
  218. charm/test/schemes/ibenc/ibenc_waters05_test.py +31 -0
  219. charm/test/schemes/ibenc/ibenc_waters09_test.py +27 -0
  220. charm/test/schemes/pk_vrf_test.py +29 -0
  221. charm/test/schemes/pkenc/__init__.py +0 -0
  222. charm/test/schemes/pkenc_test.py +255 -0
  223. charm/test/schemes/pksig/__init__.py +0 -0
  224. charm/test/schemes/pksig_test.py +376 -0
  225. charm/test/schemes/rsa_alg_test.py +340 -0
  226. charm/test/schemes/threshold_test.py +1792 -0
  227. charm/test/serialize/__init__.py +0 -0
  228. charm/test/serialize/serialize_test.py +40 -0
  229. charm/test/toolbox/__init__.py +0 -0
  230. charm/test/toolbox/conversion_test.py +30 -0
  231. charm/test/toolbox/ecgroup_test.py +53 -0
  232. charm/test/toolbox/integer_arithmetic_test.py +441 -0
  233. charm/test/toolbox/paddingschemes_test.py +238 -0
  234. charm/test/toolbox/policy_parser_stress_test.py +969 -0
  235. charm/test/toolbox/secretshare_test.py +28 -0
  236. charm/test/toolbox/symcrypto_test.py +108 -0
  237. charm/test/toolbox/test_policy_expression.py +16 -0
  238. charm/test/vectors/__init__.py +1 -0
  239. charm/test/vectors/test_bls_vectors.py +289 -0
  240. charm/test/vectors/test_pedersen_vectors.py +315 -0
  241. charm/test/vectors/test_schnorr_vectors.py +368 -0
  242. charm/test/zkp_compiler/__init__.py +9 -0
  243. charm/test/zkp_compiler/benchmark_zkp.py +258 -0
  244. charm/test/zkp_compiler/test_and_proof.py +240 -0
  245. charm/test/zkp_compiler/test_batch_verify.py +248 -0
  246. charm/test/zkp_compiler/test_dleq_proof.py +264 -0
  247. charm/test/zkp_compiler/test_or_proof.py +231 -0
  248. charm/test/zkp_compiler/test_proof_serialization.py +121 -0
  249. charm/test/zkp_compiler/test_range_proof.py +241 -0
  250. charm/test/zkp_compiler/test_representation_proof.py +325 -0
  251. charm/test/zkp_compiler/test_schnorr_proof.py +221 -0
  252. charm/test/zkp_compiler/test_thread_safety.py +169 -0
  253. charm/test/zkp_compiler/test_zkp_parser.py +139 -0
  254. charm/toolbox/ABEnc.py +26 -0
  255. charm/toolbox/ABEncMultiAuth.py +66 -0
  256. charm/toolbox/ABEnumeric.py +800 -0
  257. charm/toolbox/Commit.py +24 -0
  258. charm/toolbox/DFA.py +89 -0
  259. charm/toolbox/FSA.py +1254 -0
  260. charm/toolbox/Hash.py +39 -0
  261. charm/toolbox/IBEnc.py +62 -0
  262. charm/toolbox/IBSig.py +64 -0
  263. charm/toolbox/PKEnc.py +66 -0
  264. charm/toolbox/PKSig.py +56 -0
  265. charm/toolbox/PREnc.py +32 -0
  266. charm/toolbox/ZKProof.py +289 -0
  267. charm/toolbox/__init__.py +0 -0
  268. charm/toolbox/bitstring.py +49 -0
  269. charm/toolbox/broadcast.py +220 -0
  270. charm/toolbox/conversion.py +100 -0
  271. charm/toolbox/eccurve.py +149 -0
  272. charm/toolbox/ecgroup.py +143 -0
  273. charm/toolbox/enum.py +60 -0
  274. charm/toolbox/hash_module.py +91 -0
  275. charm/toolbox/integergroup.py +323 -0
  276. charm/toolbox/iterate.py +22 -0
  277. charm/toolbox/matrixops.py +76 -0
  278. charm/toolbox/mpc_utils.py +296 -0
  279. charm/toolbox/msp.py +175 -0
  280. charm/toolbox/mta.py +985 -0
  281. charm/toolbox/node.py +120 -0
  282. charm/toolbox/ot/__init__.py +22 -0
  283. charm/toolbox/ot/base_ot.py +374 -0
  284. charm/toolbox/ot/dpf.py +642 -0
  285. charm/toolbox/ot/mpfss.py +228 -0
  286. charm/toolbox/ot/ot_extension.py +589 -0
  287. charm/toolbox/ot/silent_ot.py +378 -0
  288. charm/toolbox/paddingschemes.py +423 -0
  289. charm/toolbox/paddingschemes_test.py +238 -0
  290. charm/toolbox/pairingcurves.py +85 -0
  291. charm/toolbox/pairinggroup.py +186 -0
  292. charm/toolbox/policy_expression_spec.py +70 -0
  293. charm/toolbox/policytree.py +189 -0
  294. charm/toolbox/reCompiler.py +346 -0
  295. charm/toolbox/redundancyschemes.py +65 -0
  296. charm/toolbox/schemebase.py +188 -0
  297. charm/toolbox/secretshare.py +104 -0
  298. charm/toolbox/secretutil.py +174 -0
  299. charm/toolbox/securerandom.py +73 -0
  300. charm/toolbox/sigmaprotocol.py +46 -0
  301. charm/toolbox/specialprimes.py +45 -0
  302. charm/toolbox/symcrypto.py +279 -0
  303. charm/toolbox/threshold_sharing.py +553 -0
  304. charm/toolbox/xmlserialize.py +94 -0
  305. charm/toolbox/zknode.py +105 -0
  306. charm/zkp_compiler/__init__.py +89 -0
  307. charm/zkp_compiler/and_proof.py +460 -0
  308. charm/zkp_compiler/batch_verify.py +324 -0
  309. charm/zkp_compiler/dleq_proof.py +423 -0
  310. charm/zkp_compiler/or_proof.py +305 -0
  311. charm/zkp_compiler/range_proof.py +417 -0
  312. charm/zkp_compiler/representation_proof.py +466 -0
  313. charm/zkp_compiler/schnorr_proof.py +273 -0
  314. charm/zkp_compiler/thread_safe.py +150 -0
  315. charm/zkp_compiler/zk_demo.py +489 -0
  316. charm/zkp_compiler/zkp_factory.py +330 -0
  317. charm/zkp_compiler/zkp_generator.py +370 -0
  318. charm/zkp_compiler/zkparser.py +269 -0
  319. charm_crypto_framework-0.61.1.dist-info/METADATA +337 -0
  320. charm_crypto_framework-0.61.1.dist-info/RECORD +323 -0
  321. charm_crypto_framework-0.61.1.dist-info/WHEEL +5 -0
  322. charm_crypto_framework-0.61.1.dist-info/licenses/LICENSE.txt +165 -0
  323. charm_crypto_framework-0.61.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,684 @@
1
+ '''
2
+ **User Collusion Avoidance CP-ABE (AR17)**
3
+
4
+ *Authors:* Jiguo Li, Wei Yao, Jinguang Han, Yichen Zhang, Jian Shen
5
+
6
+ | **Title:** "User Collusion Avoidance CP-ABE With Efficient Attribute Revocation for Cloud Storage"
7
+ | **Published in:** IEEE Systems Journal, 2017
8
+ | **Available from:** https://ieeexplore.ieee.org/abstract/document/7867082
9
+ | **Notes:** Supports user collusion avoidance with efficient attribute revocation
10
+
11
+ .. rubric:: Scheme Properties
12
+
13
+ * **Type:** ciphertext-policy attribute-based encryption (public key)
14
+ * **Setting:** Pairing groups
15
+ * **Assumption:** Decisional Bilinear Diffie-Hellman
16
+
17
+ .. rubric:: Implementation
18
+
19
+ :Authors: Ahmed Bakr
20
+ :Date: 07/2023
21
+ '''
22
+ from charm.toolbox.pairinggroup import PairingGroup,ZR,G1,G2,GT,pair
23
+ from charm.toolbox.secretutil import SecretUtil
24
+ from charm.toolbox.ABEnc import ABEnc, Input, Output
25
+
26
+ from typing import Dict, List, Tuple
27
+ import queue
28
+
29
+ # type annotations
30
+ mk_t = {'beta':ZR, 'g_alpha':G1 }
31
+ pp_t = { 'g':G1, 'g_beta':G1, 'g_1_over_beta':G1, 'e_gg_alpha':GT }
32
+
33
+
34
+
35
+ class TreeNode:
36
+ def __init__(self, sequence_number, value, parent=None):
37
+ self.parent = parent
38
+ self.sequence_number = sequence_number
39
+ self.value = value
40
+ self.left = None
41
+ self.right = None
42
+
43
+ def __str__(self):
44
+ return str(self.sequence_number)
45
+
46
+ def __repr__(self):
47
+ return self.__str__()
48
+
49
+
50
+ class UsersBinaryTree:
51
+ """
52
+ A binary tree that is used to assign users to leafs in a deterministic way.
53
+ The tree is created and maintained by the AM.
54
+ """
55
+ def __init__(self, group_obj):
56
+ self.group = group_obj
57
+ self.leafs_queue = queue.Queue()
58
+ self.sequence_number = 0
59
+ self.root = self.create_node()
60
+ self.leafs_queue.put(self.root)
61
+ self.__curr_node = self.leafs_queue.get()
62
+
63
+ def create_node(self) -> TreeNode:
64
+ self.sequence_number += 1
65
+ return TreeNode(self.sequence_number, self.group.random(ZR))
66
+
67
+ def add_node_to_tree(self, tree_node: TreeNode):
68
+ """
69
+ Add a node to the tree.
70
+ Inputs:
71
+ - tree_node: a node to be added to the tree
72
+ """
73
+ if self.__curr_node.left and self.__curr_node.right:
74
+ assert not self.leafs_queue.empty(), "Leafs queue is empty and pull attempts was made"
75
+ self.__curr_node = self.leafs_queue.get()
76
+ if not self.__curr_node.left:
77
+ self.__curr_node.left = tree_node
78
+ elif not self.__curr_node.right:
79
+ self.__curr_node.right = tree_node
80
+ else:
81
+ assert True, "This statement should not be reached"
82
+ tree_node.parent = self.__curr_node
83
+ self.leafs_queue.put(tree_node)
84
+
85
+ def print_tree(self):
86
+ print("{", end='')
87
+ self.__print_tree_rec(self.root)
88
+ print("}")
89
+
90
+ def __print_tree_rec(self, node: TreeNode):
91
+ print(node, end=', ')
92
+ if node.left:
93
+ self.__print_tree_rec(node.left)
94
+ if node.right:
95
+ self.__print_tree_rec(node.right)
96
+
97
+
98
+ class AM:
99
+ """Attribute Manager (AM)"""
100
+ def __init__(self, group_obj):
101
+ self.users_to_attrs_dict: Dict[str, list] = {}
102
+ self.attrs_to_users_dict: Dict[str, list] = {}
103
+
104
+ self.users_binary_tree = UsersBinaryTree(group_obj)
105
+
106
+ def add_attr_to_user(self, attr_str: str, user_name: str):
107
+ if user_name not in self.users_to_attrs_dict:
108
+ self.users_to_attrs_dict[user_name] = []
109
+ self.__create_node_in_binary_tree_for_new_user()
110
+
111
+ if attr_str not in self.attrs_to_users_dict:
112
+ self.attrs_to_users_dict[attr_str] = []
113
+
114
+ self.users_to_attrs_dict[user_name].append(attr_str) # AB: It is assumed that this attribute does not already
115
+ # exist in the list
116
+ self.attrs_to_users_dict[attr_str].append(user_name) # AB: It is assumed that the username does not already
117
+ # exist in the list
118
+
119
+ def __create_node_in_binary_tree_for_new_user(self):
120
+ current_number_of_users = len(list(self.users_to_attrs_dict.keys())) # AB: make sure to add the new user to the
121
+ # dict first before calling this function
122
+ while not current_number_of_users == self.users_binary_tree.leafs_queue.qsize():
123
+ new_node = self.users_binary_tree.create_node()
124
+ self.users_binary_tree.add_node_to_tree(new_node)
125
+
126
+ def remove_attr_from_user(self, attr_str: str, user_name: str):
127
+ index = self.attrs_to_users_dict[attr_str].index(user_name)
128
+ self.attrs_to_users_dict[attr_str].pop(index)
129
+
130
+ index = self.users_to_attrs_dict[user_name].index(attr_str)
131
+ self.users_to_attrs_dict[user_name].pop(index)
132
+
133
+ def get_user_assignation_to_leafs_dict(self) -> Dict[str, TreeNode]:
134
+ user_names_list = list(self.users_to_attrs_dict.keys())
135
+ assert len(user_names_list) == self.users_binary_tree.leafs_queue.qsize(), "The number of usernames list ({})" \
136
+ " has to match the number of leaf" \
137
+ " elements ({}) in the binary tree".format(
138
+ len(user_names_list), self.users_binary_tree.leafs_queue.qsize())
139
+ ret_dict: Dict[str, TreeNode] = {}
140
+ for user_name, leaf in zip(user_names_list, self.users_binary_tree.leafs_queue.queue):
141
+ ret_dict[user_name] = leaf
142
+
143
+ return ret_dict
144
+
145
+ def get_minimum_nodes_list_that_represent_users_list(self, user_names_list: List[str]) -> List[TreeNode]:
146
+ """
147
+ This is represented in the paper as calculating node(Gi)
148
+ """
149
+ visited_arr = [False] * (self.users_binary_tree.sequence_number + 1)
150
+ list_of_leaves_to_traverse = []
151
+
152
+ user_assignation_to_leafs_dict = self.get_user_assignation_to_leafs_dict()
153
+ for user_name in user_names_list:
154
+ user_leaf_node = user_assignation_to_leafs_dict[user_name]
155
+ visited_arr[user_leaf_node.sequence_number] = True
156
+ list_of_leaves_to_traverse.append(user_leaf_node)
157
+
158
+ self.__traverse_to_mark_all_children_visited_arr(self.users_binary_tree.root, visited_arr)
159
+
160
+ return self.__traverse_bfs_to_get_minimum_number_nodes_to_cover_users_list(visited_arr)
161
+
162
+ def __traverse_to_mark_all_children_visited_arr(self, node: TreeNode, visited_arr: List[bool]):
163
+ is_leaf = not node.left and not node.right
164
+ if is_leaf:
165
+ return
166
+ if node.left:
167
+ self.__traverse_to_mark_all_children_visited_arr(node.left, visited_arr)
168
+ if node.right:
169
+ self.__traverse_to_mark_all_children_visited_arr(node.right, visited_arr)
170
+
171
+ visited_arr[node.sequence_number] = visited_arr[node.left.sequence_number] and visited_arr[
172
+ node.right.sequence_number]
173
+
174
+ def __traverse_bfs_to_get_minimum_number_nodes_to_cover_users_list(self, visited_arr) -> List[TreeNode]:
175
+ ret_list = []
176
+ q = queue.Queue()
177
+ q.put(self.users_binary_tree.root)
178
+
179
+ while not q.empty():
180
+ node: TreeNode = q.get()
181
+ if visited_arr[node.sequence_number]:
182
+ ret_list.append(node)
183
+ else:
184
+ if node.left:
185
+ q.put(node.left)
186
+ if node.right:
187
+ q.put(node.right)
188
+
189
+ return ret_list
190
+
191
+ def get_user_path(self, user_name) -> List[TreeNode]:
192
+ ret_list = []
193
+ user_assignation_to_leafs_dict = self.get_user_assignation_to_leafs_dict()
194
+ assert user_name in user_assignation_to_leafs_dict, \
195
+ "Username ({}) must be inside user_assignation_to_leafs_dict ({})".format(user_name,
196
+ user_assignation_to_leafs_dict)
197
+ user_leaf_node = user_assignation_to_leafs_dict[user_name]
198
+ curr_node: TreeNode = user_leaf_node
199
+ while curr_node:
200
+ ret_list.append(curr_node)
201
+ curr_node = curr_node.parent
202
+
203
+ return ret_list
204
+
205
+ @staticmethod
206
+ def get_user_path_intersection_with_node_gi(user_path: List[TreeNode], node_gi: List[TreeNode]) -> List[TreeNode]:
207
+ ret_intersection_list = []
208
+ for user_node in user_path:
209
+ if user_node in node_gi:
210
+ ret_intersection_list.append(user_node)
211
+
212
+ return ret_intersection_list
213
+
214
+
215
+ class CaCpabeAr(ABEnc):
216
+ def __init__(self, group_obj):
217
+ ABEnc.__init__(self)
218
+ self.util = SecretUtil(group_obj, verbose=False)
219
+ self.group = group_obj
220
+
221
+ def system_setup(self) -> (mk_t, pp_t):
222
+ """
223
+ System Setup algorithm. This algorithm is performed by TA
224
+ Inputs:
225
+ - None
226
+ Outputs:
227
+ - MK: TA's master secret key.
228
+ - PP: Public Parameters.
229
+ """
230
+ alpha, beta = self.group.random(ZR), self.group.random(ZR)
231
+ g = self.group.random(G1)
232
+
233
+ MK = {'beta': beta, 'g_alpha': g ** alpha}
234
+ e_gg_alpha = pair(g, g) ** alpha
235
+ PP = {'g': g, 'g_beta': g ** beta, 'g_1_over_beta': g ** ~beta, 'e_gg_alpha': e_gg_alpha}
236
+
237
+ return MK, PP
238
+
239
+ def manager_setup(self, attribute_names: List[str], PP: pp_t):
240
+ """
241
+ Manager Setup algorithm performed by AM.
242
+ Inputs:
243
+ - attribute_names: The name of attributes that AM is responsible for.
244
+ - PP: Public Parameters from the system setup algorithm.
245
+ Outputs:
246
+ - MMK: Manager master key represented as a dictionary.
247
+ - MPK: Manager public key represented as a dictionary.
248
+ """
249
+ MMK = {}
250
+ MPK = {}
251
+ for attr in attribute_names:
252
+ t_i = self.group.random(ZR)
253
+ g = PP['g']
254
+ T_i = g ** t_i
255
+ MMK[attr] = t_i
256
+ MPK[attr] = T_i
257
+
258
+ return MMK, MPK
259
+
260
+ def key_generation(self, PP, MK, MPK, user_attribute_names_list: List[str], user_name: str,
261
+ attributes_manager: AM, UMK, users_TA_KEK):
262
+ """
263
+ This function is responsible for generating the decryption keys used by the user according to his list of
264
+ attributes.
265
+ Inputs:
266
+ - PP: Public Parameters from the system setup algorithm.
267
+ - MK: TA's master secret key.
268
+ - MPK: Manager public key represented as a dictionary.
269
+ - user_attribute_names_list: Attribute names hold by the user.
270
+ - user_name: User name.
271
+ - attributes_manager: AM.
272
+ Inputs/outputs:
273
+ - UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
274
+ user_name is the key and a group element is the value.
275
+ Outputs:
276
+ - DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user)
277
+ - KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
278
+ generated by AM. (shared with the user)
279
+ - users_TA_KEK: A dictionary that holds the TA KEK for each user. (stored privately by AM)
280
+ """
281
+ # Attribute key generation. Executed by TA.
282
+ DSK, TA_KEK = self.user_attributes_key_gen(MK, MPK, PP, user_attribute_names_list, user_name, UMK)
283
+
284
+ users_TA_KEK[user_name] = TA_KEK
285
+
286
+ # KEK generation by AM.
287
+ KEK = self.user_attributes_kek_generation(TA_KEK, attributes_manager, user_attribute_names_list, user_name)
288
+
289
+ return DSK, KEK
290
+
291
+ def user_attributes_key_gen(self, MK, MPK, PP, user_attribute_names_list, user_name, UMK):
292
+ """
293
+ This function is executed by TA and considered as part of key generation procedure.
294
+ Inputs:
295
+ - MK: TA's master secret key.
296
+ - MPK: Manager public key represented as a dictionary.
297
+ - PP: Public Parameters from the system setup algorithm.
298
+ - user_attribute_names_list: Attribute names hold by the user.
299
+ - user_name: User name.
300
+ Inputs/outputs:
301
+ - UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
302
+ user_name is the key and a group element is the value.
303
+ Outputs:
304
+ - DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user)
305
+ - KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
306
+ generated by AM. It is a preliminary one that will be changed by AM in the next algorithm.
307
+ """
308
+ r = self.group.random(ZR)
309
+ g = PP['g']
310
+ g_r = g ** r
311
+ D = (MK['g_alpha'] * g_r) ** (1 / MK['beta'])
312
+ D_i = {}
313
+ D_i_dash = {}
314
+ KEK = {}
315
+ for attr in user_attribute_names_list:
316
+ r_i = self.group.random(ZR)
317
+ D_i[attr] = g_r * (self.group.hash(attr, G1) ** r_i)
318
+ D_i_dash[attr] = g ** r_i
319
+
320
+ kek_i = MPK[attr] ** r_i
321
+ KEK[attr] = kek_i
322
+ DSK = {'D': D, 'D_i': D_i, 'D_i_dash': D_i_dash, 'attrs': user_attribute_names_list}
323
+ UMK[user_name] = g_r
324
+
325
+ return DSK, KEK
326
+
327
+ def user_attributes_kek_generation(self, TA_KEK, attributes_manager, user_attribute_names_list, user_name):
328
+ """
329
+ This function is executed by AM and considered as part of key generation procedure.
330
+ Inputs:
331
+ - TA_KEK: Preliminary KEK list generated by TA.
332
+ - attributes_manager: AM.
333
+ - user_attribute_names_list: Attribute names hold by the user.
334
+ - user_name: User name.
335
+ Outputs:
336
+ - KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
337
+ generated by AM.
338
+ """
339
+ KEK = {}
340
+ for attr in user_attribute_names_list:
341
+ KEK_attr = self.generate_kek_for_user_with_attr(TA_KEK, attr, attributes_manager, user_name)
342
+ KEK[attr] = KEK_attr
343
+ return KEK
344
+
345
+ def generate_kek_for_user_with_attr(self, TA_KEK, attr, attributes_manager, user_name):
346
+ """
347
+ This function is executed by AM and considered as part of key generation procedure.
348
+ Inputs:
349
+ - TA_KEK: Preliminary KEK list generated by TA.
350
+ - attributes_manager: AM.
351
+ - user_attribute_names_list: Attribute names hold by the user.
352
+ - user_name: User name.
353
+ Outputs:
354
+ - KEK: Key Encryption Key generated for a specific attribute hold by the user using the users binary tree
355
+ generated by AM.
356
+ """
357
+ list_of_users_hold_attr = attributes_manager.attrs_to_users_dict[attr]
358
+ node_G_i = attributes_manager.get_minimum_nodes_list_that_represent_users_list(list_of_users_hold_attr)
359
+ user_path = attributes_manager.get_user_path(user_name)
360
+ intersection = attributes_manager.get_user_path_intersection_with_node_gi(user_path, node_G_i)
361
+ if len(intersection) == 0:
362
+ # AB: Do nothing, as mentioned in the paper.
363
+ return None
364
+ else:
365
+ assert len(intersection) == 1, "The intersection list should have only one element."
366
+ vj_node: TreeNode = intersection[0]
367
+ kek_i = TA_KEK[attr] # TODO: AB: The attribute has to be added before to any other user in the system setup.
368
+ # Consider fixing it later if this functionality is needed.
369
+ KEK_i = kek_i ** (1 / vj_node.value)
370
+ KEK_attr = {'seq(vj)': vj_node.sequence_number, 'kek_i': kek_i, 'KEK_i': KEK_i}
371
+ return KEK_attr
372
+
373
+
374
+ def encrypt(self, PP, MMK, M, A: str, attributes_manager: AM):
375
+ """
376
+ This function is executed by anyone who wants to encrypt a message with an access policy, then by AM to
377
+ perform the re-encryption.
378
+ Inputs:
379
+ - PP: Public Parameters from the system setup algorithm.
380
+ - MMK: Manager master key represented as a dictionary.
381
+ - M: Message to by encrypted.
382
+ - A: Access policy represented as a boolean expression string.
383
+ Outputs:
384
+ - CT_dash: Ciphertext.
385
+ - Hdr: Header message.
386
+ """
387
+ # Local Encryption
388
+ CT = self.local_encryption(A, M, PP)
389
+ CT, Hdr = self.reencryption(CT, MMK, PP, attributes_manager)
390
+ return CT, Hdr
391
+
392
+ def reencryption(self, CT, MMK, PP, attributes_manager):
393
+ """
394
+ This function is performed by AM and it is the second part of the encryption procedure.
395
+ """
396
+ Hdr = {} # AB: TODO:
397
+ g = PP['g']
398
+ kys_dict = {}
399
+ for attr_name_with_idx in CT['Cy_tilde']:
400
+ # Index is appended only if the attribute is repeated more than one time to the access policy
401
+ k_y = self.group.random(ZR)
402
+ kys_dict[attr_name_with_idx] = k_y
403
+ g_k_y = g ** k_y
404
+ CT['Cy_tilde'][attr_name_with_idx] = CT['Cy_tilde'][attr_name_with_idx] * g_k_y
405
+
406
+ attr_name_without_idx = self.__get_attr_name_without_idx(attr_name_with_idx)
407
+ if not attr_name_without_idx in attributes_manager.attrs_to_users_dict:
408
+ # Attribute manager is not responsible for this attribute
409
+ # AB: TODO: Attention here. You might need to revisit this part.
410
+ continue
411
+ Gi = attributes_manager.attrs_to_users_dict[attr_name_without_idx]
412
+ node_Gi = attributes_manager.get_minimum_nodes_list_that_represent_users_list(Gi)
413
+ if not attr_name_with_idx in Hdr:
414
+ Hdr[attr_name_with_idx] = []
415
+ for a_node_Gi in node_Gi:
416
+ a_node_Gi: TreeNode = a_node_Gi
417
+ E_k_y = g_k_y ** (a_node_Gi.value / MMK[attr_name_without_idx])
418
+ Hdr[attr_name_with_idx].append({'seq': a_node_Gi.sequence_number, 'E(k_y)': E_k_y})
419
+ return CT, Hdr
420
+
421
+ def __get_attr_name_without_idx(self, attr_name: str):
422
+ if attr_name.find('_') == -1:
423
+ return attr_name
424
+ val = attr_name.split('_')
425
+ return val[0]
426
+
427
+ def local_encryption(self, A, M, PP):
428
+ """
429
+ This function is executed by anyone who wants to encrypt a message with an access policy.
430
+ Inputs:
431
+ - A: Access policy represented as a boolean expression string.
432
+ - M: Message to by encrypted.
433
+ - PP: Public Parameters from the system setup algorithm.
434
+ Outputs:
435
+ - CT: Ciphertext.
436
+ """
437
+ s = self.group.random(ZR)
438
+ e_gg_alpha_s = PP['e_gg_alpha'] ** s
439
+ g = PP['g']
440
+ policy = self.util.createPolicy(A)
441
+ a_list = self.util.getAttributeList(policy)
442
+ shares = self.util.calculateSharesDict(s, policy)
443
+ C0 = e_gg_alpha_s * M
444
+ C1 = PP['g_beta'] ** s
445
+ C_y, C_y_pr = {}, {}
446
+ for i in shares.keys():
447
+ j = self.util.strip_index(i)
448
+ C_y[i] = g ** shares[i]
449
+ C_y_pr[i] = self.group.hash(j, G1) ** shares[i]
450
+ CT = {'C0': C0, 'C1': C1, 'Cy': C_y, 'Cy_tilde': C_y_pr, 'A': A, 'attributes': a_list}
451
+ return CT
452
+
453
+ def decrypt(self, PP, CT_tilde, Hdr, DSK, KEK, user_name: str, attributes_manager: AM):
454
+ """
455
+ This function is used by any user who has sufficient, non revoked attributes to decrypted a message under a
456
+ specific access policy.
457
+ Inputs:
458
+ - PP: Public Parameters from the system setup algorithm.
459
+ - CT_tilde: Ciphertext after re-encryption by the AM.
460
+ - Hdr: Header message.
461
+ - DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user).
462
+ - KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
463
+ - user_name: Username who is decrypting the ciphertext.
464
+ - attributes_manager: AM.
465
+ Outputs:
466
+ - M: Recovered message, if the user has the decryption keys of the attributes that satisfy the policy.
467
+ """
468
+ ct = CT_tilde
469
+ policy_str = ct['A']
470
+ policy = self.util.createPolicy(policy_str)
471
+ pruned_list = self.util.prune(policy, DSK['attrs'])
472
+ if not pruned_list:
473
+ return False
474
+ z = self.util.getCoefficients(policy)
475
+ A = 1
476
+ for i in pruned_list:
477
+ j = i.getAttributeAndIndex()
478
+ k = i.getAttribute()
479
+ KEK_i = KEK[k]['KEK_i']
480
+ Hdr_for_attr: list = Hdr[j]
481
+ chosen_Hdr_element = None
482
+ user_path = attributes_manager.get_user_path(user_name)
483
+ for hdr_elem in Hdr_for_attr:
484
+ # If hdr_ele intersect with the user path, then it is the chosen element
485
+ found = False
486
+ for user_node in user_path:
487
+ if user_node.sequence_number == hdr_elem['seq']:
488
+ found = True
489
+ if found:
490
+ chosen_Hdr_element = hdr_elem
491
+ E_k_y = chosen_Hdr_element['E(k_y)']
492
+ A *= ( (pair(ct['Cy'][j], DSK['D_i'][k]) * pair(KEK_i, E_k_y) )/ pair(DSK['D_i_dash'][k], ct['Cy_tilde'][j]) ) ** z[j]
493
+
494
+ return ct['C0'] / (pair(ct['C1'], DSK['D']) / A)
495
+
496
+ def revoke_attribute(self, revoked_user_name, attribute_name, attributes_manager: AM, PP, users_kek_i, MMK, MPK):
497
+ """
498
+ This function is executed by AM when an attribute is revoked from a user.
499
+ Inputs:
500
+ - revoked_user_name: The name of the revoked user.
501
+ - attribute_name: revoked attribute name.
502
+ - attributes_manager: AM.
503
+ - PP: Public Parameters from the system setup algorithm.
504
+ - users_kek_i: A list privately acquired by AM from TA as part of key_generation function.
505
+ Inputs/Outputs:
506
+ - MMK: Manager master key represented as a dictionary.
507
+ - MPK: Manager public key represented as a dictionary.
508
+ Outputs:
509
+ - updated_KEK_dict: The key is the user-name of the user whose KEK key is updated and the value is the
510
+ updated KEK key value.
511
+ """
512
+ attributes_manager.remove_attr_from_user(attribute_name, revoked_user_name)
513
+
514
+ # Key Updating
515
+ g = PP['g']
516
+ t_i = self.group.random(ZR)
517
+ old_t_i = MMK[attribute_name]
518
+ t_i = t_i * old_t_i
519
+ T_i = g ** t_i
520
+ MMK[attribute_name] = t_i
521
+ MPK[attribute_name] = T_i
522
+
523
+ # Get List of the users affects. (The users who hold this attribute)
524
+ affected_users_names = attributes_manager.attrs_to_users_dict[attribute_name]
525
+ updated_KEK_dict = {}
526
+ for a_user_name in affected_users_names:
527
+ users_kek_i[a_user_name][attribute_name] = users_kek_i[a_user_name][attribute_name] ** t_i
528
+ user_attribute_names_list = attributes_manager.users_to_attrs_dict[a_user_name]
529
+ # KEK generation by AM
530
+ new_user_KEK = self.user_attributes_kek_generation(users_kek_i[a_user_name], attributes_manager,
531
+ user_attribute_names_list, a_user_name)
532
+ updated_KEK_dict[a_user_name] = new_user_KEK
533
+ return updated_KEK_dict
534
+
535
+ def add_attribute(self, user_name, attribute_name, attributes_manager: AM, PP, UMK, users_kek_i, MMK, MPK):
536
+ """
537
+ This function is executed by AM when an attribute is added to a user.
538
+ Inputs:
539
+ - user_name: The name of the user who has an attribute to be added.
540
+ - attribute_name: To be added attribute name.
541
+ - attributes_manager: AM.
542
+ - PP: Public Parameters from the system setup algorithm.
543
+ - UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
544
+ user_name is the key and a group element is the value.
545
+ - users_kek_i: A list privately acquired by AM from TA as part of key_generation function.
546
+ Inputs/Outputs:
547
+ - MMK: Manager master key represented as a dictionary.
548
+ - MPK: Manager public key represented as a dictionary.
549
+ Outputs:
550
+ - updated_KEK_dict: The key is the user-name of the user whose KEK key is updated and the value is the
551
+ updated KEK key value.
552
+ """
553
+ # TA updates D_i, D_i_tilde and send it to the user for him to append it to his DSK
554
+ g = PP['g']
555
+ r_i = self.group.random(ZR)
556
+ g_r = UMK[user_name]
557
+ D_i = g_r * self.group.hash(attribute_name, G1) ** r_i
558
+ D_i_tilde = g ** r_i
559
+ kek_i = MPK[attribute_name] ** r_i
560
+ users_kek_i[user_name][attribute_name] = kek_i
561
+
562
+ # AM updates the users tree and returns to each affected user its updated KEK for this attribute.
563
+ attributes_manager.add_attr_to_user(attribute_name, user_name)
564
+ list_of_users_hold_attr = attributes_manager.attrs_to_users_dict[attribute_name]
565
+ node_G_i = attributes_manager.get_minimum_nodes_list_that_represent_users_list(list_of_users_hold_attr)
566
+ KEK_user_names_dict_for_attr = {} # Each user gets an entry from this dict that is associated to him and
567
+ # adds/updates it in his KEK.
568
+ for a_user in list_of_users_hold_attr:
569
+ KEK_attr = self.generate_kek_for_user_with_attr(users_kek_i[a_user], attribute_name, attributes_manager,
570
+ a_user)
571
+ KEK_user_names_dict_for_attr[a_user] = KEK_attr
572
+
573
+ return D_i, D_i_tilde, KEK_user_names_dict_for_attr
574
+
575
+ def main():
576
+ group_obj = PairingGroup('SS512')
577
+
578
+ attributes_manager = AM(group_obj)
579
+ user_names_list = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7', 'U8']
580
+ attributes_manager.add_attr_to_user('ONE', 'U1')
581
+ attributes_manager.add_attr_to_user('FOUR', 'U1')
582
+ attributes_manager.add_attr_to_user('TWO', 'U1')
583
+ attributes_manager.add_attr_to_user('ONE', 'U2')
584
+ attributes_manager.add_attr_to_user('THREE', 'U2')
585
+ attributes_manager.add_attr_to_user('ONE', 'U3')
586
+ attributes_manager.add_attr_to_user('THREE', 'U4')
587
+ attributes_manager.add_attr_to_user('ONE', 'U5')
588
+ attributes_manager.add_attr_to_user('TWO', 'U6')
589
+ attributes_manager.add_attr_to_user('ONE', 'U7')
590
+ attributes_manager.add_attr_to_user('THREE', 'U8')
591
+ print("Users attributes list: ", attributes_manager.users_to_attrs_dict)
592
+
593
+ ca_cpabe_ar = CaCpabeAr(group_obj)
594
+ MK, PP = ca_cpabe_ar.system_setup()
595
+ print("MK: ", MK)
596
+ print("PP: ", PP)
597
+
598
+ attributes_names = ['ONE', 'TWO', 'THREE', 'FOUR']
599
+ MMK, MPK = ca_cpabe_ar.manager_setup(attributes_names, PP)
600
+ print("MMK: ", MMK)
601
+ print("MPK: ", MPK)
602
+
603
+ UMK = {} # A value stored privately by TA for each user.
604
+ users_private_keys_dict = {}
605
+ users_kek_i = {} # Held privately by AM
606
+ for user_name in user_names_list:
607
+ # Attribute key generation. Executed by TA.
608
+ user_attribute_names_list = attributes_manager.users_to_attrs_dict[user_name]
609
+ # KEK generation by AM.
610
+ DSK, KEK = ca_cpabe_ar.key_generation(PP, MK, MPK, user_attribute_names_list, user_name, attributes_manager,
611
+ UMK, users_kek_i)
612
+ users_private_keys_dict[user_name] = {'DSK': DSK, 'KEK': KEK}
613
+ print("KEK for {}: {}".format(user_name, users_private_keys_dict[user_name]))
614
+
615
+ rand_msg = group_obj.random(GT)
616
+ print("Message: ", rand_msg)
617
+ policy_str = '((four or three) and (three or one))'
618
+ CT_tilde, Hdr = ca_cpabe_ar.encrypt(PP, MMK, rand_msg, policy_str, attributes_manager)
619
+ print("CT: ", CT_tilde)
620
+ user_private_keys_dict = users_private_keys_dict['U2']
621
+ DSK = user_private_keys_dict['DSK']
622
+ KEK = user_private_keys_dict['KEK']
623
+ recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U2', attributes_manager)
624
+ print('Recovered Message: ', recovered_M)
625
+ assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
626
+
627
+ # Revoke the attribute `THREE` from user `U2`
628
+ updated_users_kek_values = ca_cpabe_ar.revoke_attribute('U2', 'THREE', attributes_manager, PP, users_kek_i, MMK,
629
+ MPK)
630
+ for a_user_name in updated_users_kek_values: # The updated users KEK keys need to be distributed to the users
631
+ users_private_keys_dict[user_name]['KEK'] = updated_users_kek_values[a_user_name]
632
+
633
+ # Now `U7` does not have the ability to decrypt the message because his attributes ['ONE'] does not match the policy
634
+ user_private_keys_dict = users_private_keys_dict['U7']
635
+ DSK = user_private_keys_dict['DSK']
636
+ KEK = user_private_keys_dict['KEK']
637
+ recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U7', attributes_manager)
638
+ print("Wrong recovered M for U7: ", recovered_M)
639
+ # Uncomment the following line and an error will be raised
640
+ # assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
641
+
642
+ # Add attribute `FOUR` to user `U7`
643
+ attr_to_be_added = 'FOUR'
644
+ D_i, D_i_tilde, KEK_user_names_dict_for_attr = ca_cpabe_ar.add_attribute('U7', attr_to_be_added, attributes_manager,
645
+ PP, UMK, users_kek_i, MMK, MPK)
646
+ user_private_keys_dict = users_private_keys_dict['U7']
647
+ # Update DSK for the user
648
+ DSK = user_private_keys_dict['DSK']
649
+ DSK['D_i'][attr_to_be_added] = D_i
650
+ DSK['D_i_dash'][attr_to_be_added] = D_i_tilde
651
+ DSK['attrs'].append(attr_to_be_added)
652
+ # Each user receives the updated KEK for the attribute 'U7'
653
+ for a_user_name in KEK_user_names_dict_for_attr:
654
+ user_KEK_for_added_attr = KEK_user_names_dict_for_attr[a_user_name] # KEK for attribute 'FOUR' for a specific
655
+ # user.
656
+ user_private_keys_dict = users_private_keys_dict[a_user_name]
657
+ KEK_for_user = user_private_keys_dict['KEK']
658
+ KEK_for_user[attr_to_be_added] = user_KEK_for_added_attr
659
+
660
+ # Encrypt the same message again.
661
+ CT_tilde, Hdr = ca_cpabe_ar.encrypt(PP, MMK, rand_msg, policy_str, attributes_manager)
662
+ print("CT: ", CT_tilde)
663
+ user_private_keys_dict = users_private_keys_dict['U2']
664
+ DSK = user_private_keys_dict['DSK']
665
+ KEK = user_private_keys_dict['KEK']
666
+ # Now `U2` does not have the ability to decrypt the message because his attributes no longer match the policy after
667
+ # one of his attributes was revoked.
668
+ recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U2', attributes_manager)
669
+ print("Wrong recovered M for U2: ", recovered_M)
670
+ # Uncomment the following line and an error will be raised
671
+ # assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
672
+
673
+ # U7 now has the ability to decrypt the message after because his attributes now match the policy [ONE, FOUR]
674
+ user_private_keys_dict = users_private_keys_dict['U7']
675
+ DSK = user_private_keys_dict['DSK']
676
+ KEK = user_private_keys_dict['KEK']
677
+ # `U7` has the ability to decrypt the message because his attributes match the policy after adding attribute FOUR
678
+ recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U7', attributes_manager)
679
+ print("Recovered M for U7: ", recovered_M)
680
+ assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
681
+
682
+
683
+ if __name__ == "__main__":
684
+ main()