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,325 @@
1
+ """
2
+ Unit tests for Representation ZK proof implementation.
3
+
4
+ Tests cover:
5
+ - Interactive proof protocol with multiple generators
6
+ - Non-interactive (Fiat-Shamir) proof
7
+ - Serialization/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.representation_proof import RepresentationProof, RepresentationProofData
15
+
16
+
17
+ class TestRepresentationProofInteractive(unittest.TestCase):
18
+ """Tests for interactive Representation protocol."""
19
+
20
+ def setUp(self):
21
+ """Set up test fixtures."""
22
+ self.group = PairingGroup('BN254')
23
+
24
+ def test_prove_and_verify_interactive_two_generators(self):
25
+ """Test complete interactive proof cycle with two generators (Pedersen commitment style)."""
26
+ g1 = self.group.random(G1)
27
+ g2 = self.group.random(G1)
28
+ x1 = self.group.random(ZR)
29
+ x2 = self.group.random(ZR)
30
+ h = (g1 ** x1) * (g2 ** x2)
31
+
32
+ # Create prover and verifier
33
+ prover = RepresentationProof.Prover([x1, x2], self.group)
34
+ verifier = RepresentationProof.Verifier(self.group)
35
+
36
+ # Step 1: Prover creates commitment
37
+ commitment = prover.create_commitment([g1, g2])
38
+ self.assertIsNotNone(commitment)
39
+
40
+ # Step 2: Verifier creates challenge
41
+ challenge = verifier.create_challenge()
42
+ self.assertIsNotNone(challenge)
43
+
44
+ # Step 3: Prover creates response
45
+ responses = prover.create_response(challenge)
46
+ self.assertIsNotNone(responses)
47
+ self.assertEqual(len(responses), 2)
48
+
49
+ # Step 4: Verifier verifies
50
+ result = verifier.verify([g1, g2], h, commitment, responses)
51
+ self.assertTrue(result)
52
+
53
+ def test_prove_and_verify_interactive_three_generators(self):
54
+ """Test complete interactive proof cycle with three generators."""
55
+ g1 = self.group.random(G1)
56
+ g2 = self.group.random(G1)
57
+ g3 = self.group.random(G1)
58
+ x1 = self.group.random(ZR)
59
+ x2 = self.group.random(ZR)
60
+ x3 = self.group.random(ZR)
61
+ h = (g1 ** x1) * (g2 ** x2) * (g3 ** x3)
62
+
63
+ prover = RepresentationProof.Prover([x1, x2, x3], self.group)
64
+ verifier = RepresentationProof.Verifier(self.group)
65
+
66
+ commitment = prover.create_commitment([g1, g2, g3])
67
+ challenge = verifier.create_challenge()
68
+ responses = prover.create_response(challenge)
69
+
70
+ self.assertEqual(len(responses), 3)
71
+ result = verifier.verify([g1, g2, g3], h, commitment, responses)
72
+ self.assertTrue(result)
73
+
74
+ def test_invalid_proof_fails_interactive(self):
75
+ """Test that wrong witnesses fail verification."""
76
+ g1 = self.group.random(G1)
77
+ g2 = self.group.random(G1)
78
+ x1 = self.group.random(ZR)
79
+ x2 = self.group.random(ZR)
80
+ h = (g1 ** x1) * (g2 ** x2)
81
+
82
+ # Use wrong witnesses
83
+ wrong_x1 = self.group.random(ZR)
84
+ wrong_x2 = self.group.random(ZR)
85
+ prover = RepresentationProof.Prover([wrong_x1, wrong_x2], self.group)
86
+ verifier = RepresentationProof.Verifier(self.group)
87
+
88
+ commitment = prover.create_commitment([g1, g2])
89
+ challenge = verifier.create_challenge()
90
+ responses = prover.create_response(challenge)
91
+
92
+ # Should fail because wrong witnesses
93
+ result = verifier.verify([g1, g2], h, commitment, responses)
94
+ self.assertFalse(result)
95
+
96
+ def test_prover_commitment_before_response(self):
97
+ """Test that prover must create commitment before response."""
98
+ x1 = self.group.random(ZR)
99
+ x2 = self.group.random(ZR)
100
+ prover = RepresentationProof.Prover([x1, x2], self.group)
101
+
102
+ # Try to create response without commitment
103
+ with self.assertRaises(ValueError):
104
+ prover.create_response(self.group.random(ZR))
105
+
106
+
107
+ class TestRepresentationProofNonInteractive(unittest.TestCase):
108
+ """Tests for non-interactive (Fiat-Shamir) Representation proof."""
109
+
110
+ def setUp(self):
111
+ """Set up test fixtures."""
112
+ self.group = PairingGroup('BN254')
113
+
114
+ def test_non_interactive_proof_valid_two_generators(self):
115
+ """Test Fiat-Shamir transformed proof with two generators."""
116
+ g1 = self.group.random(G1)
117
+ g2 = self.group.random(G1)
118
+ x1 = self.group.random(ZR)
119
+ x2 = self.group.random(ZR)
120
+ h = (g1 ** x1) * (g2 ** x2)
121
+
122
+ proof = RepresentationProof.prove_non_interactive(
123
+ self.group, [g1, g2], h, [x1, x2]
124
+ )
125
+
126
+ self.assertIsNotNone(proof)
127
+ self.assertIsNotNone(proof.commitment)
128
+ self.assertIsNotNone(proof.challenge)
129
+ self.assertIsNotNone(proof.responses)
130
+ self.assertEqual(len(proof.responses), 2)
131
+
132
+ result = RepresentationProof.verify_non_interactive(
133
+ self.group, [g1, g2], h, proof
134
+ )
135
+ self.assertTrue(result)
136
+
137
+ def test_non_interactive_proof_valid_three_generators(self):
138
+ """Test Fiat-Shamir transformed proof with three generators."""
139
+ g1 = self.group.random(G1)
140
+ g2 = self.group.random(G1)
141
+ g3 = self.group.random(G1)
142
+ x1 = self.group.random(ZR)
143
+ x2 = self.group.random(ZR)
144
+ x3 = self.group.random(ZR)
145
+ h = (g1 ** x1) * (g2 ** x2) * (g3 ** x3)
146
+
147
+ proof = RepresentationProof.prove_non_interactive(
148
+ self.group, [g1, g2, g3], h, [x1, x2, x3]
149
+ )
150
+
151
+ self.assertEqual(len(proof.responses), 3)
152
+ result = RepresentationProof.verify_non_interactive(
153
+ self.group, [g1, g2, g3], h, proof
154
+ )
155
+ self.assertTrue(result)
156
+
157
+ def test_non_interactive_wrong_witness_fails(self):
158
+ """Test that wrong witness fails non-interactive verification."""
159
+ g1 = self.group.random(G1)
160
+ g2 = self.group.random(G1)
161
+ x1 = self.group.random(ZR)
162
+ x2 = self.group.random(ZR)
163
+ h = (g1 ** x1) * (g2 ** x2)
164
+
165
+ # Create proof with wrong witnesses
166
+ wrong_x1 = self.group.random(ZR)
167
+ wrong_x2 = self.group.random(ZR)
168
+ proof = RepresentationProof.prove_non_interactive(
169
+ self.group, [g1, g2], h, [wrong_x1, wrong_x2]
170
+ )
171
+
172
+ result = RepresentationProof.verify_non_interactive(
173
+ self.group, [g1, g2], h, proof
174
+ )
175
+ self.assertFalse(result)
176
+
177
+ def test_non_interactive_tampered_proof_fails(self):
178
+ """Test that tampered proof fails verification."""
179
+ g1 = self.group.random(G1)
180
+ g2 = self.group.random(G1)
181
+ x1 = self.group.random(ZR)
182
+ x2 = self.group.random(ZR)
183
+ h = (g1 ** x1) * (g2 ** x2)
184
+
185
+ proof = RepresentationProof.prove_non_interactive(
186
+ self.group, [g1, g2], h, [x1, x2]
187
+ )
188
+
189
+ # Tamper with the first response
190
+ tampered_responses = list(proof.responses)
191
+ tampered_responses[0] = tampered_responses[0] + self.group.random(ZR)
192
+ tampered = RepresentationProofData(
193
+ commitment=proof.commitment,
194
+ challenge=proof.challenge,
195
+ responses=tampered_responses,
196
+ proof_type=proof.proof_type
197
+ )
198
+
199
+ result = RepresentationProof.verify_non_interactive(
200
+ self.group, [g1, g2], h, tampered
201
+ )
202
+ self.assertFalse(result)
203
+
204
+ def test_proof_deterministic_verification(self):
205
+ """Test that same proof verifies consistently."""
206
+ g1 = self.group.random(G1)
207
+ g2 = self.group.random(G1)
208
+ x1 = self.group.random(ZR)
209
+ x2 = self.group.random(ZR)
210
+ h = (g1 ** x1) * (g2 ** x2)
211
+
212
+ proof = RepresentationProof.prove_non_interactive(
213
+ self.group, [g1, g2], h, [x1, x2]
214
+ )
215
+
216
+ # Verify multiple times
217
+ for _ in range(5):
218
+ result = RepresentationProof.verify_non_interactive(
219
+ self.group, [g1, g2], h, proof
220
+ )
221
+ self.assertTrue(result)
222
+
223
+ def test_single_generator_equivalent_to_schnorr(self):
224
+ """Test that with 1 generator, representation proof works like Schnorr."""
225
+ g = self.group.random(G1)
226
+ x = self.group.random(ZR)
227
+ h = g ** x
228
+
229
+ # Create representation proof with single generator
230
+ proof = RepresentationProof.prove_non_interactive(
231
+ self.group, [g], h, [x]
232
+ )
233
+
234
+ self.assertIsNotNone(proof)
235
+ self.assertEqual(len(proof.responses), 1)
236
+
237
+ result = RepresentationProof.verify_non_interactive(
238
+ self.group, [g], h, proof
239
+ )
240
+ self.assertTrue(result)
241
+
242
+
243
+ class TestRepresentationProofSerialization(unittest.TestCase):
244
+ """Tests for proof serialization and deserialization."""
245
+
246
+ def setUp(self):
247
+ """Set up test fixtures."""
248
+ self.group = PairingGroup('BN254')
249
+
250
+ def test_serialization_roundtrip(self):
251
+ """Test that proof can be serialized and deserialized."""
252
+ g1 = self.group.random(G1)
253
+ g2 = self.group.random(G1)
254
+ x1 = self.group.random(ZR)
255
+ x2 = self.group.random(ZR)
256
+ h = (g1 ** x1) * (g2 ** x2)
257
+
258
+ proof = RepresentationProof.prove_non_interactive(
259
+ self.group, [g1, g2], h, [x1, x2]
260
+ )
261
+
262
+ # Serialize and deserialize
263
+ serialized = RepresentationProof.serialize_proof(proof, self.group)
264
+ self.assertIsInstance(serialized, bytes)
265
+
266
+ deserialized = RepresentationProof.deserialize_proof(serialized, self.group)
267
+ self.assertEqual(deserialized.commitment, proof.commitment)
268
+ self.assertEqual(deserialized.challenge, proof.challenge)
269
+ self.assertEqual(len(deserialized.responses), len(proof.responses))
270
+ for i in range(len(proof.responses)):
271
+ self.assertEqual(deserialized.responses[i], proof.responses[i])
272
+
273
+ def test_serialized_proof_verifies(self):
274
+ """Test that deserialized proof still verifies."""
275
+ g1 = self.group.random(G1)
276
+ g2 = self.group.random(G1)
277
+ x1 = self.group.random(ZR)
278
+ x2 = self.group.random(ZR)
279
+ h = (g1 ** x1) * (g2 ** x2)
280
+
281
+ proof = RepresentationProof.prove_non_interactive(
282
+ self.group, [g1, g2], h, [x1, x2]
283
+ )
284
+
285
+ # Serialize, deserialize, then verify
286
+ serialized = RepresentationProof.serialize_proof(proof, self.group)
287
+ deserialized = RepresentationProof.deserialize_proof(serialized, self.group)
288
+
289
+ result = RepresentationProof.verify_non_interactive(
290
+ self.group, [g1, g2], h, deserialized
291
+ )
292
+ self.assertTrue(result)
293
+
294
+
295
+ class TestRepresentationProofWithDifferentGroups(unittest.TestCase):
296
+ """Test Representation proofs with different pairing groups."""
297
+
298
+ def test_with_bn254_group(self):
299
+ """Test with BN254 pairing group."""
300
+ self._test_with_group('BN254')
301
+
302
+ def test_with_mnt224_group(self):
303
+ """Test with MNT224 pairing group."""
304
+ self._test_with_group('MNT224')
305
+
306
+ def _test_with_group(self, curve_name):
307
+ """Helper to test with a specific group."""
308
+ group = PairingGroup(curve_name)
309
+ g1 = group.random(G1)
310
+ g2 = group.random(G1)
311
+ x1 = group.random(ZR)
312
+ x2 = group.random(ZR)
313
+ h = (g1 ** x1) * (g2 ** x2)
314
+
315
+ proof = RepresentationProof.prove_non_interactive(
316
+ group, [g1, g2], h, [x1, x2]
317
+ )
318
+ result = RepresentationProof.verify_non_interactive(
319
+ group, [g1, g2], h, proof
320
+ )
321
+ self.assertTrue(result)
322
+
323
+
324
+ if __name__ == "__main__":
325
+ unittest.main()
@@ -0,0 +1,221 @@
1
+ """
2
+ Unit tests for Schnorr ZK proof implementation.
3
+
4
+ Tests cover:
5
+ - Interactive proof protocol
6
+ - Non-interactive (Fiat-Shamir) proof
7
+ - Different pairing groups
8
+ - Edge cases and error handling
9
+ """
10
+
11
+ import unittest
12
+ from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
13
+ from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
14
+
15
+
16
+ class TestSchnorrProofInteractive(unittest.TestCase):
17
+ """Tests for interactive Schnorr protocol."""
18
+
19
+ def setUp(self):
20
+ """Set up test fixtures."""
21
+ self.group = PairingGroup('BN254')
22
+ self.g = self.group.random(G1)
23
+ self.x = self.group.random(ZR)
24
+ self.h = self.g ** self.x
25
+
26
+ def test_prove_and_verify_interactive(self):
27
+ """Test complete interactive proof cycle."""
28
+ # Create prover and verifier
29
+ prover = SchnorrProof.Prover(self.x, self.group)
30
+ verifier = SchnorrProof.Verifier(self.group)
31
+
32
+ # Step 1: Prover creates commitment
33
+ commitment = prover.create_commitment(self.g)
34
+ self.assertIsNotNone(commitment)
35
+
36
+ # Step 2: Verifier creates challenge
37
+ challenge = verifier.create_challenge()
38
+ self.assertIsNotNone(challenge)
39
+
40
+ # Step 3: Prover creates response
41
+ response = prover.create_response(challenge)
42
+ self.assertIsNotNone(response)
43
+
44
+ # Step 4: Verifier verifies
45
+ result = verifier.verify(self.g, self.h, commitment, response)
46
+ self.assertTrue(result)
47
+
48
+ def test_invalid_proof_fails_interactive(self):
49
+ """Test that wrong secret fails verification."""
50
+ wrong_x = self.group.random(ZR)
51
+ prover = SchnorrProof.Prover(wrong_x, self.group)
52
+ verifier = SchnorrProof.Verifier(self.group)
53
+
54
+ commitment = prover.create_commitment(self.g)
55
+ challenge = verifier.create_challenge()
56
+ response = prover.create_response(challenge)
57
+
58
+ # Should fail because wrong secret
59
+ result = verifier.verify(self.g, self.h, commitment, response)
60
+ self.assertFalse(result)
61
+
62
+ def test_prover_commitment_before_response(self):
63
+ """Test that prover must create commitment before response."""
64
+ prover = SchnorrProof.Prover(self.x, self.group)
65
+
66
+ # Try to create response without commitment
67
+ with self.assertRaises(Exception):
68
+ prover.create_response(self.group.random(ZR))
69
+
70
+
71
+ class TestSchnorrProofNonInteractive(unittest.TestCase):
72
+ """Tests for non-interactive (Fiat-Shamir) Schnorr proof."""
73
+
74
+ def setUp(self):
75
+ """Set up test fixtures."""
76
+ self.group = PairingGroup('BN254')
77
+ self.g = self.group.random(G1)
78
+ self.x = self.group.random(ZR)
79
+ self.h = self.g ** self.x
80
+
81
+ def test_non_interactive_proof_valid(self):
82
+ """Test Fiat-Shamir transformed proof."""
83
+ proof = SchnorrProof.prove_non_interactive(
84
+ self.group, self.g, self.h, self.x
85
+ )
86
+
87
+ self.assertIsNotNone(proof)
88
+ self.assertIsNotNone(proof.commitment)
89
+ self.assertIsNotNone(proof.challenge)
90
+ self.assertIsNotNone(proof.response)
91
+
92
+ result = SchnorrProof.verify_non_interactive(
93
+ self.group, self.g, self.h, proof
94
+ )
95
+ self.assertTrue(result)
96
+
97
+ def test_non_interactive_wrong_secret_fails(self):
98
+ """Test that wrong secret fails non-interactive verification."""
99
+ wrong_x = self.group.random(ZR)
100
+ proof = SchnorrProof.prove_non_interactive(
101
+ self.group, self.g, self.h, wrong_x
102
+ )
103
+
104
+ result = SchnorrProof.verify_non_interactive(
105
+ self.group, self.g, self.h, proof
106
+ )
107
+ self.assertFalse(result)
108
+
109
+ def test_non_interactive_tampered_proof_fails(self):
110
+ """Test that tampered proof fails verification."""
111
+ proof = SchnorrProof.prove_non_interactive(
112
+ self.group, self.g, self.h, self.x
113
+ )
114
+
115
+ # Tamper with the response
116
+ tampered = Proof(
117
+ commitment=proof.commitment,
118
+ challenge=proof.challenge,
119
+ response=proof.response + self.group.random(ZR),
120
+ proof_type=proof.proof_type
121
+ )
122
+
123
+ result = SchnorrProof.verify_non_interactive(
124
+ self.group, self.g, self.h, tampered
125
+ )
126
+ self.assertFalse(result)
127
+
128
+ def test_proof_deterministic_verification(self):
129
+ """Test that same proof verifies consistently."""
130
+ proof = SchnorrProof.prove_non_interactive(
131
+ self.group, self.g, self.h, self.x
132
+ )
133
+
134
+ # Verify multiple times
135
+ for _ in range(5):
136
+ result = SchnorrProof.verify_non_interactive(
137
+ self.group, self.g, self.h, proof
138
+ )
139
+ self.assertTrue(result)
140
+
141
+
142
+ class TestSchnorrProofWithDifferentGroups(unittest.TestCase):
143
+ """Test Schnorr proofs with different pairing groups."""
144
+
145
+ def test_with_bn254_group(self):
146
+ """Test with BN254 pairing group."""
147
+ self._test_with_group('BN254')
148
+
149
+ def test_with_mnt224_group(self):
150
+ """Test with MNT224 pairing group."""
151
+ self._test_with_group('MNT224')
152
+
153
+ def _test_with_group(self, curve_name):
154
+ """Helper to test with a specific group."""
155
+ group = PairingGroup(curve_name)
156
+ g = group.random(G1)
157
+ x = group.random(ZR)
158
+ h = g ** x
159
+
160
+ proof = SchnorrProof.prove_non_interactive(group, g, h, x)
161
+ result = SchnorrProof.verify_non_interactive(group, g, h, proof)
162
+ self.assertTrue(result)
163
+
164
+
165
+ class TestSchnorrProofSecurity(unittest.TestCase):
166
+ """Security-focused tests for Schnorr proofs."""
167
+
168
+ def setUp(self):
169
+ """Set up test fixtures."""
170
+ self.group = PairingGroup('BN254')
171
+ self.g = self.group.random(G1)
172
+ self.x = self.group.random(ZR)
173
+ self.h = self.g ** self.x
174
+
175
+ def test_invalid_proof_structure_rejected(self):
176
+ """Test that proofs with missing attributes are rejected."""
177
+ # Create a fake proof object without required attributes
178
+ class FakeProof:
179
+ pass
180
+
181
+ fake_proof = FakeProof()
182
+ result = SchnorrProof.verify_non_interactive(self.group, self.g, self.h, fake_proof)
183
+ self.assertFalse(result)
184
+
185
+ def test_identity_commitment_rejected(self):
186
+ """Test that proofs with identity element commitment are rejected."""
187
+ # Create a valid proof first
188
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, self.h, self.x)
189
+
190
+ # Replace commitment with identity element
191
+ identity = self.group.init(G1, 1)
192
+ tampered_proof = Proof(
193
+ commitment=identity,
194
+ challenge=proof.challenge,
195
+ response=proof.response,
196
+ proof_type='schnorr'
197
+ )
198
+
199
+ result = SchnorrProof.verify_non_interactive(self.group, self.g, self.h, tampered_proof)
200
+ self.assertFalse(result)
201
+
202
+ def test_challenge_mismatch_rejected(self):
203
+ """Test that proofs with wrong challenge are rejected."""
204
+ proof = SchnorrProof.prove_non_interactive(self.group, self.g, self.h, self.x)
205
+
206
+ # Tamper with the challenge
207
+ wrong_challenge = self.group.random(ZR)
208
+ tampered_proof = Proof(
209
+ commitment=proof.commitment,
210
+ challenge=wrong_challenge,
211
+ response=proof.response,
212
+ proof_type='schnorr'
213
+ )
214
+
215
+ result = SchnorrProof.verify_non_interactive(self.group, self.g, self.h, tampered_proof)
216
+ self.assertFalse(result)
217
+
218
+
219
+ if __name__ == "__main__":
220
+ unittest.main()
221
+