File size: 27,226 Bytes
227c43a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
"""

High-Fidelity BB84 Protocol Simulation using Google Cirq with Realistic Quantum Effects.



This module builds a comprehensive BB84 quantum key distribution simulation that accounts for:

- Realistic photon loss based on distance in fiber optics

- Hardware-specific quantum noise models

- Eavesdropper detection and information leakage analysis

- Information reconciliation and privacy amplification

- Realistic security parameter estimation

"""
import cirq
import random
import numpy as np
import math
from cirq.contrib.svg import circuit_to_svg

# Physical constants
SPEED_OF_LIGHT = 299792458  # m/s
FIBER_LOSS_DB_PER_KM = 0.2  # Standard telecom fiber loss
DETECTOR_EFFICIENCY = 0.85  # Typical superconducting detector efficiency

def create_hardware_noise_model(hardware_type='fiber', distance_km=0, detector_dark_count=1e-6):
    """

    Creates a realistic hardware-specific noise model.

    

    Args:

        hardware_type: Type of quantum hardware ('fiber', 'satellite', 'trapped_ion')

        distance_km: Distance between Alice and Bob in kilometers

        detector_dark_count: Dark count probability per detection window

        

    Returns:

        Dictionary with noise parameters

    """
    models = {
        'fiber': {
            'photon_loss': 1 - 10**(-FIBER_LOSS_DB_PER_KM * distance_km / 10),
            'polarization_drift': min(0.01 * distance_km, 0.1),  # Polarization drift in fiber
            'phase_drift': min(0.005 * distance_km, 0.1),  # Phase drift
            'detector_efficiency': DETECTOR_EFFICIENCY,
            'dark_count_probability': detector_dark_count,
            'timing_jitter': 50e-12 * (1 + 0.01 * distance_km),  # Timing jitter in seconds
            'coherence_time': 1e-9  # 1 nanosecond coherence time in fiber
        },
        'satellite': {
            'photon_loss': 1 - 10**(-0.07 * distance_km / 10),  # Lower atmospheric loss
            'polarization_drift': 0.001 * distance_km,
            'phase_drift': 0.002 * distance_km,
            'detector_efficiency': 0.7,  # Lower efficiency in space-based detectors
            'dark_count_probability': 1e-7,  # Lower dark counts in space
            'timing_jitter': 100e-12,
            'coherence_time': 5e-9  # Longer coherence in free space
        },
        'trapped_ion': {
            'photon_loss': 0.1,  # Minimal loss in controlled environment
            'polarization_drift': 0.001,
            'phase_drift': 0.001,
            'detector_efficiency': 0.95,  # High efficiency
            'dark_count_probability': 1e-8,
            'timing_jitter': 10e-12,
            'coherence_time': 1e-6  # Much longer coherence in trapped ion systems
        }
    }
    
    return models.get(hardware_type, models['fiber'])

def add_realistic_noise(circuit, noise_model, qubit):
    """Add realistic hardware-specific noise to the circuit."""
    noisy_circuit = cirq.Circuit()
    
    # Add original operations
    for op in circuit.all_operations():
        noisy_circuit.append(op)
        
        # Add depolarizing channel to model general noise
        depolarizing_prob = min(0.01, noise_model['phase_drift'] + noise_model['polarization_drift'])
        noisy_circuit.append(cirq.depolarize(depolarizing_prob).on(qubit))
        
        # Add amplitude damping to model photon loss during computation
        if noise_model['photon_loss'] > 0:
            amp_damp_prob = min(0.1, noise_model['photon_loss'] / 10)  # Scale down for gate operations
            noisy_circuit.append(cirq.amplitude_damp(amp_damp_prob).on(qubit))
        
        # Add phase damping to model decoherence
        coherence_error = min(0.05, 1e-9 / noise_model['coherence_time'])
        noisy_circuit.append(cirq.phase_damp(coherence_error).on(qubit))
    
    return noisy_circuit

def simulate_eavesdropping(alice_bits, alice_bases, eve_strategy, detection_probability=0.5):
    """

    Simulate an eavesdropper with various attack strategies.

    

    Args:

        alice_bits: Alice's original random bits

        alice_bases: Alice's chosen bases

        eve_strategy: Strategy ('intercept_resend', 'beam_splitting', 'trojan_horse')

        detection_probability: Probability of Eve being detected per intercepted bit

        

    Returns:

        Dictionary with eavesdropping results and analysis

    """
    eve_bases = [random.choice(['Z', 'X']) for _ in range(len(alice_bits))]
    eve_measurements = []
    modified_states = []
    detection_events = []
    information_gain = 0
    
    for i in range(len(alice_bits)):
        if eve_strategy == 'intercept_resend':
            # Eve measures in her random basis
            if eve_bases[i] == alice_bases[i]:
                # If Eve uses same basis as Alice, she gets correct result
                eve_measurement = alice_bits[i]
                detection = False  # Eve won't be detected here
            else:
                # If Eve uses wrong basis, she gets random result
                eve_measurement = random.randint(0, 1)
                detection = random.random() < detection_probability  # Eve might be detected
            
            # Eve resends based on her measurement and basis
            if eve_bases[i] == alice_bases[i]:
                # If Eve measured in correct basis, state is unchanged
                modified_state = alice_bits[i]
            else:
                # If Eve measured in wrong basis, state is randomized
                modified_state = random.randint(0, 1)
                
        elif eve_strategy == 'beam_splitting':
            # Eve captures a portion of photons in a beam splitting attack
            # She only gets information when measuring in correct basis
            if eve_bases[i] == alice_bases[i]:
                eve_measurement = alice_bits[i]
                information_gain += 1
            else:
                eve_measurement = random.randint(0, 1)
            
            # Original state is preserved, harder to detect
            modified_state = alice_bits[i]
            detection = random.random() < (detection_probability / 3)  # Much harder to detect
            
        elif eve_strategy == 'trojan_horse':
            # Eve sends additional photons to probe the system
            eve_measurement = alice_bits[i]  # Gets perfect information
            modified_state = alice_bits[i]  # State is preserved
            detection = random.random() < (detection_probability * 2)  # Easier to detect
            information_gain += 1
            
        else:  # No eavesdropping or unknown strategy
            eve_measurement = None
            modified_state = alice_bits[i]
            detection = False
        
        eve_measurements.append(eve_measurement)
        modified_states.append(modified_state)
        detection_events.append(detection)
    
    # Calculate information leakage
    if eve_strategy != 'none':
        information_leak_ratio = information_gain / len(alice_bits)
    else:
        information_leak_ratio = 0
        
    # Calculate detection probability
    if any(detection_events):
        eve_detected = True
        detection_probability = sum(detection_events) / len(detection_events)
    else:
        eve_detected = False
        detection_probability = 0
    
    return {
        'eve_bases': eve_bases,
        'eve_measurements': eve_measurements,
        'modified_states': modified_states,
        'eve_detected': eve_detected,
        'detection_probability': detection_probability,
        'information_leak_ratio': information_leak_ratio
    }

def information_reconciliation(alice_key, bob_key, error_rate, reconciliation_efficiency=0.8):
    """

    Simulate information reconciliation to correct errors in the sifted key.

    

    Args:

        alice_key: Alice's sifted key bits

        bob_key: Bob's sifted key bits

        error_rate: Estimated quantum bit error rate

        reconciliation_efficiency: Efficiency of the reconciliation protocol

        

    Returns:

        Dictionary with reconciliation results

    """
    if not alice_key or not bob_key:
        return {'success': False, 'corrected_bits': 0, 'bits_used': 0, 'remaining_error_rate': 0, 'final_key': []}
    
    # Calculate theoretical bits needed for correction
    if error_rate <= 0:
        return {'success': True, 'corrected_bits': 0, 'bits_used': 0, 'remaining_error_rate': 0, 'final_key': alice_key}
    
    # Shannon entropy for binary symmetric channel
    h_binary = -error_rate * math.log2(error_rate) - (1-error_rate) * math.log2(1-error_rate) if 0 < error_rate < 1 else 0
    bits_needed = len(alice_key) * h_binary / reconciliation_efficiency
    
    # Simulate error correction
    errors_identified = 0
    corrected_key = bob_key.copy()
    
    # Error correction simulation (simplified CASCADE protocol)
    block_size = max(1, int(1 / error_rate))
    
    for block_start in range(0, len(alice_key), block_size):
        block_end = min(block_start + block_size, len(alice_key))
        alice_block = alice_key[block_start:block_end]
        bob_block = corrected_key[block_start:block_end]
        
        # Check parity
        alice_parity = sum(alice_block) % 2
        bob_parity = sum(bob_block) % 2
        
        # If parity differs, find and fix an error
        if alice_parity != bob_parity:
            # Binary search for error (simplified)
            if len(bob_block) > 1:
                mid = len(bob_block) // 2
                if sum(alice_block[:mid]) % 2 != sum(bob_block[:mid]) % 2:
                    # Error is in first half
                    for i in range(mid):
                        if bob_block[i] != alice_block[i]:
                            corrected_key[block_start + i] = alice_block[i]
                            errors_identified += 1
                            break
                else:
                    # Error is in second half
                    for i in range(mid, len(bob_block)):
                        if bob_block[i] != alice_block[i]:
                            corrected_key[block_start + i] = alice_block[i]
                            errors_identified += 1
                            break
            else:
                # Single bit block with error
                corrected_key[block_start] = alice_block[0]
                errors_identified += 1
    
    # Calculate remaining error rate
    remaining_errors = sum(1 for a, b in zip(alice_key, corrected_key) if a != b)
    remaining_error_rate = remaining_errors / len(alice_key) if alice_key else 0
    
    return {
        'success': remaining_error_rate < error_rate / 10,
        'corrected_bits': errors_identified,
        'bits_used': min(len(alice_key), int(bits_needed)),
        'remaining_error_rate': remaining_error_rate,
        'final_key': corrected_key
    }

def privacy_amplification(reconciled_key, leaked_bits, security_parameter=0.1):
    """

    Perform privacy amplification to reduce potential knowledge by eavesdropper.

    

    Args:

        reconciled_key: Key after information reconciliation

        leaked_bits: Estimated bits of information leaked to Eve

        security_parameter: Extra security margin (0-1)

        

    Returns:

        Final secure key after privacy amplification

    """
    if not reconciled_key:
        return []
    
    # Calculate final key length after privacy amplification
    final_length = max(1, len(reconciled_key) - int(leaked_bits) - int(security_parameter * len(reconciled_key)))
    
    if final_length <= 0:
        return []
    
    # Apply universal hash function (simplified as XOR with random bit masks)
    secure_key = []
    for i in range(final_length):
        # Create random bit mask (Toeplitz matrix row)
        mask = [random.randint(0, 1) for _ in range(len(reconciled_key))]
        
        # XOR the key with mask
        secure_bit = sum(k * m for k, m in zip(reconciled_key, mask)) % 2
        secure_key.append(secure_bit)
    
    return secure_key

def calculate_theoretical_key_rate(distance_km, hardware_type='fiber', eavesdropping=False):
    """

    Calculate theoretical key rate based on distance and hardware parameters.

    

    Args:

        distance_km: Distance between Alice and Bob

        hardware_type: Type of quantum hardware

        eavesdropping: Whether eavesdropping is present

        

    Returns:

        Estimated key rate in bits/second

    """
    # Get hardware parameters
    noise_model = create_hardware_noise_model(hardware_type, distance_km)
    
    # Calculate photon transmission probability
    transmission_prob = (1 - noise_model['photon_loss']) * noise_model['detector_efficiency']
    
    # Calculate QBER from noise parameters
    qber = min(0.5, noise_model['polarization_drift'] + noise_model['phase_drift'] + 
              noise_model['dark_count_probability'] / max(1e-15, transmission_prob))
    
    if eavesdropping:
        qber = min(0.5, qber + 0.15)  # Increased QBER due to eavesdropping
    
    # Source rate (typical for QKD systems)
    source_rate = 1e9  # 1 GHz photon generation rate
    
    # Calculate raw key rate
    raw_rate = source_rate * transmission_prob
    
    # Calculate sifted key rate (50% of raw due to basis mismatch)
    sifted_rate = raw_rate * 0.5
    
    # Error correction efficiency factor
    ec_efficiency = 1.2  # Typical CASCADE efficiency
    
    # Calculate final key rate using GLLP formula (simplified)
    if qber >= 0.11:  # Above threshold for secure BB84
        return 0
    
    # Asymptotic key rate formula
    h_binary = lambda x: 0 if x <= 0 or x >= 1 else -x*math.log2(x)-(1-x)*math.log2(1-x)
    final_rate = sifted_rate * (1 - h_binary(qber) - ec_efficiency * h_binary(qber))
    
    # Apply practical limitations
    final_rate = max(0, final_rate)  # Can't be negative
    
    return final_rate

def bb84_protocol_cirq(num_bits=10, distance_km=0, hardware_type='fiber', 

                       eve_present=False, eve_strategy='intercept_resend',

                       detector_dark_count=1e-6, detailed_simulation=True,

                       perform_reconciliation=True, perform_amplification=True,

                       noise_prob=0.0):
    """

    Simulates the BB84 quantum key distribution protocol with realistic physical effects.

    

    Args:

        num_bits: Number of qubits to transmit

        distance_km: Distance between Alice and Bob in kilometers

        hardware_type: Type of quantum hardware ('fiber', 'satellite', 'trapped_ion')

        eve_present: Whether an eavesdropper is present

        eve_strategy: Eve's attack strategy if present

        detector_dark_count: Dark count probability per detection window

        detailed_simulation: Whether to run full quantum circuit simulation for each qubit

        perform_reconciliation: Whether to perform information reconciliation

        perform_amplification: Whether to perform privacy amplification

        

    Returns:

        Dictionary with BB84 protocol results and analysis

    """
    log = []
    log.append("=== BB84 Protocol Simulation with Realistic Quantum Effects ===")
    
    # Create noise model based on hardware parameters
    noise_model = create_hardware_noise_model(hardware_type, distance_km, detector_dark_count)
    log.append(f"Hardware configuration: {hardware_type} over {distance_km} km")
    log.append(f"Noise model parameters: {noise_model}")
    
    # Calculate theoretical key rate
    theoretical_key_rate = calculate_theoretical_key_rate(distance_km, hardware_type, eve_present)
    log.append(f"Theoretical key rate: {theoretical_key_rate:.2f} bits/second")
    
    # Alice generates random bits and basis choices
    alice_bits = [random.randint(0, 1) for _ in range(num_bits)]
    alice_bases = [random.choice(['Z', 'X']) for _ in range(num_bits)]
    log.append(f"Alice generated {num_bits} random bits and basis choices")
    
    # Bob generates random basis choices
    bob_bases = [random.choice(['Z', 'X']) for _ in range(num_bits)]
    log.append(f"Bob generated {num_bits} random basis choices")
    
    # Quantum transmission simulation
    transmitted_states = []
    bob_received_states = []
    bob_measurements = []
    
    # Create a sample circuit visualization using only the first qubit
    # This ensures we always have a valid circuit for SVG generation
    sample_circuit = cirq.Circuit()
    sample_q = cirq.NamedQubit('q0')
    
    # Add representative operations to sample circuit
    sample_circuit.append(cirq.H(sample_q))
    sample_circuit.append(cirq.measure(sample_q))
    
    circuit_svg = circuit_to_svg(sample_circuit)
    
    # Process each bit for quantum transmission
    for i in range(num_bits):
        log.append(f"\n-- Bit {i} --")
        q = cirq.NamedQubit(f'q{i}')
        circuit = cirq.Circuit()
        
        # State preparation by Alice
        if alice_bits[i] == 1:
            circuit.append(cirq.X(q))
            log.append(f"Alice prepares |1⟩ state for bit {i}")
        else:
            log.append(f"Alice prepares |0⟩ state for bit {i}")
            
        # Basis selection by Alice
        if alice_bases[i] == 'X':
            circuit.append(cirq.H(q))
            log.append(f"Alice uses X basis (Hadamard applied)")
        else:
            log.append(f"Alice uses Z basis (computational basis)")
        
        # Simulate photon loss based on distance
        photon_lost = random.random() < noise_model['photon_loss']
        if photon_lost:
            log.append(f"Photon lost in transmission (probability: {noise_model['photon_loss']:.4f})")
            bob_received_states.append(None)
            bob_measurements.append(None)
            continue
        
        # Eve's interaction if present
        if eve_present:
            if i == 0:  # Log once for clarity
                log.append(f"Eve is present using '{eve_strategy}' strategy")
                
            # Create Eve's circuit for interception (detailed simulation only for first few bits)
            if i < 5 and detailed_simulation:
                eve_q = cirq.NamedQubit(f'eve_q{i}')
                eve_circuit = cirq.Circuit()
                
                # Eve measures in her chosen basis
                if eve_strategy == 'intercept_resend':
                    eve_basis = random.choice(['Z', 'X'])
                    if eve_basis == 'X':
                        eve_circuit.append(cirq.H(eve_q))
                    eve_circuit.append(cirq.measure(eve_q, key='eve_meas'))
                    
                    # Prepare state to send to Bob based on Eve's measurement
                    eve_result = random.randint(0, 1)  # Simplified for non-executed circuit
                    if eve_result == 1:
                        circuit.append(cirq.X(q))
                    if eve_basis == 'X':
                        circuit.append(cirq.H(q))
                        
                log.append(f"Eve intercepted bit {i} using {eve_strategy}")
        
        # Add realistic hardware noise
        if detailed_simulation:
            circuit = add_realistic_noise(circuit, noise_model, q)
            
        # Bob's basis selection and measurement
        if bob_bases[i] == 'X':
            circuit.append(cirq.H(q))
            log.append(f"Bob uses X basis (Hadamard applied)")
        else:
            log.append(f"Bob uses Z basis (computational basis)")
            
        # Detector dark count simulation
        dark_count_occurred = random.random() < noise_model['dark_count_probability']
        if dark_count_occurred:
            bob_measurement = random.randint(0, 1)
            log.append(f"Detector dark count occurred, random measurement: {bob_measurement}")
        else:
            # Measurement simulation
            if detailed_simulation:
                circuit.append(cirq.measure(q, key='meas'))
                simulator = cirq.Simulator()
                result = simulator.run(circuit, repetitions=1)
                bob_measurement = int(result.measurements['meas'][0][0])
            else:
                # Simplified measurement model without full circuit simulation
                correct_basis = alice_bases[i] == bob_bases[i]
                
                if correct_basis:
                    # With probability (1-error_rate), Bob gets correct result
                    error_prob = noise_model['polarization_drift'] + noise_model['phase_drift']
                    if random.random() < error_prob:
                        bob_measurement = 1 - alice_bits[i]  # Error in measurement
                    else:
                        bob_measurement = alice_bits[i]      # Correct measurement
                else:
                    # Different bases, random outcome
                    bob_measurement = random.randint(0, 1)
                    
            log.append(f"Bob's measurement: {bob_measurement}")
        
        bob_measurements.append(bob_measurement)
        bob_received_states.append(True)  # Successfully received
            
    # Sift key - keep only bits where both used same basis and photon wasn't lost
    matching_bases = [i for i in range(num_bits) if 
                     bob_received_states[i] is not None and
                     alice_bases[i] == bob_bases[i]]
    
    shared_key = [alice_bits[i] for i in matching_bases]
    bob_key = [bob_measurements[i] for i in matching_bases]
    
    # Calculate QBER (Quantum Bit Error Rate)
    errors = sum(a != b for a, b in zip(shared_key, bob_key))
    qber = errors / len(shared_key) if shared_key else 0
    
    log.append(f"\nMatching bases indices: {matching_bases}")
    log.append(f"Raw key length: {num_bits}")
    log.append(f"Sifted key length: {len(shared_key)}")
    log.append(f"Transmission efficiency: {len(bob_received_states) - bob_received_states.count(None)}/{num_bits}")
    log.append(f"Sifted key efficiency: {len(shared_key)}/{num_bits}")
    log.append(f"Alice's sifted key: {shared_key}")
    log.append(f"Bob's measured key: {bob_key}")
    log.append(f"QBER: {qber:.4f}")
    
    # Eavesdropper detection using QBER
    qber_threshold = 0.11  # Theoretical threshold for BB84
    eve_detected_by_qber = qber > qber_threshold
    
    if eve_detected_by_qber:
        log.append(f"WARNING: QBER ({qber:.4f}) exceeds threshold ({qber_threshold}), possible eavesdropper detected!")
    else:
        log.append(f"QBER within acceptable limits, no evidence of eavesdropping")
    
    # Eavesdropping simulation results
    eve_results = None
    if eve_present:
        eve_results = simulate_eavesdropping(alice_bits, alice_bases, eve_strategy)
        log.append(f"\nEavesdropping simulation:")
        log.append(f"Eve detected: {eve_results['eve_detected']}")
        log.append(f"Information leak ratio: {eve_results['information_leak_ratio']:.4f}")
    
    # Information reconciliation
    reconciliation_results = None
    if shared_key and perform_reconciliation:
        reconciliation_results = information_reconciliation(shared_key, bob_key, qber)
        log.append(f"\nInformation reconciliation:")
        log.append(f"Errors corrected: {reconciliation_results['corrected_bits']}")
        log.append(f"Bits used for correction: {reconciliation_results['bits_used']}")
        log.append(f"Remaining error rate: {reconciliation_results['remaining_error_rate']:.6f}")
        log.append(f"Reconciliation success: {reconciliation_results['success']}")
        
        bob_key = reconciliation_results['final_key']
    
    # Privacy amplification
    final_key = None
    if shared_key and bob_key and perform_amplification:
        # Estimate information leakage
        leaked_bits = 0
        if eve_present and eve_results:
            leaked_bits = int(eve_results['information_leak_ratio'] * len(shared_key))
        elif qber > 0:
            # Conservative estimate based on QBER
            leaked_bits = int(qber * len(shared_key) * 2)
            
        final_key = privacy_amplification(bob_key, leaked_bits)
        
        log.append(f"\nPrivacy amplification:")
        log.append(f"Estimated information leakage: {leaked_bits} bits")
        log.append(f"Final secure key length: {len(final_key)}")
        log.append(f"Final key rate: {len(final_key)/(num_bits)} bits per transmitted qubit")
    
    # Calculate theoretical secure key rate for this setup
    secure_key_rate = calculate_theoretical_key_rate(distance_km, hardware_type, eve_present)
    log.append(f"\nTheoretical secure key rate: {secure_key_rate:.2f} bits/second")
    
    # Return comprehensive results
    return {
        'alice_bits': alice_bits,
        'alice_bases': alice_bases,
        'bob_bases': bob_bases,
        'bob_measurements': bob_measurements,
        'matching_bases': matching_bases,
        'shared_key': shared_key,
        'bob_key': bob_key,
        'final_key': final_key,
        'error_rate': qber,
        'eve_detected_by_qber': eve_detected_by_qber,
        'photon_loss_rate': noise_model['photon_loss'],
        'transmission_efficiency': (len(bob_received_states) - bob_received_states.count(None))/num_bits,
        'sifted_key_ratio': len(shared_key)/num_bits if num_bits > 0 else 0,
        'final_key_ratio': len(final_key)/num_bits if final_key and num_bits > 0 else 0,
        'secure_key_rate': secure_key_rate,
        'noise_model': noise_model,
        'eavesdropper_results': eve_results,
        'reconciliation_results': reconciliation_results,
        'circuit_svg': circuit_svg,
        'log': "\n".join(log)
    }

if __name__ == '__main__':
    # Basic simulation
    result = bb84_protocol_cirq(10, distance_km=0)
    print("Cirq BB84 Simulation Result:")
    print("Shared key:", result['shared_key'])
    print("Error rate:", f"{result['error_rate']:.2%}")
    
    # Run realistic range test
    distances = [0, 10, 50, 100, 200]
    print("\nDistance Test:")
    for dist in distances:
        dist_result = bb84_protocol_cirq(100, distance_km=dist, detailed_simulation=False)
        print(f"{dist} km: Key rate = {dist_result['secure_key_rate']:.2f} bits/s, "
              f"QBER = {dist_result['error_rate']:.4f}")
    
    # Eavesdropper test
    eve_result = bb84_protocol_cirq(100, distance_km=50, eve_present=True, 
                                    eve_strategy='intercept_resend')
    print("\nWith Eavesdropper:")
    print(f"QBER = {eve_result['error_rate']:.4f}")
    print(f"Eve detected: {eve_result['eve_detected_by_qber']}")
    print(f"Final key length: {len(eve_result['final_key']) if eve_result['final_key'] else 0}")