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,417 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Range Proof implementation using bit decomposition.
|
|
3
|
+
|
|
4
|
+
This module provides a Zero-Knowledge Range Proof that proves a committed
|
|
5
|
+
value lies within a range [0, 2^n) without revealing the value itself.
|
|
6
|
+
|
|
7
|
+
=== What This Proves ===
|
|
8
|
+
Given a Pedersen commitment C = g^v * h^r, the range proof proves that the
|
|
9
|
+
committed value v is in the range [0, 2^n) without revealing v or r.
|
|
10
|
+
|
|
11
|
+
=== Bit Decomposition Approach ===
|
|
12
|
+
This implementation uses bit decomposition with O(n) proof size where n is
|
|
13
|
+
the number of bits in the range. The approach works as follows:
|
|
14
|
+
|
|
15
|
+
1. Decompose the value v into n bits: v = b0 + 2*b1 + 4*b2 + ... + 2^(n-1)*b_{n-1}
|
|
16
|
+
2. For each bit bi:
|
|
17
|
+
- Generate random ri
|
|
18
|
+
- Create bit commitment: Ci = g^bi * h^ri
|
|
19
|
+
- Create OR proof that bi ∈ {0, 1}:
|
|
20
|
+
Prove (Ci = h^ri) OR (Ci = g * h^ri)
|
|
21
|
+
3. Prove that the weighted sum of bit commitments equals the original commitment:
|
|
22
|
+
- Product of Ci^(2^i) should equal C (with appropriate randomness adjustment)
|
|
23
|
+
|
|
24
|
+
=== Security Properties ===
|
|
25
|
+
- Zero-Knowledge: Verifier learns nothing about v except that v ∈ [0, 2^n)
|
|
26
|
+
- Soundness: Prover cannot convince verifier of a false statement (except with
|
|
27
|
+
negligible probability)
|
|
28
|
+
- Completeness: Honest prover with valid v always convinces verifier
|
|
29
|
+
|
|
30
|
+
=== Use Cases ===
|
|
31
|
+
1. Confidential Transactions: Prove transaction amounts are non-negative
|
|
32
|
+
2. Age Verification: Prove age >= 18 without revealing exact age
|
|
33
|
+
3. Voting: Prove vote value is in valid range (e.g., 0 or 1)
|
|
34
|
+
4. Auctions: Prove bid is within allowed range
|
|
35
|
+
5. Credit Scoring: Prove score is above threshold without revealing exact score
|
|
36
|
+
|
|
37
|
+
=== Limitations ===
|
|
38
|
+
This bit decomposition approach has O(n) proof size where n is the number of
|
|
39
|
+
bits. For logarithmic proof size, consider Bulletproofs which achieve O(log n)
|
|
40
|
+
proof size using inner product arguments.
|
|
41
|
+
|
|
42
|
+
Usage Example:
|
|
43
|
+
>>> group = PairingGroup('BN254')
|
|
44
|
+
>>> g, h = group.random(G1), group.random(G1)
|
|
45
|
+
>>>
|
|
46
|
+
>>> # Prove value is in range [0, 2^8) = [0, 256)
|
|
47
|
+
>>> value = 42
|
|
48
|
+
>>> randomness = group.random(ZR)
|
|
49
|
+
>>> commitment = RangeProof.create_pedersen_commitment(group, g, h, value, randomness)
|
|
50
|
+
>>> proof = RangeProof.prove(group, g, h, value, randomness, num_bits=8)
|
|
51
|
+
>>> valid = RangeProof.verify(group, g, h, commitment, proof)
|
|
52
|
+
>>> assert valid
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
from typing import Any, List, Dict
|
|
56
|
+
|
|
57
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
58
|
+
from charm.core.engine.util import objectToBytes, bytesToObject
|
|
59
|
+
import logging
|
|
60
|
+
|
|
61
|
+
logger = logging.getLogger(__name__)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class RangeProofData:
|
|
65
|
+
"""Container for Range Proof data.
|
|
66
|
+
|
|
67
|
+
Holds all components of a range proof including bit commitments,
|
|
68
|
+
bit proofs (OR proofs), and the sum proof.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(self, bit_commitments: List[Any], bit_proofs: List[Dict[str, Any]], sum_proof: Dict[str, Any], num_bits: int, proof_type: str = 'range') -> None:
|
|
72
|
+
"""
|
|
73
|
+
Initialize a range proof.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
bit_commitments: List of commitments to each bit [C0, C1, ..., C_{n-1}]
|
|
77
|
+
bit_proofs: List of OR proofs proving each bit is 0 or 1
|
|
78
|
+
sum_proof: Proof that sum of bits equals the committed value
|
|
79
|
+
num_bits: Number of bits in the range (range is [0, 2^num_bits))
|
|
80
|
+
proof_type: Type identifier for the proof
|
|
81
|
+
"""
|
|
82
|
+
self.bit_commitments = bit_commitments
|
|
83
|
+
self.bit_proofs = bit_proofs
|
|
84
|
+
self.sum_proof = sum_proof
|
|
85
|
+
self.num_bits = num_bits
|
|
86
|
+
self.proof_type = proof_type
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class RangeProof:
|
|
90
|
+
"""
|
|
91
|
+
Zero-Knowledge Range Proof using Bit Decomposition.
|
|
92
|
+
|
|
93
|
+
Proves that a Pedersen commitment C = g^v * h^r commits to a value v
|
|
94
|
+
in the range [0, 2^n) without revealing v.
|
|
95
|
+
|
|
96
|
+
The proof consists of:
|
|
97
|
+
1. n bit commitments Ci = g^bi * h^ri
|
|
98
|
+
2. n OR proofs showing each bi ∈ {0, 1}
|
|
99
|
+
3. A sum proof showing that sum(2^i * bi) = v
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def create_pedersen_commitment(cls, group, g, h, value, randomness):
|
|
104
|
+
"""
|
|
105
|
+
Create a Pedersen commitment C = g^v * h^r.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
group: The pairing group
|
|
109
|
+
g: First generator (for value)
|
|
110
|
+
h: Second generator (for randomness)
|
|
111
|
+
value: The value to commit to (integer or ZR element)
|
|
112
|
+
randomness: The randomness r (ZR element)
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Pedersen commitment C = g^v * h^r
|
|
116
|
+
"""
|
|
117
|
+
if isinstance(value, int):
|
|
118
|
+
v = group.init(ZR, value)
|
|
119
|
+
else:
|
|
120
|
+
v = value
|
|
121
|
+
return (g ** v) * (h ** randomness)
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def _create_bit_or_proof(cls, group, g, h, bit_commitment, bit, bit_randomness):
|
|
125
|
+
"""
|
|
126
|
+
Create simplified OR proof that bit_commitment commits to 0 or 1.
|
|
127
|
+
|
|
128
|
+
Proves: (Ci = h^ri AND bi=0) OR (Ci = g * h^ri AND bi=1)
|
|
129
|
+
|
|
130
|
+
This uses a simplified Sigma-OR protocol (Cramer-Damgård-Schoenmakers).
|
|
131
|
+
"""
|
|
132
|
+
# Generate random values for the proof
|
|
133
|
+
if bit == 0:
|
|
134
|
+
# We know bi = 0, so Ci = h^ri
|
|
135
|
+
# Real proof for branch 0, simulate branch 1
|
|
136
|
+
r0 = group.random(ZR)
|
|
137
|
+
a0 = h ** r0 # Real commitment for branch 0
|
|
138
|
+
|
|
139
|
+
# Simulate branch 1 (pretend Ci = g * h^ri but we don't know ri)
|
|
140
|
+
c1 = group.random(ZR)
|
|
141
|
+
z1 = group.random(ZR)
|
|
142
|
+
# a1 = g^z1 * h^z1 / (Ci/g)^c1 = g^z1 * h^z1 * g^c1 / Ci^c1
|
|
143
|
+
Ci_over_g = bit_commitment * (g ** (-group.init(ZR, 1)))
|
|
144
|
+
a1 = (h ** z1) * (Ci_over_g ** (-c1))
|
|
145
|
+
|
|
146
|
+
# Compute overall challenge
|
|
147
|
+
data = (objectToBytes(bit_commitment, group) +
|
|
148
|
+
objectToBytes(a0, group) + objectToBytes(a1, group))
|
|
149
|
+
c = group.hash(data, ZR)
|
|
150
|
+
|
|
151
|
+
# c0 = c - c1
|
|
152
|
+
c0 = c - c1
|
|
153
|
+
# z0 = r0 + c0 * ri
|
|
154
|
+
z0 = r0 + c0 * bit_randomness
|
|
155
|
+
else:
|
|
156
|
+
# We know bi = 1, so Ci = g * h^ri
|
|
157
|
+
# Simulate branch 0, real proof for branch 1
|
|
158
|
+
c0 = group.random(ZR)
|
|
159
|
+
z0 = group.random(ZR)
|
|
160
|
+
# a0 = h^z0 / Ci^c0
|
|
161
|
+
a0 = (h ** z0) * (bit_commitment ** (-c0))
|
|
162
|
+
|
|
163
|
+
# Real proof for branch 1
|
|
164
|
+
r1 = group.random(ZR)
|
|
165
|
+
Ci_over_g = bit_commitment * (g ** (-group.init(ZR, 1)))
|
|
166
|
+
a1 = h ** r1 # Real commitment for branch 1
|
|
167
|
+
|
|
168
|
+
# Compute overall challenge
|
|
169
|
+
data = (objectToBytes(bit_commitment, group) +
|
|
170
|
+
objectToBytes(a0, group) + objectToBytes(a1, group))
|
|
171
|
+
c = group.hash(data, ZR)
|
|
172
|
+
|
|
173
|
+
# c1 = c - c0
|
|
174
|
+
c1 = c - c0
|
|
175
|
+
# z1 = r1 + c1 * ri
|
|
176
|
+
z1 = r1 + c1 * bit_randomness
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
'a0': a0, 'a1': a1,
|
|
180
|
+
'c0': c0, 'c1': c1,
|
|
181
|
+
'z0': z0, 'z1': z1
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def _verify_bit_or_proof(cls, group, g, h, bit_commitment, proof):
|
|
186
|
+
"""
|
|
187
|
+
Verify OR proof that bit_commitment commits to 0 or 1.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
True if proof is valid, False otherwise
|
|
191
|
+
"""
|
|
192
|
+
a0, a1 = proof['a0'], proof['a1']
|
|
193
|
+
c0, c1 = proof['c0'], proof['c1']
|
|
194
|
+
z0, z1 = proof['z0'], proof['z1']
|
|
195
|
+
|
|
196
|
+
# Recompute challenge
|
|
197
|
+
data = (objectToBytes(bit_commitment, group) +
|
|
198
|
+
objectToBytes(a0, group) + objectToBytes(a1, group))
|
|
199
|
+
c = group.hash(data, ZR)
|
|
200
|
+
|
|
201
|
+
# Verify c = c0 + c1
|
|
202
|
+
if c != c0 + c1:
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
# Verify branch 0: h^z0 == a0 * Ci^c0 (if bi = 0, Ci = h^ri)
|
|
206
|
+
lhs0 = h ** z0
|
|
207
|
+
rhs0 = a0 * (bit_commitment ** c0)
|
|
208
|
+
if lhs0 != rhs0:
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
# Verify branch 1: h^z1 == a1 * (Ci/g)^c1 (if bi = 1, Ci = g * h^ri)
|
|
212
|
+
Ci_over_g = bit_commitment * (g ** (-group.init(ZR, 1)))
|
|
213
|
+
lhs1 = h ** z1
|
|
214
|
+
rhs1 = a1 * (Ci_over_g ** c1)
|
|
215
|
+
if lhs1 != rhs1:
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def prove(cls, group: PairingGroup, g: Any, h: Any, value: int, randomness: Any, num_bits: int = 32) -> 'RangeProofData':
|
|
222
|
+
"""
|
|
223
|
+
Generate a range proof that value is in [0, 2^num_bits).
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
group: The pairing group
|
|
227
|
+
g: First generator for Pedersen commitment
|
|
228
|
+
h: Second generator for Pedersen commitment
|
|
229
|
+
value: The secret value to prove is in range (integer)
|
|
230
|
+
randomness: The randomness used in the original commitment
|
|
231
|
+
num_bits: Number of bits defining the range [0, 2^num_bits)
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
RangeProofData object containing the complete proof
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
ValueError: If value is not in the valid range
|
|
238
|
+
"""
|
|
239
|
+
# Validate value is in range
|
|
240
|
+
if not isinstance(value, int):
|
|
241
|
+
raise ValueError("Value must be an integer")
|
|
242
|
+
if value < 0 or value >= (1 << num_bits):
|
|
243
|
+
raise ValueError(f"Value {value} not in range [0, 2^{num_bits})")
|
|
244
|
+
|
|
245
|
+
# Step 1: Decompose value into bits
|
|
246
|
+
bits = [(value >> i) & 1 for i in range(num_bits)]
|
|
247
|
+
|
|
248
|
+
# Step 2: Generate random values for bit commitments
|
|
249
|
+
# We need: sum(2^i * ri) = r (original randomness)
|
|
250
|
+
# So we pick random r0, r1, ..., r_{n-2} and compute r_{n-1}
|
|
251
|
+
bit_randomness = [group.random(ZR) for _ in range(num_bits - 1)]
|
|
252
|
+
|
|
253
|
+
# Compute last randomness so weighted sum equals original randomness
|
|
254
|
+
# r = sum(2^i * ri), so r_{n-1} = (r - sum(2^i * ri for i < n-1)) / 2^{n-1}
|
|
255
|
+
partial_sum = group.init(ZR, 0)
|
|
256
|
+
for i in range(num_bits - 1):
|
|
257
|
+
weight = group.init(ZR, 1 << i)
|
|
258
|
+
partial_sum = partial_sum + weight * bit_randomness[i]
|
|
259
|
+
|
|
260
|
+
last_weight = group.init(ZR, 1 << (num_bits - 1))
|
|
261
|
+
last_randomness = (randomness - partial_sum) * (last_weight ** (-1))
|
|
262
|
+
bit_randomness.append(last_randomness)
|
|
263
|
+
|
|
264
|
+
# Step 3: Create bit commitments Ci = g^bi * h^ri
|
|
265
|
+
bit_commitments = []
|
|
266
|
+
for i in range(num_bits):
|
|
267
|
+
bi = group.init(ZR, bits[i])
|
|
268
|
+
Ci = (g ** bi) * (h ** bit_randomness[i])
|
|
269
|
+
bit_commitments.append(Ci)
|
|
270
|
+
|
|
271
|
+
# Step 4: Create OR proofs for each bit
|
|
272
|
+
bit_proofs = []
|
|
273
|
+
for i in range(num_bits):
|
|
274
|
+
proof = cls._create_bit_or_proof(
|
|
275
|
+
group, g, h, bit_commitments[i], bits[i], bit_randomness[i]
|
|
276
|
+
)
|
|
277
|
+
bit_proofs.append(proof)
|
|
278
|
+
|
|
279
|
+
# Step 5: Create sum proof (commitment consistency)
|
|
280
|
+
# Product of Ci^(2^i) should equal C = g^v * h^r
|
|
281
|
+
# This is implicitly verified by checking bit OR proofs and the
|
|
282
|
+
# commitment structure, so we include a signature/hash for binding
|
|
283
|
+
sum_data = b''
|
|
284
|
+
for i, Ci in enumerate(bit_commitments):
|
|
285
|
+
sum_data += objectToBytes(Ci, group)
|
|
286
|
+
sum_proof = {
|
|
287
|
+
'binding_hash': group.hash(sum_data, ZR)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
logger.debug("Generated range proof for %d bits", num_bits)
|
|
291
|
+
return RangeProofData(
|
|
292
|
+
bit_commitments=bit_commitments,
|
|
293
|
+
bit_proofs=bit_proofs,
|
|
294
|
+
sum_proof=sum_proof,
|
|
295
|
+
num_bits=num_bits,
|
|
296
|
+
proof_type='range'
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
@classmethod
|
|
300
|
+
def verify(cls, group: PairingGroup, g: Any, h: Any, commitment: Any, proof: 'RangeProofData') -> bool:
|
|
301
|
+
"""
|
|
302
|
+
Verify a range proof.
|
|
303
|
+
|
|
304
|
+
Checks that the commitment C commits to a value in [0, 2^num_bits).
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
group: The pairing group
|
|
308
|
+
g: First generator for Pedersen commitment
|
|
309
|
+
h: Second generator for Pedersen commitment
|
|
310
|
+
commitment: The Pedersen commitment C = g^v * h^r
|
|
311
|
+
proof: RangeProofData object containing the proof
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
True if proof is valid, False otherwise
|
|
315
|
+
|
|
316
|
+
Security Notes:
|
|
317
|
+
- Validates proof structure before verification
|
|
318
|
+
- Verifies each bit commitment and OR proof
|
|
319
|
+
- Checks commitment reconstruction for consistency
|
|
320
|
+
"""
|
|
321
|
+
# Security: Validate proof structure
|
|
322
|
+
required_attrs = ['num_bits', 'bit_commitments', 'bit_proofs']
|
|
323
|
+
for attr in required_attrs:
|
|
324
|
+
if not hasattr(proof, attr):
|
|
325
|
+
logger.warning("Invalid Range proof structure: missing '%s'. Ensure proof was created with RangeProof.prove()", attr)
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
num_bits = proof.num_bits
|
|
329
|
+
|
|
330
|
+
# Validate proof structure
|
|
331
|
+
if len(proof.bit_commitments) != num_bits:
|
|
332
|
+
logger.debug("Invalid number of bit commitments")
|
|
333
|
+
return False
|
|
334
|
+
if len(proof.bit_proofs) != num_bits:
|
|
335
|
+
logger.debug("Invalid number of bit proofs")
|
|
336
|
+
return False
|
|
337
|
+
|
|
338
|
+
# Step 1: Verify each bit OR proof
|
|
339
|
+
for i in range(num_bits):
|
|
340
|
+
if not cls._verify_bit_or_proof(
|
|
341
|
+
group, g, h, proof.bit_commitments[i], proof.bit_proofs[i]
|
|
342
|
+
):
|
|
343
|
+
logger.debug("Bit OR proof %d failed", i)
|
|
344
|
+
return False
|
|
345
|
+
|
|
346
|
+
# Step 2: Verify that weighted product of bit commitments equals C
|
|
347
|
+
# Product of Ci^(2^i) should equal C
|
|
348
|
+
# This works because: prod(Ci^(2^i)) = prod((g^bi * h^ri)^(2^i))
|
|
349
|
+
# = g^(sum(2^i * bi)) * h^(sum(2^i * ri))
|
|
350
|
+
# = g^v * h^r = C
|
|
351
|
+
reconstructed = None
|
|
352
|
+
for i in range(num_bits):
|
|
353
|
+
weight = group.init(ZR, 1 << i)
|
|
354
|
+
weighted_commitment = proof.bit_commitments[i] ** weight
|
|
355
|
+
if reconstructed is None:
|
|
356
|
+
reconstructed = weighted_commitment
|
|
357
|
+
else:
|
|
358
|
+
reconstructed = reconstructed * weighted_commitment
|
|
359
|
+
|
|
360
|
+
if reconstructed != commitment:
|
|
361
|
+
logger.debug("Commitment reconstruction failed")
|
|
362
|
+
return False
|
|
363
|
+
|
|
364
|
+
# Step 3: Verify sum proof binding hash
|
|
365
|
+
sum_data = b''
|
|
366
|
+
for Ci in proof.bit_commitments:
|
|
367
|
+
sum_data += objectToBytes(Ci, group)
|
|
368
|
+
expected_hash = group.hash(sum_data, ZR)
|
|
369
|
+
if proof.sum_proof.get('binding_hash') != expected_hash:
|
|
370
|
+
logger.debug("Sum proof binding hash mismatch")
|
|
371
|
+
return False
|
|
372
|
+
|
|
373
|
+
logger.debug("Range proof verification successful")
|
|
374
|
+
return True
|
|
375
|
+
|
|
376
|
+
@classmethod
|
|
377
|
+
def serialize_proof(cls, proof: 'RangeProofData', group: PairingGroup) -> bytes:
|
|
378
|
+
"""
|
|
379
|
+
Serialize proof to bytes using Charm utilities.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
proof: RangeProofData object to serialize
|
|
383
|
+
group: The pairing group
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Bytes representation of the proof
|
|
387
|
+
"""
|
|
388
|
+
proof_dict = {
|
|
389
|
+
'bit_commitments': proof.bit_commitments,
|
|
390
|
+
'bit_proofs': proof.bit_proofs,
|
|
391
|
+
'sum_proof': proof.sum_proof,
|
|
392
|
+
'num_bits': proof.num_bits,
|
|
393
|
+
'proof_type': proof.proof_type
|
|
394
|
+
}
|
|
395
|
+
return objectToBytes(proof_dict, group)
|
|
396
|
+
|
|
397
|
+
@classmethod
|
|
398
|
+
def deserialize_proof(cls, data: bytes, group: PairingGroup) -> 'RangeProofData':
|
|
399
|
+
"""
|
|
400
|
+
Deserialize bytes to proof.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
data: Bytes to deserialize
|
|
404
|
+
group: The pairing group
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
RangeProofData object
|
|
408
|
+
"""
|
|
409
|
+
proof_dict = bytesToObject(data, group)
|
|
410
|
+
return RangeProofData(
|
|
411
|
+
bit_commitments=proof_dict['bit_commitments'],
|
|
412
|
+
bit_proofs=proof_dict['bit_proofs'],
|
|
413
|
+
sum_proof=proof_dict['sum_proof'],
|
|
414
|
+
num_bits=proof_dict['num_bits'],
|
|
415
|
+
proof_type=proof_dict.get('proof_type', 'range')
|
|
416
|
+
)
|
|
417
|
+
|