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,315 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pedersen Commitment Test Vectors
|
|
3
|
+
|
|
4
|
+
Test vectors for Pedersen Commitment scheme based on:
|
|
5
|
+
- Original paper: "Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing" (Pedersen, 1992)
|
|
6
|
+
- Standard commitment scheme properties: hiding and binding
|
|
7
|
+
|
|
8
|
+
These tests verify the mathematical correctness of the Pedersen commitment implementation.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import unittest
|
|
12
|
+
from charm.toolbox.ecgroup import ECGroup, ZR, G
|
|
13
|
+
from charm.schemes.commit.commit_pedersen92 import CM_Ped92
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestPedersenMathematicalProperties(unittest.TestCase):
|
|
17
|
+
"""
|
|
18
|
+
Test mathematical properties of Pedersen commitments.
|
|
19
|
+
|
|
20
|
+
Pedersen commitments have two key properties:
|
|
21
|
+
1. Hiding: Commitment reveals nothing about the message
|
|
22
|
+
2. Binding: Cannot open commitment to different message (computationally)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def setUp(self):
|
|
26
|
+
"""Set up test fixtures with secp256k1 curve."""
|
|
27
|
+
# Use curve 714 (secp256k1) for 128-bit security
|
|
28
|
+
self.group = ECGroup(714)
|
|
29
|
+
self.pedersen = CM_Ped92(self.group)
|
|
30
|
+
self.pk = self.pedersen.setup()
|
|
31
|
+
|
|
32
|
+
def test_commitment_correctness(self):
|
|
33
|
+
"""
|
|
34
|
+
Test Vector PEDERSEN-1: Commitment Correctness
|
|
35
|
+
|
|
36
|
+
Property: commit(m, r) produces C = g^m * h^r
|
|
37
|
+
|
|
38
|
+
Source: Pedersen 1992, Definition 1
|
|
39
|
+
"""
|
|
40
|
+
msg = self.group.random(ZR)
|
|
41
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
42
|
+
|
|
43
|
+
# Verify commitment structure: C = g^m * h^r
|
|
44
|
+
expected = (self.pk['g'] ** msg) * (self.pk['h'] ** decommit)
|
|
45
|
+
|
|
46
|
+
self.assertEqual(commit, expected,
|
|
47
|
+
"Commitment must equal g^m * h^r")
|
|
48
|
+
|
|
49
|
+
def test_decommitment_verification(self):
|
|
50
|
+
"""
|
|
51
|
+
Test Vector PEDERSEN-2: Decommitment Verification
|
|
52
|
+
|
|
53
|
+
Property: decommit(C, r, m) returns True for valid (C, r, m)
|
|
54
|
+
|
|
55
|
+
Source: Pedersen 1992, Verification procedure
|
|
56
|
+
"""
|
|
57
|
+
msg = self.group.random(ZR)
|
|
58
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
59
|
+
|
|
60
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg)
|
|
61
|
+
|
|
62
|
+
self.assertTrue(result,
|
|
63
|
+
"Valid decommitment must verify")
|
|
64
|
+
|
|
65
|
+
def test_wrong_message_decommit_fails(self):
|
|
66
|
+
"""
|
|
67
|
+
Test Vector PEDERSEN-3: Binding Property
|
|
68
|
+
|
|
69
|
+
Property: Cannot decommit to a different message.
|
|
70
|
+
|
|
71
|
+
Source: Computational binding property
|
|
72
|
+
"""
|
|
73
|
+
msg1 = self.group.random(ZR)
|
|
74
|
+
msg2 = self.group.random(ZR)
|
|
75
|
+
|
|
76
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg1)
|
|
77
|
+
|
|
78
|
+
# Try to decommit with wrong message
|
|
79
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg2)
|
|
80
|
+
|
|
81
|
+
self.assertFalse(result,
|
|
82
|
+
"Decommitment with wrong message must fail (binding)")
|
|
83
|
+
|
|
84
|
+
def test_wrong_randomness_decommit_fails(self):
|
|
85
|
+
"""
|
|
86
|
+
Test Vector PEDERSEN-4: Randomness Binding
|
|
87
|
+
|
|
88
|
+
Property: Cannot decommit with wrong randomness.
|
|
89
|
+
"""
|
|
90
|
+
msg = self.group.random(ZR)
|
|
91
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
92
|
+
|
|
93
|
+
# Try with wrong randomness
|
|
94
|
+
wrong_decommit = self.group.random(ZR)
|
|
95
|
+
result = self.pedersen.decommit(self.pk, commit, wrong_decommit, msg)
|
|
96
|
+
|
|
97
|
+
self.assertFalse(result,
|
|
98
|
+
"Decommitment with wrong randomness must fail")
|
|
99
|
+
|
|
100
|
+
def test_different_randomness_different_commitments(self):
|
|
101
|
+
"""
|
|
102
|
+
Test Vector PEDERSEN-5: Hiding Property (Statistical)
|
|
103
|
+
|
|
104
|
+
Property: Same message with different randomness produces different commitments.
|
|
105
|
+
|
|
106
|
+
Source: Information-theoretic hiding property
|
|
107
|
+
"""
|
|
108
|
+
msg = self.group.random(ZR)
|
|
109
|
+
|
|
110
|
+
# Commit to same message twice (different randomness)
|
|
111
|
+
(commit1, _) = self.pedersen.commit(self.pk, msg)
|
|
112
|
+
(commit2, _) = self.pedersen.commit(self.pk, msg)
|
|
113
|
+
|
|
114
|
+
self.assertNotEqual(commit1, commit2,
|
|
115
|
+
"Same message with different randomness must produce different commitments")
|
|
116
|
+
|
|
117
|
+
def test_homomorphic_property(self):
|
|
118
|
+
"""
|
|
119
|
+
Test Vector PEDERSEN-6: Homomorphic Property
|
|
120
|
+
|
|
121
|
+
Property: C(m1, r1) * C(m2, r2) = C(m1+m2, r1+r2)
|
|
122
|
+
|
|
123
|
+
Source: Pedersen commitments are additively homomorphic
|
|
124
|
+
"""
|
|
125
|
+
m1 = self.group.random(ZR)
|
|
126
|
+
m2 = self.group.random(ZR)
|
|
127
|
+
|
|
128
|
+
(c1, r1) = self.pedersen.commit(self.pk, m1)
|
|
129
|
+
(c2, r2) = self.pedersen.commit(self.pk, m2)
|
|
130
|
+
|
|
131
|
+
# Compute product of commitments
|
|
132
|
+
c_product = c1 * c2
|
|
133
|
+
|
|
134
|
+
# This should equal commitment to sum
|
|
135
|
+
expected = (self.pk['g'] ** (m1 + m2)) * (self.pk['h'] ** (r1 + r2))
|
|
136
|
+
|
|
137
|
+
self.assertEqual(c_product, expected,
|
|
138
|
+
"Pedersen commitments must be additively homomorphic")
|
|
139
|
+
|
|
140
|
+
def test_homomorphic_decommit(self):
|
|
141
|
+
"""
|
|
142
|
+
Test Vector PEDERSEN-7: Homomorphic Decommitment
|
|
143
|
+
|
|
144
|
+
Property: Can decommit product of commitments with sum of values.
|
|
145
|
+
"""
|
|
146
|
+
m1 = self.group.random(ZR)
|
|
147
|
+
m2 = self.group.random(ZR)
|
|
148
|
+
|
|
149
|
+
(c1, r1) = self.pedersen.commit(self.pk, m1)
|
|
150
|
+
(c2, r2) = self.pedersen.commit(self.pk, m2)
|
|
151
|
+
|
|
152
|
+
# Product commitment
|
|
153
|
+
c_product = c1 * c2
|
|
154
|
+
|
|
155
|
+
# Should decommit with sums
|
|
156
|
+
result = self.pedersen.decommit(self.pk, c_product, r1 + r2, m1 + m2)
|
|
157
|
+
|
|
158
|
+
self.assertTrue(result,
|
|
159
|
+
"Homomorphic commitment must decommit with sum of values")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TestPedersenEdgeCases(unittest.TestCase):
|
|
163
|
+
"""
|
|
164
|
+
Edge case tests for Pedersen commitments.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
def setUp(self):
|
|
168
|
+
"""Set up test fixtures."""
|
|
169
|
+
self.group = ECGroup(714)
|
|
170
|
+
self.pedersen = CM_Ped92(self.group)
|
|
171
|
+
self.pk = self.pedersen.setup()
|
|
172
|
+
|
|
173
|
+
def test_zero_message(self):
|
|
174
|
+
"""
|
|
175
|
+
Test Vector PEDERSEN-EDGE-1: Zero Message
|
|
176
|
+
|
|
177
|
+
Property: Commitment to zero message works correctly.
|
|
178
|
+
"""
|
|
179
|
+
msg = self.group.init(ZR, 0)
|
|
180
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
181
|
+
|
|
182
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg)
|
|
183
|
+
|
|
184
|
+
self.assertTrue(result,
|
|
185
|
+
"Commitment to zero must work correctly")
|
|
186
|
+
|
|
187
|
+
def test_one_message(self):
|
|
188
|
+
"""
|
|
189
|
+
Test Vector PEDERSEN-EDGE-2: Message = 1
|
|
190
|
+
|
|
191
|
+
Property: Commitment to 1 works correctly.
|
|
192
|
+
"""
|
|
193
|
+
msg = self.group.init(ZR, 1)
|
|
194
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
195
|
+
|
|
196
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg)
|
|
197
|
+
|
|
198
|
+
self.assertTrue(result,
|
|
199
|
+
"Commitment to 1 must work correctly")
|
|
200
|
+
|
|
201
|
+
def test_negative_message(self):
|
|
202
|
+
"""
|
|
203
|
+
Test Vector PEDERSEN-EDGE-3: Negative Message (Modular)
|
|
204
|
+
|
|
205
|
+
Property: Commitment to negative values (mod order) works correctly.
|
|
206
|
+
"""
|
|
207
|
+
# In ZR, -1 is equivalent to order - 1
|
|
208
|
+
msg = self.group.init(ZR, -1)
|
|
209
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
210
|
+
|
|
211
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg)
|
|
212
|
+
|
|
213
|
+
self.assertTrue(result,
|
|
214
|
+
"Commitment to negative value must work correctly")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class TestPedersenSecurityProperties(unittest.TestCase):
|
|
218
|
+
"""
|
|
219
|
+
Security-focused tests for Pedersen commitments.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
def setUp(self):
|
|
223
|
+
"""Set up test fixtures."""
|
|
224
|
+
self.group = ECGroup(714)
|
|
225
|
+
self.pedersen = CM_Ped92(self.group)
|
|
226
|
+
self.pk = self.pedersen.setup()
|
|
227
|
+
|
|
228
|
+
def test_generators_are_independent(self):
|
|
229
|
+
"""
|
|
230
|
+
Test Vector PEDERSEN-SEC-1: Generator Independence
|
|
231
|
+
|
|
232
|
+
Property: g and h should be independent (no known discrete log relation).
|
|
233
|
+
|
|
234
|
+
Note: This is a structural test - we verify g ≠ h.
|
|
235
|
+
True independence requires g, h to be generated from nothing-up-my-sleeve numbers.
|
|
236
|
+
"""
|
|
237
|
+
self.assertNotEqual(self.pk['g'], self.pk['h'],
|
|
238
|
+
"Generators g and h must be different")
|
|
239
|
+
|
|
240
|
+
def test_commitment_not_identity(self):
|
|
241
|
+
"""
|
|
242
|
+
Test Vector PEDERSEN-SEC-2: Non-trivial Commitment
|
|
243
|
+
|
|
244
|
+
Property: Commitment should not be identity element for random message.
|
|
245
|
+
"""
|
|
246
|
+
msg = self.group.random(ZR)
|
|
247
|
+
(commit, _) = self.pedersen.commit(self.pk, msg)
|
|
248
|
+
|
|
249
|
+
identity = self.group.init(G, 1)
|
|
250
|
+
|
|
251
|
+
self.assertNotEqual(commit, identity,
|
|
252
|
+
"Commitment to random message should not be identity")
|
|
253
|
+
|
|
254
|
+
def test_random_commitment_does_not_verify(self):
|
|
255
|
+
"""
|
|
256
|
+
Test Vector PEDERSEN-SEC-3: Random Commitment Rejection
|
|
257
|
+
|
|
258
|
+
Property: Random group element should not verify as valid commitment.
|
|
259
|
+
"""
|
|
260
|
+
msg = self.group.random(ZR)
|
|
261
|
+
random_commit = self.group.random(G)
|
|
262
|
+
random_decommit = self.group.random(ZR)
|
|
263
|
+
|
|
264
|
+
result = self.pedersen.decommit(self.pk, random_commit, random_decommit, msg)
|
|
265
|
+
|
|
266
|
+
self.assertFalse(result,
|
|
267
|
+
"Random commitment should not verify")
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class TestPedersenMultipleRuns(unittest.TestCase):
|
|
271
|
+
"""
|
|
272
|
+
Statistical tests with multiple commitment operations.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
def setUp(self):
|
|
276
|
+
"""Set up test fixtures."""
|
|
277
|
+
self.group = ECGroup(714)
|
|
278
|
+
self.pedersen = CM_Ped92(self.group)
|
|
279
|
+
self.pk = self.pedersen.setup()
|
|
280
|
+
|
|
281
|
+
def test_multiple_commitments_all_verify(self):
|
|
282
|
+
"""
|
|
283
|
+
Test Vector PEDERSEN-STAT-1: Multiple Commitment Verification
|
|
284
|
+
|
|
285
|
+
Property: All honestly generated commitments must verify.
|
|
286
|
+
"""
|
|
287
|
+
for i in range(100):
|
|
288
|
+
msg = self.group.random(ZR)
|
|
289
|
+
(commit, decommit) = self.pedersen.commit(self.pk, msg)
|
|
290
|
+
result = self.pedersen.decommit(self.pk, commit, decommit, msg)
|
|
291
|
+
|
|
292
|
+
self.assertTrue(result,
|
|
293
|
+
f"Commitment {i+1} must verify (correctness)")
|
|
294
|
+
|
|
295
|
+
def test_all_commitments_unique(self):
|
|
296
|
+
"""
|
|
297
|
+
Test Vector PEDERSEN-STAT-2: Commitment Uniqueness
|
|
298
|
+
|
|
299
|
+
Property: Different (message, randomness) pairs produce unique commitments.
|
|
300
|
+
"""
|
|
301
|
+
commitments = set()
|
|
302
|
+
|
|
303
|
+
for _ in range(100):
|
|
304
|
+
msg = self.group.random(ZR)
|
|
305
|
+
(commit, _) = self.pedersen.commit(self.pk, msg)
|
|
306
|
+
# Convert to string for set comparison
|
|
307
|
+
commit_str = str(commit)
|
|
308
|
+
|
|
309
|
+
self.assertNotIn(commit_str, commitments,
|
|
310
|
+
"All commitments should be unique")
|
|
311
|
+
commitments.add(commit_str)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
if __name__ == '__main__':
|
|
315
|
+
unittest.main()
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Schnorr Zero-Knowledge Proof Test Vectors
|
|
3
|
+
|
|
4
|
+
Test vectors for Schnorr's ZKP protocol based on:
|
|
5
|
+
- Original paper: "Efficient Signature Generation by Smart Cards" (Schnorr, 1991)
|
|
6
|
+
- RFC 8235: Schnorr Non-interactive Zero-Knowledge Proof
|
|
7
|
+
- Fiat-Shamir heuristic for non-interactive proofs
|
|
8
|
+
|
|
9
|
+
These tests verify both interactive and non-interactive Schnorr proofs.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import unittest
|
|
13
|
+
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1
|
|
14
|
+
from charm.zkp_compiler.schnorr_proof import SchnorrProof, Proof
|
|
15
|
+
from charm.core.engine.util import objectToBytes
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestSchnorrMathematicalProperties(unittest.TestCase):
|
|
19
|
+
"""
|
|
20
|
+
Test mathematical properties of Schnorr ZK proofs.
|
|
21
|
+
|
|
22
|
+
These tests verify the fundamental algebraic properties that must hold
|
|
23
|
+
for any correct Schnorr proof implementation.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def setUp(self):
|
|
27
|
+
"""Set up test fixtures with BN254 curve."""
|
|
28
|
+
self.group = PairingGroup('BN254')
|
|
29
|
+
|
|
30
|
+
def test_completeness_interactive(self):
|
|
31
|
+
"""
|
|
32
|
+
Test Vector SCHNORR-1: Completeness (Interactive)
|
|
33
|
+
|
|
34
|
+
Property: Honest prover with valid witness always convinces honest verifier.
|
|
35
|
+
|
|
36
|
+
Source: Schnorr 1991, Definition of ZK proof system
|
|
37
|
+
"""
|
|
38
|
+
# Generate secret and public values
|
|
39
|
+
x = self.group.random(ZR) # Secret
|
|
40
|
+
g = self.group.random(G1) # Generator
|
|
41
|
+
h = g ** x # Public value h = g^x
|
|
42
|
+
|
|
43
|
+
# Interactive protocol
|
|
44
|
+
prover = SchnorrProof.Prover(x, self.group)
|
|
45
|
+
verifier = SchnorrProof.Verifier(self.group)
|
|
46
|
+
|
|
47
|
+
# Step 1: Prover creates commitment
|
|
48
|
+
commitment = prover.create_commitment(g)
|
|
49
|
+
|
|
50
|
+
# Step 2: Verifier creates challenge
|
|
51
|
+
challenge = verifier.create_challenge()
|
|
52
|
+
|
|
53
|
+
# Step 3: Prover creates response
|
|
54
|
+
response = prover.create_response(challenge)
|
|
55
|
+
|
|
56
|
+
# Step 4: Verifier verifies
|
|
57
|
+
result = verifier.verify(g, h, commitment, response)
|
|
58
|
+
|
|
59
|
+
self.assertTrue(result,
|
|
60
|
+
"Completeness: Honest prover must always convince honest verifier")
|
|
61
|
+
|
|
62
|
+
def test_completeness_non_interactive(self):
|
|
63
|
+
"""
|
|
64
|
+
Test Vector SCHNORR-2: Completeness (Non-Interactive)
|
|
65
|
+
|
|
66
|
+
Property: Non-interactive proof with valid witness always verifies.
|
|
67
|
+
|
|
68
|
+
Source: Fiat-Shamir heuristic applied to Schnorr protocol
|
|
69
|
+
"""
|
|
70
|
+
x = self.group.random(ZR)
|
|
71
|
+
g = self.group.random(G1)
|
|
72
|
+
h = g ** x
|
|
73
|
+
|
|
74
|
+
# Generate non-interactive proof
|
|
75
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
76
|
+
|
|
77
|
+
# Verify
|
|
78
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
79
|
+
|
|
80
|
+
self.assertTrue(result,
|
|
81
|
+
"Completeness: Valid non-interactive proof must verify")
|
|
82
|
+
|
|
83
|
+
def test_soundness_wrong_witness(self):
|
|
84
|
+
"""
|
|
85
|
+
Test Vector SCHNORR-3: Soundness (Wrong Witness)
|
|
86
|
+
|
|
87
|
+
Property: Prover with wrong witness cannot convince verifier.
|
|
88
|
+
|
|
89
|
+
Source: Soundness requirement for ZK proofs
|
|
90
|
+
"""
|
|
91
|
+
x_real = self.group.random(ZR)
|
|
92
|
+
x_fake = self.group.random(ZR) # Wrong witness
|
|
93
|
+
g = self.group.random(G1)
|
|
94
|
+
h = g ** x_real # h = g^x_real
|
|
95
|
+
|
|
96
|
+
# Try to prove with wrong witness
|
|
97
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x_fake)
|
|
98
|
+
|
|
99
|
+
# Should fail verification (with overwhelming probability)
|
|
100
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
101
|
+
|
|
102
|
+
self.assertFalse(result,
|
|
103
|
+
"Soundness: Proof with wrong witness must not verify")
|
|
104
|
+
|
|
105
|
+
def test_verification_equation(self):
|
|
106
|
+
"""
|
|
107
|
+
Test Vector SCHNORR-4: Verification Equation
|
|
108
|
+
|
|
109
|
+
Property: g^z = u * h^c where z = r + c*x, u = g^r, h = g^x
|
|
110
|
+
|
|
111
|
+
Source: Schnorr 1991, Protocol specification
|
|
112
|
+
"""
|
|
113
|
+
x = self.group.random(ZR)
|
|
114
|
+
g = self.group.random(G1)
|
|
115
|
+
h = g ** x
|
|
116
|
+
|
|
117
|
+
# Generate proof
|
|
118
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
119
|
+
|
|
120
|
+
# Manually verify the equation: g^z = u * h^c
|
|
121
|
+
lhs = g ** proof.response
|
|
122
|
+
rhs = proof.commitment * (h ** proof.challenge)
|
|
123
|
+
|
|
124
|
+
self.assertEqual(lhs, rhs,
|
|
125
|
+
"Verification equation g^z = u * h^c must hold")
|
|
126
|
+
|
|
127
|
+
def test_challenge_binding(self):
|
|
128
|
+
"""
|
|
129
|
+
Test Vector SCHNORR-5: Challenge Binding (Fiat-Shamir)
|
|
130
|
+
|
|
131
|
+
Property: Challenge is deterministically derived from (g, h, commitment)
|
|
132
|
+
|
|
133
|
+
Source: Fiat-Shamir heuristic security requirement
|
|
134
|
+
"""
|
|
135
|
+
x = self.group.random(ZR)
|
|
136
|
+
g = self.group.random(G1)
|
|
137
|
+
h = g ** x
|
|
138
|
+
|
|
139
|
+
# Generate two proofs
|
|
140
|
+
proof1 = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
141
|
+
proof2 = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
142
|
+
|
|
143
|
+
# Commitments are random, so challenges should differ
|
|
144
|
+
# But if we recompute challenge from same commitment, it should match
|
|
145
|
+
expected_challenge = SchnorrProof._compute_challenge_hash(
|
|
146
|
+
self.group, g, h, proof1.commitment
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
self.assertEqual(proof1.challenge, expected_challenge,
|
|
150
|
+
"Challenge must be deterministically derived from public values")
|
|
151
|
+
|
|
152
|
+
def test_zero_knowledge_simulation(self):
|
|
153
|
+
"""
|
|
154
|
+
Test Vector SCHNORR-6: Zero-Knowledge Property (Simulation)
|
|
155
|
+
|
|
156
|
+
Property: Proofs can be simulated without knowing the witness.
|
|
157
|
+
This demonstrates the zero-knowledge property.
|
|
158
|
+
|
|
159
|
+
Source: Schnorr 1991, Zero-knowledge proof
|
|
160
|
+
|
|
161
|
+
Note: This test verifies that simulated proofs have the same structure
|
|
162
|
+
as real proofs, demonstrating that proofs reveal nothing about x.
|
|
163
|
+
"""
|
|
164
|
+
g = self.group.random(G1)
|
|
165
|
+
x = self.group.random(ZR)
|
|
166
|
+
h = g ** x
|
|
167
|
+
|
|
168
|
+
# Simulate a proof (without knowing x):
|
|
169
|
+
# 1. Choose random z and c
|
|
170
|
+
# 2. Compute u = g^z * h^(-c)
|
|
171
|
+
# This creates a valid-looking proof without knowing x
|
|
172
|
+
|
|
173
|
+
z_sim = self.group.random(ZR)
|
|
174
|
+
c_sim = self.group.random(ZR)
|
|
175
|
+
u_sim = (g ** z_sim) * (h ** (-c_sim))
|
|
176
|
+
|
|
177
|
+
# Verify the simulation satisfies the verification equation
|
|
178
|
+
lhs = g ** z_sim
|
|
179
|
+
rhs = u_sim * (h ** c_sim)
|
|
180
|
+
|
|
181
|
+
self.assertEqual(lhs, rhs,
|
|
182
|
+
"Simulated proof must satisfy verification equation")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class TestSchnorrEdgeCases(unittest.TestCase):
|
|
186
|
+
"""
|
|
187
|
+
Edge case tests for Schnorr proofs.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def setUp(self):
|
|
191
|
+
"""Set up test fixtures."""
|
|
192
|
+
self.group = PairingGroup('BN254')
|
|
193
|
+
|
|
194
|
+
def test_identity_commitment_rejection(self):
|
|
195
|
+
"""
|
|
196
|
+
Test Vector SCHNORR-EDGE-1: Identity Commitment Attack
|
|
197
|
+
|
|
198
|
+
Property: Proof with identity element as commitment should be rejected.
|
|
199
|
+
|
|
200
|
+
Attack: Attacker submits identity as commitment to bypass verification.
|
|
201
|
+
"""
|
|
202
|
+
x = self.group.random(ZR)
|
|
203
|
+
g = self.group.random(G1)
|
|
204
|
+
h = g ** x
|
|
205
|
+
|
|
206
|
+
# Create malicious proof with identity commitment
|
|
207
|
+
identity = self.group.init(G1, 1)
|
|
208
|
+
malicious_proof = Proof(
|
|
209
|
+
commitment=identity,
|
|
210
|
+
challenge=self.group.random(ZR),
|
|
211
|
+
response=self.group.random(ZR)
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Should be rejected
|
|
215
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, malicious_proof)
|
|
216
|
+
|
|
217
|
+
self.assertFalse(result,
|
|
218
|
+
"Proof with identity commitment must be rejected")
|
|
219
|
+
|
|
220
|
+
def test_zero_secret(self):
|
|
221
|
+
"""
|
|
222
|
+
Test Vector SCHNORR-EDGE-2: Zero Secret
|
|
223
|
+
|
|
224
|
+
Property: Proof works correctly when secret x = 0 (h = g^0 = 1).
|
|
225
|
+
"""
|
|
226
|
+
x = self.group.init(ZR, 0) # Zero secret
|
|
227
|
+
g = self.group.random(G1)
|
|
228
|
+
h = g ** x # h = identity
|
|
229
|
+
|
|
230
|
+
# Should still work correctly
|
|
231
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
232
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
233
|
+
|
|
234
|
+
self.assertTrue(result,
|
|
235
|
+
"Proof must work correctly for zero secret")
|
|
236
|
+
|
|
237
|
+
def test_one_secret(self):
|
|
238
|
+
"""
|
|
239
|
+
Test Vector SCHNORR-EDGE-3: Secret = 1
|
|
240
|
+
|
|
241
|
+
Property: Proof works correctly when secret x = 1 (h = g).
|
|
242
|
+
"""
|
|
243
|
+
x = self.group.init(ZR, 1)
|
|
244
|
+
g = self.group.random(G1)
|
|
245
|
+
h = g ** x # h = g
|
|
246
|
+
|
|
247
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
248
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
249
|
+
|
|
250
|
+
self.assertTrue(result,
|
|
251
|
+
"Proof must work correctly for secret = 1")
|
|
252
|
+
|
|
253
|
+
def test_large_secret(self):
|
|
254
|
+
"""
|
|
255
|
+
Test Vector SCHNORR-EDGE-4: Large Secret
|
|
256
|
+
|
|
257
|
+
Property: Proof works correctly for secrets near the group order.
|
|
258
|
+
"""
|
|
259
|
+
# Use a large secret (close to group order)
|
|
260
|
+
g = self.group.random(G1)
|
|
261
|
+
x = self.group.random(ZR) # Random element in ZR (full range)
|
|
262
|
+
h = g ** x
|
|
263
|
+
|
|
264
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
265
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
266
|
+
|
|
267
|
+
self.assertTrue(result,
|
|
268
|
+
"Proof must work correctly for large secrets")
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class TestSchnorrSerialization(unittest.TestCase):
|
|
272
|
+
"""
|
|
273
|
+
Serialization tests for Schnorr proofs.
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
def setUp(self):
|
|
277
|
+
"""Set up test fixtures."""
|
|
278
|
+
self.group = PairingGroup('BN254')
|
|
279
|
+
|
|
280
|
+
def test_serialize_deserialize_roundtrip(self):
|
|
281
|
+
"""
|
|
282
|
+
Test Vector SCHNORR-SER-1: Serialization Roundtrip
|
|
283
|
+
|
|
284
|
+
Property: serialize(deserialize(proof)) == proof
|
|
285
|
+
"""
|
|
286
|
+
x = self.group.random(ZR)
|
|
287
|
+
g = self.group.random(G1)
|
|
288
|
+
h = g ** x
|
|
289
|
+
|
|
290
|
+
# Generate proof
|
|
291
|
+
original_proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
292
|
+
|
|
293
|
+
# Serialize and deserialize
|
|
294
|
+
serialized = SchnorrProof.serialize_proof(original_proof, self.group)
|
|
295
|
+
deserialized_proof = SchnorrProof.deserialize_proof(serialized, self.group)
|
|
296
|
+
|
|
297
|
+
# Verify deserialized proof
|
|
298
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, deserialized_proof)
|
|
299
|
+
|
|
300
|
+
self.assertTrue(result,
|
|
301
|
+
"Deserialized proof must verify correctly")
|
|
302
|
+
|
|
303
|
+
def test_serialized_proof_is_bytes(self):
|
|
304
|
+
"""
|
|
305
|
+
Test Vector SCHNORR-SER-2: Serialization Format
|
|
306
|
+
|
|
307
|
+
Property: Serialized proof is bytes type.
|
|
308
|
+
"""
|
|
309
|
+
x = self.group.random(ZR)
|
|
310
|
+
g = self.group.random(G1)
|
|
311
|
+
h = g ** x
|
|
312
|
+
|
|
313
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
314
|
+
serialized = SchnorrProof.serialize_proof(proof, self.group)
|
|
315
|
+
|
|
316
|
+
self.assertIsInstance(serialized, bytes,
|
|
317
|
+
"Serialized proof must be bytes")
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class TestSchnorrMultipleRuns(unittest.TestCase):
|
|
321
|
+
"""
|
|
322
|
+
Statistical tests running multiple proof generations.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
def setUp(self):
|
|
326
|
+
"""Set up test fixtures."""
|
|
327
|
+
self.group = PairingGroup('BN254')
|
|
328
|
+
|
|
329
|
+
def test_multiple_proofs_all_verify(self):
|
|
330
|
+
"""
|
|
331
|
+
Test Vector SCHNORR-STAT-1: Multiple Proof Verification
|
|
332
|
+
|
|
333
|
+
Property: All honestly generated proofs must verify.
|
|
334
|
+
"""
|
|
335
|
+
x = self.group.random(ZR)
|
|
336
|
+
g = self.group.random(G1)
|
|
337
|
+
h = g ** x
|
|
338
|
+
|
|
339
|
+
# Generate and verify 100 proofs
|
|
340
|
+
for i in range(100):
|
|
341
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
342
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
343
|
+
self.assertTrue(result,
|
|
344
|
+
f"Proof {i+1} must verify (completeness)")
|
|
345
|
+
|
|
346
|
+
def test_different_generators(self):
|
|
347
|
+
"""
|
|
348
|
+
Test Vector SCHNORR-STAT-2: Different Generators
|
|
349
|
+
|
|
350
|
+
Property: Proofs work correctly with different generators.
|
|
351
|
+
"""
|
|
352
|
+
x = self.group.random(ZR)
|
|
353
|
+
|
|
354
|
+
# Test with 10 different generators
|
|
355
|
+
for i in range(10):
|
|
356
|
+
g = self.group.random(G1)
|
|
357
|
+
h = g ** x
|
|
358
|
+
|
|
359
|
+
proof = SchnorrProof.prove_non_interactive(self.group, g, h, x)
|
|
360
|
+
result = SchnorrProof.verify_non_interactive(self.group, g, h, proof)
|
|
361
|
+
|
|
362
|
+
self.assertTrue(result,
|
|
363
|
+
f"Proof with generator {i+1} must verify")
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
if __name__ == '__main__':
|
|
367
|
+
unittest.main()
|
|
368
|
+
|