gaialive's picture
Upload 170 files
227c43a verified
"""
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}")