File size: 5,131 Bytes
dc1f241
 
 
 
82637d0
8c4f5b5
dc1f241
82637d0
 
 
dc1f241
8c4f5b5
82637d0
 
 
 
 
47a91d8
 
 
 
82637d0
a817f98
82637d0
47a91d8
a817f98
82637d0
a817f98
 
82637d0
 
 
 
 
8c4f5b5
47a91d8
a817f98
 
 
 
 
dc1f241
47a91d8
82637d0
dc1f241
 
 
 
 
82637d0
47a91d8
 
 
 
 
 
 
82637d0
8c4f5b5
 
 
 
 
82637d0
8c4f5b5
 
 
90f44f8
8c4f5b5
82637d0
8c4f5b5
82637d0
8c4f5b5
 
 
 
 
 
 
 
 
 
82637d0
8c4f5b5
30e51cd
8c4f5b5
 
 
82637d0
8c4f5b5
 
30e51cd
8c4f5b5
 
 
 
 
 
 
 
 
 
82637d0
8c4f5b5
 
 
 
 
82637d0
4090c6c
82637d0
 
 
 
8c4f5b5
82637d0
 
 
47a91d8
82637d0
 
30e51cd
8c4f5b5
47a91d8
82637d0
 
30e51cd
8c4f5b5
dc1f241
82637d0
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import gradio as gr
import matplotlib.pyplot as plt
from io import BytesIO
from PIL import Image
from matplotlib.patches import Patch
import random

# ---------------- Function to plot bit distribution (Graph 1) ----------------
def plot_key_bits(key_str):
    # Extract only 0s and 1s from input
    bits = [int(b) for b in key_str.strip() if b in '01']
    total_bits = len(bits)

    if total_bits == 0:
        return None, "⚠️ Invalid input: Please enter a binary key."

    # Count zeros and ones
    zero_count = bits.count(0)
    one_count = bits.count(1)
    diff = abs(zero_count - one_count)

    # Fixed height bars for visibility
    heights = [1] * total_bits
    # Blue for 0, Orange for 1
    colors = ['#1f77b4' if b == 0 else '#ff7f0e' for b in bits]

    # Create figure
    fig, ax = plt.subplots(figsize=(12, 2.5))
    ax.bar(range(total_bits), heights, color=colors, edgecolor='black', linewidth=0.2)

    # Add title, labels, legend
    ax.set_title("Distribution of 0s and 1s in Your Key", fontsize=12)
    ax.set_xlabel("Bit Position in Key", fontsize=10)
    ax.set_ylabel("Bit (0 = Blue, 1 = Orange)", fontsize=10)
    ax.set_yticks([])

    legend_handles = [
        Patch(color='#1f77b4', label='0 (Blue)'),
        Patch(color='#ff7f0e', label='1 (Orange)')
    ]
    ax.legend(handles=legend_handles, loc='upper right')
    plt.tight_layout()

    # Save to buffer
    buf = BytesIO()
    plt.savefig(buf, format='png')
    plt.close()
    buf.seek(0)

    # Verdict
    if diff <= total_bits * 0.1:
        verdict = f"βœ… Balanced Key: {zero_count} zeros & {one_count} ones β€” good randomness!"
    else:
        verdict = f"⚠️ Skewed Key: {zero_count} zeros & {one_count} ones β€” consider regenerating."

    return Image.open(buf), verdict

# ---------------- Add Noise to Key (simulate eavesdropping) ----------------
def add_noise_to_key(key_str, flip_percent=0.1):
    bits = list(key_str.strip())
    total_bits = len(bits)
    num_flips = int(total_bits * flip_percent)

    flip_indices = random.sample(range(total_bits), num_flips)
    for i in flip_indices:
        bits[i] = '1' if bits[i] == '0' else '0'

    return ''.join(bits), flip_indices

# ---------------- Compare Original vs Noisy Key (Graph 2) ----------------
def compare_original_vs_noisy(key_str):
    key_str = ''.join([b for b in key_str.strip() if b in '01'])  # Clean input
    if not key_str:
        return None, "⚠️ Invalid input: Please enter a binary key."

    noisy_key, flipped_indices = add_noise_to_key(key_str)
    total_bits = len(key_str)
    heights = [1] * total_bits
    x = range(total_bits)

    fig, axs = plt.subplots(2, 1, figsize=(12, 3.8), sharex=True)

    # First plot: Original Key
    axs[0].bar(x, heights, color='green', edgecolor='black', linewidth=0.2)
    axs[0].set_title("Before Noise: Original QKD Key", fontsize=11)
    axs[0].set_yticks([])
    axs[0].set_ylabel("Bit")

    # Second plot: Noisy Key
    colors = ['red' if i in flipped_indices else 'green' for i in range(total_bits)]
    axs[1].bar(x, heights, color=colors, edgecolor='black', linewidth=0.2)
    axs[1].set_title("After Noise: Key with Eavesdropper Flips", fontsize=11)
    axs[1].set_xlabel("Bit Index")
    axs[1].set_yticks([])
    axs[1].set_ylabel("Bit")

    plt.tight_layout()
    buf = BytesIO()
    plt.savefig(buf, format='png')
    plt.close()
    buf.seek(0)

    # Summary
    corruption_rate = (len(flipped_indices) / total_bits) * 100
    summary = f"⚠️ {len(flipped_indices)} bits flipped out of {total_bits} β€” {corruption_rate:.2f}% corruption detected."

    return Image.open(buf), summary

# ---------------- Combined Tab ----------------
def get_tab5_randomness():
    with gr.Tab("πŸ“Š QKD Key Analyzer"):
        gr.Markdown(
            "<h2 style='text-align: center;'>πŸ”‘ Analyze Your QKD Key for Randomness & Noise Simulation</h2>"
        )

        # Input & Button
        binary_input = gr.Textbox(label="πŸ”‘ Enter Your QKD Key (binary)", placeholder="Example: 0101011001...", lines=3)
        analyze_btn = gr.Button("Analyze Key")

        # Graph 1 Heading
        gr.Markdown("<h3 style='text-align: center;'>πŸ“ˆ Graph 1: Bit Randomness Distribution</h3>")
        randomness_graph = gr.Image(label="πŸ§ͺ Distribution of 0s and 1s in your key")
        randomness_text = gr.Textbox(label="Randomness Insight", lines=2)

        # Graph 2 Heading
        gr.Markdown("<h3 style='text-align: center;'>🧨 Graph 2: Noise Simulation – Flipped Bits due to Eavesdropping</h3>")
        noise_graph = gr.Image(label="πŸ” Original vs Flipped Bits")
        noise_summary = gr.Textbox(label="Noise Impact Summary", lines=2)

        # Combined callback
        def analyze_key_combined(key_str):
            graph1, verdict = plot_key_bits(key_str)
            graph2, summary = compare_original_vs_noisy(key_str)
            return graph1, verdict, graph2, summary

        analyze_btn.click(
            fn=analyze_key_combined,
            inputs=[binary_input],
            outputs=[randomness_graph, randomness_text, noise_graph, noise_summary]
        )