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,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for OR Composition proof (CDS94) implementation.
|
|
3
|
+
|
|
4
|
+
Tests cover:
|
|
5
|
+
- Non-interactive OR proof generation and verification
|
|
6
|
+
- Witness indistinguishability property
|
|
7
|
+
- Serialization and deserialization
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import unittest
|
|
11
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
12
|
+
from charm.zkp_compiler.or_proof import ORProof, ORProofData
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestORProofNonInteractive(unittest.TestCase):
|
|
16
|
+
"""Tests for non-interactive OR proof (CDS94)."""
|
|
17
|
+
|
|
18
|
+
def setUp(self):
|
|
19
|
+
"""Set up test fixtures."""
|
|
20
|
+
self.group = PairingGroup('BN254')
|
|
21
|
+
self.g = self.group.random(G1)
|
|
22
|
+
# Create two public values with known discrete logs
|
|
23
|
+
self.x1 = self.group.random(ZR)
|
|
24
|
+
self.x2 = self.group.random(ZR)
|
|
25
|
+
self.h1 = self.g ** self.x1
|
|
26
|
+
self.h2 = self.g ** self.x2
|
|
27
|
+
|
|
28
|
+
def test_prove_first_statement(self):
|
|
29
|
+
"""Test proving h1 = g^x (which=0)."""
|
|
30
|
+
proof = ORProof.prove_non_interactive(
|
|
31
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=0
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
self.assertIsNotNone(proof)
|
|
35
|
+
self.assertIsNotNone(proof.commitment1)
|
|
36
|
+
self.assertIsNotNone(proof.commitment2)
|
|
37
|
+
self.assertIsNotNone(proof.challenge1)
|
|
38
|
+
self.assertIsNotNone(proof.challenge2)
|
|
39
|
+
self.assertIsNotNone(proof.response1)
|
|
40
|
+
self.assertIsNotNone(proof.response2)
|
|
41
|
+
|
|
42
|
+
result = ORProof.verify_non_interactive(
|
|
43
|
+
self.group, self.g, self.h1, self.h2, proof
|
|
44
|
+
)
|
|
45
|
+
self.assertTrue(result)
|
|
46
|
+
|
|
47
|
+
def test_prove_second_statement(self):
|
|
48
|
+
"""Test proving h2 = g^x (which=1)."""
|
|
49
|
+
proof = ORProof.prove_non_interactive(
|
|
50
|
+
self.group, self.g, self.h1, self.h2, self.x2, which=1
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.assertIsNotNone(proof)
|
|
54
|
+
result = ORProof.verify_non_interactive(
|
|
55
|
+
self.group, self.g, self.h1, self.h2, proof
|
|
56
|
+
)
|
|
57
|
+
self.assertTrue(result)
|
|
58
|
+
|
|
59
|
+
def test_wrong_secret_fails(self):
|
|
60
|
+
"""Test that wrong secret fails verification."""
|
|
61
|
+
wrong_x = self.group.random(ZR)
|
|
62
|
+
proof = ORProof.prove_non_interactive(
|
|
63
|
+
self.group, self.g, self.h1, self.h2, wrong_x, which=0
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
result = ORProof.verify_non_interactive(
|
|
67
|
+
self.group, self.g, self.h1, self.h2, proof
|
|
68
|
+
)
|
|
69
|
+
self.assertFalse(result)
|
|
70
|
+
|
|
71
|
+
def test_wrong_which_fails(self):
|
|
72
|
+
"""Test that claiming wrong branch fails."""
|
|
73
|
+
# x1 is secret for h1, but claim it's for h2 (which=1)
|
|
74
|
+
proof = ORProof.prove_non_interactive(
|
|
75
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=1
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
result = ORProof.verify_non_interactive(
|
|
79
|
+
self.group, self.g, self.h1, self.h2, proof
|
|
80
|
+
)
|
|
81
|
+
self.assertFalse(result)
|
|
82
|
+
|
|
83
|
+
def test_tampered_proof_fails(self):
|
|
84
|
+
"""Test that tampered proof fails verification."""
|
|
85
|
+
proof = ORProof.prove_non_interactive(
|
|
86
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=0
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Tamper with response1
|
|
90
|
+
tampered = ORProofData(
|
|
91
|
+
commitment1=proof.commitment1,
|
|
92
|
+
commitment2=proof.commitment2,
|
|
93
|
+
challenge1=proof.challenge1,
|
|
94
|
+
challenge2=proof.challenge2,
|
|
95
|
+
response1=proof.response1 + self.group.random(ZR),
|
|
96
|
+
response2=proof.response2,
|
|
97
|
+
proof_type=proof.proof_type
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
result = ORProof.verify_non_interactive(
|
|
101
|
+
self.group, self.g, self.h1, self.h2, tampered
|
|
102
|
+
)
|
|
103
|
+
self.assertFalse(result)
|
|
104
|
+
|
|
105
|
+
def test_challenges_sum_correctly(self):
|
|
106
|
+
"""Test that c1 + c2 equals main challenge."""
|
|
107
|
+
proof = ORProof.prove_non_interactive(
|
|
108
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=0
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Recompute expected challenge
|
|
112
|
+
expected_c = ORProof._compute_challenge_hash(
|
|
113
|
+
self.group, self.g, self.h1, self.h2,
|
|
114
|
+
proof.commitment1, proof.commitment2
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Verify c1 + c2 = c
|
|
118
|
+
actual_c = proof.challenge1 + proof.challenge2
|
|
119
|
+
self.assertEqual(expected_c, actual_c)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class TestORProofWitnessIndistinguishability(unittest.TestCase):
|
|
123
|
+
"""Tests for witness indistinguishability property."""
|
|
124
|
+
|
|
125
|
+
def setUp(self):
|
|
126
|
+
"""Set up test fixtures."""
|
|
127
|
+
self.group = PairingGroup('BN254')
|
|
128
|
+
self.g = self.group.random(G1)
|
|
129
|
+
self.x1 = self.group.random(ZR)
|
|
130
|
+
self.x2 = self.group.random(ZR)
|
|
131
|
+
self.h1 = self.g ** self.x1
|
|
132
|
+
self.h2 = self.g ** self.x2
|
|
133
|
+
|
|
134
|
+
def test_proofs_look_similar(self):
|
|
135
|
+
"""Test that both branches produce valid-looking proofs."""
|
|
136
|
+
proof0 = ORProof.prove_non_interactive(
|
|
137
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=0
|
|
138
|
+
)
|
|
139
|
+
proof1 = ORProof.prove_non_interactive(
|
|
140
|
+
self.group, self.g, self.h1, self.h2, self.x2, which=1
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Both proofs should have same structure
|
|
144
|
+
self.assertEqual(proof0.proof_type, proof1.proof_type)
|
|
145
|
+
self.assertEqual(proof0.proof_type, 'or')
|
|
146
|
+
|
|
147
|
+
# Both should be valid
|
|
148
|
+
result0 = ORProof.verify_non_interactive(
|
|
149
|
+
self.group, self.g, self.h1, self.h2, proof0
|
|
150
|
+
)
|
|
151
|
+
result1 = ORProof.verify_non_interactive(
|
|
152
|
+
self.group, self.g, self.h1, self.h2, proof1
|
|
153
|
+
)
|
|
154
|
+
self.assertTrue(result0)
|
|
155
|
+
self.assertTrue(result1)
|
|
156
|
+
|
|
157
|
+
def test_verifier_cannot_distinguish(self):
|
|
158
|
+
"""Test that verifier accepts both without knowing which."""
|
|
159
|
+
# Generate multiple proofs from each branch
|
|
160
|
+
proofs = []
|
|
161
|
+
for _ in range(3):
|
|
162
|
+
proof0 = ORProof.prove_non_interactive(
|
|
163
|
+
self.group, self.g, self.h1, self.h2, self.x1, which=0
|
|
164
|
+
)
|
|
165
|
+
proof1 = ORProof.prove_non_interactive(
|
|
166
|
+
self.group, self.g, self.h1, self.h2, self.x2, which=1
|
|
167
|
+
)
|
|
168
|
+
proofs.extend([proof0, proof1])
|
|
169
|
+
|
|
170
|
+
# Verifier should accept all proofs identically
|
|
171
|
+
for proof in proofs:
|
|
172
|
+
result = ORProof.verify_non_interactive(
|
|
173
|
+
self.group, self.g, self.h1, self.h2, proof
|
|
174
|
+
)
|
|
175
|
+
self.assertTrue(result)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TestORProofSerialization(unittest.TestCase):
|
|
179
|
+
"""Tests for OR proof serialization."""
|
|
180
|
+
|
|
181
|
+
def setUp(self):
|
|
182
|
+
"""Set up test fixtures."""
|
|
183
|
+
self.group = PairingGroup('BN254')
|
|
184
|
+
self.g = self.group.random(G1)
|
|
185
|
+
self.x = self.group.random(ZR)
|
|
186
|
+
self.h1 = self.g ** self.x
|
|
187
|
+
self.h2 = self.g ** self.group.random(ZR)
|
|
188
|
+
|
|
189
|
+
def test_serialization_roundtrip(self):
|
|
190
|
+
"""Test serialize and deserialize proof."""
|
|
191
|
+
proof = ORProof.prove_non_interactive(
|
|
192
|
+
self.group, self.g, self.h1, self.h2, self.x, which=0
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Serialize
|
|
196
|
+
serialized = ORProof.serialize_proof(proof, self.group)
|
|
197
|
+
self.assertIsInstance(serialized, bytes)
|
|
198
|
+
self.assertGreater(len(serialized), 0)
|
|
199
|
+
|
|
200
|
+
# Deserialize
|
|
201
|
+
deserialized = ORProof.deserialize_proof(serialized, self.group)
|
|
202
|
+
|
|
203
|
+
# Check all fields match
|
|
204
|
+
self.assertEqual(proof.commitment1, deserialized.commitment1)
|
|
205
|
+
self.assertEqual(proof.commitment2, deserialized.commitment2)
|
|
206
|
+
self.assertEqual(proof.challenge1, deserialized.challenge1)
|
|
207
|
+
self.assertEqual(proof.challenge2, deserialized.challenge2)
|
|
208
|
+
self.assertEqual(proof.response1, deserialized.response1)
|
|
209
|
+
self.assertEqual(proof.response2, deserialized.response2)
|
|
210
|
+
self.assertEqual(proof.proof_type, deserialized.proof_type)
|
|
211
|
+
|
|
212
|
+
def test_serialized_proof_verifies(self):
|
|
213
|
+
"""Test that deserialized proof still verifies."""
|
|
214
|
+
proof = ORProof.prove_non_interactive(
|
|
215
|
+
self.group, self.g, self.h1, self.h2, self.x, which=0
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Serialize and deserialize
|
|
219
|
+
serialized = ORProof.serialize_proof(proof, self.group)
|
|
220
|
+
deserialized = ORProof.deserialize_proof(serialized, self.group)
|
|
221
|
+
|
|
222
|
+
# Deserialized proof should verify
|
|
223
|
+
result = ORProof.verify_non_interactive(
|
|
224
|
+
self.group, self.g, self.h1, self.h2, deserialized
|
|
225
|
+
)
|
|
226
|
+
self.assertTrue(result)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
unittest.main()
|
|
231
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for ZK proof serialization.
|
|
3
|
+
|
|
4
|
+
Tests cover:
|
|
5
|
+
- Serializing proofs to bytes
|
|
6
|
+
- Deserializing bytes back to proofs
|
|
7
|
+
- Roundtrip preservation
|
|
8
|
+
- Error handling for invalid data
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import unittest
|
|
12
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
13
|
+
from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestProofSerialization(unittest.TestCase):
|
|
17
|
+
"""Tests for proof serialization."""
|
|
18
|
+
|
|
19
|
+
def setUp(self):
|
|
20
|
+
"""Set up test fixtures."""
|
|
21
|
+
self.group = PairingGroup('BN254')
|
|
22
|
+
self.g = self.group.random(G1)
|
|
23
|
+
self.x = self.group.random(ZR)
|
|
24
|
+
self.h = self.g ** self.x
|
|
25
|
+
|
|
26
|
+
def test_serialize_deserialize_roundtrip(self):
|
|
27
|
+
"""Test that proof survives serialization roundtrip."""
|
|
28
|
+
# Generate proof
|
|
29
|
+
proof = SchnorrProof.prove_non_interactive(
|
|
30
|
+
self.group, self.g, self.h, self.x
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Serialize
|
|
34
|
+
data = SchnorrProof.serialize_proof(proof, self.group)
|
|
35
|
+
self.assertIsInstance(data, bytes)
|
|
36
|
+
self.assertGreater(len(data), 0)
|
|
37
|
+
|
|
38
|
+
# Deserialize
|
|
39
|
+
recovered = SchnorrProof.deserialize_proof(data, self.group)
|
|
40
|
+
self.assertIsNotNone(recovered)
|
|
41
|
+
|
|
42
|
+
# Verify recovered proof still works
|
|
43
|
+
result = SchnorrProof.verify_non_interactive(
|
|
44
|
+
self.group, self.g, self.h, recovered
|
|
45
|
+
)
|
|
46
|
+
self.assertTrue(result)
|
|
47
|
+
|
|
48
|
+
def test_serialized_proof_is_bytes(self):
|
|
49
|
+
"""Test that serialization produces bytes."""
|
|
50
|
+
proof = SchnorrProof.prove_non_interactive(
|
|
51
|
+
self.group, self.g, self.h, self.x
|
|
52
|
+
)
|
|
53
|
+
data = SchnorrProof.serialize_proof(proof, self.group)
|
|
54
|
+
self.assertIsInstance(data, bytes)
|
|
55
|
+
|
|
56
|
+
def test_different_proofs_different_serialization(self):
|
|
57
|
+
"""Test that different proofs produce different serialized data."""
|
|
58
|
+
proof1 = SchnorrProof.prove_non_interactive(
|
|
59
|
+
self.group, self.g, self.h, self.x
|
|
60
|
+
)
|
|
61
|
+
proof2 = SchnorrProof.prove_non_interactive(
|
|
62
|
+
self.group, self.g, self.h, self.x
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
data1 = SchnorrProof.serialize_proof(proof1, self.group)
|
|
66
|
+
data2 = SchnorrProof.serialize_proof(proof2, self.group)
|
|
67
|
+
|
|
68
|
+
# Different proofs should have different serializations
|
|
69
|
+
# (due to different random commitments)
|
|
70
|
+
self.assertNotEqual(data1, data2)
|
|
71
|
+
|
|
72
|
+
def test_deserialize_preserves_proof_type(self):
|
|
73
|
+
"""Test that proof_type is preserved through serialization."""
|
|
74
|
+
proof = SchnorrProof.prove_non_interactive(
|
|
75
|
+
self.group, self.g, self.h, self.x
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
data = SchnorrProof.serialize_proof(proof, self.group)
|
|
79
|
+
recovered = SchnorrProof.deserialize_proof(data, self.group)
|
|
80
|
+
|
|
81
|
+
self.assertEqual(recovered.proof_type, proof.proof_type)
|
|
82
|
+
|
|
83
|
+
def test_serialization_with_different_groups(self):
|
|
84
|
+
"""Test serialization works with different pairing groups."""
|
|
85
|
+
for curve in ['BN254', 'MNT224']:
|
|
86
|
+
with self.subTest(curve=curve):
|
|
87
|
+
group = PairingGroup(curve)
|
|
88
|
+
g = group.random(G1)
|
|
89
|
+
x = group.random(ZR)
|
|
90
|
+
h = g ** x
|
|
91
|
+
|
|
92
|
+
proof = SchnorrProof.prove_non_interactive(group, g, h, x)
|
|
93
|
+
data = SchnorrProof.serialize_proof(proof, group)
|
|
94
|
+
recovered = SchnorrProof.deserialize_proof(data, group)
|
|
95
|
+
|
|
96
|
+
result = SchnorrProof.verify_non_interactive(
|
|
97
|
+
group, g, h, recovered
|
|
98
|
+
)
|
|
99
|
+
self.assertTrue(result)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestProofSerializationErrors(unittest.TestCase):
|
|
103
|
+
"""Tests for serialization error handling."""
|
|
104
|
+
|
|
105
|
+
def setUp(self):
|
|
106
|
+
self.group = PairingGroup('BN254')
|
|
107
|
+
|
|
108
|
+
def test_deserialize_invalid_data_fails(self):
|
|
109
|
+
"""Test that invalid data raises an exception."""
|
|
110
|
+
with self.assertRaises(Exception):
|
|
111
|
+
SchnorrProof.deserialize_proof(b"not valid data", self.group)
|
|
112
|
+
|
|
113
|
+
def test_deserialize_empty_data_fails(self):
|
|
114
|
+
"""Test that empty data raises an exception."""
|
|
115
|
+
with self.assertRaises(Exception):
|
|
116
|
+
SchnorrProof.deserialize_proof(b"", self.group)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
unittest.main()
|
|
121
|
+
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for Range Proof implementation.
|
|
3
|
+
|
|
4
|
+
Tests cover:
|
|
5
|
+
- Basic range proofs with boundary values
|
|
6
|
+
- Different bit sizes for ranges
|
|
7
|
+
- Pedersen commitment creation and properties
|
|
8
|
+
- Proof serialization and deserialization
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import unittest
|
|
12
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
13
|
+
from charm.zkp_compiler.range_proof import RangeProof, RangeProofData
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestRangeProofBasic(unittest.TestCase):
|
|
17
|
+
"""Tests for basic range proof functionality with 8-bit range."""
|
|
18
|
+
|
|
19
|
+
def setUp(self):
|
|
20
|
+
"""Set up test fixtures."""
|
|
21
|
+
self.group = PairingGroup('BN254')
|
|
22
|
+
self.g = self.group.random(G1)
|
|
23
|
+
self.h = self.group.random(G1)
|
|
24
|
+
self.num_bits = 8 # Range [0, 256)
|
|
25
|
+
|
|
26
|
+
def test_value_zero(self):
|
|
27
|
+
"""Prove 0 is in range [0, 2^8)."""
|
|
28
|
+
value = 0
|
|
29
|
+
randomness = self.group.random(ZR)
|
|
30
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
31
|
+
self.group, self.g, self.h, value, randomness
|
|
32
|
+
)
|
|
33
|
+
proof = RangeProof.prove(
|
|
34
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
35
|
+
)
|
|
36
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
37
|
+
self.assertTrue(result)
|
|
38
|
+
|
|
39
|
+
def test_value_one(self):
|
|
40
|
+
"""Prove 1 is in range [0, 2^8)."""
|
|
41
|
+
value = 1
|
|
42
|
+
randomness = self.group.random(ZR)
|
|
43
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
44
|
+
self.group, self.g, self.h, value, randomness
|
|
45
|
+
)
|
|
46
|
+
proof = RangeProof.prove(
|
|
47
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
48
|
+
)
|
|
49
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
50
|
+
self.assertTrue(result)
|
|
51
|
+
|
|
52
|
+
def test_value_max(self):
|
|
53
|
+
"""Prove 255 (max value) is in range [0, 2^8)."""
|
|
54
|
+
value = 255 # 2^8 - 1
|
|
55
|
+
randomness = self.group.random(ZR)
|
|
56
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
57
|
+
self.group, self.g, self.h, value, randomness
|
|
58
|
+
)
|
|
59
|
+
proof = RangeProof.prove(
|
|
60
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
61
|
+
)
|
|
62
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
63
|
+
self.assertTrue(result)
|
|
64
|
+
|
|
65
|
+
def test_value_middle(self):
|
|
66
|
+
"""Prove 42 is in range [0, 2^8)."""
|
|
67
|
+
value = 42
|
|
68
|
+
randomness = self.group.random(ZR)
|
|
69
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
70
|
+
self.group, self.g, self.h, value, randomness
|
|
71
|
+
)
|
|
72
|
+
proof = RangeProof.prove(
|
|
73
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
74
|
+
)
|
|
75
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
76
|
+
self.assertTrue(result)
|
|
77
|
+
|
|
78
|
+
def test_value_out_of_range_fails(self):
|
|
79
|
+
"""Value >= 2^n should fail."""
|
|
80
|
+
value = 256 # 2^8, out of range
|
|
81
|
+
randomness = self.group.random(ZR)
|
|
82
|
+
with self.assertRaises(ValueError):
|
|
83
|
+
RangeProof.prove(
|
|
84
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class TestRangeProofDifferentBitSizes(unittest.TestCase):
|
|
89
|
+
"""Tests for range proofs with different bit sizes."""
|
|
90
|
+
|
|
91
|
+
def setUp(self):
|
|
92
|
+
"""Set up test fixtures."""
|
|
93
|
+
self.group = PairingGroup('BN254')
|
|
94
|
+
self.g = self.group.random(G1)
|
|
95
|
+
self.h = self.group.random(G1)
|
|
96
|
+
|
|
97
|
+
def test_4_bit_range(self):
|
|
98
|
+
"""Test range [0, 16) with 4-bit proof."""
|
|
99
|
+
num_bits = 4
|
|
100
|
+
value = 15 # Max value in range
|
|
101
|
+
randomness = self.group.random(ZR)
|
|
102
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
103
|
+
self.group, self.g, self.h, value, randomness
|
|
104
|
+
)
|
|
105
|
+
proof = RangeProof.prove(
|
|
106
|
+
self.group, self.g, self.h, value, randomness, num_bits
|
|
107
|
+
)
|
|
108
|
+
self.assertEqual(proof.num_bits, 4)
|
|
109
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
110
|
+
self.assertTrue(result)
|
|
111
|
+
|
|
112
|
+
def test_8_bit_range(self):
|
|
113
|
+
"""Test range [0, 256) with 8-bit proof."""
|
|
114
|
+
num_bits = 8
|
|
115
|
+
value = 200
|
|
116
|
+
randomness = self.group.random(ZR)
|
|
117
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
118
|
+
self.group, self.g, self.h, value, randomness
|
|
119
|
+
)
|
|
120
|
+
proof = RangeProof.prove(
|
|
121
|
+
self.group, self.g, self.h, value, randomness, num_bits
|
|
122
|
+
)
|
|
123
|
+
self.assertEqual(proof.num_bits, 8)
|
|
124
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
125
|
+
self.assertTrue(result)
|
|
126
|
+
|
|
127
|
+
def test_16_bit_range(self):
|
|
128
|
+
"""Test range [0, 65536) with 16-bit proof."""
|
|
129
|
+
num_bits = 16
|
|
130
|
+
value = 50000
|
|
131
|
+
randomness = self.group.random(ZR)
|
|
132
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
133
|
+
self.group, self.g, self.h, value, randomness
|
|
134
|
+
)
|
|
135
|
+
proof = RangeProof.prove(
|
|
136
|
+
self.group, self.g, self.h, value, randomness, num_bits
|
|
137
|
+
)
|
|
138
|
+
self.assertEqual(proof.num_bits, 16)
|
|
139
|
+
result = RangeProof.verify(self.group, self.g, self.h, commitment, proof)
|
|
140
|
+
self.assertTrue(result)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class TestRangeProofPedersenCommitment(unittest.TestCase):
|
|
144
|
+
"""Tests for Pedersen commitment creation and properties."""
|
|
145
|
+
|
|
146
|
+
def setUp(self):
|
|
147
|
+
"""Set up test fixtures."""
|
|
148
|
+
self.group = PairingGroup('BN254')
|
|
149
|
+
self.g = self.group.random(G1)
|
|
150
|
+
self.h = self.group.random(G1)
|
|
151
|
+
|
|
152
|
+
def test_create_commitment(self):
|
|
153
|
+
"""Test commitment creation helper."""
|
|
154
|
+
value = 42
|
|
155
|
+
randomness = self.group.random(ZR)
|
|
156
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
157
|
+
self.group, self.g, self.h, value, randomness
|
|
158
|
+
)
|
|
159
|
+
# Verify commitment is C = g^v * h^r
|
|
160
|
+
v = self.group.init(ZR, value)
|
|
161
|
+
expected = (self.g ** v) * (self.h ** randomness)
|
|
162
|
+
self.assertEqual(commitment, expected)
|
|
163
|
+
|
|
164
|
+
def test_commitment_hiding(self):
|
|
165
|
+
"""Same value, different randomness = different commitment."""
|
|
166
|
+
value = 42
|
|
167
|
+
r1 = self.group.random(ZR)
|
|
168
|
+
r2 = self.group.random(ZR)
|
|
169
|
+
c1 = RangeProof.create_pedersen_commitment(
|
|
170
|
+
self.group, self.g, self.h, value, r1
|
|
171
|
+
)
|
|
172
|
+
c2 = RangeProof.create_pedersen_commitment(
|
|
173
|
+
self.group, self.g, self.h, value, r2
|
|
174
|
+
)
|
|
175
|
+
# Different randomness should produce different commitments
|
|
176
|
+
self.assertNotEqual(c1, c2)
|
|
177
|
+
|
|
178
|
+
def test_commitment_binding(self):
|
|
179
|
+
"""Commitment is binding - different values produce different commitments."""
|
|
180
|
+
r = self.group.random(ZR)
|
|
181
|
+
c1 = RangeProof.create_pedersen_commitment(
|
|
182
|
+
self.group, self.g, self.h, 42, r
|
|
183
|
+
)
|
|
184
|
+
c2 = RangeProof.create_pedersen_commitment(
|
|
185
|
+
self.group, self.g, self.h, 43, r
|
|
186
|
+
)
|
|
187
|
+
# Different values with same randomness should produce different commitments
|
|
188
|
+
self.assertNotEqual(c1, c2)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class TestRangeProofSerialization(unittest.TestCase):
|
|
192
|
+
"""Tests for proof serialization and deserialization."""
|
|
193
|
+
|
|
194
|
+
def setUp(self):
|
|
195
|
+
"""Set up test fixtures."""
|
|
196
|
+
self.group = PairingGroup('BN254')
|
|
197
|
+
self.g = self.group.random(G1)
|
|
198
|
+
self.h = self.group.random(G1)
|
|
199
|
+
self.num_bits = 4 # Use small bit size for fast tests
|
|
200
|
+
|
|
201
|
+
def test_serialization_roundtrip(self):
|
|
202
|
+
"""Serialize and deserialize proof."""
|
|
203
|
+
value = 10
|
|
204
|
+
randomness = self.group.random(ZR)
|
|
205
|
+
proof = RangeProof.prove(
|
|
206
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
207
|
+
)
|
|
208
|
+
# Serialize
|
|
209
|
+
serialized = RangeProof.serialize_proof(proof, self.group)
|
|
210
|
+
self.assertIsInstance(serialized, bytes)
|
|
211
|
+
# Deserialize
|
|
212
|
+
deserialized = RangeProof.deserialize_proof(serialized, self.group)
|
|
213
|
+
# Check structure is preserved
|
|
214
|
+
self.assertEqual(deserialized.num_bits, proof.num_bits)
|
|
215
|
+
self.assertEqual(deserialized.proof_type, proof.proof_type)
|
|
216
|
+
self.assertEqual(len(deserialized.bit_commitments), len(proof.bit_commitments))
|
|
217
|
+
self.assertEqual(len(deserialized.bit_proofs), len(proof.bit_proofs))
|
|
218
|
+
|
|
219
|
+
def test_serialized_proof_verifies(self):
|
|
220
|
+
"""Deserialized proof still verifies."""
|
|
221
|
+
value = 12
|
|
222
|
+
randomness = self.group.random(ZR)
|
|
223
|
+
commitment = RangeProof.create_pedersen_commitment(
|
|
224
|
+
self.group, self.g, self.h, value, randomness
|
|
225
|
+
)
|
|
226
|
+
proof = RangeProof.prove(
|
|
227
|
+
self.group, self.g, self.h, value, randomness, self.num_bits
|
|
228
|
+
)
|
|
229
|
+
# Serialize and deserialize
|
|
230
|
+
serialized = RangeProof.serialize_proof(proof, self.group)
|
|
231
|
+
deserialized = RangeProof.deserialize_proof(serialized, self.group)
|
|
232
|
+
# Verify deserialized proof
|
|
233
|
+
result = RangeProof.verify(
|
|
234
|
+
self.group, self.g, self.h, commitment, deserialized
|
|
235
|
+
)
|
|
236
|
+
self.assertTrue(result)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if __name__ == "__main__":
|
|
240
|
+
unittest.main()
|
|
241
|
+
|