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,248 @@
1
+ """
2
+ Unit tests for batch verification implementation.
3
+
4
+ Tests cover:
5
+ - Batch verification of Schnorr proofs
6
+ - Batch verification of DLEQ proofs
7
+ - BatchVerifier class functionality
8
+ - Performance comparison with individual verification
9
+ """
10
+
11
+ import unittest
12
+ import time
13
+ from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
14
+ from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
15
+ from charm.zkp_compiler.dleq_proof import DLEQProof, DLEQProofData
16
+ from charm.zkp_compiler.batch_verify import BatchVerifier, batch_verify_schnorr, batch_verify_dleq
17
+
18
+
19
+ class TestBatchVerifySchnorr(unittest.TestCase):
20
+ """Tests for batch verification of Schnorr proofs."""
21
+
22
+ def setUp(self):
23
+ """Set up test fixtures."""
24
+ self.group = PairingGroup('BN254')
25
+ self.g = self.group.random(G1)
26
+
27
+ def _create_valid_schnorr_proof(self):
28
+ """Helper to create a valid Schnorr proof."""
29
+ x = self.group.random(ZR)
30
+ h = self.g ** x
31
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
32
+ return {'g': self.g, 'h': h, 'proof': proof}
33
+
34
+ def _create_invalid_schnorr_proof(self):
35
+ """Helper to create an invalid Schnorr proof (wrong secret)."""
36
+ x = self.group.random(ZR)
37
+ wrong_x = self.group.random(ZR)
38
+ h = self.g ** x
39
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, wrong_x)
40
+ return {'g': self.g, 'h': h, 'proof': proof}
41
+
42
+ def test_batch_verify_all_valid(self):
43
+ """Test that all valid proofs pass batch verification."""
44
+ proofs_data = [self._create_valid_schnorr_proof() for _ in range(5)]
45
+ result = batch_verify_schnorr(self.group, proofs_data)
46
+ self.assertTrue(result)
47
+
48
+ def test_batch_verify_one_invalid(self):
49
+ """Test that one invalid proof fails entire batch."""
50
+ proofs_data = [self._create_valid_schnorr_proof() for _ in range(4)]
51
+ proofs_data.append(self._create_invalid_schnorr_proof())
52
+ result = batch_verify_schnorr(self.group, proofs_data)
53
+ self.assertFalse(result)
54
+
55
+ def test_batch_verify_empty(self):
56
+ """Test that empty batch returns True (vacuously true)."""
57
+ result = batch_verify_schnorr(self.group, [])
58
+ self.assertTrue(result)
59
+
60
+ def test_batch_verify_single(self):
61
+ """Test that single proof batch works."""
62
+ proofs_data = [self._create_valid_schnorr_proof()]
63
+ result = batch_verify_schnorr(self.group, proofs_data)
64
+ self.assertTrue(result)
65
+
66
+ def test_batch_verify_many(self):
67
+ """Test that 10+ proofs batch works."""
68
+ proofs_data = [self._create_valid_schnorr_proof() for _ in range(12)]
69
+ result = batch_verify_schnorr(self.group, proofs_data)
70
+ self.assertTrue(result)
71
+
72
+
73
+ class TestBatchVerifyDLEQ(unittest.TestCase):
74
+ """Tests for batch verification of DLEQ proofs."""
75
+
76
+ def setUp(self):
77
+ """Set up test fixtures."""
78
+ self.group = PairingGroup('BN254')
79
+ self.g1 = self.group.random(G1)
80
+ self.g2 = self.group.random(G1)
81
+
82
+ def _create_valid_dleq_proof(self):
83
+ """Helper to create a valid DLEQ proof."""
84
+ x = self.group.random(ZR)
85
+ h1 = self.g1 ** x
86
+ h2 = self.g2 ** x
87
+ proof = DLEQProof.prove_non_interactive(self.group, self.g1, h1, self.g2, h2, x)
88
+ return {'g1': self.g1, 'h1': h1, 'g2': self.g2, 'h2': h2, 'proof': proof}
89
+
90
+ def _create_invalid_dleq_proof(self):
91
+ """Helper to create an invalid DLEQ proof (wrong secret)."""
92
+ x = self.group.random(ZR)
93
+ wrong_x = self.group.random(ZR)
94
+ h1 = self.g1 ** x
95
+ h2 = self.g2 ** x
96
+ proof = DLEQProof.prove_non_interactive(self.group, self.g1, h1, self.g2, h2, wrong_x)
97
+ return {'g1': self.g1, 'h1': h1, 'g2': self.g2, 'h2': h2, 'proof': proof}
98
+
99
+ def test_batch_verify_all_valid(self):
100
+ """Test that all valid DLEQ proofs pass batch verification."""
101
+ proofs_data = [self._create_valid_dleq_proof() for _ in range(5)]
102
+ result = batch_verify_dleq(self.group, proofs_data)
103
+ self.assertTrue(result)
104
+
105
+ def test_batch_verify_one_invalid(self):
106
+ """Test that one invalid DLEQ proof fails entire batch."""
107
+ proofs_data = [self._create_valid_dleq_proof() for _ in range(4)]
108
+ proofs_data.append(self._create_invalid_dleq_proof())
109
+ result = batch_verify_dleq(self.group, proofs_data)
110
+ self.assertFalse(result)
111
+
112
+
113
+ class TestBatchVerifierClass(unittest.TestCase):
114
+ """Tests for BatchVerifier class functionality."""
115
+
116
+ def setUp(self):
117
+ """Set up test fixtures."""
118
+ self.group = PairingGroup('BN254')
119
+ self.g = self.group.random(G1)
120
+ self.g1 = self.group.random(G1)
121
+ self.g2 = self.group.random(G1)
122
+
123
+ def test_add_and_verify_schnorr(self):
124
+ """Test adding Schnorr proofs and verifying."""
125
+ verifier = BatchVerifier(self.group)
126
+
127
+ for _ in range(3):
128
+ x = self.group.random(ZR)
129
+ h = self.g ** x
130
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
131
+ verifier.add_schnorr_proof(self.g, h, proof)
132
+
133
+ result = verifier.verify_all()
134
+ self.assertTrue(result)
135
+
136
+ def test_add_and_verify_dleq(self):
137
+ """Test adding DLEQ proofs and verifying."""
138
+ verifier = BatchVerifier(self.group)
139
+
140
+ for _ in range(3):
141
+ x = self.group.random(ZR)
142
+ h1 = self.g1 ** x
143
+ h2 = self.g2 ** x
144
+ proof = DLEQProof.prove_non_interactive(self.group, self.g1, h1, self.g2, h2, x)
145
+ verifier.add_dleq_proof(self.g1, h1, self.g2, h2, proof)
146
+
147
+ result = verifier.verify_all()
148
+ self.assertTrue(result)
149
+
150
+ def test_mixed_proof_types(self):
151
+ """Test mixing Schnorr and DLEQ proofs in same batch."""
152
+ verifier = BatchVerifier(self.group)
153
+
154
+ # Add Schnorr proofs
155
+ for _ in range(2):
156
+ x = self.group.random(ZR)
157
+ h = self.g ** x
158
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
159
+ verifier.add_schnorr_proof(self.g, h, proof)
160
+
161
+ # Add DLEQ proofs
162
+ for _ in range(2):
163
+ x = self.group.random(ZR)
164
+ h1 = self.g1 ** x
165
+ h2 = self.g2 ** x
166
+ proof = DLEQProof.prove_non_interactive(self.group, self.g1, h1, self.g2, h2, x)
167
+ verifier.add_dleq_proof(self.g1, h1, self.g2, h2, proof)
168
+
169
+ result = verifier.verify_all()
170
+ self.assertTrue(result)
171
+
172
+ def test_clear_batch(self):
173
+ """Test clearing and reusing verifier."""
174
+ verifier = BatchVerifier(self.group)
175
+
176
+ # Add a valid proof
177
+ x = self.group.random(ZR)
178
+ h = self.g ** x
179
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
180
+ verifier.add_schnorr_proof(self.g, h, proof)
181
+
182
+ # Verify first batch
183
+ self.assertTrue(verifier.verify_all())
184
+
185
+ # Clear the verifier
186
+ verifier.clear()
187
+
188
+ # Add new proofs
189
+ for _ in range(2):
190
+ x = self.group.random(ZR)
191
+ h = self.g ** x
192
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
193
+ verifier.add_schnorr_proof(self.g, h, proof)
194
+
195
+ # Verify second batch
196
+ result = verifier.verify_all()
197
+ self.assertTrue(result)
198
+
199
+
200
+ class TestBatchVerifyPerformance(unittest.TestCase):
201
+ """Tests for batch verification performance."""
202
+
203
+ def setUp(self):
204
+ """Set up test fixtures."""
205
+ self.group = PairingGroup('BN254')
206
+ self.g = self.group.random(G1)
207
+
208
+ def test_batch_faster_than_individual(self):
209
+ """Test that batch verification is not slower than individual verification."""
210
+ num_proofs = 10
211
+ proofs_data = []
212
+
213
+ # Generate proofs
214
+ for _ in range(num_proofs):
215
+ x = self.group.random(ZR)
216
+ h = self.g ** x
217
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, h, x)
218
+ proofs_data.append({'g': self.g, 'h': h, 'proof': proof})
219
+
220
+ # Time individual verification
221
+ start_individual = time.time()
222
+ for data in proofs_data:
223
+ SchnorrProof.verify_non_interactive(
224
+ self.group, data['g'], data['h'], data['proof']
225
+ )
226
+ time_individual = time.time() - start_individual
227
+
228
+ # Time batch verification
229
+ start_batch = time.time()
230
+ result = batch_verify_schnorr(self.group, proofs_data)
231
+ time_batch = time.time() - start_batch
232
+
233
+ # Batch verification should work
234
+ self.assertTrue(result)
235
+
236
+ # Batch should ideally be faster (or at least not significantly slower)
237
+ # Allow generous tolerance for timing variations in CI environments
238
+ # We just check that batch works, not strict performance guarantees
239
+ # as performance may vary based on system load
240
+ # Using 3x multiplier to account for CI timing variability
241
+ self.assertLessEqual(time_batch, time_individual * 3 + 0.01,
242
+ f"Batch ({time_batch:.4f}s) should not be significantly "
243
+ f"slower than individual ({time_individual:.4f}s)")
244
+
245
+
246
+ if __name__ == "__main__":
247
+ unittest.main()
248
+
@@ -0,0 +1,264 @@
1
+ """
2
+ Unit tests for DLEQ (Discrete Log Equality) ZK proof implementation.
3
+
4
+ Tests cover:
5
+ - Interactive proof protocol
6
+ - Non-interactive (Fiat-Shamir) proof
7
+ - Serialization and deserialization
8
+ - Different pairing groups
9
+ - Edge cases and error handling
10
+ """
11
+
12
+ import unittest
13
+ from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
14
+ from charm.zkp_compiler.dleq_proof import DLEQProof, DLEQProofData
15
+
16
+
17
+ class TestDLEQProofInteractive(unittest.TestCase):
18
+ """Tests for interactive DLEQ protocol."""
19
+
20
+ def setUp(self):
21
+ """Set up test fixtures."""
22
+ self.group = PairingGroup('BN254')
23
+ self.g1 = self.group.random(G1)
24
+ self.g2 = self.group.random(G1)
25
+ self.x = self.group.random(ZR)
26
+ self.h1 = self.g1 ** self.x
27
+ self.h2 = self.g2 ** self.x
28
+
29
+ def test_prove_and_verify_interactive(self):
30
+ """Test complete interactive proof cycle."""
31
+ # Create prover and verifier
32
+ prover = DLEQProof.Prover(self.x, self.group)
33
+ verifier = DLEQProof.Verifier(self.group)
34
+
35
+ # Step 1: Prover creates commitments
36
+ commitment1, commitment2 = prover.create_commitment(self.g1, self.g2)
37
+ self.assertIsNotNone(commitment1)
38
+ self.assertIsNotNone(commitment2)
39
+
40
+ # Step 2: Verifier creates challenge
41
+ challenge = verifier.create_challenge()
42
+ self.assertIsNotNone(challenge)
43
+
44
+ # Step 3: Prover creates response
45
+ response = prover.create_response(challenge)
46
+ self.assertIsNotNone(response)
47
+
48
+ # Step 4: Verifier verifies
49
+ result = verifier.verify(
50
+ self.g1, self.h1, self.g2, self.h2, commitment1, commitment2, response
51
+ )
52
+ self.assertTrue(result)
53
+
54
+ def test_invalid_proof_fails_interactive(self):
55
+ """Test that wrong secret fails verification."""
56
+ wrong_x = self.group.random(ZR)
57
+ prover = DLEQProof.Prover(wrong_x, self.group)
58
+ verifier = DLEQProof.Verifier(self.group)
59
+
60
+ commitment1, commitment2 = prover.create_commitment(self.g1, self.g2)
61
+ challenge = verifier.create_challenge()
62
+ response = prover.create_response(challenge)
63
+
64
+ # Should fail because wrong secret
65
+ result = verifier.verify(
66
+ self.g1, self.h1, self.g2, self.h2, commitment1, commitment2, response
67
+ )
68
+ self.assertFalse(result)
69
+
70
+ def test_prover_commitment_before_response(self):
71
+ """Test that prover must create commitment before response."""
72
+ prover = DLEQProof.Prover(self.x, self.group)
73
+
74
+ # Try to create response without commitment
75
+ with self.assertRaises(ValueError):
76
+ prover.create_response(self.group.random(ZR))
77
+
78
+ def test_different_exponents_fail(self):
79
+ """Test that using different x for h1 and h2 should fail."""
80
+ x1 = self.group.random(ZR)
81
+ x2 = self.group.random(ZR)
82
+ h1_wrong = self.g1 ** x1
83
+ h2_wrong = self.g2 ** x2
84
+
85
+ # Prover knows x1 but tries to prove h1 = g1^x1 AND h2 = g2^x1
86
+ # But h2 = g2^x2 (not g2^x1), so verification should fail
87
+ prover = DLEQProof.Prover(x1, self.group)
88
+ verifier = DLEQProof.Verifier(self.group)
89
+
90
+ commitment1, commitment2 = prover.create_commitment(self.g1, self.g2)
91
+ challenge = verifier.create_challenge()
92
+ response = prover.create_response(challenge)
93
+
94
+ result = verifier.verify(
95
+ self.g1, h1_wrong, self.g2, h2_wrong, commitment1, commitment2, response
96
+ )
97
+ self.assertFalse(result)
98
+
99
+
100
+ class TestDLEQProofNonInteractive(unittest.TestCase):
101
+ """Tests for non-interactive (Fiat-Shamir) DLEQ proof."""
102
+
103
+ def setUp(self):
104
+ """Set up test fixtures."""
105
+ self.group = PairingGroup('BN254')
106
+ self.g1 = self.group.random(G1)
107
+ self.g2 = self.group.random(G1)
108
+ self.x = self.group.random(ZR)
109
+ self.h1 = self.g1 ** self.x
110
+ self.h2 = self.g2 ** self.x
111
+
112
+ def test_non_interactive_proof_valid(self):
113
+ """Test Fiat-Shamir transformed proof."""
114
+ proof = DLEQProof.prove_non_interactive(
115
+ self.group, self.g1, self.h1, self.g2, self.h2, self.x
116
+ )
117
+
118
+ self.assertIsNotNone(proof)
119
+ self.assertIsNotNone(proof.commitment1)
120
+ self.assertIsNotNone(proof.commitment2)
121
+ self.assertIsNotNone(proof.challenge)
122
+ self.assertIsNotNone(proof.response)
123
+
124
+ result = DLEQProof.verify_non_interactive(
125
+ self.group, self.g1, self.h1, self.g2, self.h2, proof
126
+ )
127
+ self.assertTrue(result)
128
+
129
+ def test_non_interactive_wrong_secret_fails(self):
130
+ """Test that wrong secret fails non-interactive verification."""
131
+ wrong_x = self.group.random(ZR)
132
+ proof = DLEQProof.prove_non_interactive(
133
+ self.group, self.g1, self.h1, self.g2, self.h2, wrong_x
134
+ )
135
+
136
+ result = DLEQProof.verify_non_interactive(
137
+ self.group, self.g1, self.h1, self.g2, self.h2, proof
138
+ )
139
+ self.assertFalse(result)
140
+
141
+ def test_non_interactive_tampered_proof_fails(self):
142
+ """Test that tampered proof fails verification."""
143
+ proof = DLEQProof.prove_non_interactive(
144
+ self.group, self.g1, self.h1, self.g2, self.h2, self.x
145
+ )
146
+
147
+ # Tamper with the response
148
+ tampered = DLEQProofData(
149
+ commitment1=proof.commitment1,
150
+ commitment2=proof.commitment2,
151
+ challenge=proof.challenge,
152
+ response=proof.response + self.group.random(ZR),
153
+ proof_type=proof.proof_type
154
+ )
155
+
156
+ result = DLEQProof.verify_non_interactive(
157
+ self.group, self.g1, self.h1, self.g2, self.h2, tampered
158
+ )
159
+ self.assertFalse(result)
160
+
161
+ def test_proof_deterministic_verification(self):
162
+ """Test that same proof verifies consistently."""
163
+ proof = DLEQProof.prove_non_interactive(
164
+ self.group, self.g1, self.h1, self.g2, self.h2, self.x
165
+ )
166
+
167
+ # Verify multiple times
168
+ for _ in range(5):
169
+ result = DLEQProof.verify_non_interactive(
170
+ self.group, self.g1, self.h1, self.g2, self.h2, proof
171
+ )
172
+ self.assertTrue(result)
173
+
174
+ def test_mismatched_bases_fail(self):
175
+ """Test that h1 = g1^x but h2 = g2^y (different exponents) should fail."""
176
+ x = self.group.random(ZR)
177
+ y = self.group.random(ZR)
178
+ h1 = self.g1 ** x
179
+ h2 = self.g2 ** y
180
+
181
+ # Try to prove with x, but h2 was computed with different y
182
+ proof = DLEQProof.prove_non_interactive(
183
+ self.group, self.g1, h1, self.g2, h2, x
184
+ )
185
+
186
+ result = DLEQProof.verify_non_interactive(
187
+ self.group, self.g1, h1, self.g2, h2, proof
188
+ )
189
+ self.assertFalse(result)
190
+
191
+
192
+ class TestDLEQProofSerialization(unittest.TestCase):
193
+ """Tests for DLEQ proof serialization."""
194
+
195
+ def setUp(self):
196
+ """Set up test fixtures."""
197
+ self.group = PairingGroup('BN254')
198
+ self.g1 = self.group.random(G1)
199
+ self.g2 = self.group.random(G1)
200
+ self.x = self.group.random(ZR)
201
+ self.h1 = self.g1 ** self.x
202
+ self.h2 = self.g2 ** self.x
203
+
204
+ def test_serialization_roundtrip(self):
205
+ """Test serialize and deserialize proof."""
206
+ proof = DLEQProof.prove_non_interactive(
207
+ self.group, self.g1, self.h1, self.g2, self.h2, self.x
208
+ )
209
+
210
+ # Serialize
211
+ serialized = DLEQProof.serialize_proof(proof, self.group)
212
+ self.assertIsInstance(serialized, bytes)
213
+ self.assertGreater(len(serialized), 0)
214
+
215
+ # Deserialize
216
+ deserialized = DLEQProof.deserialize_proof(serialized, self.group)
217
+ self.assertIsNotNone(deserialized)
218
+ self.assertEqual(deserialized.proof_type, proof.proof_type)
219
+
220
+ def test_serialized_proof_verifies(self):
221
+ """Test that deserialized proof still verifies."""
222
+ proof = DLEQProof.prove_non_interactive(
223
+ self.group, self.g1, self.h1, self.g2, self.h2, self.x
224
+ )
225
+
226
+ # Serialize and deserialize
227
+ serialized = DLEQProof.serialize_proof(proof, self.group)
228
+ deserialized = DLEQProof.deserialize_proof(serialized, self.group)
229
+
230
+ # Verify the deserialized proof
231
+ result = DLEQProof.verify_non_interactive(
232
+ self.group, self.g1, self.h1, self.g2, self.h2, deserialized
233
+ )
234
+ self.assertTrue(result)
235
+
236
+
237
+ class TestDLEQProofWithDifferentGroups(unittest.TestCase):
238
+ """Test DLEQ proofs with different pairing groups."""
239
+
240
+ def test_with_bn254_group(self):
241
+ """Test with BN254 pairing group."""
242
+ self._test_with_group('BN254')
243
+
244
+ def test_with_mnt224_group(self):
245
+ """Test with MNT224 pairing group."""
246
+ self._test_with_group('MNT224')
247
+
248
+ def _test_with_group(self, curve_name):
249
+ """Helper to test with a specific group."""
250
+ group = PairingGroup(curve_name)
251
+ g1 = group.random(G1)
252
+ g2 = group.random(G1)
253
+ x = group.random(ZR)
254
+ h1 = g1 ** x
255
+ h2 = g2 ** x
256
+
257
+ proof = DLEQProof.prove_non_interactive(group, g1, h1, g2, h2, x)
258
+ result = DLEQProof.verify_non_interactive(group, g1, h1, g2, h2, proof)
259
+ self.assertTrue(result)
260
+
261
+
262
+ if __name__ == "__main__":
263
+ unittest.main()
264
+