Skip to content

Commit 1556f16

Browse files
testing commit
1 parent 8ded9fd commit 1556f16

File tree

3 files changed

+100
-43
lines changed

3 files changed

+100
-43
lines changed

ZKP_Demo_Tool/levels/base_level.py

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,53 @@
1-
21
import random
32
import hashlib
43
from PyQt5.QtWidgets import (
54
QWidget, QVBoxLayout, QLabel, QPushButton, QGraphicsScene, QGraphicsView,
6-
QHBoxLayout, QMessageBox
5+
QHBoxLayout, QMessageBox, QComboBox, QTableWidget, QTableWidgetItem, QTextEdit
76
)
8-
from PyQt5.QtGui import QFont, QBrush, QColor, QPen
7+
from PyQt5.QtGui import QFont, QBrush, QColor, QPen, QTextCursor
98
from PyQt5.QtCore import Qt, QPointF, QTimer
109

1110
from ui.node_item import NodeItem
1211

13-
1412
class BaseLevel(QWidget):
15-
def __init__(self, level_name, parent_selector, max_rounds=3):
13+
def __init__(self, level_name, parent_selector, max_rounds=3, auto_mode=False, auto_rounds=5):
1614
super().__init__()
1715
self.level_name = level_name
1816
self.parent_selector = parent_selector
1917
self.max_rounds = max_rounds
18+
self.auto_mode = auto_mode
19+
self.auto_rounds = auto_rounds
2020
self.rounds = 0
2121
self.committed = False
2222

23+
self.valid_proofs = 0
24+
self.invalid_proofs = 0
25+
self.demo_phase = True
26+
self.auto_total_rounds = auto_rounds * 2
27+
2328
self.node_colors = {}
2429
self.commitments = {}
2530
self.nonces = {}
2631
self.nodes = {}
2732
self.edges = []
2833

2934
self.setWindowTitle(f"{level_name} - ZKP Game")
30-
self.setGeometry(100, 100, 900, 650)
35+
self.setGeometry(100, 100, 900, 700)
3136
self.layout = QVBoxLayout()
3237
self.setLayout(self.layout)
3338

34-
self.narration = QLabel(f"👩\u200d💼 Prover: Color nodes secretly to convince the Verifier!")
35-
self.narration.setFont(QFont("Arial", 12))
39+
self.narration = QLabel(f"👩‍💼 Prover: Color nodes secretly to convince the Verifier!")
40+
self.narration.setFont(QFont("Arial", 14, QFont.Bold))
41+
self.narration.setStyleSheet("color: white;")
3642
self.layout.addWidget(self.narration)
3743

44+
self.log_box = QTextEdit()
45+
self.log_box.setReadOnly(True)
46+
self.log_box.setStyleSheet("background-color: #1c1c1c; color: white; font-weight: bold; font-size: 13px;")
47+
self.log_box.setFont(QFont("Consolas", 12))
48+
self.log_box.setFixedHeight(150)
49+
self.layout.addWidget(self.log_box)
50+
3851
self.scene = QGraphicsScene()
3952
self.view = QGraphicsView(self.scene)
4053
self.layout.addWidget(self.view)
@@ -53,19 +66,14 @@ def __init__(self, level_name, parent_selector, max_rounds=3):
5366
self.layout.addLayout(self.buttons_layout)
5467

5568
self.show_education_modal()
56-
57-
def show_education_modal(self):
58-
QMessageBox.information(
59-
self,
60-
"🔐 About Zero-Knowledge Rounds",
61-
"Each round simulates one ZKP exchange.\n\n"
62-
"You can only commit once per round, and reveal one edge.\n"
63-
"The verifier learns nothing beyond this — try not to leak!\n\n"
64-
"You’ll repeat this 3 times to earn trust."
65-
)
66-
69+
if self.auto_mode:
70+
QTimer.singleShot(1000, self.auto_run_verification)
6771
def update_narration(self, text):
6872
self.narration.setText(text)
73+
def log(self, message):
74+
self.log_box.append(f"➡️ {message}")
75+
self.log_box.moveCursor(QTextCursor.End)
76+
6977

7078
def create_graph(self, node_positions, edge_list):
7179
for i, pos in enumerate(node_positions):
@@ -81,7 +89,20 @@ def create_graph(self, node_positions, edge_list):
8189

8290
self.view.setScene(self.scene)
8391

84-
def commit_colors(self):
92+
def randomly_color_nodes(self, allow_collision=False):
93+
palette = ["#e74c3c", "#2ecc71", "#f1c40f", "#3498db"]
94+
self.node_colors.clear()
95+
used = {}
96+
for node_id, node in self.nodes.items():
97+
if not allow_collision:
98+
color = palette[node_id % len(palette)]
99+
else:
100+
color = random.choice(palette)
101+
self.node_colors[node_id] = color
102+
node.setBrush(QBrush(QColor(color)))
103+
self.log(f"Node {node_id} colored {color}")
104+
105+
def commit_colors(self, auto_trigger=False):
85106
missing = [nid for nid in self.nodes if nid not in self.node_colors]
86107
if missing:
87108
self.update_narration(f"⚠️ Please color all nodes: Missing {missing}")
@@ -97,13 +118,16 @@ def commit_colors(self):
97118
self.nonces[node_id] = nonce
98119
self.nodes[node_id].locked = True
99120
self.nodes[node_id].setBrush(QBrush(Qt.gray))
121+
self.log(f"Node {node_id} locked with hidden commitment")
100122

101123
self.committed = True
102-
self.update_narration("🔒 Commitments made. Verifier, choose an edge to challenge!")
124+
if not auto_trigger:
125+
self.update_narration("🔒 Commitments made. Verifier, choose an edge to challenge!")
103126

104-
def challenge_edge_once(self):
127+
def challenge_edge_once(self, auto=False):
105128
if not self.committed:
106-
QMessageBox.warning(self, "⚠️ Commit First", "You must commit before challenging.")
129+
if not auto:
130+
QMessageBox.warning(self, "⚠️ Commit First", "You must commit before challenging.")
107131
return
108132

109133
edge = random.choice(self.edges)
@@ -113,22 +137,53 @@ def challenge_edge_once(self):
113137

114138
self.nodes[node1].setBrush(QBrush(QColor(color1)))
115139
self.nodes[node2].setBrush(QBrush(QColor(color2)))
140+
self.log(f"Verifier opens edge {edge}: Node {node1} = {color1}, Node {node2} = {color2}")
116141

117142
if color1 == color2:
143+
self.invalid_proofs += 1
118144
result = f"❌ Verifier: Edge {edge} has same colors. Proof fails!"
119145
self.update_narration(result)
120-
QTimer.singleShot(1500, self.reject_proof)
121-
return
122146
else:
147+
self.valid_proofs += 1
123148
result = f"✅ Verifier: Edge {edge} looks good."
124-
self.rounds += 1
149+
self.rounds += 1
125150

126-
self.update_narration(result + f" Round {self.rounds}/{self.max_rounds}")
151+
self.update_narration(result + f" Round {self.rounds}/{self.auto_total_rounds}")
127152

128-
if self.rounds < self.max_rounds:
129-
QTimer.singleShot(1500, self.prompt_next_round)
130-
else:
131-
QTimer.singleShot(1500, self.finish_level)
153+
if not self.auto_mode:
154+
if self.rounds < self.max_rounds:
155+
QTimer.singleShot(1500, self.prompt_next_round)
156+
else:
157+
QTimer.singleShot(1500, self.finish_level)
158+
159+
def auto_run_verification(self):
160+
if self.rounds >= self.auto_total_rounds:
161+
QTimer.singleShot(1000, self.show_final_report)
162+
return
163+
164+
allow_collision = False if self.rounds < self.auto_rounds else True
165+
self.randomly_color_nodes(allow_collision=allow_collision)
166+
self.update_narration(f"🎨 Round {self.rounds + 1}: Auto-coloring graph...")
167+
QTimer.singleShot(1000, self.auto_commit_step)
168+
169+
def auto_commit_step(self):
170+
self.commit_colors(auto_trigger=True)
171+
QTimer.singleShot(1000, self.auto_challenge_step)
172+
173+
def auto_challenge_step(self):
174+
self.challenge_edge_once(auto=True)
175+
QTimer.singleShot(1500, self.auto_run_verification)
176+
177+
def show_final_report(self):
178+
total = self.valid_proofs + self.invalid_proofs
179+
success_rate = (self.valid_proofs / total) * 100 if total > 0 else 0
180+
181+
msg = QMessageBox()
182+
msg.setWindowTitle("📊 Simulation Summary")
183+
msg.setText(f"✅ Valid Proofs: {self.valid_proofs}\n❌ Invalid Proofs: {self.invalid_proofs}\n\n"
184+
f"🎯 Success Probability: {success_rate:.2f}%")
185+
msg.exec_()
186+
self.finish_level()
132187

133188
def prompt_next_round(self):
134189
QMessageBox.information(
@@ -139,10 +194,10 @@ def prompt_next_round(self):
139194
self.reset_game(preserve_round=True)
140195

141196
def finish_level(self):
142-
QMessageBox.information(self, "🎉 Success", "Verifier: I’m convinced! You passed all rounds.")
143197
self.parent_selector.update_trust_points(points_earned=3)
144198
self.close()
145199
self.parent_selector.show()
200+
146201
def reject_proof(self):
147202
QMessageBox.critical(self, "❌ Proof Rejected", "Verifier: The proof failed. I cannot be convinced.")
148203
self.close()
@@ -160,6 +215,9 @@ def reset_game(self, preserve_round=False):
160215

161216
if not preserve_round:
162217
self.rounds = 0
218+
self.valid_proofs = 0
219+
self.invalid_proofs = 0
163220
self.update_narration("🔁 Game reset. Recolor and start again!")
221+
self.log_box.clear()
164222
else:
165-
self.update_narration("🎨 Prover: Please recolor the graph for the next round.")
223+
self.update_narration("🎨 Prover: Please recolor the graph for the next round.")

ZKP_Demo_Tool/levels/level1_triangle.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55

66
class Level1Triangle(BaseLevel):
7-
def __init__(self, parent_selector):
8-
super().__init__("Level 1: Triangle", parent_selector)
7+
def __init__(self, parent_selector, auto_mode=False, auto_rounds=3):
8+
super().__init__("Level 1: Triangle", parent_selector, auto_mode=auto_mode, auto_rounds=auto_rounds)
9+
910

1011
# Define triangle layout
1112
positions = [

ZKP_Demo_Tool/levels/level2_ring.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
from levels.base_level import BaseLevel
33

44
class Level2Ring(BaseLevel):
5-
def __init__(self, parent_selector):
6-
super().__init__("Level 2: Encrypted Fraud Network", parent_selector)
7-
8-
# Realistic scenario narration
9-
self.update_narration(
10-
"🕵️ Prover: These 8 nodes represent accounts in a suspected fraud ring.\n"
11-
"Each edge is a known interaction. Prove that directly connected accounts\n"
12-
"don’t share the same fraud classification — without revealing any labels."
5+
def __init__(self, parent_selector, auto_mode=False, auto_rounds=5):
6+
super().__init__(
7+
"Level 2: Encrypted Fraud Network",
8+
parent_selector,
9+
auto_mode=auto_mode,
10+
auto_rounds=auto_rounds
1311
)
1412

1513
# Node layout (visually inspired by screenshot)

0 commit comments

Comments
 (0)