11import sys
22import hashlib
33import secrets
4+ import random
5+ import networkx as nx
46from 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 ("\n Prover 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_ ())
0 commit comments