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.
- charm/__init__.py +5 -0
- charm/adapters/__init__.py +0 -0
- charm/adapters/abenc_adapt_hybrid.py +90 -0
- charm/adapters/dabenc_adapt_hybrid.py +145 -0
- charm/adapters/ibenc_adapt_hybrid.py +72 -0
- charm/adapters/ibenc_adapt_identityhash.py +80 -0
- charm/adapters/kpabenc_adapt_hybrid.py +91 -0
- charm/adapters/pkenc_adapt_bchk05.py +121 -0
- charm/adapters/pkenc_adapt_chk04.py +91 -0
- charm/adapters/pkenc_adapt_hybrid.py +98 -0
- charm/adapters/pksig_adapt_naor01.py +89 -0
- charm/config.py +7 -0
- charm/core/__init__.py +0 -0
- charm/core/benchmark/benchmark_util.c +353 -0
- charm/core/benchmark/benchmark_util.h +61 -0
- charm/core/benchmark/benchmarkmodule.c +476 -0
- charm/core/benchmark/benchmarkmodule.h +162 -0
- charm/core/benchmark.cpython-313-darwin.so +0 -0
- charm/core/crypto/AES/AES.c +1464 -0
- charm/core/crypto/AES.cpython-313-darwin.so +0 -0
- charm/core/crypto/DES/DES.c +113 -0
- charm/core/crypto/DES.cpython-313-darwin.so +0 -0
- charm/core/crypto/DES3/DES3.c +26 -0
- charm/core/crypto/DES3.cpython-313-darwin.so +0 -0
- charm/core/crypto/__init__.py +0 -0
- charm/core/crypto/cryptobase/XOR.c +80 -0
- charm/core/crypto/cryptobase/_counter.c +496 -0
- charm/core/crypto/cryptobase/_counter.h +54 -0
- charm/core/crypto/cryptobase/block_template.c +900 -0
- charm/core/crypto/cryptobase/block_template.h +69 -0
- charm/core/crypto/cryptobase/cryptobasemodule.c +220 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt.h +90 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_argchk.h +44 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_cfg.h +186 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_cipher.h +941 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_custom.h +556 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_des.c +1912 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_hash.h +407 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_mac.h +496 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_macros.h +435 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_math.h +534 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_misc.h +103 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_pk.h +653 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_pkcs.h +90 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_prng.h +199 -0
- charm/core/crypto/cryptobase/stream_template.c +271 -0
- charm/core/crypto/cryptobase/strxor.c +229 -0
- charm/core/crypto/cryptobase.cpython-313-darwin.so +0 -0
- charm/core/engine/__init__.py +5 -0
- charm/core/engine/protocol.py +293 -0
- charm/core/engine/util.py +174 -0
- charm/core/math/__init__.py +0 -0
- charm/core/math/elliptic_curve/ecmodule.c +1986 -0
- charm/core/math/elliptic_curve/ecmodule.h +230 -0
- charm/core/math/elliptic_curve.cpython-313-darwin.so +0 -0
- charm/core/math/elliptic_curve.pyi +63 -0
- charm/core/math/integer/integermodule.c +2539 -0
- charm/core/math/integer/integermodule.h +145 -0
- charm/core/math/integer.cpython-313-darwin.so +0 -0
- charm/core/math/integer.pyi +76 -0
- charm/core/math/pairing/miracl/miracl_config.h +37 -0
- charm/core/math/pairing/miracl/miracl_interface.h +118 -0
- charm/core/math/pairing/miracl/miracl_interface2.h +126 -0
- charm/core/math/pairing/miracl/pairingmodule2.c +2094 -0
- charm/core/math/pairing/miracl/pairingmodule2.h +307 -0
- charm/core/math/pairing/pairingmodule.c +2230 -0
- charm/core/math/pairing/pairingmodule.h +241 -0
- charm/core/math/pairing/relic/pairingmodule3.c +1853 -0
- charm/core/math/pairing/relic/pairingmodule3.h +233 -0
- charm/core/math/pairing/relic/relic_interface.c +1337 -0
- charm/core/math/pairing/relic/relic_interface.h +217 -0
- charm/core/math/pairing/relic/test_relic.c +171 -0
- charm/core/math/pairing.cpython-313-darwin.so +0 -0
- charm/core/math/pairing.pyi +69 -0
- charm/core/utilities/base64.c +248 -0
- charm/core/utilities/base64.h +15 -0
- charm/schemes/__init__.py +0 -0
- charm/schemes/abenc/__init__.py +0 -0
- charm/schemes/abenc/abenc_accountability_jyjxgd20.py +647 -0
- charm/schemes/abenc/abenc_bsw07.py +146 -0
- charm/schemes/abenc/abenc_ca_cpabe_ar17.py +684 -0
- charm/schemes/abenc/abenc_dacmacs_yj14.py +298 -0
- charm/schemes/abenc/abenc_lsw08.py +159 -0
- charm/schemes/abenc/abenc_maabe_rw15.py +236 -0
- charm/schemes/abenc/abenc_maabe_yj14.py +297 -0
- charm/schemes/abenc/abenc_tbpre_lww14.py +309 -0
- charm/schemes/abenc/abenc_unmcpabe_yahk14.py +223 -0
- charm/schemes/abenc/abenc_waters09.py +144 -0
- charm/schemes/abenc/abenc_yct14.py +208 -0
- charm/schemes/abenc/abenc_yllc15.py +178 -0
- charm/schemes/abenc/ac17.py +248 -0
- charm/schemes/abenc/bsw07.py +141 -0
- charm/schemes/abenc/cgw15.py +277 -0
- charm/schemes/abenc/dabe_aw11.py +204 -0
- charm/schemes/abenc/dfa_fe12.py +144 -0
- charm/schemes/abenc/pk_hve08.py +179 -0
- charm/schemes/abenc/waters11.py +143 -0
- charm/schemes/aggrsign_MuSig.py +150 -0
- charm/schemes/aggrsign_bls.py +267 -0
- charm/schemes/blindsig_ps16.py +654 -0
- charm/schemes/chamhash_adm05.py +113 -0
- charm/schemes/chamhash_rsa_hw09.py +100 -0
- charm/schemes/commit/__init__.py +0 -0
- charm/schemes/commit/commit_gs08.py +77 -0
- charm/schemes/commit/commit_pedersen92.py +53 -0
- charm/schemes/encap_bchk05.py +62 -0
- charm/schemes/grpsig/__init__.py +0 -0
- charm/schemes/grpsig/groupsig_bgls04.py +114 -0
- charm/schemes/grpsig/groupsig_bgls04_var.py +115 -0
- charm/schemes/hibenc/__init__.py +0 -0
- charm/schemes/hibenc/hibenc_bb04.py +105 -0
- charm/schemes/hibenc/hibenc_lew11.py +193 -0
- charm/schemes/ibenc/__init__.py +0 -0
- charm/schemes/ibenc/clpkc_rp03.py +119 -0
- charm/schemes/ibenc/ibenc_CW13_z.py +168 -0
- charm/schemes/ibenc/ibenc_bb03.py +94 -0
- charm/schemes/ibenc/ibenc_bf01.py +121 -0
- charm/schemes/ibenc/ibenc_ckrs09.py +120 -0
- charm/schemes/ibenc/ibenc_cllww12_z.py +172 -0
- charm/schemes/ibenc/ibenc_lsw08.py +120 -0
- charm/schemes/ibenc/ibenc_sw05.py +238 -0
- charm/schemes/ibenc/ibenc_waters05.py +144 -0
- charm/schemes/ibenc/ibenc_waters05_z.py +164 -0
- charm/schemes/ibenc/ibenc_waters09.py +107 -0
- charm/schemes/ibenc/ibenc_waters09_z.py +147 -0
- charm/schemes/joye_scheme.py +106 -0
- charm/schemes/lem_scheme.py +207 -0
- charm/schemes/pk_fre_ccv11.py +107 -0
- charm/schemes/pk_vrf.py +127 -0
- charm/schemes/pkenc/__init__.py +0 -0
- charm/schemes/pkenc/pkenc_cs98.py +108 -0
- charm/schemes/pkenc/pkenc_elgamal85.py +122 -0
- charm/schemes/pkenc/pkenc_gm82.py +98 -0
- charm/schemes/pkenc/pkenc_paillier99.py +118 -0
- charm/schemes/pkenc/pkenc_rabin.py +254 -0
- charm/schemes/pkenc/pkenc_rsa.py +186 -0
- charm/schemes/pksig/__init__.py +0 -0
- charm/schemes/pksig/pksig_CW13_z.py +135 -0
- charm/schemes/pksig/pksig_bls04.py +87 -0
- charm/schemes/pksig/pksig_boyen.py +156 -0
- charm/schemes/pksig/pksig_chch.py +97 -0
- charm/schemes/pksig/pksig_chp.py +70 -0
- charm/schemes/pksig/pksig_cl03.py +150 -0
- charm/schemes/pksig/pksig_cl04.py +87 -0
- charm/schemes/pksig/pksig_cllww12_z.py +142 -0
- charm/schemes/pksig/pksig_cyh.py +132 -0
- charm/schemes/pksig/pksig_dsa.py +76 -0
- charm/schemes/pksig/pksig_ecdsa.py +71 -0
- charm/schemes/pksig/pksig_hess.py +104 -0
- charm/schemes/pksig/pksig_hw.py +110 -0
- charm/schemes/pksig/pksig_lamport.py +63 -0
- charm/schemes/pksig/pksig_ps01.py +135 -0
- charm/schemes/pksig/pksig_ps02.py +124 -0
- charm/schemes/pksig/pksig_ps03.py +119 -0
- charm/schemes/pksig/pksig_rsa_hw09.py +206 -0
- charm/schemes/pksig/pksig_schnorr91.py +77 -0
- charm/schemes/pksig/pksig_waters.py +115 -0
- charm/schemes/pksig/pksig_waters05.py +121 -0
- charm/schemes/pksig/pksig_waters09.py +121 -0
- charm/schemes/pre_mg07.py +150 -0
- charm/schemes/prenc/pre_afgh06.py +126 -0
- charm/schemes/prenc/pre_bbs98.py +123 -0
- charm/schemes/prenc/pre_nal16.py +216 -0
- charm/schemes/protocol_a01.py +272 -0
- charm/schemes/protocol_ao00.py +215 -0
- charm/schemes/protocol_cns07.py +274 -0
- charm/schemes/protocol_schnorr91.py +125 -0
- charm/schemes/sigma1.py +64 -0
- charm/schemes/sigma2.py +129 -0
- charm/schemes/sigma3.py +126 -0
- charm/schemes/threshold/__init__.py +59 -0
- charm/schemes/threshold/dkls23_dkg.py +556 -0
- charm/schemes/threshold/dkls23_presign.py +1089 -0
- charm/schemes/threshold/dkls23_sign.py +761 -0
- charm/schemes/threshold/xrpl_wallet.py +967 -0
- charm/test/__init__.py +0 -0
- charm/test/adapters/__init__.py +0 -0
- charm/test/adapters/abenc_adapt_hybrid_test.py +29 -0
- charm/test/adapters/dabenc_adapt_hybrid_test.py +56 -0
- charm/test/adapters/ibenc_adapt_hybrid_test.py +36 -0
- charm/test/adapters/ibenc_adapt_identityhash_test.py +32 -0
- charm/test/adapters/kpabenc_adapt_hybrid_test.py +30 -0
- charm/test/benchmark/abenc_yllc15_bench.py +92 -0
- charm/test/benchmark/benchmark_test.py +148 -0
- charm/test/benchmark_threshold.py +260 -0
- charm/test/conftest.py +38 -0
- charm/test/fuzz/__init__.py +1 -0
- charm/test/fuzz/conftest.py +5 -0
- charm/test/fuzz/fuzz_policy_parser.py +76 -0
- charm/test/fuzz/fuzz_serialization.py +83 -0
- charm/test/schemes/__init__.py +0 -0
- charm/test/schemes/abenc/__init__.py +0 -0
- charm/test/schemes/abenc/abenc_bsw07_test.py +39 -0
- charm/test/schemes/abenc/abenc_dacmacs_yj14_test.py +16 -0
- charm/test/schemes/abenc/abenc_lsw08_test.py +33 -0
- charm/test/schemes/abenc/abenc_maabe_yj14_test.py +16 -0
- charm/test/schemes/abenc/abenc_tbpre_lww14_test.py +16 -0
- charm/test/schemes/abenc/abenc_waters09_test.py +38 -0
- charm/test/schemes/abenc/abenc_yllc15_test.py +74 -0
- charm/test/schemes/chamhash_adm05_test.py +31 -0
- charm/test/schemes/chamhash_rsa_hw09_test.py +29 -0
- charm/test/schemes/commit/__init__.py +0 -0
- charm/test/schemes/commit/commit_gs08_test.py +24 -0
- charm/test/schemes/commit/commit_pedersen92_test.py +26 -0
- charm/test/schemes/dabe_aw11_test.py +45 -0
- charm/test/schemes/encap_bchk05_test.py +21 -0
- charm/test/schemes/grpsig/__init__.py +0 -0
- charm/test/schemes/grpsig/groupsig_bgls04_test.py +35 -0
- charm/test/schemes/grpsig/groupsig_bgls04_var_test.py +39 -0
- charm/test/schemes/hibenc/__init__.py +0 -0
- charm/test/schemes/hibenc/hibenc_bb04_test.py +28 -0
- charm/test/schemes/ibenc/__init__.py +0 -0
- charm/test/schemes/ibenc/ibenc_bb03_test.py +26 -0
- charm/test/schemes/ibenc/ibenc_bf01_test.py +24 -0
- charm/test/schemes/ibenc/ibenc_ckrs09_test.py +25 -0
- charm/test/schemes/ibenc/ibenc_lsw08_test.py +31 -0
- charm/test/schemes/ibenc/ibenc_sw05_test.py +32 -0
- charm/test/schemes/ibenc/ibenc_waters05_test.py +31 -0
- charm/test/schemes/ibenc/ibenc_waters09_test.py +27 -0
- charm/test/schemes/pk_vrf_test.py +29 -0
- charm/test/schemes/pkenc/__init__.py +0 -0
- charm/test/schemes/pkenc_test.py +255 -0
- charm/test/schemes/pksig/__init__.py +0 -0
- charm/test/schemes/pksig_test.py +376 -0
- charm/test/schemes/rsa_alg_test.py +340 -0
- charm/test/schemes/threshold_test.py +1792 -0
- charm/test/serialize/__init__.py +0 -0
- charm/test/serialize/serialize_test.py +40 -0
- charm/test/toolbox/__init__.py +0 -0
- charm/test/toolbox/conversion_test.py +30 -0
- charm/test/toolbox/ecgroup_test.py +53 -0
- charm/test/toolbox/integer_arithmetic_test.py +441 -0
- charm/test/toolbox/paddingschemes_test.py +238 -0
- charm/test/toolbox/policy_parser_stress_test.py +969 -0
- charm/test/toolbox/secretshare_test.py +28 -0
- charm/test/toolbox/symcrypto_test.py +108 -0
- charm/test/toolbox/test_policy_expression.py +16 -0
- charm/test/vectors/__init__.py +1 -0
- charm/test/vectors/test_bls_vectors.py +289 -0
- charm/test/vectors/test_pedersen_vectors.py +315 -0
- charm/test/vectors/test_schnorr_vectors.py +368 -0
- charm/test/zkp_compiler/__init__.py +9 -0
- charm/test/zkp_compiler/benchmark_zkp.py +258 -0
- charm/test/zkp_compiler/test_and_proof.py +240 -0
- charm/test/zkp_compiler/test_batch_verify.py +248 -0
- charm/test/zkp_compiler/test_dleq_proof.py +264 -0
- charm/test/zkp_compiler/test_or_proof.py +231 -0
- charm/test/zkp_compiler/test_proof_serialization.py +121 -0
- charm/test/zkp_compiler/test_range_proof.py +241 -0
- charm/test/zkp_compiler/test_representation_proof.py +325 -0
- charm/test/zkp_compiler/test_schnorr_proof.py +221 -0
- charm/test/zkp_compiler/test_thread_safety.py +169 -0
- charm/test/zkp_compiler/test_zkp_parser.py +139 -0
- charm/toolbox/ABEnc.py +26 -0
- charm/toolbox/ABEncMultiAuth.py +66 -0
- charm/toolbox/ABEnumeric.py +800 -0
- charm/toolbox/Commit.py +24 -0
- charm/toolbox/DFA.py +89 -0
- charm/toolbox/FSA.py +1254 -0
- charm/toolbox/Hash.py +39 -0
- charm/toolbox/IBEnc.py +62 -0
- charm/toolbox/IBSig.py +64 -0
- charm/toolbox/PKEnc.py +66 -0
- charm/toolbox/PKSig.py +56 -0
- charm/toolbox/PREnc.py +32 -0
- charm/toolbox/ZKProof.py +289 -0
- charm/toolbox/__init__.py +0 -0
- charm/toolbox/bitstring.py +49 -0
- charm/toolbox/broadcast.py +220 -0
- charm/toolbox/conversion.py +100 -0
- charm/toolbox/eccurve.py +149 -0
- charm/toolbox/ecgroup.py +143 -0
- charm/toolbox/enum.py +60 -0
- charm/toolbox/hash_module.py +91 -0
- charm/toolbox/integergroup.py +323 -0
- charm/toolbox/iterate.py +22 -0
- charm/toolbox/matrixops.py +76 -0
- charm/toolbox/mpc_utils.py +296 -0
- charm/toolbox/msp.py +175 -0
- charm/toolbox/mta.py +985 -0
- charm/toolbox/node.py +120 -0
- charm/toolbox/ot/__init__.py +22 -0
- charm/toolbox/ot/base_ot.py +374 -0
- charm/toolbox/ot/dpf.py +642 -0
- charm/toolbox/ot/mpfss.py +228 -0
- charm/toolbox/ot/ot_extension.py +589 -0
- charm/toolbox/ot/silent_ot.py +378 -0
- charm/toolbox/paddingschemes.py +423 -0
- charm/toolbox/paddingschemes_test.py +238 -0
- charm/toolbox/pairingcurves.py +85 -0
- charm/toolbox/pairinggroup.py +186 -0
- charm/toolbox/policy_expression_spec.py +70 -0
- charm/toolbox/policytree.py +189 -0
- charm/toolbox/reCompiler.py +346 -0
- charm/toolbox/redundancyschemes.py +65 -0
- charm/toolbox/schemebase.py +188 -0
- charm/toolbox/secretshare.py +104 -0
- charm/toolbox/secretutil.py +174 -0
- charm/toolbox/securerandom.py +73 -0
- charm/toolbox/sigmaprotocol.py +46 -0
- charm/toolbox/specialprimes.py +45 -0
- charm/toolbox/symcrypto.py +279 -0
- charm/toolbox/threshold_sharing.py +553 -0
- charm/toolbox/xmlserialize.py +94 -0
- charm/toolbox/zknode.py +105 -0
- charm/zkp_compiler/__init__.py +89 -0
- charm/zkp_compiler/and_proof.py +460 -0
- charm/zkp_compiler/batch_verify.py +324 -0
- charm/zkp_compiler/dleq_proof.py +423 -0
- charm/zkp_compiler/or_proof.py +305 -0
- charm/zkp_compiler/range_proof.py +417 -0
- charm/zkp_compiler/representation_proof.py +466 -0
- charm/zkp_compiler/schnorr_proof.py +273 -0
- charm/zkp_compiler/thread_safe.py +150 -0
- charm/zkp_compiler/zk_demo.py +489 -0
- charm/zkp_compiler/zkp_factory.py +330 -0
- charm/zkp_compiler/zkp_generator.py +370 -0
- charm/zkp_compiler/zkparser.py +269 -0
- charm_crypto_framework-0.61.1.dist-info/METADATA +337 -0
- charm_crypto_framework-0.61.1.dist-info/RECORD +323 -0
- charm_crypto_framework-0.61.1.dist-info/WHEEL +5 -0
- charm_crypto_framework-0.61.1.dist-info/licenses/LICENSE.txt +165 -0
- charm_crypto_framework-0.61.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DLEQ (Discrete Log Equality) Zero-Knowledge Proof implementation.
|
|
3
|
+
|
|
4
|
+
Also known as the Chaum-Pedersen protocol, this module provides proof of
|
|
5
|
+
knowledge that two discrete logarithms are equal without revealing the
|
|
6
|
+
secret exponent.
|
|
7
|
+
|
|
8
|
+
=============================================================================
|
|
9
|
+
WHAT DLEQ PROVES
|
|
10
|
+
=============================================================================
|
|
11
|
+
DLEQ proves: "I know x such that h1 = g1^x AND h2 = g2^x"
|
|
12
|
+
|
|
13
|
+
This is a proof of equality of discrete logs: the prover demonstrates that
|
|
14
|
+
the same secret exponent x was used to compute both h1 (relative to base g1)
|
|
15
|
+
and h2 (relative to base g2), without revealing x itself.
|
|
16
|
+
|
|
17
|
+
=============================================================================
|
|
18
|
+
MATHEMATICAL BASIS
|
|
19
|
+
=============================================================================
|
|
20
|
+
The protocol works as follows:
|
|
21
|
+
|
|
22
|
+
Interactive Version:
|
|
23
|
+
1. Prover picks random r ∈ Zq
|
|
24
|
+
2. Prover computes commitments: u1 = g1^r, u2 = g2^r
|
|
25
|
+
3. Verifier sends random challenge c ∈ Zq
|
|
26
|
+
4. Prover computes response: z = r + c*x (mod q)
|
|
27
|
+
5. Verifier accepts if: g1^z == u1 * h1^c AND g2^z == u2 * h2^c
|
|
28
|
+
|
|
29
|
+
Correctness:
|
|
30
|
+
- If prover is honest: g1^z = g1^(r + c*x) = g1^r * g1^(c*x) = u1 * (g1^x)^c = u1 * h1^c ✓
|
|
31
|
+
- Same reasoning applies for the second equation with g2 and h2
|
|
32
|
+
|
|
33
|
+
Soundness:
|
|
34
|
+
- A cheating prover who knows x1 ≠ x2 where h1 = g1^x1 and h2 = g2^x2 cannot
|
|
35
|
+
produce a valid response z that satisfies both verification equations
|
|
36
|
+
(except with negligible probability)
|
|
37
|
+
|
|
38
|
+
=============================================================================
|
|
39
|
+
SECURITY PROPERTIES
|
|
40
|
+
=============================================================================
|
|
41
|
+
1. HVZK (Honest-Verifier Zero-Knowledge):
|
|
42
|
+
- A simulator can produce transcripts indistinguishable from real proofs
|
|
43
|
+
- Simulator: pick random z, c; compute u1 = g1^z * h1^(-c), u2 = g2^z * h2^(-c)
|
|
44
|
+
- This transcript (u1, u2, c, z) is identically distributed to real proofs
|
|
45
|
+
|
|
46
|
+
2. NIZK (Non-Interactive ZK via Fiat-Shamir):
|
|
47
|
+
- Replace interactive challenge with hash: c = H(g1, h1, g2, h2, u1, u2)
|
|
48
|
+
- Secure in the Random Oracle Model
|
|
49
|
+
- Produces publicly verifiable proofs
|
|
50
|
+
|
|
51
|
+
3. Special Soundness:
|
|
52
|
+
- Given two accepting transcripts with same commitments but different
|
|
53
|
+
challenges (c, z) and (c', z'), one can extract: x = (z - z') / (c - c')
|
|
54
|
+
|
|
55
|
+
=============================================================================
|
|
56
|
+
USE CASES
|
|
57
|
+
=============================================================================
|
|
58
|
+
1. Verifiable Random Functions (VRFs):
|
|
59
|
+
- Prove VRF output is correctly computed without revealing secret key
|
|
60
|
+
|
|
61
|
+
2. ElGamal Re-encryption Proofs:
|
|
62
|
+
- Prove ciphertext was correctly re-randomized
|
|
63
|
+
|
|
64
|
+
3. Threshold Cryptography:
|
|
65
|
+
- Prove partial decryption shares are correctly computed
|
|
66
|
+
|
|
67
|
+
4. Voting Systems:
|
|
68
|
+
- Prove vote encryption uses consistent randomness
|
|
69
|
+
|
|
70
|
+
5. Credential Systems:
|
|
71
|
+
- Prove different presentations derive from same credential
|
|
72
|
+
|
|
73
|
+
6. Diffie-Hellman Tuple Proofs:
|
|
74
|
+
- Prove (g1, h1, g2, h2) is a valid DH tuple
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
from typing import Any
|
|
78
|
+
|
|
79
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
80
|
+
from charm.core.engine.util import objectToBytes, bytesToObject
|
|
81
|
+
import logging
|
|
82
|
+
|
|
83
|
+
logger = logging.getLogger(__name__)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class DLEQProofData:
|
|
87
|
+
"""Container for DLEQ proof data with two commitments."""
|
|
88
|
+
|
|
89
|
+
def __init__(self, commitment1: Any, commitment2: Any, challenge: Any, response: Any, proof_type: str = 'dleq') -> None:
|
|
90
|
+
"""
|
|
91
|
+
Initialize a DLEQ proof.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
commitment1: The prover's first commitment (u1 = g1^r)
|
|
95
|
+
commitment2: The prover's second commitment (u2 = g2^r)
|
|
96
|
+
challenge: The challenge value (c)
|
|
97
|
+
response: The response value (z = r + c*x)
|
|
98
|
+
proof_type: Type identifier for the proof
|
|
99
|
+
"""
|
|
100
|
+
self.commitment1 = commitment1
|
|
101
|
+
self.commitment2 = commitment2
|
|
102
|
+
self.challenge = challenge
|
|
103
|
+
self.response = response
|
|
104
|
+
self.proof_type = proof_type
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class DLEQProof:
|
|
108
|
+
"""
|
|
109
|
+
DLEQ (Discrete Log Equality) Zero-Knowledge Proof.
|
|
110
|
+
|
|
111
|
+
Proves knowledge of x such that h1 = g1^x AND h2 = g2^x without revealing x.
|
|
112
|
+
Also known as the Chaum-Pedersen protocol.
|
|
113
|
+
|
|
114
|
+
Supports both interactive and non-interactive (Fiat-Shamir) modes.
|
|
115
|
+
|
|
116
|
+
Example (non-interactive):
|
|
117
|
+
>>> group = PairingGroup('SS512')
|
|
118
|
+
>>> g1 = group.random(G1)
|
|
119
|
+
>>> g2 = group.random(G1)
|
|
120
|
+
>>> x = group.random(ZR) # Secret exponent
|
|
121
|
+
>>> h1 = g1 ** x
|
|
122
|
+
>>> h2 = g2 ** x
|
|
123
|
+
>>>
|
|
124
|
+
>>> # Prove h1 = g1^x and h2 = g2^x for the same x
|
|
125
|
+
>>> proof = DLEQProof.prove_non_interactive(group, g1, h1, g2, h2, x)
|
|
126
|
+
>>> assert DLEQProof.verify_non_interactive(group, g1, h1, g2, h2, proof)
|
|
127
|
+
|
|
128
|
+
Example (interactive):
|
|
129
|
+
>>> prover = DLEQProof.Prover(x, group)
|
|
130
|
+
>>> verifier = DLEQProof.Verifier(group)
|
|
131
|
+
>>>
|
|
132
|
+
>>> # Step 1: Prover creates commitments
|
|
133
|
+
>>> u1, u2 = prover.create_commitment(g1, g2)
|
|
134
|
+
>>>
|
|
135
|
+
>>> # Step 2: Verifier creates challenge
|
|
136
|
+
>>> c = verifier.create_challenge()
|
|
137
|
+
>>>
|
|
138
|
+
>>> # Step 3: Prover creates response
|
|
139
|
+
>>> z = prover.create_response(c)
|
|
140
|
+
>>>
|
|
141
|
+
>>> # Step 4: Verifier checks proof
|
|
142
|
+
>>> assert verifier.verify(g1, h1, g2, h2, u1, u2, z)
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
class Prover:
|
|
146
|
+
"""Prover for DLEQ protocol."""
|
|
147
|
+
|
|
148
|
+
def __init__(self, secret_x, group):
|
|
149
|
+
"""
|
|
150
|
+
Initialize prover with secret x.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
secret_x: The secret discrete log value (same for both bases)
|
|
154
|
+
group: The pairing group object
|
|
155
|
+
"""
|
|
156
|
+
self._r = None # Random commitment value (private)
|
|
157
|
+
self.group = group
|
|
158
|
+
self._x = secret_x # Secret (private)
|
|
159
|
+
|
|
160
|
+
def create_commitment(self, g1, g2):
|
|
161
|
+
"""
|
|
162
|
+
Create prover's commitments: u1 = g1^r, u2 = g2^r.
|
|
163
|
+
|
|
164
|
+
Uses the same random r for both commitments to prove
|
|
165
|
+
equality of discrete logs.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
g1: The first generator element
|
|
169
|
+
g2: The second generator element
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Tuple (u1, u2) where u1 = g1^r and u2 = g2^r
|
|
173
|
+
"""
|
|
174
|
+
self._r = self.group.random(ZR)
|
|
175
|
+
u1 = g1 ** self._r
|
|
176
|
+
u2 = g2 ** self._r
|
|
177
|
+
logger.debug("Prover created DLEQ commitments")
|
|
178
|
+
return u1, u2
|
|
179
|
+
|
|
180
|
+
def create_response(self, challenge):
|
|
181
|
+
"""
|
|
182
|
+
Create response to verifier's challenge: z = r + c*x.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
challenge: The challenge value c from verifier
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The response z = r + c*x
|
|
189
|
+
"""
|
|
190
|
+
if self._r is None:
|
|
191
|
+
raise ValueError("Must call create_commitment before create_response")
|
|
192
|
+
z = self._r + challenge * self._x
|
|
193
|
+
logger.debug("Prover created DLEQ response")
|
|
194
|
+
return z
|
|
195
|
+
|
|
196
|
+
class Verifier:
|
|
197
|
+
"""Verifier for DLEQ protocol."""
|
|
198
|
+
|
|
199
|
+
def __init__(self, group):
|
|
200
|
+
"""
|
|
201
|
+
Initialize verifier.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
group: The pairing group object
|
|
205
|
+
"""
|
|
206
|
+
self.group = group
|
|
207
|
+
self._c = None # Challenge (stored for verification)
|
|
208
|
+
|
|
209
|
+
def create_challenge(self):
|
|
210
|
+
"""
|
|
211
|
+
Create random challenge c.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Random challenge c in ZR
|
|
215
|
+
"""
|
|
216
|
+
self._c = self.group.random(ZR)
|
|
217
|
+
logger.debug("Verifier created DLEQ challenge")
|
|
218
|
+
return self._c
|
|
219
|
+
|
|
220
|
+
def verify(self, g1, h1, g2, h2, commitment1, commitment2, response):
|
|
221
|
+
"""
|
|
222
|
+
Verify DLEQ proof: g1^z == u1 * h1^c AND g2^z == u2 * h2^c.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
g1: The first generator element
|
|
226
|
+
h1: The first public value h1 = g1^x
|
|
227
|
+
g2: The second generator element
|
|
228
|
+
h2: The second public value h2 = g2^x
|
|
229
|
+
commitment1: The prover's first commitment u1
|
|
230
|
+
commitment2: The prover's second commitment u2
|
|
231
|
+
response: The prover's response z
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
True if proof is valid, False otherwise
|
|
235
|
+
"""
|
|
236
|
+
if self._c is None:
|
|
237
|
+
raise ValueError("Must call create_challenge before verify")
|
|
238
|
+
|
|
239
|
+
# Check first equation: g1^z == u1 * h1^c
|
|
240
|
+
lhs1 = g1 ** response
|
|
241
|
+
rhs1 = commitment1 * (h1 ** self._c)
|
|
242
|
+
check1 = lhs1 == rhs1
|
|
243
|
+
|
|
244
|
+
# Check second equation: g2^z == u2 * h2^c
|
|
245
|
+
lhs2 = g2 ** response
|
|
246
|
+
rhs2 = commitment2 * (h2 ** self._c)
|
|
247
|
+
check2 = lhs2 == rhs2
|
|
248
|
+
|
|
249
|
+
result = check1 and check2
|
|
250
|
+
logger.debug("DLEQ verification result: %s (check1=%s, check2=%s)",
|
|
251
|
+
result, check1, check2)
|
|
252
|
+
return result
|
|
253
|
+
|
|
254
|
+
@classmethod
|
|
255
|
+
def _compute_challenge_hash(cls, group, g1, h1, g2, h2, commitment1, commitment2):
|
|
256
|
+
"""
|
|
257
|
+
Compute Fiat-Shamir challenge as hash of all public values.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
group: The pairing group
|
|
261
|
+
g1: First generator
|
|
262
|
+
h1: First public value h1 = g1^x
|
|
263
|
+
g2: Second generator
|
|
264
|
+
h2: Second public value h2 = g2^x
|
|
265
|
+
commitment1: First commitment u1 = g1^r
|
|
266
|
+
commitment2: Second commitment u2 = g2^r
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Challenge c as element of ZR
|
|
270
|
+
"""
|
|
271
|
+
# Serialize all elements and concatenate for hashing
|
|
272
|
+
# Order: g1, h1, g2, h2, u1, u2 (matching protocol description)
|
|
273
|
+
data = (objectToBytes(g1, group) +
|
|
274
|
+
objectToBytes(h1, group) +
|
|
275
|
+
objectToBytes(g2, group) +
|
|
276
|
+
objectToBytes(h2, group) +
|
|
277
|
+
objectToBytes(commitment1, group) +
|
|
278
|
+
objectToBytes(commitment2, group))
|
|
279
|
+
return group.hash(data, ZR)
|
|
280
|
+
|
|
281
|
+
@classmethod
|
|
282
|
+
def prove_non_interactive(cls, group: PairingGroup, g1: Any, h1: Any, g2: Any, h2: Any, x: Any) -> DLEQProofData:
|
|
283
|
+
"""
|
|
284
|
+
Generate non-interactive DLEQ proof using Fiat-Shamir heuristic.
|
|
285
|
+
|
|
286
|
+
Proves knowledge of x such that h1 = g1^x AND h2 = g2^x.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
group: The pairing group
|
|
290
|
+
g1: The first generator element
|
|
291
|
+
h1: The first public value h1 = g1^x
|
|
292
|
+
g2: The second generator element
|
|
293
|
+
h2: The second public value h2 = g2^x
|
|
294
|
+
x: The secret discrete log (same for both equations)
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
DLEQProofData object containing commitments, challenge, and response
|
|
298
|
+
"""
|
|
299
|
+
# 1. Generate random r
|
|
300
|
+
r = group.random(ZR)
|
|
301
|
+
|
|
302
|
+
# 2. Compute commitments u1 = g1^r, u2 = g2^r
|
|
303
|
+
commitment1 = g1 ** r
|
|
304
|
+
commitment2 = g2 ** r
|
|
305
|
+
|
|
306
|
+
# 3. Compute challenge c = hash(g1, h1, g2, h2, u1, u2)
|
|
307
|
+
challenge = cls._compute_challenge_hash(
|
|
308
|
+
group, g1, h1, g2, h2, commitment1, commitment2)
|
|
309
|
+
|
|
310
|
+
# 4. Compute response z = r + c*x
|
|
311
|
+
response = r + challenge * x
|
|
312
|
+
|
|
313
|
+
logger.debug("Generated non-interactive DLEQ proof")
|
|
314
|
+
return DLEQProofData(
|
|
315
|
+
commitment1=commitment1,
|
|
316
|
+
commitment2=commitment2,
|
|
317
|
+
challenge=challenge,
|
|
318
|
+
response=response,
|
|
319
|
+
proof_type='dleq'
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
@classmethod
|
|
323
|
+
def verify_non_interactive(cls, group: PairingGroup, g1: Any, h1: Any, g2: Any, h2: Any, proof: DLEQProofData) -> bool:
|
|
324
|
+
"""
|
|
325
|
+
Verify non-interactive DLEQ proof.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
group: The pairing group
|
|
329
|
+
g1: The first generator element
|
|
330
|
+
h1: The first public value h1 = g1^x
|
|
331
|
+
g2: The second generator element
|
|
332
|
+
h2: The second public value h2 = g2^x
|
|
333
|
+
proof: DLEQProofData object containing commitments, challenge, and response
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
True if proof is valid, False otherwise
|
|
337
|
+
|
|
338
|
+
Security Notes:
|
|
339
|
+
- Validates proof structure before verification
|
|
340
|
+
- Checks for identity element attacks
|
|
341
|
+
- Recomputes Fiat-Shamir challenge for consistency
|
|
342
|
+
"""
|
|
343
|
+
# Security: Validate proof structure
|
|
344
|
+
required_attrs = ['commitment1', 'commitment2', 'challenge', 'response']
|
|
345
|
+
for attr in required_attrs:
|
|
346
|
+
if not hasattr(proof, attr):
|
|
347
|
+
logger.warning("Invalid DLEQ proof structure: missing '%s'. Ensure proof was created with DLEQProof.prove_non_interactive()", attr)
|
|
348
|
+
return False
|
|
349
|
+
|
|
350
|
+
# Security: Check for identity element (potential attack vector)
|
|
351
|
+
try:
|
|
352
|
+
identity = group.init(G1, 1)
|
|
353
|
+
if proof.commitment1 == identity or proof.commitment2 == identity:
|
|
354
|
+
logger.warning("Security: DLEQ proof commitment is identity element (possible attack). Proof rejected.")
|
|
355
|
+
return False
|
|
356
|
+
except Exception:
|
|
357
|
+
pass # Some groups may not support identity check
|
|
358
|
+
|
|
359
|
+
# Recompute challenge c = hash(g1, h1, g2, h2, u1, u2)
|
|
360
|
+
expected_challenge = cls._compute_challenge_hash(
|
|
361
|
+
group, g1, h1, g2, h2, proof.commitment1, proof.commitment2)
|
|
362
|
+
|
|
363
|
+
# Verify challenge matches (Fiat-Shamir consistency check)
|
|
364
|
+
if expected_challenge != proof.challenge:
|
|
365
|
+
logger.debug("Challenge mismatch in non-interactive DLEQ verification")
|
|
366
|
+
return False
|
|
367
|
+
|
|
368
|
+
# Check first equation: g1^z == u1 * h1^c
|
|
369
|
+
lhs1 = g1 ** proof.response
|
|
370
|
+
rhs1 = proof.commitment1 * (h1 ** proof.challenge)
|
|
371
|
+
check1 = lhs1 == rhs1
|
|
372
|
+
|
|
373
|
+
# Check second equation: g2^z == u2 * h2^c
|
|
374
|
+
lhs2 = g2 ** proof.response
|
|
375
|
+
rhs2 = proof.commitment2 * (h2 ** proof.challenge)
|
|
376
|
+
check2 = lhs2 == rhs2
|
|
377
|
+
|
|
378
|
+
result = check1 and check2
|
|
379
|
+
logger.debug("Non-interactive DLEQ verification result: %s (check1=%s, check2=%s)",
|
|
380
|
+
result, check1, check2)
|
|
381
|
+
return result
|
|
382
|
+
|
|
383
|
+
@classmethod
|
|
384
|
+
def serialize_proof(cls, proof: DLEQProofData, group: PairingGroup) -> bytes:
|
|
385
|
+
"""
|
|
386
|
+
Serialize DLEQ proof to bytes using Charm utilities.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
proof: DLEQProofData object to serialize
|
|
390
|
+
group: The pairing group
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Bytes representation of the proof
|
|
394
|
+
"""
|
|
395
|
+
proof_dict = {
|
|
396
|
+
'commitment1': proof.commitment1,
|
|
397
|
+
'commitment2': proof.commitment2,
|
|
398
|
+
'challenge': proof.challenge,
|
|
399
|
+
'response': proof.response,
|
|
400
|
+
'proof_type': proof.proof_type
|
|
401
|
+
}
|
|
402
|
+
return objectToBytes(proof_dict, group)
|
|
403
|
+
|
|
404
|
+
@classmethod
|
|
405
|
+
def deserialize_proof(cls, data: bytes, group: PairingGroup) -> DLEQProofData:
|
|
406
|
+
"""
|
|
407
|
+
Deserialize bytes to DLEQ proof.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
data: Bytes to deserialize
|
|
411
|
+
group: The pairing group
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
DLEQProofData object
|
|
415
|
+
"""
|
|
416
|
+
proof_dict = bytesToObject(data, group)
|
|
417
|
+
return DLEQProofData(
|
|
418
|
+
commitment1=proof_dict['commitment1'],
|
|
419
|
+
commitment2=proof_dict['commitment2'],
|
|
420
|
+
challenge=proof_dict['challenge'],
|
|
421
|
+
response=proof_dict['response'],
|
|
422
|
+
proof_type=proof_dict.get('proof_type', 'dleq')
|
|
423
|
+
)
|