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,1986 @@
1
+ /*
2
+ * Charm-Crypto is a framework for rapidly prototyping cryptosystems.
3
+ *
4
+ * Charm-Crypto is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License, or (at your option) any later version.
8
+ *
9
+ * Charm-Crypto is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ * Lesser General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser General Public License
15
+ * along with Charm-Crypto. If not, see <http://www.gnu.org/licenses/>.
16
+ *
17
+ * Please contact the charm-crypto dev team at support@charm-crypto.com
18
+ * for any questions.
19
+ */
20
+
21
+ /*
22
+ * @file ecmodule.c
23
+ *
24
+ * @brief charm interface over OpenSSL Ellipic-curve module
25
+ *
26
+ * @author jakinye3@jhu.edu
27
+ *
28
+ ************************************************************************/
29
+
30
+ #include "ecmodule.h"
31
+
32
+ /*
33
+ * Python 3.13+ made Py_IsFinalizing() public and removed _Py_IsFinalizing().
34
+ * For older versions, we need to use the private _Py_IsFinalizing().
35
+ */
36
+ #if PY_MINOR_VERSION >= 13
37
+ #define CHARM_PY_IS_FINALIZING() Py_IsFinalizing()
38
+ #else
39
+ #define CHARM_PY_IS_FINALIZING() _Py_IsFinalizing()
40
+ #endif
41
+
42
+ void printf_buffer_as_hex(uint8_t * data, size_t len)
43
+ {
44
+ #ifdef DEBUG
45
+ size_t i;
46
+
47
+ for (i = 0; i < len; i++) {
48
+ printf("%02x ", data[i]);
49
+ }
50
+ printf("\n");
51
+ #endif
52
+ }
53
+
54
+ void setBigNum(PyLongObject *obj, BIGNUM **value) {
55
+ // convert Python long object to temporary decimal string
56
+ #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13
57
+ /*
58
+ * For Python 3.13+: _PyLong_Format was removed in Python 3.13.
59
+ * Use PyObject_Str to convert the integer to a string.
60
+ */
61
+ PyObject *strObj = PyObject_Str((PyObject *)obj);
62
+ const char *tmp_str = PyUnicode_AsUTF8(strObj);
63
+ #elif PY_MAJOR_VERSION >= 3
64
+ /*
65
+ * For Python 3.3-3.12: Use _PyLong_Format (private API).
66
+ * Use PyUnicode_AsUTF8 to get a proper null-terminated UTF-8 string.
67
+ */
68
+ PyObject *strObj = _PyLong_Format((PyObject *)obj, 10);
69
+ const char *tmp_str = PyUnicode_AsUTF8(strObj);
70
+ #else
71
+ /* for Python 2.x */
72
+ PyObject *strObj = _PyLong_Format((PyObject *)obj, 10, 0, 0);
73
+ const char *tmp_str = PyString_AS_STRING(strObj);
74
+ #endif
75
+
76
+ // convert decimal string to OpenSSL bignum
77
+ BN_dec2bn(value, tmp_str);
78
+
79
+ // free temporary decimal string
80
+ Py_DECREF(strObj);
81
+ }
82
+
83
+ /*!
84
+ * Hash a null-terminated string to a byte array.
85
+ *
86
+ * @param input_buf The input buffer.
87
+ * @param input_len The input buffer length (in bytes).
88
+ * @param output_buf A pre-allocated output buffer of size hash_len.
89
+ * @param hash_len Length of the output hash (in bytes). Should be approximately bit size of curve group order.
90
+ * @param hash_prefix prefix for hash function.
91
+ */
92
+ int hash_to_bytes(uint8_t *input_buf, int input_len, uint8_t *output_buf, int hash_len, uint8_t hash_prefix)
93
+ {
94
+ EVP_MD_CTX *ctx = NULL;
95
+ int i, new_input_len = input_len + 2; // extra byte for prefix
96
+ uint8_t first_block = 0;
97
+ uint8_t new_input[new_input_len+1];
98
+ unsigned int md_len = 0;
99
+
100
+ memset(new_input, 0, new_input_len+1);
101
+ new_input[0] = first_block; // block number (always 0 by default)
102
+ new_input[1] = hash_prefix; // set hash prefix
103
+ memcpy((uint8_t *)(new_input+2), input_buf, input_len); // copy input bytes
104
+
105
+ debug("new input => \n");
106
+ printf_buffer_as_hex(new_input, new_input_len);
107
+ // prepare output buf
108
+ memset(output_buf, 0, hash_len);
109
+
110
+ ctx = EVP_MD_CTX_new();
111
+ if (ctx == NULL) return FALSE;
112
+
113
+ if (hash_len <= HASH_LEN) {
114
+ uint8_t md[HASH_LEN+1];
115
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
116
+ EVP_DigestUpdate(ctx, new_input, new_input_len);
117
+ EVP_DigestFinal_ex(ctx, md, &md_len);
118
+ memcpy(output_buf, md, hash_len);
119
+ }
120
+ else {
121
+ // apply variable-size hash technique to get desired size
122
+ // determine block count.
123
+ int blocks = (int) ceil(((double) hash_len) / HASH_LEN);
124
+ debug("Num blocks needed: %d\n", blocks);
125
+ uint8_t md[HASH_LEN+1];
126
+ uint8_t md2[(blocks * HASH_LEN)+1];
127
+ uint8_t *target_buf = md2;
128
+ for(i = 0; i < blocks; i++) {
129
+ /* compute digest = SHA-2( i || prefix || input_buf ) || ... || SHA-2( n-1 || prefix || input_buf ) */
130
+ target_buf += (i * HASH_LEN);
131
+ new_input[0] = (uint8_t) i;
132
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
133
+ debug("input %d => ", i);
134
+ printf_buffer_as_hex(new_input, new_input_len);
135
+ EVP_DigestUpdate(ctx, new_input, new_input_len);
136
+ EVP_DigestFinal_ex(ctx, md, &md_len);
137
+ memcpy(target_buf, md, hash_len);
138
+ debug("block %d => ", i);
139
+ printf_buffer_as_hex(md, HASH_LEN);
140
+ memset(md, 0, HASH_LEN);
141
+ }
142
+ // copy back to caller
143
+ memcpy(output_buf, md2, hash_len);
144
+ }
145
+
146
+ EVP_MD_CTX_free(ctx);
147
+ return TRUE;
148
+ }
149
+
150
+
151
+ /*
152
+ * Create a new point with an existing group object
153
+ */
154
+ ECElement *createNewPoint(GroupType type, ECGroup *gobj) {
155
+ if(type != ZR && type != G) return NULL;
156
+ ECElement *newObj = PyObject_New(ECElement, &ECType);
157
+ if(type == ZR) {
158
+ newObj->type = type;
159
+ newObj->elemZ = BN_new();
160
+ newObj->P = NULL;
161
+ }
162
+ else if(type == G) {
163
+ newObj->type = type;
164
+ newObj->P = EC_POINT_new(gobj->ec_group);
165
+ newObj->elemZ = NULL;
166
+ }
167
+ newObj->point_init = TRUE;
168
+ newObj->group = gobj; // gobj->group
169
+ Py_INCREF(newObj->group);
170
+ return newObj;
171
+ }
172
+
173
+ int ECElement_init(ECElement *self, PyObject *args, PyObject *kwds)
174
+ {
175
+ return 0;
176
+ }
177
+
178
+
179
+ void ECElement_dealloc(ECElement* self) {
180
+ /* clear structure */
181
+ if(self->point_init && self->type == G) { debug("clearing ec point.\n"); EC_POINT_free(self->P); }
182
+ if(self->point_init && self->type == ZR) { debug("clearing ec zr element.\n"); BN_free(self->elemZ); }
183
+ Py_XDECREF(self->group);
184
+ Py_TYPE(self)->tp_free((PyObject*)self);
185
+ }
186
+
187
+ PyObject *ECElement_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
188
+ ECElement *self;
189
+
190
+ self = (ECElement *)type->tp_alloc(type, 0);
191
+ if (self != NULL) {
192
+ /* initialize fields here */
193
+ debug("object created...\n");
194
+ self->type = NONE_G;
195
+ self->group = NULL;
196
+ self->P = NULL;
197
+ self->elemZ = NULL;
198
+ self->point_init = FALSE;
199
+ }
200
+ return (PyObject *) self;
201
+ }
202
+
203
+ void ECGroup_dealloc(ECGroup *self)
204
+ {
205
+ if(self->group_init == TRUE && self->ec_group != NULL) {
206
+ // Defensive: Add NULL checks before cleanup to prevent crashes
207
+ // Release GIL during cleanup operations for thread safety
208
+ Py_BEGIN_ALLOW_THREADS;
209
+
210
+ debug("clearing ec group struct.\n");
211
+ if(self->ec_group != NULL) {
212
+ EC_GROUP_clear_free(self->ec_group);
213
+ self->ec_group = NULL;
214
+ }
215
+ if(self->order != NULL) {
216
+ BN_free(self->order);
217
+ self->order = NULL;
218
+ }
219
+ if(self->ctx != NULL) {
220
+ BN_CTX_free(self->ctx);
221
+ self->ctx = NULL;
222
+ }
223
+ self->group_init = FALSE;
224
+
225
+ Py_END_ALLOW_THREADS;
226
+ }
227
+
228
+ #ifdef BENCHMARK_ENABLED
229
+ if(self->dBench != NULL) {
230
+ Py_CLEAR(self->dBench);
231
+ if(self->gBench != NULL) {
232
+ Py_CLEAR(self->gBench);
233
+ }
234
+ }
235
+ #endif
236
+ debug("Releasing ECGroup object!\n");
237
+ Py_TYPE(self)->tp_free((PyObject *) self);
238
+ }
239
+
240
+ PyObject *ECGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
241
+ {
242
+ ECGroup *self = (ECGroup *) type->tp_alloc(type, 0);
243
+ if(self != NULL) {
244
+ self->group_init = FALSE;
245
+ self->nid = -1;
246
+ self->ec_group = NULL;
247
+ self->order = BN_new();
248
+ self->ctx = BN_CTX_new();
249
+ #ifdef BENCHMARK_ENABLED
250
+ memset(self->bench_id, 0, ID_LEN);
251
+ self->dBench = NULL;
252
+ self->gBench = NULL;
253
+ #endif
254
+ }
255
+
256
+ return (PyObject *) self;
257
+ }
258
+
259
+ int ECGroup_init(ECGroup *self, PyObject *args, PyObject *kwds)
260
+ {
261
+ PyObject *pObj = NULL, *aObj = NULL, *bObj = NULL;
262
+ char *params = NULL, *param_string = NULL;
263
+ Py_ssize_t pf_len, ps_len;
264
+ int nid;
265
+ static char *kwlist[] = {"params", "param_string", "p", "a", "b", "nid", NULL};
266
+
267
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s#s#OOOi", kwlist,
268
+ &params, &pf_len, &param_string, &ps_len,
269
+ &pObj, &aObj, &bObj, &nid)) {
270
+ return -1;
271
+ }
272
+
273
+ debug("initializing object...\n");
274
+ if(pObj && aObj && bObj && !params && !param_string && !nid) {
275
+ // p, a, and b curve parameters are set...
276
+ if(!PyLong_Check(pObj) || !PyLong_Check(aObj) || !PyLong_Check(bObj))
277
+ {
278
+ return -1;
279
+ }
280
+
281
+ BIGNUM *p,*a,*b;
282
+ p = BN_new();
283
+ setBigNum((PyLongObject *) pObj, &p);
284
+
285
+ // make sure p is prime then continue loading a and b parameters for EC
286
+ if(BN_is_prime_ex(p, BN_prime_checks, self->ctx, NULL) != 1) {
287
+ debug("p is not prime.\n");
288
+ BN_free(p);
289
+ PyErr_SetString(PyECErrorObject, "p must be a prime integer.");
290
+ return -1;
291
+ }
292
+
293
+ a = BN_new();
294
+ b = BN_new();
295
+ setBigNum((PyLongObject *) aObj, &a);
296
+ setBigNum((PyLongObject *) bObj, &b);
297
+ debug("p (bn) is now '%s'\n", BN_bn2dec(p));
298
+ debug("a (bn) is now '%s'\n", BN_bn2dec(a));
299
+ debug("b (bn) is now '%s'\n", BN_bn2dec(b));
300
+ // now we can instantiate the ec_group
301
+ self->ec_group = EC_GROUP_new_curve_GFp(p, a, b, self->ctx);
302
+ if(!self->ec_group) {
303
+ EC_GROUP_free(self->ec_group);
304
+ PyErr_SetString(PyECErrorObject, "could not initialize ec group.");
305
+ BN_free(p);
306
+ BN_free(a);
307
+ BN_free(b);
308
+ return -1;
309
+ }
310
+ BN_free(p);
311
+ BN_free(a);
312
+ BN_free(b);
313
+ debug("Now, we're finished.\n");
314
+ }
315
+ // check if builtin curve specified.
316
+ else if(nid > 0 && !pObj && !aObj && !bObj && !params && !param_string) {
317
+ debug("nid => %d == %s...\n", nid, OBJ_nid2sn(nid));
318
+ self->ec_group = EC_GROUP_new_by_curve_name(nid);
319
+ if(self->ec_group == NULL) {
320
+ EC_GROUP_free(self->ec_group);
321
+ printf("could not find curve: error code = %s.", OBJ_nid2sn(nid));
322
+ PyErr_SetString(PyECErrorObject, "can't find specified curve.");
323
+ return -1;
324
+ }
325
+ #ifdef DEBUG
326
+ printf("OK!\n");
327
+ #endif
328
+ debug("ec group check...\n");
329
+ if(!EC_GROUP_check(self->ec_group, self->ctx)) {
330
+ EC_GROUP_free(self->ec_group);
331
+ PyErr_SetString(PyECErrorObject, "group check failed, try another curve.");
332
+ return -1;
333
+ }
334
+ self->nid = nid;
335
+ #ifdef DEBUG
336
+ printf("OK!\n");
337
+ #endif
338
+ }
339
+ else {
340
+ PyErr_SetString(PyECErrorObject, "invalid input. try again.");
341
+ return -1;
342
+ }
343
+
344
+ // obtain the order of the elliptic curve and store in group object
345
+ EC_GROUP_get_order(self->ec_group, self->order, self->ctx);
346
+ self->group_init = TRUE;
347
+ return 0;
348
+ }
349
+
350
+ PyObject *ECElement_call(ECElement *intObject, PyObject *args, PyObject *kwds) {
351
+
352
+ return NULL;
353
+ }
354
+
355
+ PyObject *ECGroup_print(ECGroup *self) {
356
+ if(!self->group_init)
357
+ return PyUnicode_FromString("");
358
+ BIGNUM *p = BN_new(), *a = BN_new(), *b = BN_new();
359
+ EC_GROUP_get_curve_GFp(self->ec_group, p, a, b, self->ctx);
360
+
361
+ const char *id;
362
+ if(self->nid == -1) id = "custom";
363
+ else id = OBJ_nid2sn(self->nid);
364
+ char *pstr = BN_bn2dec(p);
365
+ char *astr = BN_bn2dec(a);
366
+ char *bstr = BN_bn2dec(b);
367
+ PyObject *strObj = PyUnicode_FromFormat("Curve '%s' => y^2 = x^3 + a*x + b (mod p):\np = %s\na = %s\nb = %s", id, (const char *) pstr,
368
+ (const char *) astr, (const char *) bstr);
369
+ OPENSSL_free(pstr);
370
+ OPENSSL_free(astr);
371
+ OPENSSL_free(bstr);
372
+ BN_free(p);
373
+ BN_free(a);
374
+ BN_free(b);
375
+ return strObj;
376
+ }
377
+
378
+ PyObject *ECElement_print(ECElement *self) {
379
+ if(self->type == ZR) {
380
+ if(!self->point_init)
381
+ return PyUnicode_FromString("");
382
+ char *Zstr = BN_bn2dec(self->elemZ);
383
+ PyObject *strObj = PyUnicode_FromString((const char *) Zstr);
384
+ OPENSSL_free(Zstr);
385
+ return strObj;
386
+ }
387
+ else if(self->type == G) {
388
+ if(!self->point_init)
389
+ return PyUnicode_FromString("");
390
+ VERIFY_GROUP(self->group);
391
+
392
+ BIGNUM *x = BN_new(), *y = BN_new();
393
+ EC_POINT_get_affine_coordinates_GFp(self->group->ec_group, self->P, x, y, self->group->ctx);
394
+ char *xstr = BN_bn2dec(x);
395
+ char *ystr = BN_bn2dec(y);
396
+ //debug("P -> x = %s\n", xstr);
397
+ //debug("P -> y = %s\n", ystr);
398
+ PyObject *strObj = PyUnicode_FromFormat("[%s, %s]", (const char *)xstr, (const char *)ystr);
399
+ OPENSSL_free(xstr);
400
+ OPENSSL_free(ystr);
401
+ BN_free(x);
402
+ BN_free(y);
403
+ return strObj;
404
+ }
405
+
406
+ return (PyObject *) PyUnicode_FromString("");
407
+ }
408
+
409
+ PyObject *ECE_init(ECElement *self, PyObject *args) {
410
+ GroupType type = NONE_G;
411
+ ECElement *obj;
412
+ ECGroup *gobj = NULL;
413
+ PyObject *long_obj = NULL;
414
+
415
+ if(PyArg_ParseTuple(args, "Oi|O", &gobj, &type, &long_obj)) {
416
+ VERIFY_GROUP(gobj);
417
+
418
+ if(type == G) {
419
+ debug("init element in group G.\n");
420
+ obj = createNewPoint(G, gobj);
421
+ return (PyObject *) obj;
422
+ }
423
+ else if(type == ZR) {
424
+ debug("init element of ZR.\n");
425
+ obj = createNewPoint(ZR, gobj);
426
+ if(long_obj != NULL) {
427
+ if (_PyLong_Check(long_obj)) {
428
+ setBigNum((PyLongObject *) long_obj, &obj->elemZ);
429
+ BN_mod(obj->elemZ, obj->elemZ, gobj->order, gobj->ctx);
430
+ } else {
431
+ EXIT_IF(TRUE, "expecting a number (int or long)");
432
+ }
433
+ }
434
+ return (PyObject *) obj;
435
+ }
436
+ else {
437
+ EXIT_IF(TRUE, "invalid type selected.");
438
+ }
439
+ }
440
+ EXIT_IF(TRUE, "invalid argument.");
441
+ }
442
+
443
+ PyObject *ECE_random(ECElement *self, PyObject *args)
444
+ {
445
+ GroupType type = NONE_G;
446
+ ECGroup *gobj = NULL;
447
+
448
+ if(PyArg_ParseTuple(args, "Oi", &gobj, &type)) {
449
+ VERIFY_GROUP(gobj);
450
+
451
+ if(type == G) {
452
+ // generate a random element from ec group G.
453
+ // call 'EC_POINT_set_compressed_coordinates_GFp' w/ group, P, x, 1, ctx
454
+ // call 'EC_POINT_set_affine_coordinates_GFp' w/ group, P, x/y, ctx
455
+ // test group membership 'EC_POINT_is_on_curve'
456
+ ECElement *objG = createNewPoint(G, gobj);
457
+ BIGNUM *x = BN_new(), *y = BN_new(); // *order = BN_new();
458
+ //EC_GROUP_get_order(gobj->ec_group, order, gobj->ctx);
459
+ int FindAnotherPoint = TRUE;
460
+ //START_CLOCK(dBench);
461
+ do {
462
+ // generate random point
463
+ BN_rand_range(x, gobj->order);
464
+ EC_POINT_set_compressed_coordinates_GFp(gobj->ec_group, objG->P, x, 1, gobj->ctx);
465
+ EC_POINT_get_affine_coordinates_GFp(gobj->ec_group, objG->P, x, y, gobj->ctx);
466
+ // make sure point is on curve and not zero
467
+
468
+ if(BN_is_zero(x) || BN_is_zero(y)) {
469
+ FindAnotherPoint = TRUE;
470
+ continue;
471
+ }
472
+
473
+ if(EC_POINT_is_on_curve(gobj->ec_group, objG->P, gobj->ctx)) {
474
+ FindAnotherPoint = FALSE;
475
+ }
476
+ // char *xstr = BN_bn2dec(x);
477
+ // char *ystr = BN_bn2dec(y);
478
+ // debug("P -> x = %s\n", xstr);
479
+ // debug("P -> y = %s\n", ystr);
480
+ // OPENSSL_free(xstr);
481
+ // OPENSSL_free(ystr);
482
+ } while(FindAnotherPoint);
483
+
484
+ BN_free(x);
485
+ BN_free(y);
486
+ // BN_free(order);
487
+ return (PyObject *) objG;
488
+ }
489
+ else if(type == ZR) {
490
+ ECElement *objZR = createNewPoint(ZR, gobj);
491
+ BN_rand_range(objZR->elemZ, gobj->order);
492
+
493
+ return (PyObject *) objZR;
494
+ }
495
+ else {
496
+
497
+ EXIT_IF(TRUE, "invalid object type.");
498
+ }
499
+ }
500
+
501
+
502
+ EXIT_IF(TRUE, "invalid argument.");
503
+ }
504
+
505
+ static PyObject *ECE_is_infinity(ECElement *self, PyObject *args) {
506
+
507
+ Point_Init(self);
508
+ EXIT_IF(self->type != G, "element not of type G.");
509
+
510
+ if(EC_POINT_is_at_infinity(self->group->ec_group, self->P)) {
511
+ Py_INCREF(Py_True);
512
+ return Py_True;
513
+ }
514
+
515
+ Py_INCREF(Py_False);
516
+ return Py_False;
517
+ }
518
+
519
+ static PyObject *ECE_add(PyObject *o1, PyObject *o2) {
520
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
521
+ int foundLHS = FALSE, foundRHS = FALSE;
522
+
523
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
524
+
525
+ if(foundLHS) {
526
+ debug("found lhs.\n");
527
+ // if rhs == ZR, then convert lhs to a bn otherwise fail.
528
+ if(rhs->point_init && rhs->type == ZR) {
529
+ BIGNUM *lhs_val = BN_new();
530
+ setBigNum((PyLongObject *) o1, &lhs_val);
531
+ ans = createNewPoint(ZR, rhs->group);
532
+ BN_mod_add(ans->elemZ, lhs_val, rhs->elemZ, ans->group->order, ans->group->ctx);
533
+ BN_free(lhs_val);
534
+ #ifdef BENCHMARK_ENABLED
535
+ UPDATE_BENCH(ADDITION, ans->type, ans->group);
536
+ #endif
537
+ return (PyObject *) ans;
538
+ }
539
+ }
540
+ else if(foundRHS) {
541
+ debug("found rhs.\n");
542
+ // if lhs == ZR, then convert rhs to a bn otherwise fail.
543
+ if(lhs->point_init && lhs->type == ZR) {
544
+ BIGNUM *rhs_val = BN_new();
545
+ setBigNum((PyLongObject *) o2, &rhs_val);
546
+ ans = createNewPoint(ZR, lhs->group); // ->group, lhs->ctx);
547
+ BN_mod_add(ans->elemZ, lhs->elemZ, rhs_val, ans->group->order, ans->group->ctx);
548
+ BN_free(rhs_val);
549
+ #ifdef BENCHMARK_ENABLED
550
+ UPDATE_BENCH(ADDITION, ans->type, ans->group);
551
+ #endif
552
+ return (PyObject *) ans;
553
+ }
554
+ }
555
+ else {
556
+ // check whether we have two Points
557
+ Point_Init(lhs);
558
+ Point_Init(rhs);
559
+ if(ElementZR(lhs, rhs)) {
560
+
561
+ IS_SAME_GROUP(lhs, rhs);
562
+ // easy, just call BN_add
563
+ ans = createNewPoint(ZR, lhs->group);
564
+ BN_mod_add(ans->elemZ, lhs->elemZ, rhs->elemZ, ans->group->order, ans->group->ctx);
565
+ #ifdef BENCHMARK_ENABLED
566
+ UPDATE_BENCH(ADDITION, ans->type, ans->group);
567
+ #endif
568
+ return (PyObject *) ans;
569
+ }
570
+ else { // if(lhs->type == G && rhs->type == ZR) or vice versa operation undefined...
571
+
572
+ EXIT_IF(TRUE, "adding the a group element G to ZR is undefined.");
573
+ }
574
+ }
575
+
576
+ EXIT_IF(TRUE, "invalid arguments.");
577
+ }
578
+
579
+ /*
580
+ * Point Subtraction of two points A and B is really
581
+ * A + (-B) where -B is the reflection of that point with
582
+ * respect to the x-axis. i.e. (xb,yb) => (xb,-yb)
583
+ */
584
+ static PyObject *ECE_sub(PyObject *o1, PyObject *o2) {
585
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
586
+ int foundLHS = FALSE, foundRHS = FALSE;
587
+
588
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
589
+
590
+ if(foundLHS) {
591
+ debug("found lhs.\n");
592
+ // if rhs == ZR, then convert lhs to a bn otherwise fail.
593
+ // only supported for elements of Long (lhs) and ZR (rhs)
594
+ if(rhs->point_init && rhs->type == ZR) {
595
+ BIGNUM *lhs_val = BN_new();
596
+ setBigNum((PyLongObject *) o1, &lhs_val);
597
+ ans = createNewPoint(ZR, rhs->group); // ->group, rhs->ctx);
598
+ BN_mod_sub(ans->elemZ, lhs_val, rhs->elemZ, ans->group->order, ans->group->ctx);
599
+ BN_free(lhs_val);
600
+ #ifdef BENCHMARK_ENABLED
601
+ UPDATE_BENCH(SUBTRACTION, ans->type, ans->group);
602
+ #endif
603
+ return (PyObject *) ans;
604
+ }
605
+ }
606
+ else if(foundRHS) {
607
+ debug("found rhs.\n");
608
+ // if lhs == ZR, then convert rhs to a bn otherwise fail.
609
+ // only supported for elements of ZR (lhs) and Long (rhs)
610
+ if(lhs->point_init && lhs->type == ZR) {
611
+ BIGNUM *rhs_val = BN_new();
612
+ setBigNum((PyLongObject *) o2, &rhs_val);
613
+ ans = createNewPoint(ZR, lhs->group);
614
+ BN_mod_sub(ans->elemZ, lhs->elemZ, rhs_val, ans->group->order, ans->group->ctx);
615
+ BN_free(rhs_val);
616
+ #ifdef BENCHMARK_ENABLED
617
+ UPDATE_BENCH(SUBTRACTION, ans->type, ans->group);
618
+ #endif
619
+ return (PyObject *) ans;
620
+ }
621
+ }
622
+ else {
623
+ // check whether we have two Points
624
+ Point_Init(lhs);
625
+ Point_Init(rhs);
626
+
627
+ if(ElementZR(lhs, rhs)) {
628
+ IS_SAME_GROUP(lhs, rhs);
629
+ ans = createNewPoint(ZR, lhs->group);
630
+ BN_mod_sub(ans->elemZ, lhs->elemZ, rhs->elemZ, ans->group->order, ans->group->ctx);
631
+ #ifdef BENCHMARK_ENABLED
632
+ UPDATE_BENCH(SUBTRACTION, ans->type, ans->group);
633
+ #endif
634
+ return (PyObject *) ans;
635
+ }
636
+ else {
637
+ // not defined for other combinations
638
+ EXIT_IF(TRUE, "invalid combination of operands.");
639
+ }
640
+ }
641
+
642
+
643
+ EXIT_IF(TRUE, "invalid arguments.");
644
+ }
645
+
646
+ static PyObject *ECE_mul(PyObject *o1, PyObject *o2) {
647
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
648
+ int foundLHS = FALSE, foundRHS = FALSE;
649
+
650
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
651
+
652
+ if(foundLHS) {
653
+ debug("found lhs.\n");
654
+ // if rhs == ZR, then convert lhs to a bn otherwise fail.
655
+ // only supported for elements of Long (lhs) and ZR (rhs)
656
+ if(rhs->point_init && rhs->type == ZR) {
657
+ BIGNUM *lhs_val = BN_new();
658
+ setBigNum((PyLongObject *) o1, &lhs_val);
659
+ ans = createNewPoint(ZR, rhs->group);
660
+ BN_mod_mul(ans->elemZ, lhs_val, rhs->elemZ, ans->group->order, ans->group->ctx);
661
+ BN_free(lhs_val);
662
+ #ifdef BENCHMARK_ENABLED
663
+ UPDATE_BENCH(MULTIPLICATION, ans->type, ans->group);
664
+ #endif
665
+ return (PyObject *) ans;
666
+ }
667
+ }
668
+ else if(foundRHS) {
669
+ debug("found rhs.\n");
670
+ // if lhs == ZR, then convert rhs to a bn otherwise fail.
671
+ // only supported for elements of ZR (lhs) and Long (rhs)
672
+ if(lhs->point_init && lhs->type == ZR) {
673
+ BIGNUM *rhs_val = BN_new();
674
+ setBigNum((PyLongObject *) o2, &rhs_val);
675
+ ans = createNewPoint(ZR, lhs->group); // ->group, lhs->ctx);
676
+ BN_mod_mul(ans->elemZ, lhs->elemZ, rhs_val, ans->group->order, ans->group->ctx);
677
+ BN_free(rhs_val);
678
+ #ifdef BENCHMARK_ENABLED
679
+ UPDATE_BENCH(MULTIPLICATION, ans->type, ans->group);
680
+ #endif
681
+ return (PyObject *) ans;
682
+ }
683
+ }
684
+ else {
685
+ // check whether we have two Points
686
+ Point_Init(lhs);
687
+ Point_Init(rhs);
688
+ IS_SAME_GROUP(lhs, rhs);
689
+
690
+ if(ElementG(lhs, rhs)) {
691
+ ans = createNewPoint(G, lhs->group);
692
+ EC_POINT_add(ans->group->ec_group, ans->P, lhs->P, rhs->P, ans->group->ctx);
693
+ }
694
+ else if(ElementZR(lhs, rhs)) {
695
+ ans = createNewPoint(ZR, lhs->group);
696
+ BN_mod_mul(ans->elemZ, lhs->elemZ, rhs->elemZ, ans->group->order, ans->group->ctx);
697
+ }
698
+ else {
699
+
700
+ EXIT_IF(TRUE, "elements are not of the same type.");
701
+ }
702
+ #ifdef BENCHMARK_ENABLED
703
+ UPDATE_BENCH(MULTIPLICATION, ans->type, ans->group);
704
+ #endif
705
+ return (PyObject *) ans;
706
+ }
707
+
708
+
709
+ ErrorMsg("invalid argument.");
710
+ }
711
+
712
+ static PyObject *ECE_div(PyObject *o1, PyObject *o2) {
713
+ ;
714
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
715
+ BIGNUM *rm = NULL;
716
+ int foundLHS = FALSE, foundRHS = FALSE;
717
+
718
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
719
+
720
+ if(foundLHS) {
721
+ debug("found lhs.\n");
722
+ // if rhs == ZR, then convert lhs to a bn otherwise fail.
723
+ // only supported for elements of Long (lhs) and ZR (rhs)
724
+ if(rhs->point_init && rhs->type == ZR) {
725
+ BIGNUM *lhs_val = BN_new();
726
+ rm = BN_new();
727
+ setBigNum((PyLongObject *) o1, &lhs_val);
728
+ ans = createNewPoint(ZR, rhs->group);
729
+ BN_div(ans->elemZ, rm, lhs_val, rhs->elemZ, ans->group->ctx);
730
+ BN_free(lhs_val);
731
+ BN_free(rm);
732
+ #ifdef BENCHMARK_ENABLED
733
+ UPDATE_BENCH(DIVISION, ans->type, ans->group);
734
+ #endif
735
+ return (PyObject *) ans;
736
+ }
737
+ }
738
+ else if(foundRHS) {
739
+ debug("found rhs.\n");
740
+ // if lhs == ZR, then convert rhs to a bn otherwise fail.
741
+ // only supported for elements of ZR (lhs) and Long (rhs)
742
+ if(lhs->point_init && lhs->type == ZR) {
743
+ BIGNUM *rhs_val = BN_new();
744
+ rm = BN_new();
745
+ setBigNum((PyLongObject *) o2, &rhs_val);
746
+ ans = createNewPoint(ZR, lhs->group); // ->group, lhs->ctx);
747
+ BN_div(ans->elemZ, rm, lhs->elemZ, rhs_val, ans->group->ctx);
748
+ BN_free(rhs_val);
749
+ BN_free(rm);
750
+ #ifdef BENCHMARK_ENABLED
751
+ UPDATE_BENCH(DIVISION, ans->type, ans->group);
752
+ #endif
753
+ return (PyObject *) ans;
754
+ }
755
+ }
756
+ else {
757
+ // check whether we have two Points
758
+ Point_Init(lhs);
759
+ Point_Init(rhs);
760
+ IS_SAME_GROUP(lhs, rhs);
761
+
762
+ if(ElementG(lhs, rhs)) {
763
+ ECElement *rhs_neg = negatePoint(rhs);
764
+ if(rhs_neg != NULL) {
765
+ ans = createNewPoint(G, lhs->group);
766
+ EC_POINT_add(ans->group->ec_group, ans->P, lhs->P, rhs_neg->P, ans->group->ctx);
767
+ }
768
+ Py_DECREF(rhs_neg);
769
+ }
770
+ else if(ElementZR(lhs, rhs)) {
771
+ ans = createNewPoint(ZR, lhs->group);
772
+ rm = BN_new();
773
+ BN_div(ans->elemZ, rm, lhs->elemZ, rhs->elemZ, ans->group->ctx);
774
+ BN_free(rm);
775
+ }
776
+ else {
777
+
778
+ EXIT_IF(TRUE, "elements not the same type.");
779
+ }
780
+ #ifdef BENCHMARK_ENABLED
781
+ UPDATE_BENCH(DIVISION, ans->type, ans->group);
782
+ #endif
783
+ return (PyObject *) ans;
784
+ }
785
+
786
+ EXIT_IF(TRUE, "invalid argument.");
787
+ }
788
+
789
+ static PyObject *ECE_rem(PyObject *o1, PyObject *o2) {
790
+ ;
791
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
792
+ int foundLHS = FALSE, foundRHS = FALSE;
793
+
794
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
795
+
796
+ if(foundLHS) {
797
+ debug("found lhs.\n");
798
+ // if rhs == ZR, then convert lhs to a bn otherwise fail.
799
+ // only supported for elements of Long (lhs) and ZR (rhs)
800
+ if(rhs->point_init && rhs->type == ZR) {
801
+ BIGNUM *lhs_val = BN_new();
802
+ setBigNum((PyLongObject *) o1, &lhs_val);
803
+ ans = createNewPoint(ZR, rhs->group);
804
+ BN_mod(ans->elemZ, lhs_val, rhs->elemZ, ans->group->ctx);
805
+ BN_free(lhs_val);
806
+
807
+ return (PyObject *) ans;
808
+ }
809
+ }
810
+ else if(foundRHS) {
811
+ debug("found rhs.\n");
812
+ // if lhs == ZR, then convert rhs to a bn otherwise fail.
813
+ // only supported for elements of ZR (lhs) and Long (rhs)
814
+ if(lhs->point_init && lhs->type == ZR) {
815
+ BIGNUM *rhs_val = BN_new();
816
+ setBigNum((PyLongObject *) o2, &rhs_val);
817
+ ans = createNewPoint(ZR, lhs->group);
818
+ BN_mod(ans->elemZ, lhs->elemZ, rhs_val, ans->group->ctx);
819
+ BN_free(rhs_val);
820
+ return (PyObject *) ans;
821
+ }
822
+ }
823
+ else {
824
+ Point_Init(lhs);
825
+ Point_Init(rhs);
826
+
827
+ if(ElementZR(lhs, rhs)) {
828
+ ans = createNewPoint(ZR, lhs->group);
829
+ // reall calls BN_div with the dv se to NULL.
830
+ BN_mod(ans->elemZ, lhs->elemZ, rhs->elemZ, ans->group->ctx);
831
+ return (PyObject *) ans;
832
+ }
833
+ else {
834
+
835
+ EXIT_IF(TRUE, "invalid combination of element types");
836
+ }
837
+ }
838
+
839
+
840
+ EXIT_IF(TRUE, "invalid argument type.");
841
+ }
842
+
843
+ static PyObject *ECE_pow(PyObject *o1, PyObject *o2, PyObject *o3) {
844
+ ECElement *lhs = NULL, *rhs = NULL, *ans = NULL;
845
+ int foundLHS = FALSE, foundRHS = FALSE;
846
+
847
+ Check_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
848
+
849
+ if(foundLHS) {
850
+ // TODO: implement for elements of Long ** ZR
851
+ if(rhs->point_init && rhs->type == ZR) {
852
+ BIGNUM *lhs_val = BN_new();
853
+ setBigNum((PyLongObject *) o1, &lhs_val);
854
+ ans = createNewPoint(ZR, rhs->group);
855
+ BN_mod_exp(ans->elemZ, lhs_val, rhs->elemZ, ans->group->order, ans->group->ctx);
856
+ BN_free(lhs_val);
857
+ #ifdef BENCHMARK_ENABLED
858
+ UPDATE_BENCH(EXPONENTIATION, ans->type, ans->group);
859
+ #endif
860
+ return (PyObject *) ans;
861
+ }
862
+ EXIT_IF(TRUE, "element type combination not supported.");
863
+ }
864
+ else if(foundRHS) {
865
+ // TODO: implement for elements of G ** Long or ZR ** Long
866
+ long rhs = PyLong_AsLong(o2);
867
+ if(lhs->type == ZR) {
868
+ if(PyErr_Occurred() || rhs >= 0) {
869
+ // clear error and continue
870
+ // PyErr_Print(); // for debug purposes
871
+ PyErr_Clear();
872
+ BIGNUM *rhs_val = BN_new();
873
+ setBigNum((PyLongObject *) o2, &rhs_val);
874
+
875
+ ans = createNewPoint(ZR, lhs->group);
876
+ BN_mod_exp(ans->elemZ, lhs->elemZ, rhs_val, ans->group->order, ans->group->ctx);
877
+ BN_free(rhs_val);
878
+ }
879
+ else if(rhs == -1) {
880
+ debug("finding modular inverse.\n");
881
+ ans = invertECElement(lhs);
882
+ }
883
+ else {
884
+ EXIT_IF(TRUE, "unsupported operation.");
885
+ }
886
+ }
887
+ else if(lhs->type == G) {
888
+ if(PyErr_Occurred() || rhs >= 0) {
889
+ // clear error and continue
890
+ // PyErr_Print(); // for debug purposes
891
+ PyErr_Clear();
892
+ BIGNUM *rhs_val = BN_new();
893
+ setBigNum((PyLongObject *) o2, &rhs_val);
894
+ ans = createNewPoint(G, lhs->group); // ->group, lhs->ctx);
895
+ EC_POINT_mul(ans->group->ec_group, ans->P, NULL, lhs->P, rhs_val, ans->group->ctx);
896
+ BN_free(rhs_val);
897
+ }
898
+ else if(rhs == -1) {
899
+ debug("finding modular inverse.\n");
900
+ ans = invertECElement(lhs);
901
+ }
902
+ else {
903
+ EXIT_IF(TRUE, "unsupported operation.");
904
+ }
905
+ }
906
+ else {
907
+ EXIT_IF(TRUE, "element type combination not supported.");
908
+ }
909
+ #ifdef BENCHMARK_ENABLED
910
+ UPDATE_BENCH(EXPONENTIATION, ans->type, ans->group);
911
+ #endif
912
+ return (PyObject *) ans;
913
+ }
914
+ else {
915
+ // check whether we have two Points
916
+ Point_Init(lhs);
917
+ Point_Init(rhs);
918
+ IS_SAME_GROUP(lhs, rhs);
919
+
920
+ if(lhs->type == G && rhs->type == ZR) {
921
+ ans = createNewPoint(G, lhs->group);
922
+ EC_POINT_mul(ans->group->ec_group, ans->P, NULL, lhs->P, rhs->elemZ, ans->group->ctx);
923
+ }
924
+ else if(ElementZR(lhs, rhs)) {
925
+ ans = createNewPoint(ZR, lhs->group);
926
+ BN_mod_exp(ans->elemZ, lhs->elemZ, rhs->elemZ, ans->group->order, ans->group->ctx);
927
+ }
928
+ else {
929
+
930
+ EXIT_IF(TRUE, "cannot exponentiate two points.");
931
+ }
932
+ #if BENCHMARK_ENABLED
933
+ UPDATE_BENCH(EXPONENTIATION, ans->type, ans->group);
934
+ #endif
935
+ return (PyObject *) ans;
936
+ }
937
+
938
+ EXIT_IF(TRUE, "invalid arguments.");
939
+ }
940
+
941
+ /* assume 'self' is a valid ECElement instance */
942
+ ECElement *invertECElement(ECElement *self) {
943
+ ECElement *newObj = NULL;
944
+ if(self->type == G) {
945
+ newObj = createNewPoint(G, self->group); // ->group, self->ctx);
946
+ EC_POINT_copy(newObj->P, self->P);
947
+ if(EC_POINT_invert(newObj->group->ec_group, newObj->P, newObj->group->ctx)) {
948
+ return newObj;
949
+ }
950
+ Py_XDECREF(newObj);
951
+ }
952
+ else if(self->type == ZR) {
953
+ // get modulus and compute mod_inverse
954
+ BIGNUM *x = BN_mod_inverse(NULL, self->elemZ, self->group->order, self->group->ctx);
955
+ if(x != NULL) {
956
+ newObj = createNewPoint(ZR, self->group);
957
+ BN_copy(newObj->elemZ, x);
958
+ BN_free(x);
959
+ return newObj;
960
+ }
961
+ Py_XDECREF(newObj);
962
+ }
963
+ /* error */
964
+ return NULL;
965
+ }
966
+
967
+ static PyObject *ECE_invert(PyObject *o1) {
968
+
969
+ if(PyEC_Check(o1)) {
970
+ ECElement *obj1 = (ECElement *) o1;
971
+ Point_Init(obj1);
972
+
973
+ ECElement *obj2 = invertECElement(obj1);
974
+
975
+ if(obj2 != NULL) {
976
+
977
+ return (PyObject *) obj2;
978
+ }
979
+
980
+ EXIT_IF(TRUE, "could not find inverse of element.");
981
+ }
982
+
983
+ EXIT_IF(TRUE, "invalid argument type.");
984
+ }
985
+
986
+ /* assume 'self' is a valid ECElement instance */
987
+ ECElement *negatePoint(ECElement *self) {
988
+ ECElement *newObj = NULL;
989
+
990
+ BIGNUM *x = BN_new(), *y = BN_new();
991
+ EC_POINT_get_affine_coordinates_GFp(self->group->ec_group, self->P, x, y, self->group->ctx);
992
+ BN_set_negative(y, TRUE);
993
+
994
+ newObj = createNewPoint(G, self->group);
995
+ EC_POINT_set_affine_coordinates_GFp(newObj->group->ec_group, newObj->P, x, y, newObj->group->ctx);
996
+ BN_free(x);
997
+ BN_free(y);
998
+ if(EC_POINT_is_on_curve(newObj->group->ec_group, newObj->P, newObj->group->ctx)) {
999
+ return newObj;
1000
+ }
1001
+ /* error */
1002
+ Py_DECREF(newObj);
1003
+ return NULL;
1004
+ }
1005
+
1006
+ static PyObject *ECE_neg(PyObject *o1) {
1007
+ ECElement *obj1 = NULL, *obj2 = NULL;
1008
+
1009
+ if(PyEC_Check(o1)) {
1010
+ obj1 = (ECElement *) o1;
1011
+ Point_Init(obj1);
1012
+
1013
+ if(obj1->type == G) {
1014
+ if((obj2 = negatePoint(obj1)) != NULL) {
1015
+ return (PyObject *) obj2;
1016
+ }
1017
+ }
1018
+ else if(obj1->type == ZR) {
1019
+ // consider supporting this type.
1020
+ obj2 = createNewPoint(ZR, obj1->group);
1021
+ if(BN_copy(obj2->elemZ, obj1->elemZ) != NULL) {
1022
+ int negate;
1023
+ if(!BN_is_negative(obj2->elemZ)) negate = -1;
1024
+ else negate = 0;
1025
+ BN_set_negative(obj2->elemZ, negate);
1026
+
1027
+ return (PyObject *) obj2;
1028
+ }
1029
+ Py_XDECREF(obj2);
1030
+ }
1031
+
1032
+ }
1033
+
1034
+
1035
+ EXIT_IF(TRUE, "invalid argument.");
1036
+ }
1037
+
1038
+ static PyObject *ECE_long(PyObject *o1) {
1039
+ ECElement *obj1 = NULL;
1040
+ if(PyEC_Check(o1)) {
1041
+ obj1 = (ECElement *) o1;
1042
+ if(obj1->type == ZR) {
1043
+ /* borrowed from mixminion 0.0.7.1 */
1044
+ // now convert to python integer
1045
+ char *hex = BN_bn2hex(obj1->elemZ);
1046
+ PyObject *output = PyLong_FromString(hex, NULL, BASE_HEX);
1047
+ OPENSSL_free(hex);
1048
+ return output; /* pass along errors */
1049
+ }
1050
+ }
1051
+ EXIT_IF(TRUE, "cannot convert this type of object to an integer.");
1052
+ }
1053
+
1054
+ static PyObject *ECE_convertToZR(ECElement *self, PyObject *args) {
1055
+ ECElement *obj = NULL;
1056
+ ECGroup *gobj = NULL;
1057
+ PyObject *retXY = NULL;
1058
+
1059
+ /* gobj - initialized ec group object */
1060
+ /* obj - ecc point object on an elliptic curve */
1061
+ /* retXY => whether to return just x (Py_True) or x and y (Py_False) */
1062
+ if(PyArg_ParseTuple(args, "OOO", &gobj, &obj, &retXY)) {
1063
+ VERIFY_GROUP(gobj);
1064
+
1065
+ if(PyEC_Check(obj)) {
1066
+ // convert to
1067
+ Point_Init(obj);
1068
+ if(obj->type == G) {
1069
+ BIGNUM *x = BN_new(), *y = BN_new();
1070
+ EC_POINT_get_affine_coordinates_GFp(gobj->ec_group, obj->P, x, y, gobj->ctx);
1071
+ if(PyBool_Check(retXY)) {
1072
+ // see if retXY is Py_True or Py_False
1073
+ if(retXY == Py_True) {
1074
+ debug("Py_True detected.\n");
1075
+ ECElement *X = createNewPoint(ZR, gobj);
1076
+ ECElement *Y = createNewPoint(ZR, gobj);
1077
+ BN_copy(X->elemZ, x);
1078
+ BN_copy(Y->elemZ, y);
1079
+ BN_free(x); BN_free(y);
1080
+ return (PyObject *) PyTuple_Pack(2, (PyObject *) X, (PyObject *) Y);
1081
+ }
1082
+ else {
1083
+ BN_free(y);
1084
+ ECElement *newObj = createNewPoint(ZR, gobj);
1085
+ BN_copy(newObj->elemZ, x);
1086
+ BN_free(x);
1087
+ return (PyObject *) newObj;
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ EXIT_IF(TRUE, "invalid type.");
1094
+ }
1095
+ EXIT_IF(TRUE, "invalid argument.");
1096
+ }
1097
+
1098
+ static PyObject *ECE_getOrder(ECElement *self, PyObject *arg) {
1099
+ if(PyECGroup_Check(arg)) {
1100
+ ECGroup *gobj = (ECGroup*) arg;
1101
+ VERIFY_GROUP(gobj);
1102
+
1103
+ ECElement *order = createNewPoint(ZR, gobj);
1104
+ BN_copy(order->elemZ, gobj->order);
1105
+ // return the order of the group
1106
+ return (PyObject *) order;
1107
+ }
1108
+ EXIT_IF(TRUE, "invalid argument.");
1109
+ }
1110
+
1111
+ static PyObject *ECE_bitsize(ECElement *self, PyObject *arg) {
1112
+ if(PyECGroup_Check(arg)) {
1113
+ ECGroup *gobj = (ECGroup *) arg;
1114
+ VERIFY_GROUP(gobj);
1115
+
1116
+ size_t max_len = BN_num_bytes(gobj->order) - RESERVED_ENCODING_BYTES;
1117
+ debug("order len in bytes => '%zd'\n", max_len);
1118
+
1119
+ // maximum bitsize for messages encoded for the selected group
1120
+ return Py_BuildValue("i", max_len);
1121
+ }
1122
+ EXIT_IF(TRUE, "invalid argument.");
1123
+ }
1124
+
1125
+
1126
+ static PyObject *ECE_equals(PyObject *o1, PyObject *o2, int opid) {
1127
+ EXIT_IF(opid != Py_EQ && opid != Py_NE, "'==' and '!=' only comparisons supported.");
1128
+
1129
+ int foundLongLHS = FALSE, foundLongRHS = FALSE, result = FALSE;
1130
+ ECElement *lhs = NULL, *rhs = NULL;
1131
+ Check_Types2(o1, o2, lhs, rhs, foundLongLHS, foundLongRHS);
1132
+
1133
+ if(foundLongLHS) {
1134
+ if(rhs->type == ZR) {
1135
+ BIGNUM *lhs_val = BN_new();
1136
+ BN_set_word(lhs_val, PyLong_ToUnsignedLong(o1));
1137
+ if(BN_cmp(lhs_val, rhs->elemZ) == 0) {
1138
+ if(opid == Py_EQ) result = TRUE;
1139
+ }
1140
+ else if(opid == Py_NE) result = TRUE;
1141
+ BN_free(lhs_val);
1142
+ }
1143
+ else {
1144
+ EXIT_IF(TRUE, "comparison types not supported."); }
1145
+ }
1146
+ else if(foundLongRHS) {
1147
+ if(lhs->type == ZR) {
1148
+ BIGNUM *rhs_val = BN_new();
1149
+ BN_set_word(rhs_val, PyLong_ToUnsignedLong(o2));
1150
+ if(BN_cmp(lhs->elemZ, rhs_val) == 0) {
1151
+ if(opid == Py_EQ) result = TRUE;
1152
+ }
1153
+ else if(opid == Py_NE) result = TRUE;
1154
+ BN_free(rhs_val);
1155
+ }
1156
+ else {
1157
+
1158
+ EXIT_IF(TRUE, "comparison types not supported."); }
1159
+ }
1160
+ else {
1161
+ // Point_Init(lhs)
1162
+ // Point_Init(rhs)
1163
+
1164
+ if(ElementG(lhs, rhs)) {
1165
+ if(EC_POINT_cmp(lhs->group->ec_group, lhs->P, rhs->P, lhs->group->ctx) == 0) {
1166
+ if(opid == Py_EQ) result = TRUE;
1167
+ }
1168
+ else if(opid == Py_NE) result = TRUE;
1169
+ }
1170
+ else if(ElementZR(lhs, rhs)) {
1171
+ if(BN_cmp(lhs->elemZ, rhs->elemZ) == 0) {
1172
+ if(opid == Py_EQ) result = TRUE;
1173
+ }
1174
+ else if(opid == Py_NE) result = TRUE;
1175
+ }
1176
+ else {
1177
+
1178
+ EXIT_IF(TRUE, "cannot compare point to an integer.\n"); }
1179
+ }
1180
+
1181
+ /* return the result here */
1182
+ if(result) {
1183
+ Py_INCREF(Py_True);
1184
+ return Py_True;
1185
+ }
1186
+
1187
+ Py_INCREF(Py_False);
1188
+ return Py_False;
1189
+ }
1190
+
1191
+ static PyObject *ECE_getGen(ECElement *self, PyObject *arg) {
1192
+ if(PyECGroup_Check(arg)) {
1193
+ ECGroup *gobj = (ECGroup *) arg;
1194
+ VERIFY_GROUP(gobj);
1195
+
1196
+ ECElement *genObj = createNewPoint(G, gobj);
1197
+ const EC_POINT *gen = EC_GROUP_get0_generator(gobj->ec_group);
1198
+ EC_POINT_copy(genObj->P, gen);
1199
+
1200
+ return (PyObject *) genObj;
1201
+ }
1202
+ EXIT_IF(TRUE, "invalid argument.");
1203
+ }
1204
+
1205
+ /*
1206
+ * Takes an arbitrary string and returns a group element
1207
+ */
1208
+ void set_element_from_hash(ECElement *self, uint8_t *input, int input_len)
1209
+ {
1210
+ if (self->type != G) {
1211
+ PyErr_SetString(PyECErrorObject, "element not of type G.");
1212
+ }
1213
+
1214
+ BIGNUM *x = BN_new(), *y = BN_new();
1215
+ int TryNextX = TRUE;
1216
+ BN_CTX *ctx = BN_CTX_new();
1217
+ ECGroup *gobj = self->group;
1218
+ // assume input string is a binary string, then set x to (x mod q)
1219
+ BN_bin2bn((const uint8_t *) input, input_len, x);
1220
+ BN_mod(x, x, gobj->order, ctx);
1221
+ do {
1222
+ // set x coordinate and then test whether it's on curve
1223
+ #ifdef DEBUG
1224
+ char *xstr = BN_bn2dec(x);
1225
+ debug("Generating another x => %s\n", xstr);
1226
+ OPENSSL_free(xstr);
1227
+ #endif
1228
+ EC_POINT_set_compressed_coordinates_GFp(gobj->ec_group, self->P, x, 1, ctx);
1229
+ EC_POINT_get_affine_coordinates_GFp(gobj->ec_group, self->P, x, y, ctx);
1230
+
1231
+ if(BN_is_zero(x) || BN_is_zero(y)) {
1232
+ BN_add(x, x, BN_value_one());
1233
+ continue;
1234
+ }
1235
+
1236
+ if(EC_POINT_is_on_curve(gobj->ec_group, self->P, ctx)) {
1237
+ TryNextX = FALSE;
1238
+ }
1239
+ else {
1240
+ BN_add(x, x, BN_value_one());
1241
+ }
1242
+ }while(TryNextX);
1243
+
1244
+ BN_free(x);
1245
+ BN_free(y);
1246
+ BN_CTX_free(ctx);
1247
+ }
1248
+
1249
+ static PyObject *ECE_hash(ECElement *self, PyObject *args) {
1250
+
1251
+ char *msg = NULL;
1252
+ Py_ssize_t msg_len;
1253
+ GroupType type;
1254
+ ECElement *hashObj = NULL;
1255
+ ECGroup *gobj = NULL;
1256
+
1257
+ if(PyArg_ParseTuple(args, "Os#i", &gobj, &msg, &msg_len, &type)) {
1258
+ VERIFY_GROUP(gobj);
1259
+ // compute bit size of group
1260
+ int hash_len = BN_num_bytes(gobj->order);
1261
+ debug("hash_len => %d\n", hash_len);
1262
+ uint8_t hash_buf[hash_len+1];
1263
+ if(type == G) {
1264
+ // hash input bytes
1265
+ hash_to_bytes((uint8_t *) msg, (int) msg_len, hash_buf, hash_len, HASH_FUNCTION_STR_TO_G_CRH);
1266
+ debug("Message => '%s'\n", msg);
1267
+ debug("Digest => ");
1268
+ printf_buffer_as_hex(hash_buf, hash_len);
1269
+ // generate an EC element from message digest
1270
+ hashObj = createNewPoint(G, gobj);
1271
+ set_element_from_hash(hashObj, (uint8_t *) hash_buf, hash_len);
1272
+ return (PyObject *) hashObj;
1273
+ }
1274
+ else if(type == ZR) {
1275
+ hash_to_bytes((uint8_t *) msg, (int) msg_len, hash_buf, hash_len, HASH_FUNCTION_STR_TO_ZR_CRH);
1276
+ debug("Message => '%s'\n", msg);
1277
+ debug("Digest => ");
1278
+ printf_buffer_as_hex(hash_buf, hash_len);
1279
+
1280
+ hashObj = createNewPoint(ZR, gobj);
1281
+ BN_bin2bn((const uint8_t *) hash_buf, hash_len, hashObj->elemZ);
1282
+ return (PyObject *) hashObj;
1283
+ }
1284
+ else {
1285
+
1286
+ EXIT_IF(TRUE, "invalid argument type");
1287
+ }
1288
+ }
1289
+
1290
+
1291
+ EXIT_IF(TRUE, "invalid arguments");
1292
+ }
1293
+
1294
+ /*
1295
+ * Encode a message as a group element
1296
+ */
1297
+ static PyObject *ECE_encode(ECElement *self, PyObject *args) {
1298
+ PyObject *old_m;
1299
+ uint8_t *old_msg;
1300
+ int include_ctr = FALSE;
1301
+ uint32_t msg_len, ctr = 1, ERROR_SET = FALSE; // always have a ctr start from 1
1302
+ BIGNUM *x = NULL, *y = NULL;
1303
+ ECGroup *gobj = NULL;
1304
+
1305
+ if(PyArg_ParseTuple(args, "OO|i", &gobj, &old_m, &include_ctr)) {
1306
+ VERIFY_GROUP(gobj);
1307
+
1308
+ if(PyBytes_Check(old_m)) {
1309
+ old_msg = (uint8_t *) PyBytes_AS_STRING(old_m);
1310
+ msg_len = PyBytes_Size(old_m);
1311
+ debug("Encoding hex msg => ");
1312
+ // check if msg len is big enough to fit into length
1313
+ printf_buffer_as_hex((uint8_t *) old_msg, msg_len);
1314
+ debug("len => '%d'\n", msg_len);
1315
+ }
1316
+ else {
1317
+ /* return error */
1318
+ EXIT_IF(TRUE, "message not a bytes object");
1319
+ }
1320
+
1321
+ // make sure msg will fit into group (get order num bits / 8)
1322
+ int max_len = BN_num_bytes(gobj->order); // (BN_num_bits(gobj->order) / BYTE);
1323
+ debug("max msg len => '%d'\n", max_len);
1324
+
1325
+ debug("msg_len accepted => '%d'\n", msg_len);
1326
+ int len = msg_len;
1327
+ if (include_ctr == FALSE) {
1328
+ len += RESERVED_ENCODING_BYTES;
1329
+ }
1330
+
1331
+ // use default of 32-bits (4 bytes) to represent ctr
1332
+ // concatenate 'ctr' to buffer and set x coordinate and test for y coordiate on curve
1333
+ // if point not on curve, increment ctr by 1
1334
+ if(len == max_len) {
1335
+ // concatenate msg
1336
+ char *input = (char *) malloc(len + 1);
1337
+ if (input == NULL) {
1338
+ PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for input buffer");
1339
+ return NULL;
1340
+ }
1341
+ memset(input, 0, len);
1342
+ memcpy(input, old_msg, msg_len);
1343
+ int TryNextCTR = TRUE;
1344
+ ECElement *encObj = NULL;
1345
+ y=BN_new();
1346
+ x=BN_new();
1347
+ do {
1348
+
1349
+ if(encObj!=NULL)
1350
+ Py_DECREF(encObj);
1351
+
1352
+ if (include_ctr == FALSE) {
1353
+ /* == msg_len ctr
1354
+ * encoding [ message | \x01 \x00 \x00 \x00 ]
1355
+ */
1356
+ *((uint32_t*)(input + msg_len)) = (uint32_t) ctr;
1357
+ }
1358
+
1359
+ debug("input hex msg => ");
1360
+ // check if msg len is big enough to fit into length
1361
+ printf_buffer_as_hex((uint8_t *) input, len);
1362
+ encObj = createNewPoint(G, gobj);
1363
+ BN_bin2bn((const uint8_t *) input, len, x);
1364
+ BN_free(y);
1365
+ y = BN_new();
1366
+ // Uncomment for debugging purposes
1367
+ //char *xstr = BN_bn2dec(x);
1368
+ //debug("gen x => %s\n", xstr);
1369
+ //OPENSSL_free(xstr);
1370
+ EC_POINT_set_compressed_coordinates_GFp(gobj->ec_group, encObj->P, x, 1, gobj->ctx);
1371
+ EC_POINT_get_affine_coordinates_GFp(gobj->ec_group, encObj->P, x, y, gobj->ctx);
1372
+
1373
+ if(BN_is_zero(x) || BN_is_zero(y)) {
1374
+ ctr++;
1375
+ continue;
1376
+ }
1377
+
1378
+ if(EC_POINT_is_on_curve(gobj->ec_group, encObj->P, gobj->ctx)) {
1379
+ debug("point is on curve!\n");
1380
+ debug("final hex msg => ");
1381
+ // check if msg len is big enough to fit into length
1382
+ printf_buffer_as_hex((uint8_t *) input, len);
1383
+ free(input);
1384
+ TryNextCTR = FALSE;
1385
+ }
1386
+ else {
1387
+ ctr++;
1388
+ }
1389
+ }while(TryNextCTR);
1390
+
1391
+ BN_free(x);
1392
+ BN_free(y);
1393
+
1394
+ return (PyObject *) encObj;
1395
+ }
1396
+ else {
1397
+ printf("expected message len: %lu, you provided: %d\n", (max_len - sizeof(uint32_t)), msg_len);
1398
+ EXIT_IF(TRUE, "message length does not match the selected group size.");
1399
+ }
1400
+ }
1401
+
1402
+ EXIT_IF(ERROR_SET, "Ran out of counters. So, could not be encode message at given length. make it smaller.");
1403
+ Py_INCREF(Py_False);
1404
+
1405
+ return Py_False;
1406
+ }
1407
+
1408
+
1409
+ /*
1410
+ * Decode a group element to a message (PyUnicode_String)
1411
+ */
1412
+ static PyObject *ECE_decode(ECElement *self, PyObject *args) {
1413
+ ECElement *obj = NULL;
1414
+ ECGroup *gobj = NULL;
1415
+ int include_ctr = FALSE;
1416
+
1417
+ if(PyArg_ParseTuple(args, "OO|i", &gobj, &obj, &include_ctr)) {
1418
+ VERIFY_GROUP(gobj);
1419
+
1420
+ // make sure it is a point and not a scalar
1421
+ if(PyEC_Check(obj) && isPoint(obj)) {
1422
+ BIGNUM *x = BN_new(), *y = BN_new();
1423
+ // verifies that element is on the curve then gets coordinates
1424
+ EC_POINT_get_affine_coordinates_GFp(gobj->ec_group, obj->P, x, y, gobj->ctx);
1425
+ int max_byte_len = BN_num_bytes(gobj->order);
1426
+ int prepend_zeros = max_byte_len;
1427
+ // by default we will strip out the counter part (unless specified otherwise by user)
1428
+ if (include_ctr == FALSE) {
1429
+ max_byte_len -= RESERVED_ENCODING_BYTES;
1430
+ }
1431
+ debug("Size of order => '%d'\n", max_byte_len);
1432
+ int x_len = BN_num_bytes(x);
1433
+ prepend_zeros -= x_len;
1434
+ if (prepend_zeros > 0) {
1435
+ x_len += prepend_zeros;
1436
+ }
1437
+ uint8_t *xstr = (uint8_t*) malloc(x_len + 1);
1438
+ if (xstr == NULL) {
1439
+ PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for xstr buffer");
1440
+ BN_free(x);
1441
+ BN_free(y);
1442
+ return NULL;
1443
+ }
1444
+ memset(xstr, 0, x_len);
1445
+ debug("Size of xstr => '%d'\n", x_len);
1446
+ // BN_bn2bin does not include leading null bytes that might've been included in original message
1447
+ // so doing that here by counting length and then pre-pending zeroes
1448
+ BN_bn2bin(x, (uint8_t*)(xstr + prepend_zeros));
1449
+ debug("Decoded x => ");
1450
+ printf_buffer_as_hex((uint8_t *) (xstr), x_len);
1451
+ BN_free(x);
1452
+ BN_free(y);
1453
+
1454
+ int size_msg = max_byte_len;
1455
+ PyObject *decObj = PyBytes_FromStringAndSize((const char *)xstr, size_msg);
1456
+ OPENSSL_free(xstr);
1457
+ return decObj;
1458
+ }
1459
+ }
1460
+
1461
+ EXIT_IF(TRUE, "invalid argument");
1462
+ }
1463
+
1464
+ static PyObject *Serialize(ECElement *self, PyObject *args) {
1465
+
1466
+ ECElement *obj = NULL;
1467
+ if(!PyArg_ParseTuple(args, "O", &obj)) {
1468
+ ErrorMsg("invalid argument.");
1469
+ return NULL;
1470
+ }
1471
+
1472
+ if(obj != NULL && PyEC_Check(obj)) {
1473
+ // allows export a compressed string
1474
+ if(obj->point_init && obj->type == G) {
1475
+ uint8_t p_buf[MAX_BUF+1];
1476
+ memset(p_buf, 0, MAX_BUF);
1477
+ size_t len = EC_POINT_point2oct(obj->group->ec_group, obj->P, POINT_CONVERSION_COMPRESSED, p_buf, MAX_BUF, obj->group->ctx);
1478
+ EXIT_IF(len == 0, "could not serialize point.");
1479
+
1480
+ debug("Serialized point => ");
1481
+ printf_buffer_as_hex(p_buf, len);
1482
+ size_t length = 0;
1483
+ char *base64_buf = NewBase64Encode(p_buf, len, FALSE, &length);
1484
+
1485
+ PyObject *result = PyBytes_FromString((const char *) base64_buf);
1486
+ PyObject *obj2 = PyBytes_FromFormat("%d:", obj->type);
1487
+ PyBytes_ConcatAndDel(&obj2, result);
1488
+ free(base64_buf);
1489
+ return obj2;
1490
+ }
1491
+ else if(obj->point_init && obj->type == ZR) {
1492
+ size_t len = BN_num_bytes(obj->elemZ);
1493
+ uint8_t z_buf[len+1];
1494
+ memset(z_buf, 0, len);
1495
+ if((size_t)BN_bn2bin(obj->elemZ, z_buf) == len) {
1496
+ // we're okay
1497
+ // convert z_buf to base64 and the rest is history.
1498
+ size_t length = 0;
1499
+ char *base64_buf = NewBase64Encode(z_buf, len, FALSE, &length);
1500
+
1501
+ PyObject *result = PyBytes_FromString((const char *) base64_buf);
1502
+ PyObject *obj2 = PyBytes_FromFormat("%d:", obj->type);
1503
+ PyBytes_ConcatAndDel(&obj2, result);
1504
+ free(base64_buf);
1505
+ return obj2;
1506
+ }
1507
+ }
1508
+ }
1509
+
1510
+
1511
+ return NULL;
1512
+ }
1513
+
1514
+ static PyObject *Deserialize(ECElement *self, PyObject *args)
1515
+ {
1516
+ PyObject *obj = NULL;
1517
+ ECGroup *gobj = NULL;
1518
+
1519
+ if(PyArg_ParseTuple(args, "OO", &gobj, &obj)) {
1520
+ VERIFY_GROUP(gobj);
1521
+ if(PyBytes_Check(obj)) {
1522
+ unsigned char *serial_buf = (unsigned char *) PyBytes_AsString(obj);
1523
+ GroupType type = atoi((const char *) &(serial_buf[0]));
1524
+ uint8_t *base64_buf = (uint8_t *)(serial_buf + 2);
1525
+
1526
+ size_t deserialized_len = 0;
1527
+ uint8_t *buf = NewBase64Decode((const char *) base64_buf, strlen((char *) base64_buf), &deserialized_len);
1528
+ size_t len = deserialized_len;
1529
+ debug("Deserialize this => ");
1530
+ printf_buffer_as_hex(buf, len);
1531
+ if(type == G) {
1532
+ ECElement *newObj = createNewPoint(type, gobj); // ->group, gobj->ctx);
1533
+ EC_POINT_oct2point(gobj->ec_group, newObj->P, (const uint8_t *) buf, len, gobj->ctx);
1534
+
1535
+ if(EC_POINT_is_on_curve(gobj->ec_group, newObj->P, gobj->ctx)) {
1536
+ obj=(PyObject *) newObj;
1537
+ }
1538
+ }
1539
+ else if(type == ZR) {
1540
+ ECElement *newObj = createNewPoint(type, gobj);
1541
+ BN_bin2bn((const uint8_t *) buf, len, newObj->elemZ);
1542
+ obj = (PyObject *) newObj;
1543
+ }else{
1544
+ Py_INCREF(Py_False);
1545
+ obj = Py_False;
1546
+ }
1547
+ free(buf);
1548
+ return obj;
1549
+ }
1550
+ else {
1551
+ EXIT_IF(TRUE, "invalid object type");
1552
+ }
1553
+ }
1554
+ EXIT_IF(TRUE, "invalid argument");
1555
+ }
1556
+
1557
+ #ifdef BENCHMARK_ENABLED
1558
+
1559
+ #define BenchmarkIdentifier 2
1560
+ #define GET_RESULTS_FUNC GetResults
1561
+ #define GROUP_OBJECT ECGroup
1562
+ #define BENCH_ERROR PyECErrorObject
1563
+
1564
+ PyObject *PyCreateList(Operations *gBench, MeasureType type)
1565
+ {
1566
+ int countZR = -1, countG = -1;
1567
+ GetField(countZR, type, ZR, gBench);
1568
+ GetField(countG, type, G, gBench);
1569
+
1570
+ PyObject *objList = Py_BuildValue("[ii]", countZR, countG);
1571
+ return objList;
1572
+ }
1573
+
1574
+ #include "benchmark_util.c"
1575
+
1576
+ #endif
1577
+
1578
+ PyMemberDef ECElement_members[] = {
1579
+ {"type", T_INT, offsetof(ECElement, type), 0,
1580
+ "group type"},
1581
+ {"initialized", T_INT, offsetof(ECElement, point_init), 0,
1582
+ "determine initialization status"},
1583
+ {NULL} /* Sentinel */
1584
+ };
1585
+
1586
+ PyMethodDef ECElement_methods[] = {
1587
+ {"isInf", (PyCFunction)ECE_is_infinity, METH_NOARGS, "Checks whether a point is at infinity."},
1588
+ {NULL}
1589
+ };
1590
+
1591
+ #if PY_MAJOR_VERSION >= 3
1592
+ PyNumberMethods ec_number = {
1593
+ (binaryfunc) ECE_add, /* nb_add */
1594
+ (binaryfunc) ECE_sub, /* nb_subtract */
1595
+ (binaryfunc) ECE_mul, /* nb_multiply */
1596
+ (binaryfunc) ECE_rem, /* nb_remainder */
1597
+ 0, /* nb_divmod */
1598
+ (ternaryfunc) ECE_pow, /* nb_power */
1599
+ (unaryfunc) ECE_neg, /* nb_negative */
1600
+ 0, /* nb_positive */
1601
+ 0, /* nb_absolute */
1602
+ 0, /* nb_bool */
1603
+ (unaryfunc)ECE_invert, /* nb_invert */
1604
+ 0, /* nb_lshift */
1605
+ 0, /* nb_rshift */
1606
+ 0, /* nb_and */
1607
+ 0, /* nb_xor */
1608
+ 0, /* nb_or */
1609
+ (unaryfunc)ECE_long, /* nb_int */
1610
+ 0, /* nb_reserved */
1611
+ 0, /* nb_float */
1612
+ (binaryfunc) ECE_add, /* nb_inplace_add */
1613
+ (binaryfunc) ECE_sub, /* nb_inplace_subtract */
1614
+ (binaryfunc) ECE_mul, /* nb_inplace_multiply */
1615
+ (binaryfunc) ECE_rem, /* nb_inplace_remainder */
1616
+ (ternaryfunc) ECE_pow, /* nb_inplace_power */
1617
+ 0, /* nb_inplace_lshift */
1618
+ 0, /* nb_inplace_rshift */
1619
+ 0, /* nb_inplace_and */
1620
+ 0, /* nb_inplace_xor */
1621
+ 0, /* nb_inplace_or */
1622
+ 0, /* nb_floor_divide */
1623
+ ECE_div, /* nb_true_divide */
1624
+ 0, /* nb_inplace_floor_divide */
1625
+ ECE_div, /* nb_inplace_true_divide */
1626
+ 0, /* nb_index */
1627
+ };
1628
+
1629
+ PyTypeObject ECType = {
1630
+ PyVarObject_HEAD_INIT(NULL, 0)
1631
+ "elliptic_curve.Element", /*tp_name*/
1632
+ sizeof(ECElement), /*tp_basicsize*/
1633
+ 0, /*tp_itemsize*/
1634
+ (destructor)ECElement_dealloc, /*tp_dealloc*/
1635
+ 0, /*tp_print*/
1636
+ 0, /*tp_getattr*/
1637
+ 0, /*tp_setattr*/
1638
+ 0, /*tp_reserved*/
1639
+ (reprfunc)ECElement_print, /*tp_repr*/
1640
+ &ec_number, /*tp_as_number*/
1641
+ 0, /*tp_as_sequence*/
1642
+ 0, /*tp_as_mapping*/
1643
+ 0, /*tp_hash */
1644
+ 0, /*tp_call*/
1645
+ (reprfunc)ECElement_print, /*tp_str*/
1646
+ 0, /*tp_getattro*/
1647
+ 0, /*tp_setattro*/
1648
+ 0, /*tp_as_buffer*/
1649
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1650
+ "Elliptic Curve objects", /* tp_doc */
1651
+ 0, /* tp_traverse */
1652
+ 0, /* tp_clear */
1653
+ ECE_equals, /* tp_richcompare */
1654
+ 0, /* tp_weaklistoffset */
1655
+ 0, /* tp_iter */
1656
+ 0, /* tp_iternext */
1657
+ ECElement_methods, /* tp_methods */
1658
+ ECElement_members, /* tp_members */
1659
+ 0, /* tp_getset */
1660
+ 0, /* tp_base */
1661
+ 0, /* tp_dict */
1662
+ 0, /* tp_descr_get */
1663
+ 0, /* tp_descr_set */
1664
+ 0, /* tp_dictoffset */
1665
+ (initproc)ECElement_init, /* tp_init */
1666
+ 0, /* tp_alloc */
1667
+ ECElement_new, /* tp_new */
1668
+ };
1669
+ #else
1670
+ /* python 2.x series */
1671
+ PyNumberMethods ec_number = {
1672
+ ECE_add, /* nb_add */
1673
+ ECE_sub, /* nb_subtract */
1674
+ ECE_mul, /* nb_multiply */
1675
+ ECE_div, /* nb_divide */
1676
+ ECE_rem, /* nb_remainder */
1677
+ 0, /* nb_divmod */
1678
+ ECE_pow, /* nb_power */
1679
+ ECE_neg, /* nb_negative */
1680
+ 0, /* nb_positive */
1681
+ 0, /* nb_absolute */
1682
+ 0, /* nb_nonzero */
1683
+ (unaryfunc)ECE_invert, /* nb_invert */
1684
+ 0, /* nb_lshift */
1685
+ 0, /* nb_rshift */
1686
+ 0, /* nb_and */
1687
+ 0, /* nb_xor */
1688
+ 0, /* nb_or */
1689
+ 0, /* nb_coerce */
1690
+ 0, /* nb_int */
1691
+ (unaryfunc)ECE_long, /* nb_long */
1692
+ 0, /* nb_float */
1693
+ 0, /* nb_oct */
1694
+ 0, /* nb_hex */
1695
+ ECE_add, /* nb_inplace_add */
1696
+ ECE_sub, /* nb_inplace_subtract */
1697
+ ECE_mul, /* nb_inplace_multiply */
1698
+ ECE_div, /* nb_inplace_divide */
1699
+ 0, /* nb_inplace_remainder */
1700
+ 0, /* nb_inplace_power */
1701
+ 0, /* nb_inplace_lshift */
1702
+ 0, /* nb_inplace_rshift */
1703
+ 0, /* nb_inplace_and */
1704
+ 0, /* nb_inplace_xor */
1705
+ 0, /* nb_inplace_or */
1706
+ 0, /* nb_floor_divide */
1707
+ 0, /* nb_true_divide */
1708
+ 0, /* nb_inplace_floor_divide */
1709
+ 0, /* nb_inplace_true_divide */
1710
+ 0, /* nb_index */
1711
+ };
1712
+
1713
+ PyTypeObject ECType = {
1714
+ PyObject_HEAD_INIT(NULL)
1715
+ 0, /*ob_size*/
1716
+ "elliptic_curve.Element", /*tp_name*/
1717
+ sizeof(ECElement), /*tp_basicsize*/
1718
+ 0, /*tp_itemsize*/
1719
+ (destructor)ECElement_dealloc, /*tp_dealloc*/
1720
+ 0, /*tp_print*/
1721
+ 0, /*tp_getattr*/
1722
+ 0, /*tp_setattr*/
1723
+ 0, /*tp_compare*/
1724
+ (reprfunc)ECElement_print, /*tp_repr*/
1725
+ &ec_number, /*tp_as_number*/
1726
+ 0, /*tp_as_sequence*/
1727
+ 0, /*tp_as_mapping*/
1728
+ 0, /*tp_hash */
1729
+ 0, /*tp_call*/
1730
+ (reprfunc)ECElement_print, /*tp_str*/
1731
+ 0, /*tp_getattro*/
1732
+ 0, /*tp_setattro*/
1733
+ 0, /*tp_as_buffer*/
1734
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
1735
+ "Elliptic Curve objects", /* tp_doc */
1736
+ 0, /* tp_traverse */
1737
+ 0, /* tp_clear */
1738
+ ECE_equals, /* tp_richcompare */
1739
+ 0, /* tp_weaklistoffset */
1740
+ 0, /* tp_iter */
1741
+ 0, /* tp_iternext */
1742
+ ECElement_methods, /* tp_methods */
1743
+ ECElement_members, /* tp_members */
1744
+ 0, /* tp_getset */
1745
+ 0, /* tp_base */
1746
+ 0, /* tp_dict */
1747
+ 0, /* tp_descr_get */
1748
+ 0, /* tp_descr_set */
1749
+ 0, /* tp_dictoffset */
1750
+ (initproc) ECElement_init, /* tp_init */
1751
+ 0, /* tp_alloc */
1752
+ ECElement_new, /* tp_new */
1753
+ };
1754
+
1755
+ #endif
1756
+
1757
+ #if PY_MAJOR_VERSION >= 3
1758
+
1759
+ PyTypeObject ECGroupType = {
1760
+ PyVarObject_HEAD_INIT(NULL, 0)
1761
+ "elliptic_curve.ECGroup", /*tp_name*/
1762
+ sizeof(ECGroup), /*tp_basicsize*/
1763
+ 0, /*tp_itemsize*/
1764
+ (destructor)ECGroup_dealloc, /*tp_dealloc*/
1765
+ 0, /*tp_print*/
1766
+ 0, /*tp_getattr*/
1767
+ 0, /*tp_setattr*/
1768
+ 0, /*tp_reserved*/
1769
+ (reprfunc)ECGroup_print, /*tp_str*/
1770
+ 0, /*tp_as_number*/
1771
+ 0, /*tp_as_sequence*/
1772
+ 0, /*tp_as_mapping*/
1773
+ 0, /*tp_hash */
1774
+ 0, /*tp_call*/
1775
+ 0, /*tp_str*/
1776
+ 0, /*tp_getattro*/
1777
+ 0, /*tp_setattro*/
1778
+ 0, /*tp_as_buffer*/
1779
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1780
+ "ECGroup parameters", /* tp_doc */
1781
+ 0, /* tp_traverse */
1782
+ 0, /* tp_clear */
1783
+ 0, /* tp_richcompare */
1784
+ 0, /* tp_weaklistoffset */
1785
+ 0, /* tp_iter */
1786
+ 0, /* tp_iternext */
1787
+ 0, /* tp_methods */
1788
+ 0, /* tp_members */
1789
+ 0, /* tp_getset */
1790
+ 0, /* tp_base */
1791
+ 0, /* tp_dict */
1792
+ 0, /* tp_descr_get */
1793
+ 0, /* tp_descr_set */
1794
+ 0, /* tp_dictoffset */
1795
+ (initproc)ECGroup_init, /* tp_init */
1796
+ 0, /* tp_alloc */
1797
+ ECGroup_new, /* tp_new */
1798
+ };
1799
+ #else
1800
+ /* python 2.x series */
1801
+ PyTypeObject ECGroupType = {
1802
+ PyObject_HEAD_INIT(NULL)
1803
+ 0, /*ob_size*/
1804
+ "elliptic_curve.ECGroup", /*tp_name*/
1805
+ sizeof(ECGroup), /*tp_basicsize*/
1806
+ 0, /*tp_itemsize*/
1807
+ (destructor)ECGroup_dealloc, /*tp_dealloc*/
1808
+ 0, /*tp_print*/
1809
+ 0, /*tp_getattr*/
1810
+ 0, /*tp_setattr*/
1811
+ 0, /*tp_compare*/
1812
+ 0, /*tp_repr*/
1813
+ 0, /*tp_as_number*/
1814
+ 0, /*tp_as_sequence*/
1815
+ 0, /*tp_as_mapping*/
1816
+ 0, /*tp_hash */
1817
+ 0, /*tp_call*/
1818
+ (reprfunc)ECGroup_print, /*tp_str*/
1819
+ 0, /*tp_getattro*/
1820
+ 0, /*tp_setattro*/
1821
+ 0, /*tp_as_buffer*/
1822
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1823
+ "ECGroup parameters", /* tp_doc */
1824
+ 0, /* tp_traverse */
1825
+ 0, /* tp_clear */
1826
+ 0, /* tp_richcompare */
1827
+ 0, /* tp_weaklistoffset */
1828
+ 0, /* tp_iter */
1829
+ 0, /* tp_iternext */
1830
+ 0, /* tp_methods */
1831
+ 0, /* tp_members */
1832
+ 0, /* tp_getset */
1833
+ 0, /* tp_base */
1834
+ 0, /* tp_dict */
1835
+ 0, /* tp_descr_get */
1836
+ 0, /* tp_descr_set */
1837
+ 0, /* tp_dictoffset */
1838
+ (initproc) ECGroup_init, /* tp_init */
1839
+ 0, /* tp_alloc */
1840
+ ECGroup_new, /* tp_new */
1841
+ };
1842
+
1843
+ #endif
1844
+
1845
+
1846
+ struct module_state {
1847
+ PyObject *error;
1848
+ //#ifdef BENCHMARK_ENABLED
1849
+ // Benchmark *dBench;
1850
+ //#endif
1851
+ };
1852
+
1853
+ #if PY_MAJOR_VERSION >= 3
1854
+ #define GETSTATE(m) ((struct module_state *) PyModule_GetState(m))
1855
+ #else
1856
+ #define GETSTATE(m) (&_state)
1857
+ static struct module_state _state;
1858
+ #endif
1859
+
1860
+ static PyMethodDef ec_methods[] = {
1861
+ {"init", (PyCFunction)ECE_init, METH_VARARGS, "Create an element in a specific group G or ZR."},
1862
+ {"random", (PyCFunction)ECE_random, METH_VARARGS, "Return a random element in a specific group G or ZR."},
1863
+ {"order", (PyCFunction)ECE_getOrder, METH_O, "Return the order of a group."},
1864
+ {"getGenerator", (PyCFunction)ECE_getGen, METH_O, "Get the generator of the group."},
1865
+ {"bitsize", (PyCFunction)ECE_bitsize, METH_O, "Returns number of bytes to represent a message."},
1866
+ {"serialize", (PyCFunction)Serialize, METH_VARARGS, "Serialize an element to a string"},
1867
+ {"deserialize", (PyCFunction)Deserialize, METH_VARARGS, "Deserialize an element to G or ZR"},
1868
+ {"hashEC", (PyCFunction)ECE_hash, METH_VARARGS, "Perform a hash of a string to a group element of G."},
1869
+ {"encode", (PyCFunction)ECE_encode, METH_VARARGS, "Encode string as a group element of G"},
1870
+ {"decode", (PyCFunction)ECE_decode, METH_VARARGS, "Decode group element to a string."},
1871
+ {"getXY", (PyCFunction)ECE_convertToZR, METH_VARARGS, "Returns the x and/or y coordinates of point on an elliptic curve."},
1872
+ #ifdef BENCHMARK_ENABLED
1873
+ {"InitBenchmark", (PyCFunction)InitBenchmark, METH_VARARGS, "Initialize a benchmark object"},
1874
+ {"StartBenchmark", (PyCFunction)StartBenchmark, METH_VARARGS, "Start a new benchmark with some options"},
1875
+ {"EndBenchmark", (PyCFunction)EndBenchmark, METH_VARARGS, "End a given benchmark"},
1876
+ {"GetBenchmark", (PyCFunction)GetBenchmark, METH_VARARGS, "Returns contents of a benchmark object"},
1877
+ {"GetGeneralBenchmarks", (PyCFunction)GetAllBenchmarks, METH_VARARGS, "Retrieve general benchmark info as a dictionary"},
1878
+ {"GetGranularBenchmarks", (PyCFunction) GranularBenchmark, METH_VARARGS, "Retrieve granular benchmarks as a dictionary"},
1879
+ #endif
1880
+ {NULL, NULL}
1881
+ };
1882
+
1883
+
1884
+ #if PY_MAJOR_VERSION >= 3
1885
+ static int ec_traverse(PyObject *m, visitproc visit, void *arg) {
1886
+ Py_VISIT(GETSTATE(m)->error);
1887
+ return 0;
1888
+ }
1889
+
1890
+ static int ec_clear(PyObject *m) {
1891
+ Py_CLEAR(GETSTATE(m)->error);
1892
+ Py_XDECREF(PyECErrorObject);
1893
+ return 0;
1894
+ }
1895
+
1896
+ static int ec_free(PyObject *m) {
1897
+ // Defensive cleanup for OpenSSL to prevent hangs during Python 3.12+ shutdown
1898
+ // Only cleanup if not in abnormal finalization state
1899
+ if(m != NULL && !CHARM_PY_IS_FINALIZING()) {
1900
+ // Note: OpenSSL 1.1.0+ handles cleanup automatically
1901
+ // This is a no-op for compatibility but prevents potential hangs
1902
+ }
1903
+ return 0;
1904
+ }
1905
+
1906
+ static struct PyModuleDef moduledef = {
1907
+ PyModuleDef_HEAD_INIT,
1908
+ "elliptic_curve",
1909
+ NULL,
1910
+ sizeof(struct module_state),
1911
+ ec_methods,
1912
+ NULL,
1913
+ ec_traverse,
1914
+ ec_clear,
1915
+ (freefunc) ec_free
1916
+ };
1917
+
1918
+ #define CLEAN_EXIT goto LEAVE;
1919
+ #define INITERROR return NULL
1920
+ PyMODINIT_FUNC
1921
+ PyInit_elliptic_curve(void) {
1922
+ #else
1923
+ #define CLEAN_EXIT goto LEAVE;
1924
+ #define INITERROR return
1925
+ void initelliptic_curve(void) {
1926
+ #endif
1927
+ PyObject *m;
1928
+ if(PyType_Ready(&ECGroupType) < 0)
1929
+ CLEAN_EXIT;
1930
+ if(PyType_Ready(&ECType) < 0)
1931
+ CLEAN_EXIT;
1932
+ #ifdef BENCHMARK_ENABLED
1933
+ if(import_benchmark() < 0)
1934
+ CLEAN_EXIT;
1935
+ if(PyType_Ready(&BenchmarkType) < 0)
1936
+ CLEAN_EXIT;
1937
+ if(PyType_Ready(&OperationsType) < 0)
1938
+ CLEAN_EXIT;
1939
+ #endif
1940
+
1941
+ #if PY_MAJOR_VERSION >= 3
1942
+ m = PyModule_Create(&moduledef);
1943
+ #else
1944
+ m = Py_InitModule("elliptic_curve", ec_methods);
1945
+ #endif
1946
+
1947
+ struct module_state *st = GETSTATE(m);
1948
+ st->error = PyErr_NewException("elliptic_curve.Error", NULL, NULL);
1949
+ if (st->error == NULL)
1950
+ CLEAN_EXIT;
1951
+ PyECErrorObject = st->error;
1952
+ Py_INCREF(PyECErrorObject);
1953
+
1954
+ Py_INCREF(&ECType);
1955
+ if(PyModule_AddObject(m, "ec_element", (PyObject *)&ECType) != 0)
1956
+ CLEAN_EXIT;
1957
+ Py_INCREF(&ECGroupType);
1958
+ if(PyModule_AddObject(m, "elliptic_curve", (PyObject *)&ECGroupType) != 0)
1959
+ CLEAN_EXIT;
1960
+
1961
+ PyModule_AddIntConstant(m, "G", G);
1962
+ PyModule_AddIntConstant(m, "ZR", ZR);
1963
+ #ifdef BENCHMARK_ENABLED
1964
+ ADD_BENCHMARK_OPTIONS(m);
1965
+ PyModule_AddStringConstant(m, "Granular", _GRAN_OPT);
1966
+ #endif
1967
+ // initialize PRNG
1968
+ // replace with read from some source of randomness
1969
+ #ifndef MS_WINDOWS
1970
+ debug("Linux: seeding openssl prng.\n");
1971
+ char *rand_file = "/dev/urandom";
1972
+ RAND_load_file(rand_file, RAND_MAX_BYTES);
1973
+ #else
1974
+ debug("Windows: seeding openssl prng.\n");
1975
+ RAND_poll();
1976
+ #endif
1977
+
1978
+ LEAVE:
1979
+ if (PyErr_Occurred()) {
1980
+ PyErr_Clear();
1981
+ Py_XDECREF(m);
1982
+ INITERROR;
1983
+ }
1984
+
1985
+ return m;
1986
+ }