### Q2.py ### ```python import tkinter as tk from tkinter import ttk import numpy as np from tools import gen_pipeline_2 import constants as C import time import os TILE = 16 # size (px) of the repeating background tile MARGIN = 2 * TILE # border of visible background around the content class CyberApp(tk.Tk): def __init__(self): super().__init__() self.title("Super Intelligent Attack on Hamming PUFs") self.resizable(False, False) self.model = None self._build_layout() if C.VERBOSE: print("Starting model training ...", end="", flush=True) tic = time.perf_counter() self._model_training() if C.VERBOSE: toc = time.perf_counter() print(f"... done in {toc-tic:0.3g} seconds", end="", flush=True) self._set_log("Ready when you are!") def _build_tiled_background(self, width, height): """Fill the canvas with a repeating 16x16 tile of image.png.""" if not os.path.exists("image.png"): return from PIL import Image, ImageTk img = Image.open("image.png").convert("RGBA").resize((TILE, TILE)) self.bg_image = ImageTk.PhotoImage(img) # keep a reference alive for x in range(0, width, TILE): for y in range(0, height, TILE): self.canvas.create_image( x, y, image=self.bg_image, anchor="nw", tags="bg" ) self.canvas.tag_lower("bg") def _build_layout(self): self.configure(bg=C.BG_COLOR) style = ttk.Style(self) style.theme_use("clam") style.configure("App.TFrame", background=C.BG_COLOR) style.configure( "App.TLabel", background=C.BG_COLOR, foreground=C.TXT_COLOR, font=C.FONT ) style.configure( "Resp.TLabel", background=C.TXT_COLOR, foreground=C.BG_COLOR, font=C.FONT, anchor="center", ) style.configure( "App.TEntry", fieldbackground=C.TXT_COLOR, foreground=C.BG_COLOR, insertcolor=C.BG_COLOR, padding=4, ) style.configure( "App.TButton", background=C.LOG_COLOR, foreground=C.TXT_COLOR, font=C.FONT, padding=6, borderwidth=1, focuscolor=C.LOG_COLOR, ) style.map( "App.TButton", background=[("active", "#202020"), ("pressed", "#000000")], foreground=[("active", C.TXT_COLOR)], ) # Canvas holds the tiled background; the content frame sits on top of it self.canvas = tk.Canvas( self, highlightthickness=0, borderwidth=0, bg=C.BG_COLOR ) self.canvas.pack(fill="both", expand=True) frame = ttk.Frame(self.canvas, style="App.TFrame", padding=15) frame.columnconfigure(0, weight=1) frame.columnconfigure(1, weight=1) self.canvas.create_window(MARGIN, MARGIN, window=frame, anchor="nw") self.tag_label = ttk.Label( frame, width=20, text="Challenge →", style="App.TLabel" ) self.tag_label.grid(row=0, column=0, padx=5, pady=8, sticky="w") self.entry = ttk.Entry(frame, width=20, style="App.TEntry", font=C.FONT) self.entry.grid(row=0, column=1, padx=5, pady=8, sticky="ew") self.play_button = ttk.Button( frame, text="Go Predict! →", width=15, style="App.TButton", command=self._on_predict, ) self.play_button.grid(row=1, column=0, padx=5, pady=8, sticky="w") self.response_label = ttk.Label(frame, width=5, text="", style="Resp.TLabel") self.response_label.grid(row=1, column=1, padx=5, pady=8, ipady=4) self.log = tk.Text( frame, width=60, height=1, bg=C.LOG_COLOR, fg=C.TXT_COLOR, font=C.LOG_FONT, wrap="char", state="disabled", relief="flat", padx=6, pady=6, highlightthickness=0, ) self.log.grid(row=2, column=0, columnspan=2, padx=5, pady=(12, 0), sticky="ew") # Size the canvas to the content plus margin, then tile the background self.update_idletasks() width = frame.winfo_reqwidth() + 2 * MARGIN height = frame.winfo_reqheight() + 2 * MARGIN self.canvas.configure(width=width, height=height) self._build_tiled_background(width, height) self.entry.focus_set() def _on_predict(self): text = self.entry.get().strip() self.response_label.config(text="") if any(ch not in "01" for ch in text): self._set_log("Invalid Characters in challenge string") return if len(text) != 20: self._set_log("Challenge must be 20 bits long") return if self.model is None: self._set_log("Model is not trained") return c = np.array([int(ch) for ch in text], dtype=float).reshape((1, -1)) prediction = int(self.model.predict(c)[0]) self.response_label.config(text=str(prediction)) self._set_log(str(prediction)) def _model_training(self): K = 4 prefix = "Q1.2_pub" Z = np.loadtxt(prefix + "_trn.txt") N, D = Z.shape B = D - 1 # Z contains both features and labels X = Z[:, :-1] y = Z[:, -1] self.model = gen_pipeline_2(X, y, K) self.model.fit(X, y) if C.VERBOSE: Z_tst = np.loadtxt(prefix + "_tst.txt") y_hat_test = self.model.predict(Z_tst[:, :-1]) correct_idx = np.where(y_hat_test == Z_tst[:, -1])[0][:5] wrong_idx = np.where(y_hat_test != Z_tst[:, -1])[0][:5] for idx in correct_idx: data = Z_tst[idx, :-1].reshape((1, -1)) label = Z_tst[idx, -1] print( "".join(data.ravel().astype(int).astype(str).tolist()), f"right: pred {self.model.predict(data).astype(int)[0]} vs true {label.astype(int)}", ) for idx in wrong_idx: data = Z_tst[idx, :-1].reshape((1, -1)) label = Z_tst[idx, -1] print( "".join(data.ravel().astype(int).astype(str).tolist()), f"wrong: pred {self.model.predict(data).astype(int)[0]} vs true {label.astype(int)}", ) def _set_log(self, text): self.log.configure(state="normal") self.log.delete("1.0", "end") self.log.insert("1.0", " LOG: " + text) self.log.configure(state="disabled") def main(): app = CyberApp() app.mainloop() if __name__ == "__main__": main() ```