dryymatt commited on
Commit
ead509f
·
verified ·
1 Parent(s): 866c197

Upload phantom_shard/zkp/verifier.py

Browse files
Files changed (1) hide show
  1. phantom_shard/zkp/verifier.py +181 -0
phantom_shard/zkp/verifier.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Phantom Shard Protocol — Zero-Knowledge Proof Verification
3
+ ===========================================================
4
+ Verify computation integrity without revealing shard logic. Uses Merkle-tree-based
5
+ verification (lightweight, Python-native) with hash-chain proofs.
6
+
7
+ Architecture:
8
+ - Merkle Tree commitments for shard computation traces
9
+ - Hash-chain proofs for recursive verification
10
+ - ZKP pattern: "Computation C, on input X, produces output Y" — verified without
11
+ revealing C or X.
12
+ """
13
+
14
+ import hashlib
15
+ import json
16
+ import struct
17
+ from dataclasses import dataclass
18
+ from typing import Optional
19
+
20
+
21
+ @dataclass
22
+ class ZKPProof:
23
+ """A zero-knowledge proof bundle for shard computation verification."""
24
+ proof_id: str
25
+ computation_hash: str # Hash of the computation being proven
26
+ output_commitment: str # Merkle root of output
27
+ witness_hash: str # Hash of the witness (kept secret)
28
+ proof_chain: list[str] # Hash chain for verification
29
+ public_signals: dict # Public information visible to verifier
30
+
31
+ def verify(self, expected_output_hash: str) -> bool:
32
+ """Verify the proof without knowing the computation logic."""
33
+ # Reconstruct the proof chain
34
+ chain_valid = True
35
+ for i in range(1, len(self.proof_chain)):
36
+ if self.proof_chain[i] != self._hash_pair(
37
+ self.proof_chain[i-1], self.proof_chain[i-1]
38
+ ):
39
+ chain_valid = False
40
+ break
41
+
42
+ # Verify output commitment matches
43
+ output_match = self.output_commitment == expected_output_hash
44
+
45
+ # Verify the computation hash links to the proof chain root
46
+ chain_root = self.proof_chain[-1] if self.proof_chain else ""
47
+ root_valid = hashlib.sha256(
48
+ (self.computation_hash + chain_root).encode()
49
+ ).hexdigest()[:16] == self.witness_hash[:16]
50
+
51
+ return chain_valid and output_match and root_valid
52
+
53
+ @staticmethod
54
+ def _hash_pair(a: str, b: str) -> str:
55
+ return hashlib.sha256((a + b).encode()).hexdigest()
56
+
57
+
58
+ class MerkleTree:
59
+ """Merkle Tree for committing to shard computation traces."""
60
+
61
+ def __init__(self, leaves: list[bytes]):
62
+ self.leaves = [hashlib.sha256(leaf).digest() for leaf in leaves]
63
+ self._tree: list[list[bytes]] = []
64
+ self._build()
65
+
66
+ def _build(self):
67
+ """Build Merkle tree from leaves."""
68
+ self._tree = [self.leaves]
69
+ current = self.leaves
70
+
71
+ while len(current) > 1:
72
+ next_level = []
73
+ for i in range(0, len(current), 2):
74
+ if i + 1 < len(current):
75
+ combined = hashlib.sha256(current[i] + current[i+1]).digest()
76
+ else:
77
+ combined = current[i] # Odd node promoted
78
+ next_level.append(combined)
79
+ self._tree.append(next_level)
80
+ current = next_level
81
+
82
+ @property
83
+ def root(self) -> bytes:
84
+ """Merkle root — the commitment to all leaves."""
85
+ return self._tree[-1][0] if self._tree else b""
86
+
87
+ @property
88
+ def root_hex(self) -> str:
89
+ return self.root.hex()
90
+
91
+ def get_proof(self, leaf_index: int) -> list[tuple[bytes, bool]]:
92
+ """Generate Merkle inclusion proof for a leaf."""
93
+ proof = []
94
+ idx = leaf_index
95
+ for level in self._tree[:-1]:
96
+ if idx % 2 == 0 and idx + 1 < len(level):
97
+ proof.append((level[idx + 1], True)) # Right sibling
98
+ elif idx % 2 == 1:
99
+ proof.append((level[idx - 1], False)) # Left sibling
100
+ else:
101
+ proof.append((level[idx], False)) # Self (odd node)
102
+ idx //= 2
103
+ return proof
104
+
105
+ @staticmethod
106
+ def verify_proof(root: bytes, leaf: bytes, proof: list[tuple[bytes, bool]]) -> bool:
107
+ """Verify a Merkle inclusion proof."""
108
+ current = hashlib.sha256(leaf).digest()
109
+ for sibling, is_right in proof:
110
+ if is_right:
111
+ current = hashlib.sha256(current + sibling).digest()
112
+ else:
113
+ current = hashlib.sha256(sibling + current).digest()
114
+ return current == root
115
+
116
+
117
+ class ShardZKP:
118
+ """Zero-Knowledge Proof generator and verifier for Phantom Shards."""
119
+
120
+ PROOF_VERSION = "phantom-zkp-v1"
121
+
122
+ @staticmethod
123
+ def prove_computation(
124
+ computation_id: str,
125
+ computation_logic_hash: str,
126
+ input_hash: str,
127
+ output_hash: str,
128
+ witness_data: bytes,
129
+ depth: int = 8,
130
+ ) -> ZKPProof:
131
+ """Generate a ZKP that proves computation was executed correctly
132
+ without revealing the computation logic or witness."""
133
+
134
+ # Build proof chain (recursive hashing)
135
+ proof_chain = []
136
+ current = hashlib.sha256(
137
+ f"{computation_logic_hash}:{input_hash}:{ShardZKP.PROOF_VERSION}".encode()
138
+ ).hexdigest()
139
+ proof_chain.append(current)
140
+
141
+ for i in range(depth):
142
+ current = hashlib.sha256(
143
+ (current + witness_data[i % len(witness_data):(i+1) % len(witness_data) or 1].hex()).encode()
144
+ ).hexdigest()
145
+ proof_chain.append(current)
146
+
147
+ # Witness hash (never revealed directly)
148
+ witness_hash = hashlib.sha256(witness_data).hexdigest()
149
+
150
+ return ZKPProof(
151
+ proof_id=hashlib.sha256(f"{computation_id}:{witness_hash}".encode()).hexdigest()[:16],
152
+ computation_hash=computation_logic_hash,
153
+ output_commitment=output_hash,
154
+ witness_hash=witness_hash,
155
+ proof_chain=proof_chain,
156
+ public_signals={
157
+ "version": ShardZKP.PROOF_VERSION,
158
+ "computation_id": computation_id,
159
+ "input_hash": input_hash,
160
+ "depth": depth,
161
+ "timestamp": str(__import__("time").time()),
162
+ },
163
+ )
164
+
165
+ @staticmethod
166
+ def verify_shard(proof: ZKPProof, expected_output: bytes) -> bool:
167
+ """Verify a shard's ZKP without knowing the computation logic."""
168
+ expected_hash = hashlib.sha256(expected_output).hexdigest()
169
+ return proof.verify(expected_hash)
170
+
171
+ @staticmethod
172
+ def batch_verify(proofs: list[ZKPProof], expected_outputs: list[bytes]) -> dict:
173
+ """Batch verify multiple shard proofs."""
174
+ results = {}
175
+ for i, (proof, expected) in enumerate(zip(proofs, expected_outputs)):
176
+ valid = ShardZKP.verify_shard(proof, expected)
177
+ results[proof.proof_id] = {
178
+ "valid": valid,
179
+ "computation_hash": proof.computation_hash,
180
+ }
181
+ return results