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
charm/toolbox/zknode.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
"""
|
|
3
|
+
Binary tree node structure for representing parsed ZK statements.
|
|
4
|
+
|
|
5
|
+
This module provides the BinNode class used by the ZKP compiler to represent
|
|
6
|
+
parsed zero-knowledge proof statements as a binary tree structure.
|
|
7
|
+
|
|
8
|
+
Note:
|
|
9
|
+
This module is part of the experimental ZKP compiler and should be
|
|
10
|
+
considered proof-of-concept quality.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BinNode:
|
|
15
|
+
"""
|
|
16
|
+
Binary tree node for representing ZK proof statement components.
|
|
17
|
+
|
|
18
|
+
Node types:
|
|
19
|
+
- ATTR (0): Attribute/variable node (leaf)
|
|
20
|
+
- OR (1): Logical OR node
|
|
21
|
+
- AND (2): Logical AND node
|
|
22
|
+
- EXP (3): Exponentiation node (^)
|
|
23
|
+
- EQ (4): Equality node (=)
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
value: Either a string (creates ATTR node) or int (creates operator node)
|
|
27
|
+
left: Left child node (optional)
|
|
28
|
+
right: Right child node (optional)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, value, left=None, right=None):
|
|
32
|
+
# Node type constants
|
|
33
|
+
self.OR = 1
|
|
34
|
+
self.AND = 2
|
|
35
|
+
self.EXP = 3 # '^' or exponent
|
|
36
|
+
self.EQ = 4 # ==
|
|
37
|
+
self.ATTR = 0
|
|
38
|
+
|
|
39
|
+
if isinstance(value, str):
|
|
40
|
+
self.type = self.ATTR
|
|
41
|
+
self.attribute = value.upper() # Python 3 compatible
|
|
42
|
+
|
|
43
|
+
elif isinstance(value, int):
|
|
44
|
+
if value > 0 and value <= self.EQ:
|
|
45
|
+
self.type = value
|
|
46
|
+
self.attribute = ''
|
|
47
|
+
|
|
48
|
+
self.left = left
|
|
49
|
+
self.right = right
|
|
50
|
+
|
|
51
|
+
def __str__(self):
|
|
52
|
+
if self.type == self.ATTR:
|
|
53
|
+
return self.attribute
|
|
54
|
+
else:
|
|
55
|
+
left = str(self.left)
|
|
56
|
+
right = str(self.right)
|
|
57
|
+
|
|
58
|
+
if self.type == self.OR:
|
|
59
|
+
return '(' + left + ') or (' + right + ')'
|
|
60
|
+
elif self.type == self.AND:
|
|
61
|
+
return '(' + left + ') and (' + right + ')'
|
|
62
|
+
elif self.type == self.EXP:
|
|
63
|
+
return left + '^' + right
|
|
64
|
+
elif self.type == self.EQ:
|
|
65
|
+
return left + ' = ' + right
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def getAttribute(self):
|
|
69
|
+
"""Return the attribute value if this is an ATTR node, else None."""
|
|
70
|
+
if self.type == self.ATTR:
|
|
71
|
+
return self.attribute
|
|
72
|
+
else:
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
def getLeft(self):
|
|
76
|
+
"""Return the left child node."""
|
|
77
|
+
return self.left
|
|
78
|
+
|
|
79
|
+
def getRight(self):
|
|
80
|
+
"""Return the right child node."""
|
|
81
|
+
return self.right
|
|
82
|
+
|
|
83
|
+
def addSubNode(self, left, right):
|
|
84
|
+
"""Set the left and right child nodes."""
|
|
85
|
+
self.left = left if left is not None else None
|
|
86
|
+
self.right = right if right is not None else None # Fixed: was checking left
|
|
87
|
+
|
|
88
|
+
def traverse(self, function):
|
|
89
|
+
"""
|
|
90
|
+
Traverse the tree and apply function to each node.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
function: Callable that takes (node_type, node) as arguments
|
|
94
|
+
"""
|
|
95
|
+
# Visit node then traverse left and right
|
|
96
|
+
function(self.type, self)
|
|
97
|
+
if self.left is None:
|
|
98
|
+
return None
|
|
99
|
+
self.left.traverse(function)
|
|
100
|
+
if self.right is None:
|
|
101
|
+
return None
|
|
102
|
+
self.right.traverse(function)
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Charm ZKP Compiler Module
|
|
3
|
+
=========================
|
|
4
|
+
|
|
5
|
+
This module provides zero-knowledge proof implementations for Charm-Crypto.
|
|
6
|
+
|
|
7
|
+
Recommended (Secure) API
|
|
8
|
+
------------------------
|
|
9
|
+
The following modules provide secure, production-ready ZKP implementations:
|
|
10
|
+
|
|
11
|
+
- :mod:`charm.zkp_compiler.schnorr_proof` - Schnorr protocol (discrete log)
|
|
12
|
+
- :mod:`charm.zkp_compiler.dleq_proof` - DLEQ/Chaum-Pedersen protocol
|
|
13
|
+
- :mod:`charm.zkp_compiler.representation_proof` - Knowledge of representation
|
|
14
|
+
- :mod:`charm.zkp_compiler.and_proof` - AND composition of proofs
|
|
15
|
+
- :mod:`charm.zkp_compiler.or_proof` - OR composition (CDS94)
|
|
16
|
+
- :mod:`charm.zkp_compiler.range_proof` - Range proofs via bit decomposition
|
|
17
|
+
- :mod:`charm.zkp_compiler.batch_verify` - Batch verification utilities
|
|
18
|
+
- :mod:`charm.zkp_compiler.zkp_factory` - Factory for creating proofs
|
|
19
|
+
- :mod:`charm.zkp_compiler.thread_safe` - Thread-safe wrappers
|
|
20
|
+
|
|
21
|
+
Deprecated (Legacy) API
|
|
22
|
+
-----------------------
|
|
23
|
+
The following module is DEPRECATED and will be removed in v0.80:
|
|
24
|
+
|
|
25
|
+
- :mod:`charm.zkp_compiler.zkp_generator` - Uses insecure exec()/compile()
|
|
26
|
+
|
|
27
|
+
Example Migration
|
|
28
|
+
-----------------
|
|
29
|
+
Old (deprecated)::
|
|
30
|
+
|
|
31
|
+
from charm.zkp_compiler.zkp_generator import executeIntZKProof
|
|
32
|
+
result = executeIntZKProof(public, secret, statement, party_info)
|
|
33
|
+
|
|
34
|
+
New (recommended)::
|
|
35
|
+
|
|
36
|
+
from charm.zkp_compiler.schnorr_proof import SchnorrProof
|
|
37
|
+
proof = SchnorrProof.prove_non_interactive(group, g, h, x)
|
|
38
|
+
is_valid = SchnorrProof.verify_non_interactive(group, g, h, proof)
|
|
39
|
+
|
|
40
|
+
Curve Recommendation
|
|
41
|
+
--------------------
|
|
42
|
+
Use BN254 curve for ~128-bit security (recommended for production)::
|
|
43
|
+
|
|
44
|
+
from charm.toolbox.pairinggroup import PairingGroup
|
|
45
|
+
group = PairingGroup('BN254')
|
|
46
|
+
|
|
47
|
+
See Also
|
|
48
|
+
--------
|
|
49
|
+
- doc/zkp_proof_types_design.md for detailed documentation
|
|
50
|
+
- charm/zkp_compiler/zk_demo.py for usage examples
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Secure API exports (recommended)
|
|
54
|
+
from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
|
|
55
|
+
from charm.zkp_compiler.dleq_proof import DLEQProof
|
|
56
|
+
from charm.zkp_compiler.representation_proof import RepresentationProof
|
|
57
|
+
from charm.zkp_compiler.and_proof import ANDProof
|
|
58
|
+
from charm.zkp_compiler.or_proof import ORProof
|
|
59
|
+
from charm.zkp_compiler.range_proof import RangeProof
|
|
60
|
+
from charm.zkp_compiler.batch_verify import BatchVerifier, batch_verify_schnorr, batch_verify_dleq
|
|
61
|
+
from charm.zkp_compiler.zkp_factory import (
|
|
62
|
+
ZKProofFactory,
|
|
63
|
+
configure_logging,
|
|
64
|
+
prove_and_verify_schnorr,
|
|
65
|
+
prove_and_verify_dleq,
|
|
66
|
+
)
|
|
67
|
+
from charm.zkp_compiler.thread_safe import ThreadSafeProver, ThreadSafeVerifier
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
# Proof types
|
|
71
|
+
'SchnorrProof',
|
|
72
|
+
'DLEQProof',
|
|
73
|
+
'RepresentationProof',
|
|
74
|
+
'ANDProof',
|
|
75
|
+
'ORProof',
|
|
76
|
+
'RangeProof',
|
|
77
|
+
'Proof',
|
|
78
|
+
# Utilities
|
|
79
|
+
'BatchVerifier',
|
|
80
|
+
'batch_verify_schnorr',
|
|
81
|
+
'batch_verify_dleq',
|
|
82
|
+
'ZKProofFactory',
|
|
83
|
+
'ThreadSafeProver',
|
|
84
|
+
'ThreadSafeVerifier',
|
|
85
|
+
# Convenience functions
|
|
86
|
+
'configure_logging',
|
|
87
|
+
'prove_and_verify_schnorr',
|
|
88
|
+
'prove_and_verify_dleq',
|
|
89
|
+
]
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AND Composition for Zero-Knowledge Proofs.
|
|
3
|
+
|
|
4
|
+
This module provides AND composition functionality that allows proving multiple
|
|
5
|
+
statements simultaneously using a shared challenge.
|
|
6
|
+
|
|
7
|
+
=============================================================================
|
|
8
|
+
WHAT AND COMPOSITION PROVES
|
|
9
|
+
=============================================================================
|
|
10
|
+
AND composition proves: "Statement A AND Statement B AND ... AND Statement N"
|
|
11
|
+
|
|
12
|
+
Given multiple statements (e.g., Schnorr proofs, DLEQ proofs, representation proofs),
|
|
13
|
+
AND composition allows a prover to demonstrate knowledge of all corresponding
|
|
14
|
+
witnesses in a single, compact proof.
|
|
15
|
+
|
|
16
|
+
=============================================================================
|
|
17
|
+
HOW IT WORKS
|
|
18
|
+
=============================================================================
|
|
19
|
+
The key insight is that Sigma protocols (Schnorr, DLEQ, representation) can be
|
|
20
|
+
composed using a SHARED CHALLENGE:
|
|
21
|
+
|
|
22
|
+
1. Generate random commitments for each sub-proof independently
|
|
23
|
+
2. Compute a SINGLE shared challenge by hashing ALL commitments together
|
|
24
|
+
3. Compute responses for each sub-proof using the shared challenge
|
|
25
|
+
4. Verification checks all sub-proofs against the same shared challenge
|
|
26
|
+
|
|
27
|
+
This is more efficient than running independent proofs because:
|
|
28
|
+
- Only one challenge hash computation is needed
|
|
29
|
+
- The shared challenge binds all sub-proofs together cryptographically
|
|
30
|
+
- The total proof size is smaller than independent proofs
|
|
31
|
+
|
|
32
|
+
=============================================================================
|
|
33
|
+
SECURITY PROPERTIES
|
|
34
|
+
=============================================================================
|
|
35
|
+
1. Soundness: An adversary cannot forge a proof without knowing ALL witnesses.
|
|
36
|
+
The shared challenge ensures that all statements must be proven simultaneously.
|
|
37
|
+
|
|
38
|
+
2. Zero-Knowledge: The simulator can produce transcripts indistinguishable from
|
|
39
|
+
real proofs by simulating each sub-proof with the shared challenge.
|
|
40
|
+
|
|
41
|
+
3. Composability: AND composition preserves the security properties of the
|
|
42
|
+
underlying Sigma protocols.
|
|
43
|
+
|
|
44
|
+
=============================================================================
|
|
45
|
+
USE CASES
|
|
46
|
+
=============================================================================
|
|
47
|
+
1. Multi-Attribute Proofs: Prove knowledge of multiple hidden attributes in a
|
|
48
|
+
credential system (e.g., "I know age AND name AND address").
|
|
49
|
+
|
|
50
|
+
2. Compound Statements: Prove complex statements combining different proof types
|
|
51
|
+
(e.g., "I know x such that h1 = g^x AND I know y such that h2 = g^y").
|
|
52
|
+
|
|
53
|
+
3. Efficient Batching: Combine multiple proofs into a single verification.
|
|
54
|
+
|
|
55
|
+
4. Anonymous Credentials: Prove multiple properties about a credential holder.
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
>>> from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
59
|
+
>>> from charm.zkp_compiler.and_proof import ANDProof
|
|
60
|
+
>>>
|
|
61
|
+
>>> group = PairingGroup('SS512')
|
|
62
|
+
>>> g = group.random(G1)
|
|
63
|
+
>>> x, y = group.random(ZR), group.random(ZR)
|
|
64
|
+
>>> h1, h2 = g ** x, g ** y
|
|
65
|
+
>>>
|
|
66
|
+
>>> # Prove knowledge of x AND y such that h1 = g^x AND h2 = g^y
|
|
67
|
+
>>> statements = [
|
|
68
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h1, 'x': x}},
|
|
69
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h2, 'x': y}},
|
|
70
|
+
... ]
|
|
71
|
+
>>> proof = ANDProof.prove_non_interactive(group, statements)
|
|
72
|
+
>>>
|
|
73
|
+
>>> # For verification, use public statements (without secrets)
|
|
74
|
+
>>> statements_public = [
|
|
75
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h1}},
|
|
76
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h2}},
|
|
77
|
+
... ]
|
|
78
|
+
>>> valid = ANDProof.verify_non_interactive(group, statements_public, proof)
|
|
79
|
+
>>> assert valid
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
from typing import List, Any, Dict
|
|
83
|
+
|
|
84
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
85
|
+
from charm.core.engine.util import objectToBytes, bytesToObject
|
|
86
|
+
from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
|
|
87
|
+
from charm.zkp_compiler.dleq_proof import DLEQProof, DLEQProofData
|
|
88
|
+
from charm.zkp_compiler.representation_proof import RepresentationProof, RepresentationProofData
|
|
89
|
+
import logging
|
|
90
|
+
|
|
91
|
+
logger = logging.getLogger(__name__)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class ANDProofData:
|
|
95
|
+
"""Container for AND proof data with multiple sub-proofs."""
|
|
96
|
+
|
|
97
|
+
def __init__(self, sub_proofs: List[Dict[str, Any]], shared_challenge: Any, proof_type: str = 'and') -> None:
|
|
98
|
+
"""
|
|
99
|
+
Initialize an AND proof.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
sub_proofs: List of individual proof data objects (commitments and responses)
|
|
103
|
+
shared_challenge: The common challenge used for all proofs
|
|
104
|
+
proof_type: Type identifier for the proof
|
|
105
|
+
"""
|
|
106
|
+
self.sub_proofs = sub_proofs
|
|
107
|
+
self.shared_challenge = shared_challenge
|
|
108
|
+
self.proof_type = proof_type
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class ANDProof:
|
|
112
|
+
"""
|
|
113
|
+
AND Composition for Zero-Knowledge Proofs.
|
|
114
|
+
|
|
115
|
+
Allows proving multiple statements simultaneously with a shared challenge.
|
|
116
|
+
Supports combining Schnorr, DLEQ, and Representation proofs.
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
>>> group = PairingGroup('SS512')
|
|
120
|
+
>>> g = group.random(G1)
|
|
121
|
+
>>> x, y = group.random(ZR), group.random(ZR)
|
|
122
|
+
>>> h1, h2 = g ** x, g ** y
|
|
123
|
+
>>>
|
|
124
|
+
>>> statements = [
|
|
125
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h1, 'x': x}},
|
|
126
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h2, 'x': y}},
|
|
127
|
+
... ]
|
|
128
|
+
>>> proof = ANDProof.prove_non_interactive(group, statements)
|
|
129
|
+
>>>
|
|
130
|
+
>>> statements_public = [
|
|
131
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h1}},
|
|
132
|
+
... {'type': 'schnorr', 'params': {'g': g, 'h': h2}},
|
|
133
|
+
... ]
|
|
134
|
+
>>> valid = ANDProof.verify_non_interactive(group, statements_public, proof)
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def _generate_commitment(cls, group, statement):
|
|
139
|
+
"""
|
|
140
|
+
Generate random commitment for a single statement.
|
|
141
|
+
|
|
142
|
+
Returns tuple of (commitment_data, random_values) where commitment_data
|
|
143
|
+
contains the public commitment(s) and random_values contains the secret
|
|
144
|
+
randomness for computing responses.
|
|
145
|
+
"""
|
|
146
|
+
stmt_type = statement['type']
|
|
147
|
+
params = statement['params']
|
|
148
|
+
|
|
149
|
+
if stmt_type == 'schnorr':
|
|
150
|
+
r = group.random(ZR)
|
|
151
|
+
commitment = params['g'] ** r
|
|
152
|
+
return {'type': 'schnorr', 'commitment': commitment}, {'r': r}
|
|
153
|
+
|
|
154
|
+
elif stmt_type == 'dleq':
|
|
155
|
+
r = group.random(ZR)
|
|
156
|
+
commitment1 = params['g1'] ** r
|
|
157
|
+
commitment2 = params['g2'] ** r
|
|
158
|
+
return {
|
|
159
|
+
'type': 'dleq',
|
|
160
|
+
'commitment1': commitment1,
|
|
161
|
+
'commitment2': commitment2
|
|
162
|
+
}, {'r': r}
|
|
163
|
+
|
|
164
|
+
elif stmt_type == 'representation':
|
|
165
|
+
generators = params['generators']
|
|
166
|
+
r_values = [group.random(ZR) for _ in range(len(generators))]
|
|
167
|
+
commitment = generators[0] ** r_values[0]
|
|
168
|
+
for i in range(1, len(generators)):
|
|
169
|
+
commitment = commitment * (generators[i] ** r_values[i])
|
|
170
|
+
return {
|
|
171
|
+
'type': 'representation',
|
|
172
|
+
'commitment': commitment
|
|
173
|
+
}, {'r_values': r_values}
|
|
174
|
+
|
|
175
|
+
else:
|
|
176
|
+
raise ValueError(f"Unsupported statement type: {stmt_type}")
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def _compute_shared_challenge(cls, group, statements, commitments):
|
|
180
|
+
"""
|
|
181
|
+
Compute shared Fiat-Shamir challenge from all public values and commitments.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
group: The pairing group
|
|
185
|
+
statements: List of statement dictionaries
|
|
186
|
+
commitments: List of commitment data dictionaries
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Shared challenge as element of ZR
|
|
190
|
+
"""
|
|
191
|
+
data = b''
|
|
192
|
+
|
|
193
|
+
# Hash all public values and commitments in order
|
|
194
|
+
for i, (stmt, commit) in enumerate(zip(statements, commitments)):
|
|
195
|
+
stmt_type = stmt['type']
|
|
196
|
+
params = stmt['params']
|
|
197
|
+
|
|
198
|
+
if stmt_type == 'schnorr':
|
|
199
|
+
data += objectToBytes(params['g'], group)
|
|
200
|
+
data += objectToBytes(params['h'], group)
|
|
201
|
+
data += objectToBytes(commit['commitment'], group)
|
|
202
|
+
|
|
203
|
+
elif stmt_type == 'dleq':
|
|
204
|
+
data += objectToBytes(params['g1'], group)
|
|
205
|
+
data += objectToBytes(params['h1'], group)
|
|
206
|
+
data += objectToBytes(params['g2'], group)
|
|
207
|
+
data += objectToBytes(params['h2'], group)
|
|
208
|
+
data += objectToBytes(commit['commitment1'], group)
|
|
209
|
+
data += objectToBytes(commit['commitment2'], group)
|
|
210
|
+
|
|
211
|
+
elif stmt_type == 'representation':
|
|
212
|
+
for g in params['generators']:
|
|
213
|
+
data += objectToBytes(g, group)
|
|
214
|
+
data += objectToBytes(params['h'], group)
|
|
215
|
+
data += objectToBytes(commit['commitment'], group)
|
|
216
|
+
|
|
217
|
+
return group.hash(data, ZR)
|
|
218
|
+
|
|
219
|
+
@classmethod
|
|
220
|
+
def _compute_response(cls, group, statement, random_values, challenge):
|
|
221
|
+
"""
|
|
222
|
+
Compute response for a single statement given challenge.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
group: The pairing group
|
|
226
|
+
statement: Statement dictionary with type and params
|
|
227
|
+
random_values: Random values used for commitment
|
|
228
|
+
challenge: The shared challenge
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Response value(s) for this statement
|
|
232
|
+
"""
|
|
233
|
+
stmt_type = statement['type']
|
|
234
|
+
params = statement['params']
|
|
235
|
+
|
|
236
|
+
if stmt_type == 'schnorr':
|
|
237
|
+
# z = r + c*x
|
|
238
|
+
return random_values['r'] + challenge * params['x']
|
|
239
|
+
|
|
240
|
+
elif stmt_type == 'dleq':
|
|
241
|
+
# z = r + c*x
|
|
242
|
+
return random_values['r'] + challenge * params['x']
|
|
243
|
+
|
|
244
|
+
elif stmt_type == 'representation':
|
|
245
|
+
# zi = ri + c*xi for each witness
|
|
246
|
+
responses = []
|
|
247
|
+
for i, xi in enumerate(params['witnesses']):
|
|
248
|
+
z_i = random_values['r_values'][i] + challenge * xi
|
|
249
|
+
responses.append(z_i)
|
|
250
|
+
return responses
|
|
251
|
+
|
|
252
|
+
else:
|
|
253
|
+
raise ValueError(f"Unsupported statement type: {stmt_type}")
|
|
254
|
+
|
|
255
|
+
@classmethod
|
|
256
|
+
def prove_non_interactive(cls, group: PairingGroup, statements: List[Dict[str, Any]]) -> 'ANDProofData':
|
|
257
|
+
"""
|
|
258
|
+
Generate non-interactive AND proof using Fiat-Shamir heuristic.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
group: The pairing group
|
|
262
|
+
statements: List of statement dictionaries, each with:
|
|
263
|
+
- 'type': 'schnorr', 'dleq', or 'representation'
|
|
264
|
+
- 'params': Dict with required parameters for that proof type
|
|
265
|
+
- schnorr: {'g': generator, 'h': public_value, 'x': secret}
|
|
266
|
+
- dleq: {'g1': gen1, 'h1': pub1, 'g2': gen2, 'h2': pub2, 'x': secret}
|
|
267
|
+
- representation: {'generators': [g1,...], 'h': public, 'witnesses': [x1,...]}
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
ANDProofData object containing sub-proofs and shared challenge
|
|
271
|
+
"""
|
|
272
|
+
if not statements:
|
|
273
|
+
raise ValueError("At least one statement is required")
|
|
274
|
+
|
|
275
|
+
# Step 1: Generate commitments for all statements
|
|
276
|
+
commitments = []
|
|
277
|
+
random_values_list = []
|
|
278
|
+
for stmt in statements:
|
|
279
|
+
commit_data, rand_vals = cls._generate_commitment(group, stmt)
|
|
280
|
+
commitments.append(commit_data)
|
|
281
|
+
random_values_list.append(rand_vals)
|
|
282
|
+
|
|
283
|
+
# Step 2: Compute shared challenge from all commitments
|
|
284
|
+
shared_challenge = cls._compute_shared_challenge(group, statements, commitments)
|
|
285
|
+
|
|
286
|
+
# Step 3: Compute responses for each statement using shared challenge
|
|
287
|
+
sub_proofs = []
|
|
288
|
+
for i, stmt in enumerate(statements):
|
|
289
|
+
response = cls._compute_response(
|
|
290
|
+
group, stmt, random_values_list[i], shared_challenge
|
|
291
|
+
)
|
|
292
|
+
sub_proof = {
|
|
293
|
+
'type': stmt['type'],
|
|
294
|
+
'commitment': commitments[i],
|
|
295
|
+
'response': response
|
|
296
|
+
}
|
|
297
|
+
sub_proofs.append(sub_proof)
|
|
298
|
+
|
|
299
|
+
logger.debug("Generated AND proof with %d sub-proofs", len(statements))
|
|
300
|
+
return ANDProofData(
|
|
301
|
+
sub_proofs=sub_proofs,
|
|
302
|
+
shared_challenge=shared_challenge,
|
|
303
|
+
proof_type='and'
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
@classmethod
|
|
307
|
+
def _verify_sub_proof(cls, group, statement, sub_proof, challenge):
|
|
308
|
+
"""
|
|
309
|
+
Verify a single sub-proof against the shared challenge.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
group: The pairing group
|
|
313
|
+
statement: Statement dictionary with type and public params
|
|
314
|
+
sub_proof: Sub-proof dictionary with commitment and response
|
|
315
|
+
challenge: The shared challenge
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
True if sub-proof is valid, False otherwise
|
|
319
|
+
"""
|
|
320
|
+
stmt_type = statement['type']
|
|
321
|
+
params = statement['params']
|
|
322
|
+
commitment = sub_proof['commitment']
|
|
323
|
+
response = sub_proof['response']
|
|
324
|
+
|
|
325
|
+
if stmt_type == 'schnorr':
|
|
326
|
+
# Check: g^z == commitment * h^c
|
|
327
|
+
lhs = params['g'] ** response
|
|
328
|
+
rhs = commitment['commitment'] * (params['h'] ** challenge)
|
|
329
|
+
return lhs == rhs
|
|
330
|
+
|
|
331
|
+
elif stmt_type == 'dleq':
|
|
332
|
+
# Check: g1^z == u1 * h1^c AND g2^z == u2 * h2^c
|
|
333
|
+
lhs1 = params['g1'] ** response
|
|
334
|
+
rhs1 = commitment['commitment1'] * (params['h1'] ** challenge)
|
|
335
|
+
check1 = lhs1 == rhs1
|
|
336
|
+
|
|
337
|
+
lhs2 = params['g2'] ** response
|
|
338
|
+
rhs2 = commitment['commitment2'] * (params['h2'] ** challenge)
|
|
339
|
+
check2 = lhs2 == rhs2
|
|
340
|
+
|
|
341
|
+
return check1 and check2
|
|
342
|
+
|
|
343
|
+
elif stmt_type == 'representation':
|
|
344
|
+
# Check: g1^z1 * g2^z2 * ... * gn^zn == commitment * h^c
|
|
345
|
+
generators = params['generators']
|
|
346
|
+
n = len(generators)
|
|
347
|
+
|
|
348
|
+
if len(response) != n:
|
|
349
|
+
return False
|
|
350
|
+
|
|
351
|
+
lhs = generators[0] ** response[0]
|
|
352
|
+
for i in range(1, n):
|
|
353
|
+
lhs = lhs * (generators[i] ** response[i])
|
|
354
|
+
|
|
355
|
+
rhs = commitment['commitment'] * (params['h'] ** challenge)
|
|
356
|
+
return lhs == rhs
|
|
357
|
+
|
|
358
|
+
else:
|
|
359
|
+
logger.warning("Unknown statement type in verification: %s", stmt_type)
|
|
360
|
+
return False
|
|
361
|
+
|
|
362
|
+
@classmethod
|
|
363
|
+
def verify_non_interactive(cls, group: PairingGroup, statements: List[Dict[str, Any]], proof: 'ANDProofData') -> bool:
|
|
364
|
+
"""
|
|
365
|
+
Verify non-interactive AND proof.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
group: The pairing group
|
|
369
|
+
statements: List of statement dictionaries with public parameters only
|
|
370
|
+
- schnorr: {'g': generator, 'h': public_value}
|
|
371
|
+
- dleq: {'g1': gen1, 'h1': pub1, 'g2': gen2, 'h2': pub2}
|
|
372
|
+
- representation: {'generators': [g1,...], 'h': public_value}
|
|
373
|
+
proof: ANDProofData object containing sub-proofs and shared challenge
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
True if all sub-proofs are valid, False otherwise
|
|
377
|
+
|
|
378
|
+
Security Notes:
|
|
379
|
+
- Validates proof structure before verification
|
|
380
|
+
- Verifies shared challenge consistency across all sub-proofs
|
|
381
|
+
- Recomputes Fiat-Shamir challenge for consistency
|
|
382
|
+
"""
|
|
383
|
+
# Security: Validate proof structure
|
|
384
|
+
required_attrs = ['sub_proofs', 'shared_challenge']
|
|
385
|
+
for attr in required_attrs:
|
|
386
|
+
if not hasattr(proof, attr):
|
|
387
|
+
logger.warning("Invalid AND proof structure: missing '%s'. Ensure proof was created with ANDProof.prove_non_interactive()", attr)
|
|
388
|
+
return False
|
|
389
|
+
|
|
390
|
+
if len(statements) != len(proof.sub_proofs):
|
|
391
|
+
logger.debug(
|
|
392
|
+
"Statement count (%d) doesn't match sub-proof count (%d)",
|
|
393
|
+
len(statements), len(proof.sub_proofs)
|
|
394
|
+
)
|
|
395
|
+
return False
|
|
396
|
+
|
|
397
|
+
# Reconstruct commitments list for challenge verification
|
|
398
|
+
commitments = [sp['commitment'] for sp in proof.sub_proofs]
|
|
399
|
+
|
|
400
|
+
# Recompute shared challenge
|
|
401
|
+
expected_challenge = cls._compute_shared_challenge(group, statements, commitments)
|
|
402
|
+
|
|
403
|
+
# Verify challenge matches
|
|
404
|
+
if expected_challenge != proof.shared_challenge:
|
|
405
|
+
logger.debug("Shared challenge mismatch in AND proof verification")
|
|
406
|
+
return False
|
|
407
|
+
|
|
408
|
+
# Verify each sub-proof
|
|
409
|
+
for i, (stmt, sub_proof) in enumerate(zip(statements, proof.sub_proofs)):
|
|
410
|
+
if stmt['type'] != sub_proof['type']:
|
|
411
|
+
logger.debug(
|
|
412
|
+
"Statement type mismatch at index %d: expected %s, got %s",
|
|
413
|
+
i, stmt['type'], sub_proof['type']
|
|
414
|
+
)
|
|
415
|
+
return False
|
|
416
|
+
|
|
417
|
+
if not cls._verify_sub_proof(group, stmt, sub_proof, proof.shared_challenge):
|
|
418
|
+
logger.debug("Sub-proof %d verification failed", i)
|
|
419
|
+
return False
|
|
420
|
+
|
|
421
|
+
logger.debug("AND proof verification succeeded for %d sub-proofs", len(statements))
|
|
422
|
+
return True
|
|
423
|
+
|
|
424
|
+
@classmethod
|
|
425
|
+
def serialize_proof(cls, proof: 'ANDProofData', group: PairingGroup) -> bytes:
|
|
426
|
+
"""
|
|
427
|
+
Serialize AND proof to bytes using Charm utilities.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
proof: ANDProofData object to serialize
|
|
431
|
+
group: The pairing group
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
Bytes representation of the proof
|
|
435
|
+
"""
|
|
436
|
+
proof_dict = {
|
|
437
|
+
'sub_proofs': proof.sub_proofs,
|
|
438
|
+
'shared_challenge': proof.shared_challenge,
|
|
439
|
+
'proof_type': proof.proof_type
|
|
440
|
+
}
|
|
441
|
+
return objectToBytes(proof_dict, group)
|
|
442
|
+
|
|
443
|
+
@classmethod
|
|
444
|
+
def deserialize_proof(cls, data: bytes, group: PairingGroup) -> 'ANDProofData':
|
|
445
|
+
"""
|
|
446
|
+
Deserialize bytes to AND proof.
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
data: Bytes to deserialize
|
|
450
|
+
group: The pairing group
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
ANDProofData object
|
|
454
|
+
"""
|
|
455
|
+
proof_dict = bytesToObject(data, group)
|
|
456
|
+
return ANDProofData(
|
|
457
|
+
sub_proofs=proof_dict['sub_proofs'],
|
|
458
|
+
shared_challenge=proof_dict['shared_challenge'],
|
|
459
|
+
proof_type=proof_dict.get('proof_type', 'and')
|
|
460
|
+
)
|