Skip to content

Commit 3c8e311

Browse files
rewrite commitment_game.py with full ZKP simulation, prover-verifier transcript, and educational modal
1 parent dd70c08 commit 3c8e311

File tree

2 files changed

+199
-88
lines changed

2 files changed

+199
-88
lines changed

ZKP_Demo_Tool/commitment_game.py

Lines changed: 197 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,217 @@
11
import sys
22
import hashlib
33
import secrets
4+
import random
5+
import networkx as nx
46
from PyQt5.QtWidgets import (
57
QApplication, QWidget, QVBoxLayout, QPushButton, QLabel, QLineEdit,
6-
QMessageBox, QHBoxLayout, QTextEdit
8+
QMessageBox, QHBoxLayout, QTextEdit, QGraphicsEllipseItem,
9+
QGraphicsTextItem, QColorDialog, QComboBox, QGraphicsScene, QGraphicsView,QDialog, QDialogButtonBox
710
)
8-
from PyQt5.QtGui import QFont
9-
from PyQt5.QtCore import Qt
11+
from PyQt5.QtGui import QFont, QBrush, QColor, QPen
12+
from PyQt5.QtCore import Qt, QRectF
1013

11-
class CommitmentGameWindow(QWidget):
14+
class CommitmentGame(QWidget):
1215
def __init__(self):
1316
super().__init__()
17+
self.setWindowTitle("ZKP Commitment Game - Master Edition")
18+
self.setGeometry(100, 100, 1200, 700)
1419

15-
self.setWindowTitle("🔒 Commitment Game")
16-
self.setFixedSize(500, 500)
17-
self.setStyleSheet("background-color: #2C3E50;")
20+
self.graph = nx.cycle_graph(5)
21+
self.colors = {}
22+
self.commitments = {}
23+
self.nonces = {}
24+
self.revealed = set()
1825

19-
layout = QVBoxLayout()
26+
self.init_ui()
27+
self.draw_graph()
28+
29+
def init_ui(self):
30+
layout = QHBoxLayout()
31+
32+
self.scene = QGraphicsScene()
33+
self.view = QGraphicsView(self.scene)
34+
layout.addWidget(self.view, 70)
35+
36+
control_panel = QVBoxLayout()
37+
38+
self.commit_button = QPushButton("🔒 Commit to Colors")
39+
self.commit_button.clicked.connect(self.commit_colors)
40+
control_panel.addWidget(self.commit_button)
41+
42+
self.challenge_button = QPushButton("🎯 Verifier: Challenge Random Edge")
43+
self.challenge_button.clicked.connect(self.challenge_edge)
44+
control_panel.addWidget(self.challenge_button)
45+
46+
self.cheat_button = QPushButton("😈 Try to Cheat (Change Color)")
47+
self.cheat_button.clicked.connect(self.try_to_cheat)
48+
control_panel.addWidget(self.cheat_button)
2049

21-
title = QLabel("🔐 Commitment Scheme Simulation")
22-
title.setFont(QFont("Arial", 16, QFont.Bold))
23-
title.setStyleSheet("color: white; padding: 10px;")
24-
title.setAlignment(Qt.AlignCenter)
25-
layout.addWidget(title)
26-
27-
role_label = QLabel("🧑‍💻 You are the Prover. The system plays the Verifier.")
28-
role_label.setStyleSheet("color: #ECF0F1; padding: 5px;")
29-
role_label.setAlignment(Qt.AlignCenter)
30-
layout.addWidget(role_label)
31-
32-
self.secret_input = QLineEdit()
33-
self.secret_input.setPlaceholderText("Enter your secret value")
34-
self.secret_input.setFont(QFont("Arial", 12))
35-
self.secret_input.setStyleSheet("padding: 8px;")
36-
layout.addWidget(self.secret_input)
37-
38-
commit_btn = QPushButton("🔒 Commit to Secret")
39-
commit_btn.setFont(QFont("Arial", 12))
40-
commit_btn.setStyleSheet("margin: 10px; padding: 10px;")
41-
commit_btn.clicked.connect(self.generate_commitment)
42-
layout.addWidget(commit_btn)
43-
44-
reveal_btn = QPushButton("🔓 Reveal to Verifier")
45-
reveal_btn.setFont(QFont("Arial", 12))
46-
reveal_btn.setStyleSheet("margin: 10px; padding: 10px;")
47-
reveal_btn.clicked.connect(self.reveal_secret)
48-
layout.addWidget(reveal_btn)
49-
50-
self.commitment_label = QLabel("Commitment: ...")
51-
self.commitment_label.setStyleSheet("color: #ECF0F1; margin: 10px;")
52-
layout.addWidget(self.commitment_label)
53-
54-
self.transcript_box = QTextEdit()
55-
self.transcript_box.setReadOnly(True)
56-
self.transcript_box.setStyleSheet("background-color: #34495E; color: #F1C40F; padding: 10px;")
57-
layout.addWidget(self.transcript_box)
58-
59-
self.result_label = QLabel("")
60-
self.result_label.setStyleSheet("color: #1ABC9C; font-weight: bold; padding: 10px;")
61-
layout.addWidget(self.result_label)
50+
self.education_button = QPushButton("🧠 What’s Happening?")
51+
self.education_button.clicked.connect(self.show_education_modal)
52+
control_panel.addWidget(self.education_button)
6253

54+
self.color_select = QComboBox()
55+
self.color_select.addItems(["Red", "Green", "Blue"])
56+
control_panel.addWidget(QLabel("Choose color for next node click:"))
57+
control_panel.addWidget(self.color_select)
58+
59+
self.status = QLabel("🔐 Set colors by clicking nodes. Then commit.")
60+
self.status.setWordWrap(True)
61+
control_panel.addWidget(self.status)
62+
63+
self.transcript = QTextEdit()
64+
self.transcript.setReadOnly(True)
65+
self.transcript.setFont(QFont("Courier", 10))
66+
control_panel.addWidget(QLabel("📝 ZKP Transcript:"))
67+
control_panel.addWidget(self.transcript)
68+
69+
layout.addLayout(control_panel, 30)
6370
self.setLayout(layout)
6471

65-
self.nonce = None
66-
self.commitment = None
72+
def draw_graph(self):
73+
self.scene.clear()
74+
self.pos = nx.spring_layout(self.graph, seed=42)
75+
self.node_items = {}
76+
77+
for node in self.graph.nodes:
78+
x, y = self.pos[node]
79+
x, y = x * 300 + 300, y * 300 + 200
80+
ellipse = QGraphicsEllipseItem(QRectF(x, y, 40, 40))
81+
ellipse.setBrush(QBrush(Qt.lightGray))
82+
ellipse.setPen(QPen(Qt.black))
83+
ellipse.setFlag(QGraphicsEllipseItem.ItemIsSelectable)
84+
ellipse.mousePressEvent = lambda event, n=node: self.set_node_color(n)
85+
self.scene.addItem(ellipse)
86+
87+
label = QGraphicsTextItem(str(node))
88+
label.setPos(x + 12, y + 10)
89+
self.scene.addItem(label)
90+
91+
self.node_items[node] = (ellipse, label)
92+
93+
for u, v in self.graph.edges:
94+
x1, y1 = self.pos[u]
95+
x2, y2 = self.pos[v]
96+
x1, y1 = x1 * 300 + 320, y1 * 300 + 220
97+
x2, y2 = x2 * 300 + 320, y2 * 300 + 220
98+
self.scene.addLine(x1, y1, x2, y2, QPen(Qt.black))
99+
100+
def set_node_color(self, node):
101+
color = self.color_select.currentText()
102+
self.colors[node] = color
103+
ellipse, _ = self.node_items[node]
104+
ellipse.setBrush(QBrush(QColor(color)))
105+
self.status.setText(f"🎨 Node {node} set to {color} (only you know this)")
106+
self.transcript.append(f"[Prover] Sets node {node} to {color}")
107+
108+
def commit_colors(self):
109+
self.commitments.clear()
110+
self.nonces.clear()
111+
self.revealed.clear()
112+
113+
missing = [n for n in self.graph.nodes if n not in self.colors]
114+
if missing:
115+
self.status.setText(f"⚠️ Color all nodes first! Missing: {missing}")
116+
return
117+
118+
for node, color in self.colors.items():
119+
nonce = secrets.token_hex(8)
120+
self.nonces[node] = nonce
121+
self.commitments[node] = hashlib.sha256((color + nonce).encode()).hexdigest()
122+
ellipse, _ = self.node_items[node]
123+
ellipse.setBrush(QBrush(Qt.darkGray))
124+
self.transcript.append(f"[Prover] Commits to node {node} with hash = {self.commitments[node]}")
125+
126+
self.status.setText("🔒 All node colors committed! Verifier may now challenge an edge.")
67127

68-
def generate_commitment(self):
69-
secret = self.secret_input.text().strip()
70-
if not secret:
71-
QMessageBox.warning(self, "Input Error", "Please enter a secret value.")
128+
def challenge_edge(self):
129+
edge = random.choice(list(self.graph.edges))
130+
u, v = edge
131+
132+
if u in self.revealed or v in self.revealed:
133+
self.status.setText("⏭️ This edge was already revealed. Try again.")
72134
return
73135

74-
self.nonce = secrets.token_hex(8)
75-
combined = secret + self.nonce
76-
self.commitment = hashlib.sha256(combined.encode()).hexdigest()
77-
78-
self.commitment_label.setText(f"Commitment: {self.commitment}")
79-
self.transcript_box.clear()
80-
self.transcript_box.append("Prover commits to a secret using SHA-256(secret || nonce)")
81-
self.transcript_box.append(f"nonce: {self.nonce}")
82-
self.transcript_box.append("Commitment sent to Verifier")
83-
self.result_label.setText("✅ Secret committed. You may now reveal.")
84-
self.result_label.setStyleSheet("color: #1ABC9C; font-weight: bold; padding: 10px;")
85-
86-
def reveal_secret(self):
87-
if not self.commitment:
88-
QMessageBox.warning(self, "No Commitment", "Please commit to a value first.")
136+
self.revealed.update([u, v])
137+
result = self.reveal_and_verify(u, v)
138+
self.status.setText(result)
139+
140+
def reveal_and_verify(self, u, v):
141+
color_u, color_v = self.colors[u], self.colors[v]
142+
nonce_u, nonce_v = self.nonces[u], self.nonces[v]
143+
144+
commit_u = hashlib.sha256((color_u + nonce_u).encode()).hexdigest()
145+
commit_v = hashlib.sha256((color_v + nonce_v).encode()).hexdigest()
146+
147+
self.transcript.append(f"\n[Verifier] Challenges edge ({u}, {v})")
148+
self.transcript.append(f"→ Prover reveals: node {u} = {color_u}, nonce = {nonce_u}")
149+
self.transcript.append(f"→ Prover reveals: node {v} = {color_v}, nonce = {nonce_v}")
150+
self.transcript.append(f"→ Verifier recomputes H({color_u}||{nonce_u}) = {commit_u}")
151+
self.transcript.append(f"→ Verifier recomputes H({color_v}||{nonce_v}) = {commit_v}")
152+
153+
if commit_u != self.commitments[u] or commit_v != self.commitments[v]:
154+
self.transcript.append("❌ Commitment mismatch! Binding property violated!")
155+
return "🚨 Verification Failed! Commitment mismatch (binding broken)"
156+
157+
if color_u == color_v:
158+
self.transcript.append("❌ Same color for both nodes! Invalid coloring.")
159+
return "❌ Verification Failed! Adjacent nodes have same color."
160+
161+
ellipse_u, _ = self.node_items[u]
162+
ellipse_v, _ = self.node_items[v]
163+
ellipse_u.setBrush(QBrush(QColor(color_u)))
164+
ellipse_v.setBrush(QBrush(QColor(color_v)))
165+
166+
self.transcript.append("✅ Commitment verified. Coloring valid for edge.")
167+
return f"✅ Edge ({u}, {v}) verified! {color_u}{color_v}"
168+
169+
def try_to_cheat(self):
170+
if not self.commitments:
171+
self.status.setText("⚠️ Commit first before cheating.")
89172
return
90173

91-
secret = self.secret_input.text().strip()
92-
combined = secret + self.nonce
93-
check = hashlib.sha256(combined.encode()).hexdigest()
94-
95-
self.transcript_box.append("\nProver reveals the secret and nonce...")
96-
self.transcript_box.append(f"secret: {secret}")
97-
self.transcript_box.append(f"recomputed hash: {check}")
98-
99-
if check == self.commitment:
100-
self.result_label.setStyleSheet("color: #1ABC9C; font-weight: bold; padding: 10px;")
101-
self.result_label.setText("✅ Reveal successful. Verifier is convinced.")
102-
self.transcript_box.append("Verifier confirms: ✅ commitment is valid!")
103-
else:
104-
self.result_label.setStyleSheet("color: red; font-weight: bold; padding: 10px;")
105-
self.result_label.setText("❌ Reveal failed. Commitment mismatch.")
106-
self.transcript_box.append("Verifier says: ❌ mismatch in commitment!")
174+
node = random.choice(list(self.graph.nodes))
175+
new_color = random.choice([c for c in ["Red", "Green", "Blue"] if c != self.colors[node]])
176+
self.colors[node] = new_color
177+
178+
self.status.setText(f"😈 Prover changed color of node {node} to {new_color} post-commit. Now try verifying it!")
179+
self.transcript.append(f"🚨 [Prover] Illegally changed color of node {node} to {new_color} after committing!")
180+
181+
def show_education_modal(self):
182+
modal = QDialog(self)
183+
modal.setWindowTitle("🔍 Understanding Commitment Schemes")
184+
layout = QVBoxLayout()
185+
186+
explanation = QLabel("""
187+
🔐 Commitment Schemes
188+
--------------------------
189+
✔️ Hiding: The verifier cannot know the secret until you reveal it.
190+
✔️ Binding: You cannot change your mind after committing.
191+
192+
Example:
193+
- You commit to a color by hashing it with a random nonce.
194+
- You lock that value and show the lock to the verifier.
195+
- Later, you reveal the color + nonce.
196+
- Verifier checks if the lock matches the key.
197+
198+
🚫 Hash Collisions: Very unlikely two different messages give same hash.
199+
200+
That's why commitment = secrecy + honesty.
201+
""")
202+
explanation.setWordWrap(True)
203+
layout.addWidget(explanation)
204+
205+
button_box = QDialogButtonBox(QDialogButtonBox.Ok)
206+
button_box.accepted.connect(modal.accept)
207+
layout.addWidget(button_box)
208+
209+
modal.setLayout(layout)
210+
modal.exec_()
211+
212+
213+
if __name__ == "__main__":
214+
app = QApplication(sys.argv)
215+
window = CommitmentGame()
216+
window.show()
217+
sys.exit(app.exec_())

ZKP_Demo_Tool/zkp_gui_launcher.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
)
55
from PyQt5.QtGui import QFont, QPalette, QColor
66
from PyQt5.QtCore import Qt
7-
from commitment_game import CommitmentGameWindow
7+
from commitment_game import CommitmentGame
88
class ZKPGUILauncher(QWidget):
99
def __init__(self):
1010
super().__init__()
@@ -52,7 +52,7 @@ def __init__(self):
5252
self.setLayout(layout)
5353

5454
def commitment_game(self):
55-
self.commit_window = CommitmentGameWindow()
55+
self.commit_window = CommitmentGame()
5656
self.commit_window.show()
5757
def zkp_game(self):
5858
QMessageBox.information(self, "Coming Soon", "\ud83d\udc65 Prover-Verifier ZKP Game will launch here!")

0 commit comments

Comments
 (0)