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,2539 @@
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 integermodule.c
23
+ *
24
+ * @brief charm interface over GMP multi-precision integers
25
+ *
26
+ * @author jakinye3@jhu.edu
27
+ *
28
+ ************************************************************************/
29
+
30
+ #include "integermodule.h"
31
+
32
+ /*
33
+ * Python 3.12+ changed the internal structure of PyLongObject:
34
+ * - Old (Python 3.11-): ob_size stores digit count (via Py_SIZE()), ob_digit is the digit array
35
+ * - New (Python 3.12+): long_value.lv_tag stores digit count, sign, and flags; long_value.ob_digit is the digit array
36
+ *
37
+ * In Python 3.12+:
38
+ * - lv_tag bits 0-1: Sign (0=positive, 1=zero, 2=negative)
39
+ * - lv_tag bit 2: Reserved for immortality
40
+ * - lv_tag bits 3+: Unsigned digit count
41
+ *
42
+ * We need to use different macros to access the digit array and get the digit count.
43
+ */
44
+
45
+ #if PY_MINOR_VERSION >= 12
46
+ #define PythonLongVal(l) l->long_value.ob_digit
47
+ #define _PYLONG_NON_SIZE_BITS 3
48
+ #define _PYLONG_SIGN_MASK 3
49
+ #define _PYLONG_SIGN_NEGATIVE 2
50
+ #define _PYLONG_SIGN_ZERO 1
51
+ /* Get the digit count from lv_tag (bits 3+) */
52
+ #define PythonLongDigitCount(l) ((Py_ssize_t)(((PyLongObject *)(l))->long_value.lv_tag >> _PYLONG_NON_SIZE_BITS))
53
+ /* Check if negative (sign bits == 2) */
54
+ #define PythonLongIsNegative(l) ((((PyLongObject *)(l))->long_value.lv_tag & _PYLONG_SIGN_MASK) == _PYLONG_SIGN_NEGATIVE)
55
+ /* Set the digit count and sign in lv_tag */
56
+ #define PythonLongSetTag(l, sign, size) (((PyLongObject *)(l))->long_value.lv_tag = ((1 - (sign)) | ((size_t)(size) << _PYLONG_NON_SIZE_BITS)))
57
+ #else
58
+ #define PythonLongVal(l) l->ob_digit
59
+ /* In Python 3.11-, Py_SIZE() returns signed digit count (negative for negative numbers) */
60
+ #define PythonLongDigitCount(l) (Py_SIZE(l) < 0 ? -Py_SIZE(l) : Py_SIZE(l))
61
+ #define PythonLongIsNegative(l) (Py_SIZE(l) < 0)
62
+ /* Set the size (signed) */
63
+ #define PythonLongSetTag(l, sign, size) PYTHON_SET_SIZE(l, (sign) < 0 ? -(size) : (size))
64
+ #endif
65
+
66
+ #if PY_MINOR_VERSION <= 10
67
+ #define PYTHON_SET_SIZE(l, i) Py_SIZE(l) = i
68
+ #else
69
+ #define PYTHON_SET_SIZE(l, i) Py_SET_SIZE(l, i);
70
+ #endif
71
+
72
+ /*
73
+ * Python 3.13+ made Py_IsFinalizing() public and removed _Py_IsFinalizing().
74
+ * For older versions, we need to use the private _Py_IsFinalizing().
75
+ */
76
+ #if PY_MINOR_VERSION >= 13
77
+ #define CHARM_PY_IS_FINALIZING() Py_IsFinalizing()
78
+ #else
79
+ #define CHARM_PY_IS_FINALIZING() _Py_IsFinalizing()
80
+ #endif
81
+
82
+ struct module_state {
83
+ PyObject *error;
84
+ #ifdef BENCHMARK_ENABLED
85
+ Benchmark *dBench;
86
+ #endif
87
+ };
88
+
89
+ #define GETSTATE(m) ((struct module_state *) PyModule_GetState(m))
90
+
91
+ #ifdef BENCHMARK_ENABLED
92
+ static Benchmark *tmpBench;
93
+ #endif
94
+
95
+ #define SET_BENCH(mod_obj, obj) \
96
+ struct module_state *st = GETSTATE(mod_obj); \
97
+ obj->dBench = (Benchmark *) st->dBench; \
98
+ Py_INCREF(obj->dBench);
99
+ //printf("%s: Refcnt dBench = '%i'\n", __FUNCTION__, (int) Py_REFCNT(obj->dBench));
100
+
101
+ #define COPY_BENCH(obj_dst, obj_src) \
102
+ if(obj_src->dBench != NULL && obj_dst->dBench == NULL) { \
103
+ obj_dst->dBench = obj_src->dBench; \
104
+ Py_INCREF(obj_dst->dBench); }
105
+
106
+ #define CAST_TO_LONG(obj, lng) \
107
+ if(PyLong_Check(obj)) { \
108
+ lng = PyLong_AsLong(obj); } \
109
+ else { \
110
+ Py_INCREF(Py_NotImplemented); \
111
+ return Py_NotImplemented; } \
112
+
113
+
114
+ static inline size_t size(mpz_t n) {
115
+ return mpz_sizeinbase(n, 2);
116
+ }
117
+
118
+ void longObjToMPZ(mpz_t m, PyObject * o) {
119
+ PyLongObject *p = (PyLongObject *) PyNumber_Long(o);
120
+ Py_ssize_t size, i;
121
+ int isNeg = FALSE;
122
+ mpz_t temp, temp2;
123
+ mpz_init(temp);
124
+ mpz_init(temp2);
125
+
126
+ /* Use the new macros that work correctly on both Python 3.11- and 3.12+ */
127
+ size = PythonLongDigitCount(p);
128
+ isNeg = PythonLongIsNegative(p);
129
+
130
+ mpz_set_ui(m, 0);
131
+ for (i = 0; i < size; i++) {
132
+ mpz_set_ui(temp, PythonLongVal(p)[i]);
133
+ mpz_mul_2exp(temp2, temp, PyLong_SHIFT * i);
134
+ mpz_add(m, m, temp2);
135
+ }
136
+ mpz_clear(temp);
137
+ mpz_clear(temp2);
138
+ Py_XDECREF(p);
139
+ if(isNeg) mpz_neg(m, m);
140
+ }
141
+
142
+ //void longObjToBN(BIGNUM *m, PyObject *o) {
143
+ // PyLongObject *p = (PyLongObject *) PyNumber_Long(o);
144
+ // int size, i, tmp = Py_SIZE(p);
145
+ // BIGNUM *temp = BN_new(), *temp2 = BN_new();
146
+ // BN_init(temp);
147
+ // BN_init(temp2);
148
+ // if (tmp > 0)
149
+ // size = tmp;
150
+ // else
151
+ // size = -tmp;
152
+ // BN_zero(m, 0);
153
+ // for (i = 0; i < size; i++) {
154
+ // BN_set_word(temp, p->long_value.ob_digit[i]);
155
+ // mpz_mul_2exp(temp2, temp, PyLong_SHIFT * i);
156
+ // mpz_add(m, m, temp2);
157
+ // }
158
+ // mpz_clear(temp);
159
+ // mpz_clear(temp2);
160
+ //}
161
+
162
+ PyObject *bnToLongObj(BIGNUM *m) {
163
+ return PyLong_FromString(BN_bn2hex(m), NULL, 16);
164
+ }
165
+
166
+ int bnToMPZ(BIGNUM *p, mpz_t m) {
167
+ size_t count = BN_num_bytes(p);
168
+ unsigned char* tmp = malloc(count);
169
+ if(!tmp) {
170
+ return FALSE;
171
+ }
172
+ BN_bn2bin(p, tmp);
173
+ mpz_import(m, count, 1, 1, 0, 0, tmp);
174
+ if(BN_is_negative(p)) {
175
+ mpz_neg(m, m);
176
+ }
177
+ free(tmp);
178
+
179
+ return TRUE;
180
+ }
181
+
182
+ // generate a BN from an mpz_t type
183
+ int mpzToBN(mpz_t m, BIGNUM *b) {
184
+ void (*freefunc) (void *, size_t);
185
+ mp_get_memory_functions (NULL, NULL, &freefunc);
186
+
187
+ size_t count;
188
+ unsigned char* bytes = mpz_export (NULL, &count, 1, 1, 0, 0, m);
189
+ BN_bin2bn(bytes, count, b);
190
+ freefunc(bytes, count);
191
+
192
+ debug("Original input m => ");
193
+ print_mpz(m, 10);
194
+ debug("GMP num bits => '%i'\n", GMP_NUMB_BITS);
195
+ debug("BN num bits => '%i'\n", BN_BITS2);
196
+ return TRUE;
197
+ }
198
+
199
+ PyObject *mpzToLongObj(mpz_t m) {
200
+ /* borrowed from gmpy */
201
+ int size = (mpz_sizeinbase(m, 2) + PyLong_SHIFT - 1) / PyLong_SHIFT;
202
+ int i, isNeg = (mpz_sgn(m) < 0) ? TRUE : FALSE;
203
+ mpz_t temp;
204
+ PyLongObject *l = _PyLong_New(size);
205
+ if (!l)
206
+ return NULL;
207
+ mpz_init_set(temp, m);
208
+ /* Work with absolute value for digit extraction.
209
+ * mpz_fdiv_q_2exp does floor division, which gives incorrect results
210
+ * for negative numbers (e.g., -5 / 2 = -3 with floor, not -2).
211
+ * By using the absolute value, we extract digits correctly and
212
+ * apply the sign at the end. */
213
+ if (isNeg) {
214
+ mpz_abs(temp, temp);
215
+ }
216
+ for (i = 0; i < size; i++) {
217
+ PythonLongVal(l)[i] = (digit)(mpz_get_ui(temp) & PyLong_MASK);
218
+ mpz_fdiv_q_2exp(temp, temp, PyLong_SHIFT);
219
+ }
220
+ /* Normalize: remove leading zeros */
221
+ i = size;
222
+ while ((i > 0) && (PythonLongVal(l)[i - 1] == 0))
223
+ i--;
224
+ /* Set the size/sign using the appropriate method for the Python version */
225
+ #if PY_MINOR_VERSION >= 12
226
+ /* Python 3.12+: Set lv_tag with sign and digit count */
227
+ int sign = isNeg ? -1 : (i == 0 ? 0 : 1);
228
+ PythonLongSetTag(l, sign, i);
229
+ #else
230
+ /* Python 3.11-: Set ob_size (negative for negative numbers) */
231
+ if(isNeg) {
232
+ PYTHON_SET_SIZE(l, -i);
233
+ }
234
+ else {
235
+ PYTHON_SET_SIZE(l, i);
236
+ }
237
+ #endif
238
+ mpz_clear(temp);
239
+ return (PyObject *) l;
240
+ }
241
+
242
+ void print_mpz(mpz_t x, int base) {
243
+ #ifdef DEBUG
244
+ if(base <= 2 || base > 64) return;
245
+ size_t x_size = mpz_sizeinbase(x, base) + 2;
246
+ char *x_str = (char *) malloc(x_size);
247
+ if (x_str == NULL) return;
248
+ x_str = mpz_get_str(x_str, base, x);
249
+ debug("Element => '%s'\n", x_str);
250
+ debug("Order of Element => '%zd'\n", x_size);
251
+ free(x_str);
252
+ #endif
253
+ }
254
+
255
+ void print_bn_dec(const BIGNUM *bn) {
256
+ #ifdef DEBUG
257
+ printf("BIGNUM *bn => ");
258
+ char *pstr = BN_bn2dec(bn);
259
+ printf("%s\n", pstr);
260
+ OPENSSL_free(pstr);
261
+ #endif
262
+ }
263
+
264
+ void printf_buffer_as_hex(uint8_t *data, size_t len) {
265
+ #ifdef DEBUG
266
+ size_t i;
267
+
268
+ for (i = 0; i < len; i++) {
269
+ printf("%02x ", data[i]);
270
+ }
271
+ printf("\n");
272
+ #endif
273
+ }
274
+
275
+ /*!
276
+ * Hash a null-terminated string to a byte array.
277
+ *
278
+ * @param input_buf The input buffer.
279
+ * @param input_len The input buffer length (in bytes).
280
+ * @param output_buf A pre-allocated output buffer of size hash_len.
281
+ * @param hash_len Length of the output hash (in bytes). Should be approximately bit size of curve group order.
282
+ * @param hash_prefix prefix for hash function.
283
+ */
284
+ int hash_to_bytes(uint8_t *input_buf, int input_len, uint8_t *output_buf, int hash_len, uint8_t hash_prefix)
285
+ {
286
+ EVP_MD_CTX *ctx = NULL;
287
+ unsigned int md_len = 0;
288
+ int i, new_input_len = input_len + 2; // extra byte for prefix
289
+ uint8_t first_block = 0;
290
+ uint8_t new_input[new_input_len+1];
291
+
292
+ memset(new_input, 0, new_input_len+1);
293
+ new_input[0] = first_block; // block number (always 0 by default)
294
+ new_input[1] = hash_prefix; // set hash prefix
295
+ memcpy((uint8_t *)(new_input+2), input_buf, input_len); // copy input bytes
296
+
297
+ debug("new input => \n");
298
+ printf_buffer_as_hex(new_input, new_input_len);
299
+ // prepare output buf
300
+ memset(output_buf, 0, hash_len);
301
+
302
+ ctx = EVP_MD_CTX_new();
303
+ if (ctx == NULL) return FALSE;
304
+
305
+ if (hash_len <= HASH_LEN) {
306
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
307
+ EVP_DigestUpdate(ctx, new_input, new_input_len);
308
+ uint8_t md[HASH_LEN+1];
309
+ EVP_DigestFinal_ex(ctx, md, &md_len);
310
+ memcpy(output_buf, md, hash_len);
311
+ }
312
+ else {
313
+ // apply variable-size hash technique to get desired size
314
+ // determine block count.
315
+ int blocks = (int) ceil(((double) hash_len) / HASH_LEN);
316
+ debug("Num blocks needed: %d\n", blocks);
317
+ uint8_t md[HASH_LEN+1];
318
+ uint8_t md2[(blocks * HASH_LEN)+1];
319
+ uint8_t *target_buf = md2;
320
+ for(i = 0; i < blocks; i++) {
321
+ /* compute digest = SHA-2( i || prefix || input_buf ) || ... || SHA-2( n-1 || prefix || input_buf ) */
322
+ target_buf += (i * HASH_LEN);
323
+ new_input[0] = (uint8_t) i;
324
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
325
+ debug("input %d => ", i);
326
+ printf_buffer_as_hex(new_input, new_input_len);
327
+ EVP_DigestUpdate(ctx, new_input, new_input_len);
328
+ EVP_DigestFinal_ex(ctx, md, &md_len);
329
+ memcpy(target_buf, md, hash_len);
330
+ debug("block %d => ", i);
331
+ printf_buffer_as_hex(md, HASH_LEN);
332
+ memset(md, 0, HASH_LEN);
333
+ }
334
+ // copy back to caller
335
+ memcpy(output_buf, md2, hash_len);
336
+ }
337
+
338
+ EVP_MD_CTX_free(ctx);
339
+ return TRUE;
340
+ }
341
+
342
+
343
+ int hash_to_group_element(mpz_t x, int block_num, uint8_t *output_buf) {
344
+
345
+ size_t count = 0;
346
+ uint8_t *rop_buf = (uint8_t *) mpz_export(NULL, &count, 1, sizeof(char), 0,
347
+ 0, x);
348
+
349
+ debug("rop_buf...\n");
350
+ printf_buffer_as_hex(rop_buf, count);
351
+ // create another buffer with block_num and rop_buf as input. Maybe use snprintf?
352
+ if (block_num > 0) {
353
+ int len = count + sizeof(uint32_t);
354
+ uint8_t *tmp_buf = (uint8_t *) malloc(len + 1);
355
+ if (tmp_buf == NULL) return FALSE;
356
+ memset(tmp_buf, 0, len);
357
+ // sprintf(tmp_buf, "%d%s", block_num, (char *) rop_buf);
358
+ uint32_t block_str = (uint32_t) block_num;
359
+ *((uint32_t*) tmp_buf) = block_str;
360
+ strncat((char *) (tmp_buf + sizeof(uint32_t)), (const char *) rop_buf,
361
+ count);
362
+
363
+ debug("tmp_buf after strcat...\n");
364
+ printf_buffer_as_hex(tmp_buf, len);
365
+
366
+ hash_to_bytes(tmp_buf, len, output_buf, HASH_LEN,
367
+ HASH_FUNCTION_KEM_DERIVE);
368
+ free(tmp_buf);
369
+ } else {
370
+ hash_to_bytes(rop_buf, (int) count, output_buf, HASH_LEN,
371
+ HASH_FUNCTION_KEM_DERIVE);
372
+ }
373
+
374
+ free(rop_buf);
375
+ return TRUE;
376
+ }
377
+
378
+ void _reduce(Integer *object) {
379
+ if (object != NULL && mpz_sgn(object->m) > 0)
380
+ mpz_mod(object->e, object->e, object->m);
381
+ }
382
+
383
+ void Integer_dealloc(Integer* self) {
384
+ /* clear structure */
385
+ mpz_clear(self->m);
386
+ mpz_clear(self->e);
387
+ Py_TYPE(self)->tp_free((PyObject*) self);
388
+ }
389
+
390
+ PyObject *Integer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
391
+ Integer *self;
392
+
393
+ self = (Integer *) type->tp_alloc(type, 0);
394
+ if (self != NULL) {
395
+ /* initialize fields here */
396
+ mpz_init(self->e);
397
+ mpz_init(self->m);
398
+ self->initialized = TRUE;
399
+ }
400
+ return (PyObject *) self;
401
+ }
402
+
403
+ int Integer_init(Integer *self, PyObject *args, PyObject *kwds) {
404
+ PyObject *num = NULL, *mod = NULL;
405
+ static char *kwlist[] = { "number", "modulus", NULL };
406
+
407
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, &num, &mod)) {
408
+ return -1;
409
+ }
410
+
411
+ // check if they are of type long
412
+ if(PyInteger_Check(num)) {
413
+ Integer *num1 = (Integer *) num;
414
+ mpz_set(self->e, num1->e);
415
+ }
416
+ else if(_PyLong_Check(num)) {
417
+ longObjToMPZ(self->e, num);
418
+ }
419
+ // raise error
420
+ else if (PyBytes_Check(num)) {
421
+ // convert directly to a char string of bytes
422
+ char *bytes = PyBytes_AS_STRING(num);
423
+ int bytes_len = strlen(bytes);
424
+ mpz_import(self->e, bytes_len, 1, sizeof(bytes[0]), 0, 0, bytes);
425
+ } else if (PyUnicode_Check(num)) {
426
+ // cast to a bytes object, then interpret as a string of bytes
427
+ PyObject *_num = PyUnicode_AsUTF8String(num);
428
+ const char *bytes = PyBytes_AS_STRING(_num);
429
+ int bytes_len = strlen(bytes);
430
+ mpz_import(self->e, bytes_len, 1, sizeof(bytes[0]), 0, 0, bytes);
431
+ Py_DECREF(_num);
432
+ } else {
433
+ return -1;
434
+ }
435
+
436
+ if (mod != NULL) {
437
+ if (_PyLong_Check(mod)) {
438
+ mpz_t m;
439
+ mpz_init(m);
440
+ longObjToMPZ(m, mod);
441
+ if(mpz_sgn(m) > 0) mpz_set(self->m, m);
442
+ else {
443
+ mpz_clear(m);
444
+ PyErr_SetString(IntegerError, "negative modulus not allowed.");
445
+ return -1;
446
+ }
447
+ mpz_clear(m);
448
+ }
449
+ else if(PyInteger_Check(mod)) {
450
+ Integer *mod1 = (Integer *) mod;
451
+ mpz_set(self->m, mod1->e);
452
+ }
453
+ else {
454
+ PyErr_SetString(IntegerError, "invalid type for modulus");
455
+ return -1;
456
+ }
457
+ }
458
+ // else leave self->m set to 0.
459
+ return 0;
460
+ }
461
+
462
+ static PyObject *Integer_equals(PyObject *o1, PyObject *o2, int opid) {
463
+ Integer *lhs = NULL, *rhs = NULL;
464
+ int foundLHS = FALSE, foundRHS = FALSE, result = -1, errorOccured = FALSE;
465
+ mpz_t lhs_mpz, rhs_mpz, l, r;
466
+ mpz_init(lhs_mpz);
467
+ mpz_init(rhs_mpz);
468
+
469
+ Convert_Types(o1, o2, lhs, rhs, foundLHS, foundRHS, lhs_mpz, rhs_mpz, errorOccured);
470
+ // perform operation
471
+ if(errorOccured) {
472
+ mpz_clear(lhs_mpz);
473
+ mpz_clear(rhs_mpz);
474
+ ErrorMsg("invalid left or right operand type.");
475
+ }
476
+ else if (foundLHS) {
477
+ debug("foundLHS\n");
478
+ if (mpz_sgn(rhs->m) == 0) {
479
+ result = mpz_cmp(lhs_mpz, rhs->e);
480
+ } else {
481
+ mpz_init(r);
482
+ mpz_mod(r, rhs->e, rhs->m);
483
+ result = mpz_cmp(r, lhs_mpz);
484
+ mpz_clear(r);
485
+ }
486
+ } else if (foundRHS) {
487
+ debug("foundRHS!\n");
488
+
489
+ if (mpz_sgn(lhs->m) == 0) {
490
+ result = mpz_cmp(lhs->e, rhs_mpz);
491
+ } else {
492
+ mpz_init(l);
493
+ mpz_mod(l, lhs->e, lhs->m);
494
+ result = mpz_cmp(l, rhs_mpz);
495
+ mpz_clear(l);
496
+ }
497
+ } else {
498
+ debug("Modulus equal? %d =?= 0\n", mpz_cmp(lhs->m, rhs->m));
499
+ if (mpz_sgn(lhs->m) == 0 && mpz_sgn(rhs->m) == 0) {
500
+ // comparing ints without a modulous
501
+ result = mpz_cmp(lhs->e, rhs->e);
502
+ }
503
+ else if (mpz_cmp(lhs->m, rhs->m) == 0) {
504
+ // comparing ints with a modolus that are equal
505
+ mpz_init(l);
506
+ mpz_init(r);
507
+ mpz_mod(l, lhs->e, lhs->m);
508
+ mpz_mod(r, rhs->e, rhs->m);
509
+ result = mpz_cmp(l, r);
510
+ mpz_clear(l);
511
+ mpz_clear(r);
512
+ }
513
+ else {
514
+ mpz_clear(lhs_mpz);
515
+ mpz_clear(rhs_mpz);
516
+ ErrorMsg("cannot compare integers with different modulus.");
517
+ }
518
+ }
519
+ mpz_clear(lhs_mpz);
520
+ mpz_clear(rhs_mpz);
521
+
522
+ if(opid == Py_EQ) {
523
+ if(result == 0) Py_RETURN_TRUE;
524
+ else Py_RETURN_FALSE;
525
+ }
526
+ else if(opid == Py_NE) { /* Py_NE */
527
+ if(result != 0) Py_RETURN_TRUE;
528
+ else Py_RETURN_FALSE;
529
+ }
530
+ else if(opid == Py_LT) {
531
+ if(result < 0) Py_RETURN_TRUE;
532
+ else Py_RETURN_FALSE;
533
+ }
534
+ else if(opid == Py_LE) {
535
+ if(result <= 0) Py_RETURN_TRUE;
536
+ else Py_RETURN_FALSE;
537
+ }
538
+ else if(opid == Py_GT) {
539
+ if(result > 0) Py_RETURN_TRUE;
540
+ else Py_RETURN_FALSE;
541
+ }
542
+ else if(opid == Py_GE) {
543
+ if(result >= 0) Py_RETURN_TRUE;
544
+ else Py_RETURN_FALSE;
545
+ }
546
+
547
+ ErrorMsg("unexpected comparison operator.");
548
+ }
549
+
550
+ PyObject *Integer_print(Integer *self) {
551
+ PyObject *strObject = NULL;
552
+ if (self->initialized) {
553
+ size_t e_size = mpz_sizeinbase(self->e, 10) + 2;
554
+ char *e_str = (char *) malloc(e_size);
555
+ if (e_str == NULL) return NULL;
556
+ mpz_get_str(e_str, 10, self->e);
557
+
558
+ if (mpz_sgn(self->m) != 0) {
559
+ size_t m_size = mpz_sizeinbase(self->m, 10) + 2;
560
+ char *m_str = (char *) malloc(m_size);
561
+ if (m_str == NULL) {
562
+ free(e_str);
563
+ return NULL;
564
+ }
565
+ mpz_get_str(m_str, 10, self->m);
566
+ strObject = PyUnicode_FromFormat("%s mod %s", (const char *) e_str,
567
+ (const char *) m_str);
568
+ free(m_str);
569
+ } else {
570
+ strObject = PyUnicode_FromFormat("%s", (const char *) e_str);
571
+ }
572
+ free(e_str);
573
+ return strObject;
574
+ }
575
+ //
576
+ // if (self->state_init) {
577
+ // return PyUnicode_FromString("");
578
+ // }
579
+
580
+ PyErr_SetString(IntegerError, "invalid integer object.");
581
+ return NULL;
582
+ }
583
+
584
+ Integer *createNewInteger() {
585
+ Integer *newObject = PyObject_New(Integer, &IntegerType);
586
+ //mpz_init(newObject->e);
587
+ //mpz_init_set(newObject->m, m);
588
+ newObject->initialized = TRUE;
589
+ return newObject;
590
+ }
591
+
592
+ //Integer *createNewIntegerNoMod(void) {
593
+ // Integer *newObject = PyObject_New(Integer, &IntegerType);
594
+ //
595
+ // //mpz_init(newObject->e);
596
+ // //mpz_init(newObject->m);
597
+ // newObject->initialized = TRUE;
598
+ //
599
+ // return newObject;
600
+ //}
601
+
602
+ static PyObject *Integer_set(Integer *self, PyObject *args) {
603
+ PyObject *obj = NULL;
604
+ Integer *intObj = NULL;
605
+
606
+ if (PyArg_ParseTuple(args, "O", &obj)) {
607
+
608
+ if (PyInteger_Check(obj)) {
609
+ intObj = (Integer *) obj;
610
+ self->initialized = TRUE;
611
+ mpz_set(self->e, intObj->e);
612
+ mpz_set(self->m, intObj->m);
613
+ return Py_BuildValue("i", TRUE);
614
+ }
615
+ }
616
+
617
+ return Py_BuildValue("i", FALSE);
618
+ }
619
+
620
+ static PyObject *Integer_add(PyObject *o1, PyObject *o2) {
621
+ // determine type of each side
622
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
623
+ int foundLHS = FALSE, foundRHS = FALSE, errorOccured = FALSE;
624
+ mpz_t lhs_mpz, rhs_mpz;
625
+ mpz_init(lhs_mpz);
626
+ mpz_init(rhs_mpz);
627
+
628
+ Convert_Types(o1, o2, lhs, rhs, foundLHS, foundRHS, lhs_mpz, rhs_mpz, errorOccured);
629
+ // perform operation
630
+ if(errorOccured) {
631
+ mpz_clear(lhs_mpz);
632
+ mpz_clear(rhs_mpz);
633
+ ErrorMsg("invalid left or right operand type.");
634
+ }
635
+ else if (foundLHS) {
636
+ //debug("foundLHS\n");
637
+ if(mpz_sgn(rhs->m) == 0) { // mpz_sgn(lhs_mpz) > 0
638
+ rop = createNewInteger();
639
+ mpz_init(rop->e);
640
+ mpz_init(rop->m);
641
+ mpz_add(rop->e, lhs_mpz, rhs->e);
642
+ }
643
+ else {
644
+ // operation: a + b % n = c... no longer allowed
645
+ ErrorMsg("unsupported operation.");
646
+ }
647
+ } else if (foundRHS) {
648
+ // debug("foundRHS!\n");
649
+ if(mpz_sgn(lhs->m) == 0) {
650
+ rop = createNewInteger();
651
+ mpz_init(rop->e);
652
+ mpz_init(rop->m);
653
+ mpz_add(rop->e, lhs->e, rhs_mpz);
654
+ }
655
+ else {
656
+ // operation: a % n + b ... are no longer allowed
657
+ ErrorMsg("unsupported operation.");
658
+ }
659
+ } else {
660
+ // debug("Modulus equal? %d =?= 0\n", mpz_cmp(lhs->m, rhs->m));
661
+ if (mpz_cmp(lhs->m, rhs->m) == 0) {
662
+ rop = createNewInteger();
663
+ mpz_init(rop->e);
664
+ mpz_init_set(rop->m, lhs->m);
665
+ mpz_add(rop->e, lhs->e, rhs->e);
666
+ } else {
667
+ EXIT_IF(TRUE, "cannot add integers with different modulus.");
668
+ }
669
+ }
670
+
671
+ // if(mpz_sgn(rop->e) < 0 || mpz_cmp(rop->e, rop->m) > 0) {
672
+ // _reduce(rop);
673
+ // }
674
+
675
+ #ifdef BENCHMARK_ENABLED
676
+ UPDATE_BENCHMARK(ADDITION, tmpBench);
677
+ #endif
678
+ return (PyObject *) rop;
679
+ }
680
+
681
+ static PyObject *Integer_sub(PyObject *o1, PyObject *o2) {
682
+ // determine type of each side
683
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
684
+ int foundLHS = FALSE, foundRHS = FALSE, errorOccured = FALSE;
685
+ mpz_t lhs_mpz, rhs_mpz;
686
+ mpz_init(lhs_mpz);
687
+ mpz_init(rhs_mpz);
688
+
689
+ Convert_Types(o1, o2, lhs, rhs, foundLHS, foundRHS, lhs_mpz, rhs_mpz, errorOccured);
690
+ // perform operation
691
+ if(errorOccured) {
692
+ mpz_clear(lhs_mpz);
693
+ mpz_clear(rhs_mpz);
694
+ ErrorMsg("invalid left or right operand type.");
695
+ }
696
+ else if (foundLHS) {
697
+ // debug("foundLHS\n");
698
+ if(mpz_sgn(rhs->m) == 0) { // mpz_sgn(lhs_mpz) > 0
699
+ rop = createNewInteger();
700
+ mpz_init(rop->e);
701
+ mpz_init(rop->m);
702
+ mpz_sub(rop->e, lhs_mpz, rhs->e);
703
+ }
704
+ else {
705
+ // operation: a - b % n = c... no longer allowed
706
+ ErrorMsg("unsupported operation.");
707
+ }
708
+ } else if (foundRHS) {
709
+ // debug("foundRHS!\n");
710
+ if(mpz_sgn(lhs->m) == 0) {
711
+ rop = createNewInteger();
712
+ mpz_init(rop->e);
713
+ mpz_init(rop->m);
714
+ mpz_sub(rop->e, lhs->e, rhs_mpz);
715
+ }
716
+ else {
717
+ // operation: a % n - b ... are no longer allowed
718
+ ErrorMsg("unsupported operation.");
719
+ }
720
+ } else {
721
+ // debug("Modulus equal? %d =?= 0\n", mpz_cmp(lhs->m, rhs->m));
722
+ if (mpz_cmp(lhs->m, rhs->m) == 0) {
723
+ rop = createNewInteger();
724
+ mpz_init(rop->e);
725
+ mpz_init_set(rop->m, lhs->m);
726
+ mpz_sub(rop->e, lhs->e, rhs->e);
727
+ } else {
728
+ EXIT_IF(TRUE,"cannot subtract integers with different modulus.");
729
+ }
730
+ }
731
+
732
+ mpz_clear(lhs_mpz);
733
+ mpz_clear(rhs_mpz);
734
+ if(mpz_sgn(rop->e) < 0) {
735
+ mpz_add(rop->e, rop->e, rop->m);
736
+ }
737
+ #ifdef BENCHMARK_ENABLED
738
+ UPDATE_BENCHMARK(SUBTRACTION, tmpBench);
739
+ #endif
740
+ return (PyObject *) rop;
741
+ }
742
+
743
+ static PyObject *Integer_mul(PyObject *o1, PyObject *o2) {
744
+ // determine type of each side
745
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
746
+ int foundLHS = FALSE, foundRHS = FALSE, errorOccured = FALSE;
747
+ // long lhs_value = 0, rhs_value = 0;
748
+ mpz_t lhs_mpz, rhs_mpz;
749
+ mpz_init(lhs_mpz);
750
+ mpz_init(rhs_mpz);
751
+
752
+ Convert_Types(o1, o2, lhs, rhs, foundLHS, foundRHS, lhs_mpz, rhs_mpz, errorOccured);
753
+ // perform operation
754
+ if(errorOccured) {
755
+ mpz_clear(lhs_mpz);
756
+ mpz_clear(rhs_mpz);
757
+ ErrorMsg("invalid left or right operand type.");
758
+ }
759
+ else if (foundLHS) {
760
+ //debug("foundLHS\n");
761
+ if(mpz_sgn(rhs->m) == 0) { // mpz_sgn(lhs_mpz) > 0
762
+ rop = createNewInteger();
763
+ mpz_init(rop->e);
764
+ mpz_init(rop->m);
765
+ mpz_mul(rop->e, lhs_mpz, rhs->e);
766
+ }
767
+ else {
768
+ // operation: a * b % n = c... no longer allowed
769
+ ErrorMsg("unsupported operation.");
770
+ }
771
+ } else if (foundRHS) {
772
+ // debug("foundRHS!\n");
773
+ if(mpz_sgn(lhs->m) == 0) {
774
+ rop = createNewInteger();
775
+ mpz_init(rop->e);
776
+ mpz_init(rop->m);
777
+ mpz_mul(rop->e, lhs->e, rhs_mpz);
778
+ }
779
+ else {
780
+ // operation: a % n * b ... are no longer allowed
781
+ ErrorMsg("unsupported operation.");
782
+ }
783
+ } else {
784
+ // debug("Modulus equal? %d =?= 0\n", mpz_cmp(lhs->m, rhs->m));
785
+ // if modulus is equal
786
+ if (mpz_cmp(lhs->m, rhs->m) == 0) {
787
+ // compute ((lhs % m) * (rhs % m)) % m (reduce before)
788
+ rop = createNewInteger();
789
+ mpz_init_set(rop->e, lhs->e);
790
+ mpz_init_set(rop->m, lhs->m);
791
+ mpz_mul(rop->e, rop->e, rhs->e);
792
+ }
793
+ else {
794
+ EXIT_IF(TRUE, "invalid operation - integers with different or no modulus.");
795
+ }
796
+ }
797
+
798
+ mpz_clear(lhs_mpz);
799
+ mpz_clear(rhs_mpz);
800
+ // _reduce(rop);
801
+ #ifdef BENCHMARK_ENABLED
802
+ UPDATE_BENCHMARK(MULTIPLICATION, tmpBench);
803
+ #endif
804
+ return (PyObject *) rop;
805
+ }
806
+
807
+ static PyObject *Integer_invert(PyObject *o1) {
808
+ Integer *base = NULL, *rop = NULL;
809
+ if (PyInteger_Check(o1)) {
810
+ // let's try to compute inverse
811
+ base = (Integer *) o1;
812
+ if (base->initialized) {
813
+ rop = createNewInteger();
814
+ mpz_init(rop->e);
815
+ mpz_init_set(rop->m, base->m);
816
+ int errcode = mpz_invert(rop->e, base->e, base->m);
817
+ if (errcode > 0) {
818
+ return (PyObject *) rop;
819
+ }
820
+ Py_DECREF(rop);
821
+ EXIT_IF(TRUE, "could not find a modular inverse");
822
+ }
823
+ }
824
+ EXIT_IF(TRUE, "not an integer object type.");
825
+ }
826
+
827
+ static PyObject *Integer_long(PyObject *o1) {
828
+ if (PyInteger_Check(o1)) {
829
+ Integer *value = (Integer *) o1;
830
+ if (mpz_sgn(value->m) != 0)
831
+ _reduce(value);
832
+ return mpzToLongObj(value->e);
833
+ }
834
+
835
+ EXIT_IF(TRUE, "invalid argument.");
836
+ }
837
+
838
+ static PyObject *Integer_reduce(PyObject *self, PyObject *args) {
839
+ if (PyInteger_Check(args)) {
840
+ Integer *in = (Integer *) args;
841
+ if(in->initialized) {
842
+ Integer *rop = createNewInteger();
843
+ mpz_init_set(rop->e, in->e);
844
+ mpz_init_set(rop->m, in->m);
845
+ if (mpz_sgn(rop->m) != 0)
846
+ _reduce(rop);
847
+ return (PyObject *) rop;
848
+ }
849
+ }
850
+
851
+ EXIT_IF(TRUE, "invalid argument.");
852
+ }
853
+
854
+
855
+ /** a / b mod N ...
856
+ * only defined when b is invertible modulo N, meaning a*b mod N = c*b mod N iff b has b^-1 s.t.
857
+ * b*b^-1 = 1 mod N.
858
+ */
859
+ static PyObject *Integer_div(PyObject *o1, PyObject *o2) {
860
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
861
+ int foundLHS = FALSE, foundRHS = FALSE, errorOccured = FALSE;
862
+ mpz_t lhs_mpz, rhs_mpz;
863
+ mpz_init(lhs_mpz);
864
+ mpz_init(rhs_mpz);
865
+
866
+ Convert_Types(o1, o2, lhs, rhs, foundLHS, foundRHS, lhs_mpz, rhs_mpz, errorOccured);
867
+ // perform operation
868
+ if(errorOccured) {
869
+ mpz_clear(lhs_mpz);
870
+ mpz_clear(rhs_mpz);
871
+ ErrorMsg("invalid left or right operand type.");
872
+ }
873
+ else if (foundRHS && mpz_sgn(rhs_mpz) > 0) {
874
+ /* Let d = gcd(a, n). The congruence equation ax = b (mod n) has a solution x if and only if d divides b,
875
+ * in which case there are exactly d solutions between [0, n-1] these solutions are all congruent modulo n/d. */
876
+ rop = createNewInteger();
877
+ mpz_init_set(rop->e, lhs->e);
878
+ mpz_init_set(rop->m, lhs->m);
879
+ if (mpz_divisible_p(lhs->e, rhs_mpz) != 0) {
880
+ if (mpz_sgn(lhs->m) == 0) {
881
+ mpz_divexact(rop->e, lhs->e, rhs_mpz);
882
+ }
883
+ }
884
+ else if(mpz_sgn(rop->m) > 0 && mpz_cmp_ui(rhs_mpz, 1) == 0) {
885
+ mpz_mod(rop->e, rop->e, rop->m);
886
+ if(mpz_cmp(rop->e, rop->m) < 0) { // check if e < m, then divide e / rhs_value.
887
+ // EXIT_IF(TRUE, "unimplemented operation.");
888
+ // mpz_init_set_ui(tmp, lhs_value);
889
+ // mpz_gcd(tmp, tmp, rop->m);
890
+ // mpz_div(rop->e, tmp, rop->e);
891
+ // mpz_clear(tmp);
892
+ }
893
+ }
894
+ } else if (foundLHS && mpz_sgn(lhs_mpz) > 0) {
895
+ rop = createNewInteger();
896
+ mpz_init(rop->e);
897
+ int rhs_mod = mpz_sgn(rhs->m);
898
+ if(rhs_mod > 0) {
899
+ mpz_init_set(rop->m, rhs->m);
900
+ int errcode = mpz_invert(rop->e, rhs->e, rhs->m);
901
+ if(errcode == 0) {
902
+ Py_DECREF(rop);
903
+ mpz_clear(lhs_mpz);
904
+ mpz_clear(rhs_mpz);
905
+ ErrorMsg("division failed: could not find modular inverse.\n");
906
+ }
907
+
908
+ if(mpz_cmp_ui(lhs_mpz, 1) != 0) {
909
+ mpz_mul(rop->e, lhs_mpz, rop->e);
910
+ mpz_mod(rop->e, rop->e, rop->m);
911
+ }
912
+ }
913
+ else if(rhs_mod == 0 && mpz_divisible_p(lhs_mpz, rhs->e) != 0) {
914
+ rop = createNewInteger();
915
+ mpz_init(rop->e);
916
+ mpz_init_set(rop->m, rhs->m);
917
+ mpz_divexact(rop->e, lhs_mpz, rhs->e);
918
+ }
919
+ } else {
920
+ // printf("lhs and rhs init? => ");
921
+ if (mpz_cmp(lhs->m, rhs->m) == 0 && mpz_sgn(lhs->m) > 0) {
922
+ mpz_t rhs_inv;
923
+ mpz_init(rhs_inv);
924
+ mpz_invert(rhs_inv, rhs->e, rhs->m);
925
+ debug("rhs_inv...\n");
926
+ print_mpz(rhs_inv, 10);
927
+
928
+ rop = createNewInteger();
929
+ mpz_init(rop->e);
930
+ mpz_init_set(rop->m, lhs->m);
931
+ mpz_mul(rop->e, lhs->e, rhs_inv);
932
+ mpz_mod(rop->e, rop->e, rop->m);
933
+ mpz_clear(rhs_inv);
934
+ } else if (mpz_cmp(lhs->m, rhs->m) == 0 && mpz_sgn(lhs->m) == 0) {
935
+ rop = createNewInteger();
936
+ mpz_init(rop->e);
937
+ mpz_init_set(rop->m, lhs->m);
938
+ mpz_div(rop->e, lhs->e, rhs->e);
939
+ }
940
+ }
941
+
942
+ mpz_clear(lhs_mpz);
943
+ mpz_clear(rhs_mpz);
944
+ if (rop != NULL && mpz_sgn(rop->e) == 0) {
945
+ //PyObject_Del(rop);
946
+ Py_DECREF(rop);
947
+ EXIT_IF(TRUE, "division failed: could not find modular inverse.");
948
+ }
949
+ #ifdef BENCHMARK_ENABLED
950
+ UPDATE_BENCHMARK(DIVISION, tmpBench);
951
+ #endif
952
+ return (PyObject *) rop;
953
+ }
954
+
955
+ static PyObject *Integer_pow(PyObject *o1, PyObject *o2, PyObject *o3) {
956
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
957
+ int foundLHS = FALSE, foundRHS = FALSE;
958
+ mpz_t exponent;
959
+ mpz_init(exponent);
960
+
961
+ Convert_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
962
+ // TODO: handle foundLHS (e.g. 2 ** <int.Elem>)
963
+ if (foundRHS) {
964
+ debug("foundRHS!\n");
965
+ // long rhs = PyLong_AsLong(o2);
966
+ longObjToMPZ(exponent, o2);
967
+
968
+ if(PyErr_Occurred() || mpz_sgn(exponent) >= 0) {
969
+ //PyErr_Print(); // for debug purposes
970
+ PyErr_Clear();
971
+ debug("exponent is positive\n");
972
+ int sgn = mpz_sgn(lhs->m);
973
+ if(sgn > 0) {
974
+ if(mpz_odd_p(lhs->m) > 0) {
975
+ // mpz_t exp;
976
+ // mpz_init(exp);
977
+ // longObjToMPZ(exp, o2);
978
+ // print_mpz(exp, 10);
979
+ rop = createNewInteger();
980
+ mpz_init(rop->e);
981
+ mpz_init_set(rop->m, lhs->m);
982
+ mpz_powm_sec(rop->e, lhs->e, exponent, rop->m);
983
+ }
984
+ }
985
+ else if(sgn == 0) { // no modulus
986
+ unsigned long int exp = PyLong_AsUnsignedLong(o2);
987
+ EXIT_IF(PyErr_Occurred(), "integer too large to exponentiate without modulus.");
988
+ rop = createNewInteger();
989
+ mpz_init(rop->e);
990
+ mpz_init_set(rop->m, lhs->m);
991
+ mpz_pow_ui(rop->e, lhs->e, exp);
992
+ }
993
+ else {
994
+ mpz_clear(exponent);
995
+ EXIT_IF(TRUE, "cannot exponentiate integers without modulus.");
996
+ }
997
+ }
998
+ else if(mpz_cmp_si(exponent, -1) == 0) {
999
+ debug("find modular inverse.\n");
1000
+ rop = createNewInteger();
1001
+ mpz_init(rop->e);
1002
+ mpz_init_set(rop->m, lhs->m);
1003
+ int errcode = mpz_invert(rop->e, lhs->e, lhs->m);
1004
+ if(errcode == 0) {
1005
+ Py_XDECREF(rop);
1006
+ mpz_clear(exponent);
1007
+ ErrorMsg("failed to find modular inverse.\n");
1008
+ }
1009
+ }
1010
+ else {
1011
+ // less than -1.
1012
+ rop = createNewInteger();
1013
+ mpz_init(rop->e);
1014
+ mpz_init_set(rop->m, lhs->m);
1015
+ int errcode = mpz_invert(rop->e, lhs->e, rop->m);
1016
+ if(errcode > 0) {
1017
+ mpz_neg(exponent, exponent);
1018
+ mpz_powm_sec(rop->e, rop->e, exponent, rop->m);
1019
+ }
1020
+ else {
1021
+ mpz_clear(exponent);
1022
+ Py_XDECREF(rop);
1023
+ ErrorMsg("failed to find modular inverse.\n");
1024
+ }
1025
+ }
1026
+ mpz_clear(exponent);
1027
+ } else if (foundLHS) {
1028
+ mpz_clear(exponent);
1029
+ ErrorMsg("unsupported operation: left operand expected to be a charm.integer type.");
1030
+ } else {
1031
+ // if rhs has negative exponent
1032
+ if (mpz_sgn(rhs->e) < 0) {
1033
+ if(mpz_sgn(lhs->m) > 0) {
1034
+ // base modulus is positive
1035
+ rop = createNewInteger();
1036
+ mpz_init(rop->e);
1037
+ mpz_init_set(rop->m, lhs->m);
1038
+ int errcode = mpz_invert(rop->e, lhs->e, rop->m);
1039
+ if(errcode > 0) {
1040
+ mpz_t exp;
1041
+ mpz_init_set(exp, rhs->e);
1042
+ mpz_neg(exp, exp);
1043
+ mpz_powm_sec(rop->e, rop->e, exp, rop->m);
1044
+ mpz_clear(exp);
1045
+ goto leave;
1046
+ }
1047
+ else {
1048
+ mpz_clear(exponent);
1049
+ Py_XDECREF(rop);
1050
+ ErrorMsg("failed to find modular inverse.\n");
1051
+ }
1052
+ }
1053
+ }
1054
+
1055
+ // result takes modulus of base
1056
+ debug("both integer objects: ");
1057
+ if (mpz_sgn(lhs->m) > 0) {
1058
+ // common case for modular exponentiation
1059
+ rop = createNewInteger();
1060
+ mpz_init(rop->e);
1061
+ mpz_init_set(rop->m, lhs->m);
1062
+ mpz_powm_sec(rop->e, lhs->e, rhs->e, rop->m);
1063
+ }
1064
+ // lhs is a reg int
1065
+ else if (mpz_fits_ulong_p(lhs->e) && mpz_fits_ulong_p(rhs->e)) {
1066
+ // convert base (lhs) to an unsigned long (if possible)
1067
+ unsigned long int base = mpz_get_ui(lhs->e);
1068
+ unsigned long int exp = mpz_get_ui(rhs->e);
1069
+ rop = createNewInteger();
1070
+ mpz_init(rop->e);
1071
+ mpz_init(rop->m);
1072
+ mpz_ui_pow_ui(rop->e, base, exp);
1073
+ }
1074
+ // lhs reg int and rhs can be represented as ulong
1075
+ else if (mpz_fits_ulong_p(rhs->e)) {
1076
+ unsigned long int exp = mpz_get_ui(rhs->e);
1077
+ rop = createNewInteger();
1078
+ mpz_init(rop->e);
1079
+ mpz_init(rop->m);
1080
+ mpz_pow_ui(rop->e, lhs->e, exp);
1081
+ } else { // last option...
1082
+ // cannot represent reg ints as ulong's, so error out.
1083
+ EXIT_IF(TRUE, "could not exponentiate integers.");
1084
+ }
1085
+ }
1086
+
1087
+ leave:
1088
+ #ifdef BENCHMARK_ENABLED
1089
+ UPDATE_BENCHMARK(EXPONENTIATION, tmpBench);
1090
+ #endif
1091
+ return (PyObject *) rop;
1092
+ }
1093
+
1094
+ /*
1095
+ * Description: hash elements into a group element
1096
+ * inputs: group elements, p, q, and True or False
1097
+ * (return value mod p when TRUE and value mod q when FALSE)
1098
+ */
1099
+ static PyObject *Integer_hash(PyObject *self, PyObject *args) {
1100
+ PyObject *object, *order, *order2;
1101
+ Integer *pObj, *qObj;
1102
+ uint8_t *rop_buf = NULL;
1103
+ mpz_t p, q, v, tmp;
1104
+ mpz_init(p);
1105
+ mpz_init(q);
1106
+ mpz_init(v);
1107
+ mpz_init(tmp);
1108
+ int modP = FALSE;
1109
+
1110
+ if (PyArg_ParseTuple(args, "OOO|i", &object, &order, &order2, &modP)) {
1111
+ // one single integer group element
1112
+ if (PyInteger_Check(order) && PyInteger_Check(order2)) {
1113
+ pObj = (Integer *) order;
1114
+ qObj = (Integer *) order2;
1115
+ mpz_set(p, pObj->e);
1116
+ mpz_set(q, qObj->e);
1117
+ mpz_mul_ui(tmp, q, 2);
1118
+ mpz_add_ui(tmp, tmp, 1);
1119
+
1120
+ if (mpz_cmp(tmp, p) != 0) {
1121
+ PyErr_SetString(IntegerError,
1122
+ "can only encode messages into groups where p = 2*q+1.");
1123
+ goto cleanup;
1124
+ }
1125
+ } else {
1126
+ PyErr_SetString(IntegerError,
1127
+ "failed to specify large primes p and q.");
1128
+ goto cleanup;
1129
+ }
1130
+
1131
+ int i, object_size = PySequence_Length(object);
1132
+
1133
+ // dealing with a tuple element here...
1134
+ if (object_size > 0) {
1135
+
1136
+ int o_size = 0;
1137
+ // get length of all objects
1138
+ for (i = 0; i < object_size; i++) {
1139
+ PyObject *tmpObject = PySequence_GetItem(object, i);
1140
+ if (PyInteger_Check(tmpObject)) {
1141
+ Integer *object1 = (Integer *) tmpObject;
1142
+ if (object1->initialized) {
1143
+ o_size += size(object1->e);
1144
+ }
1145
+ }
1146
+ Py_XDECREF(tmpObject);
1147
+ }
1148
+
1149
+ /* allocate space big enough to hold exported objects */
1150
+ rop_buf = (uint8_t *) malloc(o_size + 1);
1151
+ if (rop_buf == NULL) return NULL;
1152
+ memset(rop_buf, 0, o_size);
1153
+ int cur_ptr = 0;
1154
+ /* export objects here using mpz_export into allocated buffer */
1155
+ for (i = 0; i < object_size; i++) {
1156
+ PyObject *tmpObject = PySequence_GetItem(object, i);
1157
+
1158
+ if (PyInteger_Check(tmpObject)) {
1159
+ Integer *tmpObject2 = (Integer *) tmpObject;
1160
+ if (tmpObject2->initialized) {
1161
+ uint8_t *target_ptr = (uint8_t *) (rop_buf + cur_ptr);
1162
+ size_t len = 0;
1163
+ mpz_export(target_ptr, &len, 1, sizeof(char), 0, 0,
1164
+ tmpObject2->e);
1165
+ cur_ptr += size(tmpObject2->e);
1166
+ }
1167
+ }
1168
+ Py_XDECREF(tmpObject);
1169
+ }
1170
+
1171
+ // hash the buffer
1172
+ uint8_t hash_buf2[HASH_LEN + 1];
1173
+ hash_to_bytes(rop_buf, o_size, hash_buf2, HASH_LEN,
1174
+ HASH_FUNCTION_KEM_DERIVE);
1175
+ free(rop_buf);
1176
+
1177
+ // mpz_import hash to a element from 1 to q-1 inclusive.
1178
+ mpz_import(tmp, HASH_LEN, 1, sizeof(hash_buf2[0]), 0, 0, hash_buf2);
1179
+ // now hash to match desired output size of q.
1180
+ if (modP)
1181
+ mpz_mod(tmp, tmp, p);
1182
+ else
1183
+ mpz_mod(tmp, tmp, q);
1184
+ debug("print group tuple...\n");
1185
+ print_mpz(tmp, 2);
1186
+
1187
+ // calculate ceiling |q|/160 => blocks
1188
+ int i, blocks = ceil((double) size(q) / (HASH_LEN * 8));
1189
+ debug("blocks => '%d'\n", blocks);
1190
+ size_t out_len = HASH_LEN * blocks;
1191
+ uint8_t out_buf[(out_len * 2) + 1];
1192
+ memset(out_buf, 0, out_len*2);
1193
+
1194
+ if (blocks > 1) {
1195
+ for (i = 1; i <= blocks; i++) {
1196
+ // how to add num in front of tmp_buf?
1197
+ // compute sha1( i || tmp_buf ) ->
1198
+ uint8_t *ptr = (uint8_t *) &out_buf[HASH_LEN * i];
1199
+ debug("pointer to block => '%p\n", ptr);
1200
+ // doesn't work like this yet
1201
+ hash_to_group_element(tmp, i, ptr);
1202
+ }
1203
+ } else {
1204
+ debug("Only 1 block to hash.\n");
1205
+ hash_to_group_element(tmp, -1, out_buf);
1206
+ }
1207
+
1208
+ debug("print out_len => '%zd'\n", out_len);
1209
+ debug("print out_buf...\n");
1210
+ printf_buffer_as_hex(out_buf, out_len);
1211
+ // convert v' to mpz_t type mod q => v
1212
+ mpz_import(v, out_len, 1, sizeof(char), 0, 0, out_buf);
1213
+ mpz_t modulus;
1214
+ if (modP) {
1215
+ // v = v' mod p
1216
+ debug("doing mod p\n");
1217
+ mpz_mod(v, v, p);
1218
+ // y = v^2 mod q
1219
+ mpz_powm_ui(v, v, 2, q);
1220
+ mpz_init_set(modulus, q);
1221
+ } else {
1222
+ debug("doing mod q\n");
1223
+ mpz_mod(v, v, q);
1224
+ // y = v^2 mod p : return y mod p
1225
+ mpz_powm_ui(v, v, 2, p);
1226
+ mpz_init_set(modulus, p);
1227
+ }
1228
+ debug("print v => \n");
1229
+ print_mpz(v, 10);
1230
+ Integer *rop = createNewInteger();
1231
+ mpz_init_set(rop->e, v);
1232
+ mpz_init_set(rop->m, modulus);
1233
+ mpz_clear(p);
1234
+ mpz_clear(q);
1235
+ mpz_clear(v);
1236
+ mpz_clear(tmp);
1237
+ mpz_clear(modulus);
1238
+ return (PyObject *) rop;
1239
+ } else { /* non-tuple element - maybe single element? */
1240
+ Integer *obj = (Integer *) object;
1241
+
1242
+ // make sure object was initialized
1243
+ if (!obj->initialized) {
1244
+ PyErr_SetString(IntegerError, "integer object not initialized.");
1245
+ goto cleanup;
1246
+ }
1247
+ // not a group element
1248
+ if (mpz_cmp(p, obj->m) != 0) {
1249
+ PyErr_SetString(IntegerError,
1250
+ "integer object not a group element.");
1251
+ goto cleanup;
1252
+ }
1253
+
1254
+ // mpz_export base to a string (ignore modulus) => val
1255
+ size_t count = 0;
1256
+ rop_buf = (uint8_t *) mpz_export(NULL, &count, 1, sizeof(char), 0,
1257
+ 0, obj->e);
1258
+
1259
+ // hash the buffer
1260
+ uint8_t hash_buf[HASH_LEN + 1];
1261
+ hash_to_bytes(rop_buf, (int) count, hash_buf, HASH_LEN,
1262
+ HASH_FUNCTION_KEM_DERIVE);
1263
+
1264
+ // mpz_import hash to a element from 1 to q-1 inclusive.
1265
+ mpz_import(tmp, HASH_LEN, 1, sizeof(hash_buf[0]), 0, 0, hash_buf);
1266
+ // now hash to match desired output size of q.
1267
+ if (modP)
1268
+ mpz_mod(tmp, tmp, p);
1269
+ else
1270
+ mpz_mod(tmp, tmp, q);
1271
+ print_mpz(tmp, 2);
1272
+
1273
+ // calculate ceiling |q|/160 => blocks
1274
+ int i, blocks = ceil((double) size(q) / (HASH_LEN * 8));
1275
+ debug("blocks => '%d'\n", blocks);
1276
+ size_t out_len = HASH_LEN * blocks;
1277
+ uint8_t out_buf[out_len + 4];
1278
+ memset(out_buf, 0, out_len);
1279
+
1280
+ for (i = 0; i < blocks; i++) {
1281
+ // how to add num in front of tmp_buf?
1282
+ // compute sha1( i || tmp_buf ) ->
1283
+ uint8_t *ptr = (uint8_t *) &out_buf[HASH_LEN * i];
1284
+ debug("pointer to block => '%p\n", ptr);
1285
+ // doesn't work like this yet
1286
+ hash_to_group_element(tmp, i, ptr);
1287
+ }
1288
+
1289
+ // convert v' to mpz_t type mod q => v
1290
+ mpz_import(v, out_len, 1, sizeof(out_buf[0]), 0, 0, out_buf);
1291
+ mpz_t modulus;
1292
+ if (modP) {
1293
+ // v = v' mod p
1294
+ debug("doing mod p");
1295
+ mpz_mod(v, v, p);
1296
+ // y = v^2 mod q
1297
+ mpz_powm_ui(v, v, 2, q);
1298
+ mpz_init_set(modulus, q);
1299
+ } else {
1300
+ debug("doing mod q");
1301
+ mpz_mod(v, v, q);
1302
+ // y = v^2 mod p : return y mod p
1303
+ mpz_powm_ui(v, v, 2, p);
1304
+ mpz_init_set(modulus, p);
1305
+ }
1306
+
1307
+ free(rop_buf);
1308
+ print_mpz(v, 10);
1309
+ Integer *rop = createNewInteger();
1310
+ mpz_init_set(rop->e, v);
1311
+ mpz_init_set(rop->e, modulus);
1312
+ mpz_clear(v);
1313
+ mpz_clear(p);
1314
+ mpz_clear(q);
1315
+ mpz_clear(tmp);
1316
+ mpz_clear(modulus);
1317
+ return (PyObject *) rop;
1318
+ }
1319
+ // a tuple of various elements
1320
+
1321
+ }
1322
+
1323
+ cleanup:
1324
+ mpz_clear(v);
1325
+ mpz_clear(p);
1326
+ mpz_clear(q);
1327
+ mpz_clear(tmp);
1328
+ return NULL;
1329
+
1330
+ }
1331
+
1332
+ //static PyObject *Integer_reduce(Integer *self, PyObject *arg) {
1333
+ //
1334
+ // if (!self->initialized) {
1335
+ // PyErr_SetString(IntegerError, "invalid integer object.");
1336
+ // Py_INCREF(Py_False);
1337
+ // return Py_False;
1338
+ // }
1339
+ //
1340
+ // _reduce(self);
1341
+ // Py_INCREF(Py_True);
1342
+ // return Py_True;
1343
+ //}
1344
+
1345
+ static PyObject *Integer_remainder(PyObject *o1, PyObject *o2) {
1346
+
1347
+ Integer *lhs = NULL, *rhs = NULL, *rop = NULL;
1348
+ int foundLHS = FALSE, foundRHS = FALSE;
1349
+
1350
+ Convert_Types2(o1, o2, lhs, rhs, foundLHS, foundRHS);
1351
+
1352
+ if (foundLHS) {
1353
+ rop = createNewInteger();
1354
+ mpz_init(rop->e);
1355
+ mpz_init_set(rop->m, rhs->m);
1356
+ if (_PyLong_Check(o1)) {
1357
+ PyObject *tmp = PyNumber_Long(o1);
1358
+ mpz_t e;
1359
+ mpz_init(e);
1360
+ longObjToMPZ(e, tmp);
1361
+ mpz_mod(rop->e, e, rhs->e);
1362
+ mpz_set(rop->m, rhs->e);
1363
+ mpz_clear(e);
1364
+ Py_XDECREF(tmp);
1365
+ } else if (PyInteger_Check(o1)) {
1366
+ Integer *tmp_mod = (Integer *) o1;
1367
+ // ignore the modulus of tmp_mod
1368
+ mpz_mod(rop->e, rhs->e, tmp_mod->e);
1369
+ mpz_set(rop->m, tmp_mod->e);
1370
+ }
1371
+ } else if (foundRHS) {
1372
+ rop = createNewInteger();
1373
+ mpz_init(rop->e);
1374
+ mpz_init_set(rop->m, lhs->m);
1375
+ if (_PyLong_Check(o2)) {
1376
+ PyObject *tmp = PyNumber_Long(o2);
1377
+ mpz_t modulus;
1378
+ mpz_init(modulus);
1379
+ longObjToMPZ(modulus, tmp);
1380
+ mpz_mod(rop->e, lhs->e, modulus);
1381
+ mpz_set(rop->m, modulus);
1382
+ mpz_clear(modulus);
1383
+ Py_XDECREF(tmp);
1384
+ }
1385
+ } else {
1386
+ rop = createNewInteger();
1387
+ mpz_init(rop->e);
1388
+ mpz_init_set(rop->m, rhs->e);
1389
+ mpz_mod(rop->e, lhs->e, rop->m);
1390
+ }
1391
+ return (PyObject *) rop;
1392
+ }
1393
+
1394
+ /* END: module function definitions */
1395
+
1396
+ /* START: helper function definition */
1397
+ //#define MAX_RABIN_MILLER_ROUNDS 255
1398
+
1399
+ static PyObject *testPrimality(PyObject *self, PyObject *arg) {
1400
+ int result = -1;
1401
+
1402
+ if (arg != NULL) {
1403
+ if (_PyLong_Check(arg)) {
1404
+ PyObject *obj = PyNumber_Long(arg);
1405
+ mpz_t value;
1406
+ mpz_init(value);
1407
+ longObjToMPZ(value, obj);
1408
+ result = mpz_probab_prime_p(value, MAX_RUN);
1409
+ mpz_clear(value);
1410
+ Py_XDECREF(obj);
1411
+ } else if (PyInteger_Check(arg)) {
1412
+ Integer *obj = (Integer *) arg;
1413
+ if (obj->initialized)
1414
+ result = mpz_probab_prime_p(obj->e, MAX_RUN);
1415
+ }
1416
+ }
1417
+
1418
+ if (result > 0) {
1419
+ debug("probably prime: %d\n", result);
1420
+ Py_INCREF(Py_True);
1421
+ return Py_True;
1422
+ } else if (result == 0) {
1423
+ debug("not prime.\n");
1424
+ Py_INCREF(Py_False);
1425
+ return Py_False;
1426
+ } else {
1427
+ PyErr_SetString(IntegerError, "invalid input.");
1428
+ return NULL;
1429
+ }
1430
+ }
1431
+
1432
+ static PyObject *genRandomBits(PyObject *self, PyObject *args) {
1433
+ unsigned int bits;
1434
+
1435
+ if (PyArg_ParseTuple(args, "i", &bits)) {
1436
+ if (bits > 0) {
1437
+ // generate random number that is in 0 to 2^n-1 range.
1438
+ // TODO: fix code very very soon!
1439
+ PyLongObject *v;
1440
+ unsigned char buff[sizeof(long)];
1441
+ long t;
1442
+ int ndigits = (bits + PyLong_SHIFT - 1) / PyLong_SHIFT;
1443
+ int digitsleft = ndigits;
1444
+ int bitsleft = bits;
1445
+
1446
+ v = _PyLong_New(ndigits);
1447
+ if (v != NULL) {
1448
+ digit *p = PythonLongVal(v);
1449
+ while (digitsleft > 1) {
1450
+ RAND_bytes(buff, sizeof(long));
1451
+ memcpy(&t, buff, sizeof(long));
1452
+ *p++ = (digit)(t & PyLong_MASK);
1453
+ digitsleft--;
1454
+ bitsleft -= PyLong_SHIFT;
1455
+ }
1456
+
1457
+ if (digitsleft == 1) {
1458
+ RAND_bytes(buff, sizeof(long));
1459
+ memcpy(&t, buff, sizeof(long));
1460
+ unsigned long mask = (1 << bitsleft) - 1;
1461
+ *p++ = (digit)(t & PyLong_MASK & mask);
1462
+ }
1463
+
1464
+ }
1465
+ return (PyObject *) v;
1466
+ }
1467
+ }
1468
+
1469
+ EXIT_IF(TRUE, "number of bits must be > 0.");
1470
+ }
1471
+
1472
+ static PyObject *genRandom(PyObject *self, PyObject *args) {
1473
+ PyObject *obj = NULL;
1474
+ Integer *rop = NULL;
1475
+ mpz_t N;
1476
+
1477
+ if (PyArg_ParseTuple(args, "O", &obj)) {
1478
+
1479
+ if (_PyLong_Check(obj)) {
1480
+ mpz_init(N);
1481
+ longObjToMPZ(N, obj);
1482
+ } else if (PyInteger_Check(obj)) {
1483
+ Integer *obj1 = (Integer *) obj;
1484
+ mpz_init_set(N, obj1->e);
1485
+ } else {
1486
+ /* error */
1487
+ EXIT_IF(TRUE, "invalid object type.");
1488
+ }
1489
+
1490
+ BIGNUM *s = BN_new(), *bN = BN_new();
1491
+ BN_one(s);
1492
+ mpzToBN(N, bN);
1493
+ rop = createNewInteger();
1494
+ mpz_init(rop->e);
1495
+ mpz_init_set(rop->m, N);
1496
+
1497
+ BN_rand_range(s, bN);
1498
+ bnToMPZ(s, rop->e);
1499
+ print_bn_dec(s);
1500
+ BN_free(s);
1501
+ BN_free(bN);
1502
+ mpz_clear(N);
1503
+ return (PyObject *) rop;
1504
+ }
1505
+ EXIT_IF(TRUE, "invalid arguments.");
1506
+ }
1507
+
1508
+ /* takes as input the number of bits and produces a prime number of that size. */
1509
+ static PyObject *genRandomPrime(PyObject *self, PyObject *args) {
1510
+ int bits, safe = FALSE;
1511
+
1512
+ if (PyArg_ParseTuple(args, "i|i", &bits, &safe)) {
1513
+ if (bits > 0) {
1514
+ // mpz_t tmp;
1515
+ Integer *rop = createNewInteger();
1516
+ mpz_init(rop->e);
1517
+ mpz_init(rop->m);
1518
+
1519
+ BIGNUM *bn = BN_new();
1520
+ /* This routine generates safe prime only when safe=TRUE in which prime, p is selected
1521
+ * iff (p-1)/2 is also prime.
1522
+ *
1523
+ * Use BN_generate_prime_ex() instead of deprecated BN_generate_prime().
1524
+ * This fixes Python 3.12+ hanging issues with prime generation.
1525
+ */
1526
+ int result;
1527
+ if(safe == TRUE) // safe is non-zero
1528
+ result = BN_generate_prime_ex(bn, bits, safe, NULL, NULL, NULL);
1529
+ else
1530
+ /* generate strong primes only */
1531
+ result = BN_generate_prime_ex(bn, bits, FALSE, NULL, NULL, NULL);
1532
+
1533
+ if (!result) {
1534
+ BN_free(bn);
1535
+ mpz_clear(rop->e);
1536
+ mpz_clear(rop->m);
1537
+ PyMem_Free(rop);
1538
+ EXIT_IF(TRUE, "BN_generate_prime_ex failed");
1539
+ }
1540
+
1541
+ debug("Safe prime => ");
1542
+ print_bn_dec(bn);
1543
+ bnToMPZ(bn, rop->e);
1544
+ BN_free(bn);
1545
+ return (PyObject *) rop;
1546
+ }
1547
+ }
1548
+
1549
+ EXIT_IF(TRUE, "invalid input.");
1550
+ }
1551
+
1552
+ static PyObject *encode_message(PyObject *self, PyObject *args) {
1553
+ //char *m; // handle arbitrary messages
1554
+ uint8_t *old_m;
1555
+ int m_size;
1556
+ PyObject *order, *order2, *old_msg;
1557
+ Integer *pObj, *qObj;
1558
+ mpz_t p, q, result;
1559
+ mpz_t tmp, exp, rop;
1560
+ Integer *rop2;
1561
+
1562
+ if (PyArg_ParseTuple(args, "OOO", &old_msg, &order, &order2)) {
1563
+ // make sure p = 2 * q + 1
1564
+ if (PyInteger_Check(order) && PyInteger_Check(order2)) {
1565
+ mpz_init(p);
1566
+ mpz_init(q);
1567
+ mpz_init(result);
1568
+
1569
+ pObj = (Integer *) order;
1570
+ qObj = (Integer *) order2;
1571
+ mpz_set(p, pObj->e);
1572
+ mpz_set(q, qObj->e);
1573
+ mpz_mul_ui(result, q, 2);
1574
+ mpz_add_ui(result, result, 1);
1575
+
1576
+ if (mpz_cmp(result, p) != 0) {
1577
+ mpz_clear(p);
1578
+ mpz_clear(q);
1579
+ mpz_clear(result);
1580
+ EXIT_IF(TRUE, "can only encode messages into groups where p = 2*q+1.");
1581
+ }
1582
+ } else {
1583
+ EXIT_IF(TRUE, "failed to specify large primes p and q.");
1584
+ }
1585
+ mpz_clear(q);
1586
+ mpz_clear(result);
1587
+
1588
+ // for python 3
1589
+ if(PyBytes_Check(old_msg)) {
1590
+ old_m = (uint8_t *) PyBytes_AS_STRING(old_msg);
1591
+ m_size = strlen((char *) old_m);
1592
+ debug("Message => ");
1593
+ printf_buffer_as_hex(old_m, m_size);
1594
+ debug("Size => '%d'\n", m_size);
1595
+
1596
+ if(m_size > MSG_LEN-2) {
1597
+ mpz_clear(p);
1598
+ EXIT_IF(TRUE, "message too large. Cannot represent as an element of Zp.");
1599
+ }
1600
+ }
1601
+ else {
1602
+ mpz_clear(p);
1603
+ EXIT_IF(TRUE, "message not a bytes object");
1604
+ }
1605
+
1606
+ //longest message can be is 128 characters (1024 bits) => check on this!!!
1607
+ char m[MSG_LEN+2]; //128 byte message, 1 byte length, null byte
1608
+ m[0] = m_size & 0xFF; //->this one works too...results in order 207
1609
+ snprintf((m+1), MSG_LEN+1, "%s", old_m); //copying message over
1610
+ m_size = m_size + 1; //we added an extra byte
1611
+
1612
+ // p and q values valid
1613
+ mpz_init(tmp);
1614
+ mpz_import(tmp, m_size, 1, sizeof(m[0]), 0, 0, m);
1615
+ // bytes_to_mpz(tmp2, (const unsigned char *) m, (size_t) m_size);
1616
+
1617
+ // perform encoding...
1618
+ // get the order object (only works for p = 2q + 1)
1619
+ mpz_init(exp);
1620
+ mpz_init(rop);
1621
+ mpz_add_ui(tmp, tmp, 1);
1622
+
1623
+ // (p - 1) / 2
1624
+ mpz_sub_ui(exp, p, 1);
1625
+ mpz_divexact_ui(exp, exp, 2);
1626
+ // y ^ exp mod p
1627
+ mpz_powm(rop, tmp, exp, p);
1628
+
1629
+ // check if rop is 1
1630
+ if (mpz_cmp_ui(rop, 1) == 0) {
1631
+ // if so, then we can return y
1632
+ debug("true case: just return y.\n");
1633
+ print_mpz(p, 10);
1634
+ print_mpz(tmp, 10);
1635
+
1636
+ rop2 = createNewInteger();
1637
+ mpz_init(rop2->e);
1638
+ mpz_init_set(rop2->m, p);
1639
+ mpz_set(rop2->e, tmp);
1640
+ } else {
1641
+ // debug("Order of group => '%zd'\n", mpz_sizeinbase(p, 2));
1642
+ // -y mod p
1643
+ debug("false case: return -y mod p.\n");
1644
+ mpz_neg(tmp, tmp);
1645
+ mpz_mod(tmp, tmp, p);
1646
+ debug("tmp...\n");
1647
+ print_mpz(tmp, 10);
1648
+ debug("p...\n");
1649
+ print_mpz(p, 10);
1650
+
1651
+ rop2 = createNewInteger();
1652
+ mpz_init(rop2->e);
1653
+ mpz_init_set(rop2->m, p);
1654
+ mpz_set(rop2->e, tmp);
1655
+ }
1656
+ mpz_clear(rop);
1657
+ mpz_clear(p);
1658
+ mpz_clear(exp);
1659
+ mpz_clear(tmp);
1660
+ return (PyObject *) rop2;
1661
+ }
1662
+
1663
+ EXIT_IF(TRUE, "invalid input types.");
1664
+ }
1665
+
1666
+ static PyObject *decode_message(PyObject *self, PyObject *args) {
1667
+ PyObject *element, *order, *order2;
1668
+ if (PyArg_ParseTuple(args, "OOO", &element, &order, &order2)) {
1669
+ if (PyInteger_Check(element) && PyInteger_Check(order)
1670
+ && PyInteger_Check(order2)) {
1671
+ mpz_t p, q;
1672
+ Integer *elem, *pObj, *qObj; // mpz_init(elem);
1673
+ mpz_init(p);
1674
+ mpz_init(q);
1675
+
1676
+ // convert to mpz_t types...
1677
+ elem = (Integer *) element;
1678
+ pObj = (Integer *) order;
1679
+ qObj = (Integer *) order2;
1680
+ mpz_set(p, pObj->e);
1681
+ mpz_set(q, qObj->e);
1682
+ // test if elem <= q
1683
+ if (mpz_cmp(elem->e, q) <= 0) {
1684
+ debug("true case: g <= q.\n");
1685
+ mpz_sub_ui(elem->e, elem->e, 1);
1686
+ } else {
1687
+ debug("false case: g > q. so, y = -elem mod p.\n");
1688
+ // y = -elem mod p
1689
+ mpz_neg(elem->e, elem->e);
1690
+ mpz_mod(elem->e, elem->e, p);
1691
+ mpz_sub_ui(elem->e, elem->e, 1);
1692
+ }
1693
+
1694
+ size_t count = 0;
1695
+ unsigned char *Rop = (unsigned char *) mpz_export(NULL, &count, 1,
1696
+ sizeof(char), 0, 0, elem->e);
1697
+ debug("rop => '%s'\n", Rop);
1698
+ debug("count => '%zd'\n", count);
1699
+
1700
+ int size_Rop = Rop[0];
1701
+ char m[MSG_LEN+1];
1702
+ *m = '\0';
1703
+ strncat(m, (const char *)(Rop+1), size_Rop);
1704
+
1705
+ mpz_clear(p);
1706
+ mpz_clear(q);
1707
+
1708
+ PyObject *newObj = PyBytes_FromFormat("%s", m);
1709
+ free(Rop);
1710
+ return newObj;
1711
+ }
1712
+ }
1713
+
1714
+ return Py_BuildValue("i", FALSE);
1715
+ }
1716
+
1717
+ static PyObject *bitsize(PyObject *self, PyObject *args) {
1718
+ PyObject *object = NULL;
1719
+ int tmp_size;
1720
+
1721
+ if (PyArg_ParseTuple(args, "O", &object)) {
1722
+ if (_PyLong_Check(object)) {
1723
+ mpz_t tmp;
1724
+ mpz_init(tmp);
1725
+ longObjToMPZ(tmp, object);
1726
+ tmp_size = size(tmp);
1727
+ mpz_clear(tmp);
1728
+ return Py_BuildValue("i", tmp_size);
1729
+ } else if (PyInteger_Check(object)) {
1730
+ Integer *obj = (Integer *) object;
1731
+ if (obj->initialized) {
1732
+ tmp_size = size(obj->e);
1733
+ return Py_BuildValue("i", tmp_size);
1734
+ }
1735
+ }
1736
+ }
1737
+ PyErr_SetString(IntegerError, "invalid input type.");
1738
+ return NULL;
1739
+ }
1740
+
1741
+ static PyObject *testCoPrime(Integer *self, PyObject *arg) {
1742
+ mpz_t tmp, rop;
1743
+ int result = FALSE;
1744
+
1745
+ if (!self->initialized) {
1746
+ PyErr_SetString(IntegerError, "integer object not initialized.");
1747
+ return NULL;
1748
+ }
1749
+
1750
+ mpz_init(rop);
1751
+ if (arg != NULL) {
1752
+ PyObject *obj = PyNumber_Long(arg);
1753
+ if (obj != NULL) {
1754
+ mpz_init(tmp);
1755
+ longObjToMPZ(tmp, obj);
1756
+ mpz_gcd(rop, self->e, tmp);
1757
+ print_mpz(rop, 1);
1758
+ result = (mpz_cmp_ui(rop, 1) == 0) ? TRUE : FALSE;
1759
+ mpz_clear(tmp);
1760
+ Py_XDECREF(obj);
1761
+ }
1762
+
1763
+ } else {
1764
+ mpz_gcd(rop, self->e, self->m);
1765
+ print_mpz(rop, 1);
1766
+ result = (mpz_cmp_ui(rop, 1) == 0) ? TRUE : FALSE;
1767
+ }
1768
+ mpz_clear(rop);
1769
+
1770
+ if (result) {
1771
+ Py_INCREF(Py_True);
1772
+ return Py_True;
1773
+ } else {
1774
+ Py_INCREF(Py_False);
1775
+ return Py_False;
1776
+ }
1777
+ }
1778
+
1779
+ /*
1780
+ * Description: B.isCongruent(A) => A === B mod N. Test whether A is congruent to B mod N.
1781
+ */
1782
+ static PyObject *testCongruency(Integer *self, PyObject *args) {
1783
+ PyObject *obj = NULL;
1784
+
1785
+ if (!self->initialized) {
1786
+ PyErr_SetString(IntegerError, "integer object not initialized.");
1787
+ return NULL;
1788
+ }
1789
+
1790
+ if (PyArg_ParseTuple(args, "O", &obj)) {
1791
+ if (_PyLong_Check(obj)) {
1792
+ PyObject *obj2 = PyNumber_Long(obj);
1793
+ if (obj2 != NULL) {
1794
+ mpz_t rop;
1795
+ mpz_init(rop);
1796
+ longObjToMPZ(rop, obj2);
1797
+ Py_XDECREF(obj2);
1798
+ if (mpz_congruent_p(rop, self->e, self->m) != 0) {
1799
+ mpz_clear(rop);
1800
+ Py_INCREF(Py_True);
1801
+ return Py_True;
1802
+ } else {
1803
+ mpz_clear(rop);
1804
+ Py_INCREF(Py_False);
1805
+ return Py_False;
1806
+ }
1807
+ }
1808
+ } else if (PyInteger_Check(obj)) {
1809
+ Integer *obj2 = (Integer *) obj;
1810
+ if (obj2->initialized && mpz_congruent_p(obj2->e, self->e, self->m)
1811
+ != 0) {
1812
+ Py_INCREF(Py_True);
1813
+ return Py_True;
1814
+ } else {
1815
+ Py_XDECREF(Py_False);
1816
+ return Py_False;
1817
+ }
1818
+ }
1819
+
1820
+ }
1821
+
1822
+ EXIT_IF(TRUE, "need long or int value to test congruency.");
1823
+ }
1824
+
1825
+ static PyObject *legendre(PyObject *self, PyObject *args) {
1826
+ PyObject *obj1 = NULL, *obj2 = NULL;
1827
+ mpz_t a, p;
1828
+ mpz_init(a);
1829
+ mpz_init(p);
1830
+
1831
+ if (PyArg_ParseTuple(args, "OO", &obj1, &obj2)) {
1832
+ if (_PyLong_Check(obj1)) {
1833
+ longObjToMPZ(a, obj1);
1834
+ } else if (PyInteger_Check(obj1)) {
1835
+ Integer *tmp = (Integer *) obj1;
1836
+ mpz_set(a, tmp->e);
1837
+ }
1838
+
1839
+ if (_PyLong_Check(obj2)) {
1840
+ longObjToMPZ(p, obj2);
1841
+ } else if (PyInteger_Check(obj2)) {
1842
+ Integer *tmp2 = (Integer *) obj2;
1843
+ mpz_set(p, tmp2->e);
1844
+ }
1845
+
1846
+ // make sure a,p have been set
1847
+ if (mpz_cmp_ui(a, 0) != 0 && mpz_cmp_ui(p, 0) != 0) {
1848
+ // make sure p is odd and positive prime number
1849
+ int prop_p = mpz_probab_prime_p(p, MAX_RUN);
1850
+ if (mpz_odd_p(p) > 0 && prop_p > 0) {
1851
+ return Py_BuildValue("i", mpz_legendre(a, p));
1852
+ } else {
1853
+ return Py_BuildValue("i", FALSE);
1854
+ }
1855
+ }
1856
+ }
1857
+
1858
+ EXIT_IF(TRUE, "invalid input.");
1859
+ }
1860
+
1861
+ static PyObject *gcdCall(PyObject *self, PyObject *args) {
1862
+ PyObject *obj1 = NULL, *obj2 = NULL;
1863
+ mpz_t op1, op2;
1864
+
1865
+ if (PyArg_ParseTuple(args, "OO", &obj1, &obj2)) {
1866
+ if (_PyLong_Check(obj1)) {
1867
+ mpz_init(op1);
1868
+ longObjToMPZ(op1, obj1);
1869
+ } else if (PyInteger_Check(obj1)) {
1870
+ mpz_init(op1);
1871
+ Integer *tmp = (Integer *) obj1;
1872
+ mpz_set(op1, tmp->e);
1873
+ } else {
1874
+ ErrorMsg("invalid argument type: 1");
1875
+ }
1876
+
1877
+ if (_PyLong_Check(obj2)) {
1878
+ mpz_init(op2);
1879
+ longObjToMPZ(op2, obj2);
1880
+ } else if (PyInteger_Check(obj2)) {
1881
+ mpz_init(op2);
1882
+ Integer *tmp = (Integer *) obj2;
1883
+ mpz_set(op2, tmp->e);
1884
+ } else {
1885
+ mpz_clear(op1);
1886
+ ErrorMsg("invalid argument type: 2");
1887
+ }
1888
+
1889
+ Integer *rop = createNewInteger();
1890
+ mpz_init(rop->e);
1891
+ mpz_init(rop->m);
1892
+ mpz_gcd(rop->e, op1, op2);
1893
+ mpz_clear(op1);
1894
+ mpz_clear(op2);
1895
+ return (PyObject *) rop;
1896
+ }
1897
+
1898
+ EXIT_IF(TRUE, "invalid input.");
1899
+ }
1900
+
1901
+ static PyObject *lcmCall(PyObject *self, PyObject *args) {
1902
+ PyObject *obj1 = NULL, *obj2 = NULL;
1903
+ mpz_t op1, op2;
1904
+
1905
+ if (PyArg_ParseTuple(args, "OO", &obj1, &obj2)) {
1906
+ if (_PyLong_Check(obj1)) {
1907
+ mpz_init(op1);
1908
+ longObjToMPZ(op1, obj1);
1909
+ } else if (PyInteger_Check(obj1)) {
1910
+ mpz_init(op1);
1911
+ Integer *tmp = (Integer *) obj1;
1912
+ mpz_set(op1, tmp->e);
1913
+ } else {
1914
+ EXIT_IF(TRUE, "invalid argument type: 1");
1915
+ }
1916
+
1917
+ if (_PyLong_Check(obj2)) {
1918
+ mpz_init(op2);
1919
+ longObjToMPZ(op2, obj2);
1920
+ } else if (PyInteger_Check(obj2)) {
1921
+ mpz_init(op2);
1922
+ Integer *tmp = (Integer *) obj2;
1923
+ mpz_set(op2, tmp->e);
1924
+ } else {
1925
+ mpz_clear(op1);
1926
+ EXIT_IF(TRUE, "invalid argument type: 2");
1927
+ }
1928
+
1929
+ Integer *rop = createNewInteger();
1930
+ mpz_init(rop->e);
1931
+ mpz_init(rop->m);
1932
+ mpz_lcm(rop->e, op1, op2);
1933
+ mpz_clear(op1);
1934
+ mpz_clear(op2);
1935
+ return (PyObject *) rop;
1936
+ }
1937
+
1938
+ EXIT_IF(TRUE, "invalid input.");
1939
+ }
1940
+
1941
+ static PyObject *serialize(PyObject *self, PyObject *args) {
1942
+ Integer *obj = NULL;
1943
+ int isNeg;
1944
+
1945
+ if (!PyArg_ParseTuple(args, "O", &obj)) {
1946
+ ErrorMsg("invalid argument");
1947
+ }
1948
+ if(!PyInteger_Check(obj)) EXIT_IF(TRUE, "not a valid element object.");
1949
+
1950
+ // export the object first
1951
+ size_t count1 = 0, count2 = 0;
1952
+ char *base64_rop = NULL, *base64_rop2 = NULL;
1953
+ PyObject *bytes1 = NULL, *bytes2 = NULL;
1954
+ // if (mpz_sgn(obj->e) > 0) {
1955
+ uint8_t *rop = (uint8_t *) mpz_export(NULL, &count1, 1, sizeof(char),
1956
+ 0, 0, obj->e);
1957
+ // convert string to base64 encoding
1958
+ size_t length = 0;
1959
+ base64_rop = NewBase64Encode(rop, count1, FALSE, &length);
1960
+ isNeg = mpz_sgn(obj->e) < 0 ? TRUE : FALSE;
1961
+ // convert to bytes (length : base64 integer)
1962
+ bytes1 = PyBytes_FromFormat("%d:%d:%s:", isNeg, (int) length,
1963
+ (const char *) base64_rop);
1964
+ free(base64_rop);
1965
+ free(rop);
1966
+ // }
1967
+
1968
+ if (mpz_sgn(obj->m) > 0) {
1969
+ uint8_t *rop2 = (uint8_t *) mpz_export(NULL, &count2, 1, sizeof(char),
1970
+ 0, 0, obj->m);
1971
+ size_t length2 = 0;
1972
+ base64_rop2 = NewBase64Encode(rop2, count2, FALSE, &length2);
1973
+ // convert to bytes
1974
+ bytes2 = PyBytes_FromFormat("%d:%s:", (int) length2,
1975
+ (const char *) base64_rop2);
1976
+ free(base64_rop2);
1977
+ free(rop2);
1978
+ }
1979
+
1980
+ if (bytes2 != NULL && bytes1 != NULL) {
1981
+ PyBytes_ConcatAndDel(&bytes1, bytes2);
1982
+ return bytes1;
1983
+ } else if (bytes1 != NULL) {
1984
+ return bytes1;
1985
+ } else {
1986
+ EXIT_IF(TRUE, "invalid integer object.");
1987
+ }
1988
+ }
1989
+
1990
+ void deserialize_helper(int length, char *encoded_value, mpz_t target)
1991
+ {
1992
+ debug("encoded_value len => '%zd'", strlen(encoded_value));
1993
+
1994
+ size_t deserialized_len = 0;
1995
+ uint8_t *buf = NewBase64Decode((const char *) encoded_value, length, &deserialized_len);
1996
+
1997
+ mpz_import(target, deserialized_len, 1, sizeof(buf[0]), 0, 0, buf);
1998
+ free(buf);
1999
+ }
2000
+
2001
+ static PyObject *deserialize(PyObject *self, PyObject *args) {
2002
+ PyObject *bytesObj = NULL;
2003
+
2004
+ if (!PyArg_ParseTuple(args, "O", &bytesObj)) {
2005
+ EXIT_IF(TRUE, "invalid argument.");
2006
+ }
2007
+
2008
+ uint8_t *serial_buf2 = (uint8_t *) PyBytes_AsString(bytesObj);
2009
+ int serial_buf2_len = strlen((char *) serial_buf2);
2010
+ uint8_t serial_buf[serial_buf2_len + 1];
2011
+ memset(serial_buf, 0, serial_buf2_len + 1);
2012
+ memcpy(serial_buf, serial_buf2, serial_buf2_len);
2013
+ /* get integer value */
2014
+ char delim[] = ":";
2015
+ char *token = NULL;
2016
+ token = strtok((char *) serial_buf, delim);
2017
+ // positive or negative
2018
+ int isNeg = atoi((const char *) token);
2019
+ token = strtok(NULL, delim);
2020
+ // length
2021
+ int int_len = atoi((const char *) token);
2022
+ debug("length => '%d'\n", int_len);
2023
+ mpz_t x,m;
2024
+ mpz_init(x);
2025
+ mpz_init(m);
2026
+
2027
+ // parse the first half of the bytes/str object
2028
+ token = strtok(NULL, delim);
2029
+ debug("encoded value x => '%s'\n", token);
2030
+ if(token != NULL) {
2031
+ deserialize_helper(int_len, token, x);
2032
+ debug("decoded value x => ");
2033
+ print_mpz(x, 10);
2034
+ }
2035
+
2036
+ // parse modulus (if indeed modular integer)
2037
+ token = strtok(NULL, delim);
2038
+ if(token != NULL) {
2039
+ int_len = atoi((const char *) token);
2040
+ token = strtok(NULL, delim);
2041
+ deserialize_helper(int_len, token, m);
2042
+ debug("decoded value m => ");
2043
+ print_mpz(m, 10);
2044
+ }
2045
+
2046
+ Integer *obj = NULL;
2047
+ if(mpz_sgn(m) > 0) {
2048
+ obj = createNewInteger();
2049
+ mpz_init(obj->e);
2050
+ mpz_init_set(obj->m, m);
2051
+ }
2052
+ else {
2053
+ obj = createNewInteger();
2054
+ mpz_init(obj->e);
2055
+ mpz_init(obj->m);
2056
+ }
2057
+ mpz_set(obj->e, x);
2058
+ if(isNeg) mpz_neg(obj->e, obj->e);
2059
+
2060
+ mpz_clear(x);
2061
+ mpz_clear(m);
2062
+ return (PyObject *) obj;
2063
+ }
2064
+
2065
+ // class method for conversion
2066
+ // integer.toBytes(x) => b'blah blah'
2067
+ static PyObject *toBytes(PyObject *self, PyObject *args) {
2068
+ Integer *intObj = NULL;
2069
+
2070
+ if (PyInteger_Check(args)) {
2071
+ intObj = (Integer *) args;
2072
+ size_t count = 0;
2073
+ unsigned char *Rop = (unsigned char *) mpz_export(NULL, &count, 1,
2074
+ sizeof(char), 0, 0, intObj->e);
2075
+ debug("Rop => '%s', len =>'%zd'\n", Rop, count);
2076
+ PyObject *newObj = PyBytes_FromStringAndSize((const char *) Rop, (Py_ssize_t) count);
2077
+ free(Rop);
2078
+ return newObj;
2079
+ }
2080
+
2081
+ EXIT_IF(TRUE, "invalid type.");
2082
+ }
2083
+
2084
+ // class method for conversion for modular integer to an integer
2085
+ // integer.toInt(x mod Y) => x
2086
+ static PyObject *toInt(PyObject *self, PyObject *args) {
2087
+ Integer *intObj = NULL;
2088
+
2089
+ if (PyInteger_Check(args)) {
2090
+ intObj = (Integer *) args;
2091
+ Integer *rop = createNewInteger();
2092
+ mpz_init_set(rop->e, intObj->e);
2093
+ mpz_init(rop->m);
2094
+
2095
+ return (PyObject *) rop;
2096
+ }
2097
+
2098
+ EXIT_IF(TRUE, "not a charm integer type.");
2099
+ }
2100
+
2101
+ static PyObject *getMod(PyObject *self, PyObject *args) {
2102
+ Integer *intObj = NULL;
2103
+
2104
+ if (PyInteger_Check(args)) {
2105
+ intObj = (Integer *) args;
2106
+ Integer *rop = createNewInteger();
2107
+ mpz_init_set(rop->e, intObj->m);
2108
+ mpz_init(rop->m);
2109
+ return (PyObject *) rop;
2110
+ }
2111
+
2112
+ EXIT_IF(TRUE, "not a charm integer type.");
2113
+ }
2114
+
2115
+ static PyObject *Integer_xor(PyObject *self, PyObject *other) {
2116
+ Integer *rop = NULL, *op1 = NULL, *op2 = NULL;
2117
+
2118
+ if (PyInteger_Check(self))
2119
+ op1 = (Integer *) self;
2120
+ if (PyInteger_Check(other))
2121
+ op2 = (Integer *) other;
2122
+
2123
+ EXIT_IF(op1 == NULL || op2 == NULL, "both types are not of charm integer types.");
2124
+ if (PyInteger_Init(op1, op2)) {
2125
+ rop = createNewInteger();
2126
+ mpz_init(rop->e);
2127
+ mpz_init(rop->m);
2128
+ mpz_xor(rop->e, op1->e, op2->e);
2129
+ return (PyObject *) rop;
2130
+ }
2131
+
2132
+ EXIT_IF(TRUE, "objects not initialized properly.");
2133
+ }
2134
+
2135
+ #ifdef BENCHMARK_ENABLED
2136
+ #define BenchmarkIdentifier 3
2137
+
2138
+ #if defined(__APPLE__)
2139
+ // benchmark new
2140
+ PyObject *Benchmark_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2141
+ {
2142
+ Benchmark *self;
2143
+ self = (Benchmark *)type->tp_alloc(type, 0);
2144
+ if(self != NULL) {
2145
+ self->bench_initialized = FALSE;
2146
+ self->bench_inprogress = FALSE; // false until we StartBenchmark( ... )
2147
+ self->op_add = self->op_sub = self->op_mult = 0;
2148
+ self->op_div = self->op_exp = self->op_pair = 0;
2149
+ self->cpu_time_ms = self->real_time_ms = 0.0;
2150
+ self->cpu_option = self->real_option = FALSE;
2151
+ debug("Creating new benchmark object.\n");
2152
+ }
2153
+ return (PyObject *) self;
2154
+ }
2155
+
2156
+ // benchmark init
2157
+ int Benchmark_init(Benchmark *self, PyObject *args, PyObject *kwds)
2158
+ {
2159
+ return 0;
2160
+ }
2161
+ // benchmark dealloc
2162
+ void Benchmark_dealloc(Benchmark *self) {
2163
+ debug("Releasing benchmark object.\n");
2164
+ Py_TYPE(self)->tp_free((PyObject*)self);
2165
+ }
2166
+
2167
+ PyTypeObject BenchmarkType = {
2168
+ PyVarObject_HEAD_INIT(NULL, 0)
2169
+ "profile.Benchmark", /*tp_name*/
2170
+ sizeof(Benchmark), /*tp_basicsize*/
2171
+ 0, /*tp_itemsize*/
2172
+ (destructor)Benchmark_dealloc, /*tp_dealloc*/
2173
+ 0, /*tp_print*/
2174
+ 0, /*tp_getattr*/
2175
+ 0, /*tp_setattr*/
2176
+ 0, /*tp_reserved*/
2177
+ 0, /*tp_repr*/
2178
+ 0, /*tp_as_number*/
2179
+ 0, /*tp_as_sequence*/
2180
+ 0, /*tp_as_mapping*/
2181
+ 0, /*tp_hash */
2182
+ 0, /*tp_call*/
2183
+ 0, /*tp_str*/
2184
+ 0, /*tp_getattro*/
2185
+ 0, /*tp_setattro*/
2186
+ 0, /*tp_as_buffer*/
2187
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
2188
+ "Benchmark objects", /* tp_doc */
2189
+ 0, /* tp_traverse */
2190
+ 0, /* tp_clear */
2191
+ 0, /* tp_richcompare */
2192
+ 0, /* tp_weaklistoffset */
2193
+ 0, /* tp_iter */
2194
+ 0, /* tp_iternext */
2195
+ 0, /* tp_methods */
2196
+ 0, /* tp_members */
2197
+ 0, /* tp_getset */
2198
+ 0, /* tp_base */
2199
+ 0, /* tp_dict */
2200
+ 0, /* tp_descr_get */
2201
+ 0, /* tp_descr_set */
2202
+ 0, /* tp_dictoffset */
2203
+ (initproc)Benchmark_init, /* tp_init */
2204
+ 0, /* tp_alloc */
2205
+ Benchmark_new, /* tp_new */
2206
+ };
2207
+
2208
+ #endif
2209
+
2210
+ PyObject *InitBenchmark(PyObject *self, PyObject *args) {
2211
+ Benchmark *b = GETSTATE(self)->dBench;
2212
+ if(b == NULL) {
2213
+ GETSTATE(self)->dBench = PyObject_New(Benchmark, &BenchmarkType);
2214
+ if(GETSTATE(self)->dBench == NULL) {
2215
+ PyErr_SetString(IntegerError, "InitBenchmark - out of memory.");
2216
+ return NULL;
2217
+ }
2218
+ Py_INCREF(GETSTATE(self)->dBench);
2219
+ tmpBench = GETSTATE(self)->dBench;
2220
+ Benchmark *dBench = GETSTATE(self)->dBench;
2221
+ PyClearBenchmark(dBench);
2222
+ dBench->bench_initialized = TRUE;
2223
+ dBench->bench_inprogress = FALSE;
2224
+ dBench->identifier = BenchmarkIdentifier;
2225
+ Py_RETURN_TRUE;
2226
+ }
2227
+ else if(b != NULL && b->bench_initialized == FALSE) {
2228
+ debug("%s: bench init: '%i'\n", __FUNCTION__, b->bench_initialized);
2229
+ debug("%s: bench id set: '%i'\n", __FUNCTION__, b->identifier);
2230
+ b->bench_initialized = TRUE;
2231
+ b->identifier = BenchmarkIdentifier;
2232
+ debug("Initialized benchmark object.\n");
2233
+ Py_RETURN_TRUE;
2234
+ }
2235
+ else if(b != NULL && b->bench_inprogress == FALSE && b->bench_initialized == TRUE) {
2236
+ PyClearBenchmark(b);
2237
+ b->bench_initialized = TRUE;
2238
+ b->bench_inprogress = FALSE;
2239
+ b->identifier = BenchmarkIdentifier;
2240
+ Py_RETURN_TRUE;
2241
+ }
2242
+ else if(b != NULL && b->bench_inprogress == TRUE) {
2243
+ printf("Benchmark in progress.\n");
2244
+ }
2245
+
2246
+ debug("Benchmark already initialized.\n");
2247
+ Py_RETURN_FALSE;
2248
+ }
2249
+
2250
+ PyObject *StartBenchmark(PyObject *self, PyObject *args) {
2251
+ PyObject *list = NULL;
2252
+ Benchmark *b = GETSTATE(self)->dBench;
2253
+ if(!PyArg_ParseTuple(args, "O", &list)) {
2254
+ PyErr_SetString(IntegerError, "StartBenchmark - invalid argument.");
2255
+ return NULL;
2256
+ }
2257
+ if(b == NULL) {
2258
+ PyErr_SetString(IntegerError, "uninitialized benchmark object.");
2259
+ return NULL;
2260
+ }
2261
+ else if(PyList_Check(list) && b->bench_initialized == TRUE && b->bench_inprogress == FALSE && b->identifier == BenchmarkIdentifier) {
2262
+ debug("%s: bench id: '%i'\n", __FUNCTION__, b->identifier);
2263
+ size_t size = PyList_Size(list);
2264
+ PyStartBenchmark(b, list, size);
2265
+ debug("list size => %zd\n", size);
2266
+ debug("benchmark enabled and initialized!\n");
2267
+ Py_RETURN_TRUE;
2268
+ }
2269
+ Py_RETURN_FALSE;
2270
+ }
2271
+
2272
+ PyObject *EndBenchmark(PyObject *self, PyObject *args) {
2273
+ Benchmark *b = GETSTATE(self)->dBench;
2274
+ if(b != NULL) {
2275
+ debug("%s: bench init: '%i'\n", __FUNCTION__, b->bench_initialized);
2276
+ debug("%s: bench id: '%i'\n", __FUNCTION__, b->identifier);
2277
+ if(b->bench_initialized == TRUE && b->bench_inprogress == TRUE && b->identifier == BenchmarkIdentifier) {
2278
+ PyEndBenchmark(b);
2279
+ debug("%s: bench id: '%i'\n", __FUNCTION__, b->identifier);
2280
+ Py_RETURN_TRUE;
2281
+ }
2282
+ }
2283
+
2284
+ PyErr_SetString(IntegerError, "uninitialized benchmark object.");
2285
+ return NULL;
2286
+ }
2287
+
2288
+ static PyObject *GetBenchmark(PyObject *self, PyObject *args) {
2289
+ char *opt = NULL;
2290
+ Benchmark *b = GETSTATE(self)->dBench;
2291
+ if(!PyArg_ParseTuple(args, "s", &opt))
2292
+ {
2293
+ PyErr_SetString(IntegerError, "GetBenchmark - invalid argument.");
2294
+ return NULL;
2295
+ }
2296
+
2297
+ if(b == NULL) {
2298
+ PyErr_SetString(IntegerError, "uninitialized benchmark object.");
2299
+ return NULL;
2300
+ }
2301
+ else if(b->bench_initialized == TRUE && b->bench_inprogress == FALSE && b->identifier == BenchmarkIdentifier) {
2302
+ return Retrieve_result(b, opt);
2303
+ }
2304
+ Py_RETURN_FALSE;
2305
+ }
2306
+
2307
+ static PyObject *GetAllBenchmarks(PyObject *self, PyObject *args) {
2308
+ Benchmark *b = GETSTATE(self)->dBench;
2309
+ if(b != NULL) {
2310
+ debug("%s: bench id: '%i'\n", __FUNCTION__, b->identifier);
2311
+ if(b->bench_initialized == TRUE && b->bench_inprogress == FALSE && b->identifier == BenchmarkIdentifier)
2312
+ return GetResults(b);
2313
+ debug("Invalid benchmark identifier.\n");
2314
+ }
2315
+
2316
+ PyErr_SetString(IntegerError, "uninitialized benchmark object.");
2317
+ return NULL;
2318
+ }
2319
+
2320
+ #endif
2321
+
2322
+ PyMethodDef Integer_methods[] = {
2323
+ { "set", (PyCFunction) Integer_set, METH_VARARGS, "initialize with another integer object." },
2324
+ #if PY_MINOR_VERSION <= 7
2325
+ { "isCoPrime", (PyCFunction) testCoPrime, METH_O | METH_NOARGS, "determine whether two integers a and b are relatively prime." },
2326
+ #else
2327
+ { "isCoPrime", (PyCFunction) testCoPrime, METH_O, "determine whether two integers a and b are relatively prime." },
2328
+ #endif
2329
+ { "isCongruent", (PyCFunction) testCongruency, METH_VARARGS, "determine whether two integers are congruent mod n." },
2330
+ // { "reduce", (PyCFunction) Integer_reduce, METH_NOARGS, "reduce an integer object modulo N." },
2331
+ { NULL }
2332
+ };
2333
+
2334
+ PyNumberMethods integer_number = {
2335
+ Integer_add, /* nb_add */
2336
+ Integer_sub, /* nb_subtract */
2337
+ Integer_mul, /* nb_multiply */
2338
+ Integer_remainder, /* nb_remainder */
2339
+ 0, /* nb_divmod */
2340
+ Integer_pow, /* nb_power */
2341
+ 0, /* nb_negative */
2342
+ 0, /* nb_positive */
2343
+ 0, /* nb_absolute */
2344
+ 0, /* nb_bool */
2345
+ (unaryfunc) Integer_invert, /* nb_invert */
2346
+ 0, /* nb_lshift */
2347
+ 0, /* nb_rshift */
2348
+ 0, /* nb_and */
2349
+ Integer_xor, /* nb_xor */
2350
+ 0, /* nb_or */
2351
+ (unaryfunc) Integer_long, /* nb_int */
2352
+ 0, /* nb_reserved */
2353
+ 0, /* nb_float */
2354
+ Integer_add, /* nb_inplace_add */
2355
+ Integer_sub, /* nb_inplace_subtract */
2356
+ Integer_mul, /* nb_inplace_multiply */
2357
+ Integer_remainder, /* nb_inplace_remainder */
2358
+ Integer_pow, /* nb_inplace_power */
2359
+ 0, /* nb_inplace_lshift */
2360
+ 0, /* nb_inplace_rshift */
2361
+ 0, /* nb_inplace_and */
2362
+ 0, /* nb_inplace_xor */
2363
+ 0, /* nb_inplace_or */
2364
+ 0, /* nb_floor_divide */
2365
+ Integer_div, /* nb_true_divide */
2366
+ 0, /* nb_inplace_floor_divide */
2367
+ Integer_div, /* nb_inplace_true_divide */
2368
+ 0, /* nb_index */
2369
+ };
2370
+
2371
+ PyTypeObject IntegerType = {
2372
+ PyVarObject_HEAD_INIT(NULL, 0)
2373
+ "integer.Element", /*tp_name*/
2374
+ sizeof(Integer), /*tp_basicsize*/
2375
+ 0, /*tp_itemsize*/
2376
+ (destructor)Integer_dealloc, /*tp_dealloc*/
2377
+ 0, /*tp_print*/
2378
+ 0, /*tp_getattr*/
2379
+ 0, /*tp_setattr*/
2380
+ 0, /*tp_reserved*/
2381
+ (reprfunc)Integer_print, /*tp_repr*/
2382
+ &integer_number, /*tp_as_number*/
2383
+ 0, /*tp_as_sequence*/
2384
+ 0, /*tp_as_mapping*/
2385
+ 0, /*tp_hash */
2386
+ 0, /*tp_call*/
2387
+ 0, /*tp_str*/
2388
+ 0, /*tp_getattro*/
2389
+ 0, /*tp_setattro*/
2390
+ 0, /*tp_as_buffer*/
2391
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
2392
+ "Modular Integer objects", /* tp_doc */
2393
+ 0, /* tp_traverse */
2394
+ 0, /* tp_clear */
2395
+ Integer_equals, /* tp_richcompare */
2396
+ 0, /* tp_weaklistoffset */
2397
+ 0, /* tp_iter */
2398
+ 0, /* tp_iternext */
2399
+ Integer_methods, /* tp_methods */
2400
+ 0, /* tp_members */
2401
+ 0, /* tp_getset */
2402
+ 0, /* tp_base */
2403
+ 0, /* tp_dict */
2404
+ 0, /* tp_descr_get */
2405
+ 0, /* tp_descr_set */
2406
+ 0, /* tp_dictoffset */
2407
+ (initproc)Integer_init, /* tp_init */
2408
+ 0, /* tp_alloc */
2409
+ Integer_new, /* tp_new */
2410
+ };
2411
+
2412
+ /* global module methods (include isPrime, randomPrime, etc. here). */
2413
+ PyMethodDef module_methods[] = {
2414
+ { "randomBits", (PyCFunction) genRandomBits, METH_VARARGS, "generate a random number of bits from 0 to 2^n-1." },
2415
+ { "random", (PyCFunction) genRandom, METH_VARARGS, "generate a random number in range of 0 to n-1 where n is large number." },
2416
+ { "randomPrime", (PyCFunction) genRandomPrime, METH_VARARGS, "generate a probabilistic random prime number that is n-bits." },
2417
+ { "isPrime", (PyCFunction) testPrimality, METH_O, "probabilistic algorithm to whether a given integer is prime." },
2418
+ { "encode", (PyCFunction) encode_message, METH_VARARGS, "encode a message as a group element where p = 2*q + 1 only." },
2419
+ { "decode", (PyCFunction) decode_message, METH_VARARGS, "decode a message from a group element where p = 2*q + 1 to a message." },
2420
+ { "hashInt", (PyCFunction) Integer_hash, METH_VARARGS, "hash to group elements in which p = 2*q+1." },
2421
+ { "bitsize", (PyCFunction) bitsize, METH_VARARGS, "determine how many bits required to represent a given value." },
2422
+ { "legendre", (PyCFunction) legendre, METH_VARARGS, "given a and a positive prime p compute the legendre symbol." },
2423
+ { "gcd", (PyCFunction) gcdCall, METH_VARARGS, "compute the gcd of two integers a and b." },
2424
+ { "lcm", (PyCFunction) lcmCall, METH_VARARGS, "compute the lcd of two integers a and b." },
2425
+ { "serialize", (PyCFunction) serialize, METH_VARARGS, "Serialize an integer type into bytes." },
2426
+ { "deserialize", (PyCFunction) deserialize, METH_VARARGS, "De-serialize an bytes object into an integer object" },
2427
+ #ifdef BENCHMARK_ENABLED
2428
+ { "InitBenchmark", (PyCFunction) InitBenchmark, METH_NOARGS, "Initialize a benchmark object" },
2429
+ { "StartBenchmark", (PyCFunction) StartBenchmark, METH_VARARGS, "Start a new benchmark with some options" },
2430
+ { "EndBenchmark", (PyCFunction) EndBenchmark, METH_NOARGS, "End a given benchmark" },
2431
+ { "GetBenchmark", (PyCFunction) GetBenchmark, METH_VARARGS, "Returns contents of a benchmark object" },
2432
+ { "GetGeneralBenchmarks", (PyCFunction) GetAllBenchmarks, METH_NOARGS, "Retrieve general benchmark info as a dictionary."},
2433
+ #endif
2434
+ { "int2Bytes", (PyCFunction) toBytes, METH_O, "convert an integer object to a bytes object."},
2435
+ { "toInt", (PyCFunction) toInt, METH_O, "convert modular integer into an integer object."},
2436
+ { "getMod", (PyCFunction) getMod, METH_O, "get the modulus of a given modular integer object."},
2437
+ { "reduce", (PyCFunction) Integer_reduce, METH_O, "reduce a modular integer by its modulus. x = mod(y)"},
2438
+ { NULL, NULL }
2439
+ };
2440
+
2441
+ static int int_traverse(PyObject *m, visitproc visit, void *arg) {
2442
+ Py_VISIT(GETSTATE(m)->error);
2443
+ #if defined(BENCHMARK_ENABLED)
2444
+ Py_VISIT(GETSTATE(m)->dBench);
2445
+ #endif
2446
+ return 0;
2447
+ }
2448
+
2449
+ static int int_clear(PyObject *m) {
2450
+ Py_CLEAR(GETSTATE(m)->error);
2451
+ Py_XDECREF(IntegerError);
2452
+ #if defined(BENCHMARK_ENABLED)
2453
+ //printf("int_clear: Refcnt dBench = '%i'\n", (int) Py_REFCNT(GETSTATE(m)->dBench));
2454
+ Py_CLEAR(GETSTATE(m)->dBench);
2455
+ #endif
2456
+ return 0;
2457
+ }
2458
+
2459
+ static int int_free(PyObject *m) {
2460
+ // Defensive cleanup for OpenSSL PRNG to prevent hangs during Python 3.12+ shutdown
2461
+ // Only cleanup if not in abnormal finalization state
2462
+ if(m != NULL && !CHARM_PY_IS_FINALIZING()) {
2463
+ // Note: RAND_cleanup() was removed in OpenSSL 1.1.0
2464
+ // Modern OpenSSL handles cleanup automatically
2465
+ // This is a no-op for compatibility but prevents potential hangs
2466
+ }
2467
+ return 0;
2468
+ }
2469
+
2470
+ static struct PyModuleDef moduledef = {
2471
+ PyModuleDef_HEAD_INIT,
2472
+ "integer",
2473
+ NULL,
2474
+ sizeof(struct module_state),
2475
+ module_methods,
2476
+ NULL,
2477
+ int_traverse,
2478
+ (inquiry) int_clear,
2479
+ (freefunc) int_free
2480
+ };
2481
+
2482
+ #define CLEAN_EXIT goto LEAVE;
2483
+ #define INITERROR return NULL
2484
+ PyMODINIT_FUNC
2485
+ PyInit_integer(void) {
2486
+ PyObject *m=NULL;
2487
+ if (PyType_Ready(&IntegerType) < 0)
2488
+ CLEAN_EXIT;
2489
+ #ifdef BENCHMARK_ENABLED
2490
+ if(import_benchmark() < 0)
2491
+ CLEAN_EXIT;
2492
+ if(PyType_Ready(&BenchmarkType) < 0)
2493
+ INITERROR;
2494
+ #endif
2495
+
2496
+ // initialize module
2497
+ m = PyModule_Create(&moduledef);
2498
+ // add integer type to module
2499
+ struct module_state *st = GETSTATE(m);
2500
+ st->error = PyErr_NewException("integer.Error", NULL, NULL);
2501
+ if (st->error == NULL)
2502
+ CLEAN_EXIT;
2503
+ IntegerError = st->error;
2504
+ #ifdef BENCHMARK_ENABLED
2505
+ st->dBench = NULL;
2506
+ tmpBench = NULL;
2507
+ #endif
2508
+
2509
+ Py_INCREF(&IntegerType);
2510
+ PyModule_AddObject(m, "integer", (PyObject *) &IntegerType);
2511
+
2512
+ #ifdef BENCHMARK_ENABLED
2513
+ // add integer error to module
2514
+ ADD_BENCHMARK_OPTIONS(m);
2515
+ #endif
2516
+ // initialize PRNG
2517
+ // replace with read from some source of randomness
2518
+ #ifndef MS_WINDOWS
2519
+ debug("Linux: seeding openssl prng.\n");
2520
+ char *rand_file = "/dev/urandom";
2521
+ RAND_load_file(rand_file, RAND_MAX_BYTES);
2522
+ #else
2523
+ debug("Windows: seeding openssl prng.\n");
2524
+ RAND_poll();
2525
+ #endif
2526
+
2527
+ LEAVE:
2528
+ if (PyErr_Occurred()) {
2529
+ printf("ERROR: module load failed!\n");
2530
+ PyErr_Clear();
2531
+ if(m!=NULL) {
2532
+ Py_XDECREF(m);
2533
+ }
2534
+ INITERROR;
2535
+ }
2536
+
2537
+ debug("importing integer module.\n");
2538
+ return m;
2539
+ }