Tutorials

Step-by-step guides from beginner to advanced

Learning Path

Beginner
Intermediate
Advanced

Beginner Tutorials

Beginner 30 min
Tutorial 1

Getting Started with CV-QKD

Introduction to continuous-variable quantum key distribution concepts and your first simulation.

What you'll learn:

  • • Quantum key distribution basics
  • • CV vs DV-QKD comparison
  • • Setting up the simulator
  • • Running your first key generation
# Your first CV-QKD simulation
from qkd import GMCSTransmitter, GMCSReceiver, QuantumChannel

# Create Alice (transmitter)
alice = GMCSTransmitter(variance=4.0)

# Create quantum channel (25 km fiber)
channel = QuantumChannel(distance_km=25)

# Create Bob (receiver)
bob = GMCSReceiver(detection_mode="homodyne")

# Generate and exchange 10000 symbols
states = alice.prepare_states(10000)
measurements = bob.measure(states, channel)

print("Key generation complete!")
Beginner 45 min
Tutorial 2

Understanding Key Rate Calculations

Learn how secret key rates are calculated from mutual information and Holevo bounds.

# Calculate secret key rate
from qkd import KeyRateCalculator, ChannelParams

calc = KeyRateCalculator(reconciliation_efficiency=0.95)

params = ChannelParams(
    distance_km=25,
    excess_noise=0.01,  # SNU
    variance=4.0,       # SNU
    detector_qe=0.6
)

# Asymptotic key rate
key_rate = calc.asymptotic_rate(params)
print(f"Key rate: {key_rate:.4f} bits/symbol")

# Breakdown
I_AB = calc.mutual_information(params)
chi_BE = calc.holevo_bound(params)
print(f"I_AB: {I_AB:.4f}, χ_BE: {chi_BE:.4f}")
Beginner 30 min
Tutorial 3

Shot Noise Units Explained

Master the concept of shot noise units (SNU) and noise characterization in CV-QKD.

Key Concepts:

  • • Quantum vacuum noise = 1 SNU
  • • Excess noise typically 0.001-0.05 SNU
  • • Electronic noise should be < 0.01 SNU
  • • Channel noise grows with distance

Intermediate Tutorials

Intermediate 60 min
Tutorial 4

PIC Loss Budget Analysis

Design and analyze photonic integrated circuit loss budgets for CV-QKD.

# Build a PIC loss budget
from qkd import PICLossBudget

budget = PICLossBudget()

# Transmitter PIC
budget.add_component("TX grating coupler", 3.5)
budget.add_component("TX waveguide (2cm @ 0.5dB/cm)", 1.0)
budget.add_component("IQ modulator", 3.0)
budget.add_component("TX output coupler", 3.5)

# Receiver PIC
budget.add_component("RX grating coupler", 3.5)
budget.add_component("90° hybrid", 0.5)
budget.add_component("LO routing", 3.0)

print(budget.summary())
print(f"\nTotal PIC loss: {budget.total_loss():.1f} dB")
print(f"Transmittance: {budget.transmittance():.4f}")
Intermediate 45 min
Tutorial 5

Detector Characterization

Model balanced detectors and understand their impact on system performance.

# Characterize balanced detector
from qkd import BalancedDetector

detector = BalancedDetector(
    quantum_efficiency=0.65,
    bandwidth_ghz=20,
    electronic_noise_snu=0.008,
    cmrr_db=35
)

# Check shot noise clearance with 10 mW LO
clearance = detector.shot_noise_clearance(lo_power_mw=10)
print(f"Shot noise clearance: {clearance:.1f} dB")

# Effective efficiency
eta_eff = detector.effective_efficiency()
print(f"Effective QE: {eta_eff:.2f}")
Intermediate 60 min
Tutorial 6

Parameter Sensitivity Analysis

Identify critical parameters and perform multi-parameter sweeps.

# Sensitivity sweep
import numpy as np
from qkd import KeyRateCalculator, ChannelParams

calc = KeyRateCalculator(beta=0.95)

# Sweep excess noise at 25 km
excess_values = np.linspace(0.001, 0.05, 50)
rates = []

for xi in excess_values:
    params = ChannelParams(
        distance_km=25, excess_noise=xi,
        variance=4.0, detector_qe=0.6
    )
    rates.append(calc.asymptotic_rate(params))

# Find where key rate drops to half
idx_half = np.argmin(np.abs(np.array(rates) - rates[0]/2))
print(f"Half-rate at ξ = {excess_values[idx_half]:.3f} SNU")
Intermediate 45 min
Tutorial 7

Homodyne vs Heterodyne Detection

Compare detection modes and understand when to use each.

Homodyne
  • ✓ No 3dB noise penalty
  • ✓ Higher key rate
  • ✗ Basis sifting needed
  • ✗ More complex timing
Heterodyne
  • ✓ No basis selection
  • ✓ Simpler implementation
  • ✗ 3dB noise penalty
  • ✗ Lower key rate

Advanced Tutorials

Advanced 90 min
Tutorial 8

Finite-Size Security Analysis

Implement composable security proofs with finite-size corrections.

# Finite-size key rate calculation
from qkd import FiniteSizeAnalyzer

analyzer = FiniteSizeAnalyzer(
    block_size=1e8,          # 10^8 symbols
    pe_fraction=0.10,        # 10% for parameter estimation
    epsilon_sec=1e-10,       # Security parameter
    epsilon_cor=1e-10,       # Correctness parameter
    attack_model="collective"
)

params = ChannelParams(distance_km=25, excess_noise=0.01,
                       variance=4.0, detector_qe=0.6)

# Get finite-size rate
finite_rate = analyzer.key_rate(params)
asymptotic = calc.asymptotic_rate(params)

penalty = (asymptotic - finite_rate) / asymptotic * 100
print(f"Finite-size rate: {finite_rate:.4f}")
print(f"Penalty: {penalty:.1f}%")
Advanced 120 min
Tutorial 9

Covariance Matrix Methods

Deep dive into Gaussian quantum information and symplectic eigenvalues.

# Covariance matrix analysis
from common.gaussian import (
    covariance_matrix, symplectic_eigenvalues, g
)
import numpy as np

V_A = 4.0  # Modulation variance
T = 0.1   # Transmittance
xi = 0.01  # Excess noise

# Build 4x4 covariance matrix
gamma = covariance_matrix(V_A, T, xi)
print("Covariance matrix:")
print(gamma)

# Calculate symplectic eigenvalues
lambdas = symplectic_eigenvalues(gamma)
print(f"\nSymplectic eigenvalues: {lambdas}")

# Compute Holevo bound from eigenvalues
chi_BE = sum(g((l-1)/2) for l in lambdas if l > 1)
print(f"Holevo bound χ_BE: {chi_BE:.4f}")
Advanced 90 min
Tutorial 10

System Optimization

Optimize modulation variance and other parameters for maximum key rate.

# Optimize modulation variance for given channel
from scipy.optimize import minimize_scalar

def neg_key_rate(V_A, distance, xi, eta):
    params = ChannelParams(
        distance_km=distance, excess_noise=xi,
        variance=V_A, detector_qe=eta
    )
    return -calc.asymptotic_rate(params)

# Find optimal V_A for 50 km link
result = minimize_scalar(
    neg_key_rate,
    bounds=(1, 20),
    args=(50, 0.01, 0.6),
    method='bounded'
)

print(f"Optimal V_A: {result.x:.2f} SNU")
print(f"Maximum key rate: {-result.fun:.4f} bits/symbol")

Next Steps