Skip to content

Commit cb0f687

Browse files
Simulate zkp through bipartate graph
1 parent 63f8e5e commit cb0f687

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import sys
2+
import hashlib
3+
import random
4+
from PyQt5.QtWidgets import (
5+
QApplication, QWidget, QVBoxLayout, QPushButton, QLabel, QGraphicsScene,
6+
QGraphicsView, QGraphicsEllipseItem, QGraphicsTextItem, QGraphicsLineItem,
7+
QHBoxLayout, QTextEdit
8+
)
9+
from PyQt5.QtGui import QPen, QBrush, QColor, QFont
10+
from PyQt5.QtCore import Qt, QPointF
11+
12+
class Node(QGraphicsEllipseItem):
13+
def __init__(self, name, pos, color, node_type, description=""):
14+
super().__init__(-30, -30, 60, 60)
15+
self.setBrush(QBrush(color))
16+
self.setPen(QPen(Qt.white, 2))
17+
self.setPos(pos)
18+
self.name = name
19+
self.node_type = node_type
20+
self.description = description
21+
22+
self.label = QGraphicsTextItem(name)
23+
self.label.setDefaultTextColor(Qt.white)
24+
self.label.setFont(QFont("Arial", 8))
25+
self.label.setParentItem(self)
26+
self.label.setPos(-30, 40)
27+
28+
class Edge:
29+
def __init__(self, scene, node1, node2):
30+
self.line = QGraphicsLineItem(node1.x(), node1.y(), node2.x(), node2.y())
31+
self.line.setPen(QPen(Qt.gray, 2, Qt.SolidLine))
32+
scene.addItem(self.line)
33+
self.nodes = (node1, node2)
34+
35+
class ZKPVerifierExplained(QWidget):
36+
def __init__(self):
37+
super().__init__()
38+
self.setWindowTitle("🔐 ZKP Simulation with Verifier Explanation")
39+
self.setGeometry(100, 100, 1300, 850)
40+
self.setStyleSheet("background-color: #1e1e1e; color: white;")
41+
42+
self.layout = QVBoxLayout()
43+
self.setLayout(self.layout)
44+
45+
self.scene = QGraphicsScene()
46+
self.view = QGraphicsView(self.scene)
47+
self.layout.addWidget(self.view)
48+
49+
self.statement_label = QLabel("🎓 Knowledge Statement: 'I know (u, v) ∈ G such that employee u has access to account v.'")
50+
self.statement_label.setStyleSheet("padding: 8px; font-size: 16px;")
51+
self.layout.addWidget(self.statement_label)
52+
53+
self.protocol_log = QTextEdit()
54+
self.protocol_log.setReadOnly(True)
55+
self.protocol_log.setStyleSheet("background-color: #111; color: #ddd; font-family: monospace;")
56+
self.layout.addWidget(self.protocol_log)
57+
58+
self.button_layout = QHBoxLayout()
59+
self.commit_button = QPushButton("🔐 Step 1: Commit to Secret Edge")
60+
self.challenge_account_btn = QPushButton("Step 2: Reveal Account")
61+
self.challenge_employee_btn = QPushButton("Step 2: Reveal Employee")
62+
self.challenge_account_btn.setEnabled(False)
63+
self.challenge_employee_btn.setEnabled(False)
64+
self.button_layout.addWidget(self.commit_button)
65+
self.button_layout.addWidget(self.challenge_account_btn)
66+
self.button_layout.addWidget(self.challenge_employee_btn)
67+
self.layout.addLayout(self.button_layout)
68+
69+
self.commit_button.clicked.connect(self.commit_phase)
70+
self.challenge_account_btn.clicked.connect(lambda: self.reveal("account"))
71+
self.challenge_employee_btn.clicked.connect(lambda: self.reveal("employee"))
72+
73+
self.accounts = []
74+
self.employees = []
75+
self.edges = []
76+
self.secret_edge = None
77+
self.nonce = None
78+
self.commitment = None
79+
80+
self.build_graph()
81+
82+
def build_graph(self):
83+
account_data = [
84+
("Vault#011", "$800K"),
85+
("Account#992", "Suspicious Flow"),
86+
("Loan#743", "Offshore Link")
87+
]
88+
89+
emp_data = [
90+
("Alice", "Teller - Branch A"),
91+
("Bob", "Manager - HQ"),
92+
("Claire", "Auditor - Internal Affairs")
93+
]
94+
95+
for i, (name, desc) in enumerate(account_data):
96+
node = Node(name, QPointF(200, 100 + i * 200), QColor("gold"), "account", desc)
97+
self.accounts.append(node)
98+
self.scene.addItem(node)
99+
100+
for i, (name, desc) in enumerate(emp_data):
101+
node = Node(name, QPointF(1000, 100 + i * 200), QColor("skyblue"), "employee", desc)
102+
self.employees.append(node)
103+
self.scene.addItem(node)
104+
105+
access_list = [
106+
(0, 0),
107+
(1, 1),
108+
(2, 2),
109+
(0, 1)
110+
]
111+
112+
for a_idx, e_idx in access_list:
113+
self.edges.append(Edge(self.scene, self.accounts[a_idx], self.employees[e_idx]))
114+
115+
def commit_phase(self):
116+
self.secret_edge = random.choice(self.edges)
117+
u, v = self.secret_edge.nodes
118+
self.nonce = str(random.randint(100000, 999999))
119+
combined = u.name + v.name + self.nonce
120+
self.commitment = hashlib.sha256(combined.encode()).hexdigest()
121+
122+
self.protocol_log.clear()
123+
self.protocol_log.append("🔐 [Commit Phase]")
124+
self.protocol_log.append(f"Secret Edge: {u.name}{v.name} (kept hidden)")
125+
self.protocol_log.append(f"Nonce (random salt): {self.nonce}")
126+
self.protocol_log.append(f"Commitment = SHA256({u.name} + {v.name} + nonce)")
127+
self.protocol_log.append(f"→ {self.commitment}\n")
128+
129+
self.challenge_account_btn.setEnabled(True)
130+
self.challenge_employee_btn.setEnabled(True)
131+
132+
def reveal(self, challenge_type):
133+
u, v = self.secret_edge.nodes
134+
self.protocol_log.append(f" [Challenge Phase] Verifier asks to reveal: {challenge_type.upper()}")
135+
136+
if challenge_type == "account":
137+
revealed = u.name
138+
self.protocol_log.append(f"Prover reveals: {revealed} + nonce")
139+
self.protocol_log.append("\nVerifier tries every employee to match the hash:")
140+
for emp in self.employees:
141+
trial = hashlib.sha256((u.name + emp.name + self.nonce).encode()).hexdigest()
142+
match = "✅ MATCH" if trial == self.commitment else "❌"
143+
self.protocol_log.append(f" • H({u.name} + {emp.name} + {self.nonce}) → {trial[:20]}... {match}")
144+
else:
145+
revealed = v.name
146+
self.protocol_log.append(f"Prover reveals: {revealed} + nonce")
147+
self.protocol_log.append("\nVerifier tries every account to match the hash:")
148+
for acc in self.accounts:
149+
trial = hashlib.sha256((acc.name + v.name + self.nonce).encode()).hexdigest()
150+
match = "✅ MATCH" if trial == self.commitment else "❌"
151+
self.protocol_log.append(f" • H({acc.name} + {v.name} + {self.nonce}) → {trial[:20]}... {match}")
152+
153+
self.protocol_log.append("\n🛡️ If any match → verifier is convinced.")
154+
self.challenge_account_btn.setEnabled(False)
155+
self.challenge_employee_btn.setEnabled(False)
156+
157+
if __name__ == "__main__":
158+
app = QApplication(sys.argv)
159+
window = ZKPVerifierExplained()
160+
window.show()
161+
sys.exit(app.exec_())

0 commit comments

Comments
 (0)