Spaces:
Sleeping
Sleeping
Upload 17 files
Browse files- README.md +104 -13
- app.py +135 -0
- data/03bd51fa-e441-47dd-bd2e-ecc9fde0da3d.png +0 -0
- data/2f47bf75-5546-44ee-815a-f408612230f4.png +0 -0
- data/3a8ba655-50ed-4ddc-93ca-2eabee5a36b5.png +0 -0
- data/3ed20c5a-74a1-4b16-bc33-ab745360536a.png +0 -0
- requirements.txt +70 -0
- src/__pycache__/base.cpython-310.pyc +0 -0
- src/__pycache__/bb84.cpython-310.pyc +0 -0
- src/__pycache__/circuit_viz.cpython-310.pyc +0 -0
- src/__pycache__/e91.cpython-310.pyc +0 -0
- src/base.py +20 -0
- src/bb84.py +341 -0
- src/circuit_viz.py +15 -0
- src/e91.py +167 -0
- src/generate.py +226 -0
- src/qec.py +24 -0
README.md
CHANGED
|
@@ -1,14 +1,105 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# QuantumCrypt
|
| 2 |
+
|
| 3 |
+
## BB84
|
| 4 |
+
|
| 5 |
+
## Introduction
|
| 6 |
+
The BB84 protocol is a Quantum Key Distribution (QKD) scheme developed by Charles Bennett and Gilles Brassard in 1984. It enables two parties, traditionally called Alice and Bob, to securely share a secret key, ensuring resistance against eavesdropping attempts by an adversary (Eve).
|
| 7 |
+
|
| 8 |
+
## Working Principle
|
| 9 |
+
BB84 leverages quantum mechanics to ensure secure communication. It relies on the properties of photon polarization and Heisenberg's uncertainty principle, making it impossible for an eavesdropper to measure photon states without disturbing the transmission.
|
| 10 |
+
|
| 11 |
+
The protocol operates as follows:
|
| 12 |
+
1. **Photon Transmission:** Alice sends a sequence of randomly polarized photons in one of two possible bases (rectilinear `+` or diagonal `×`).
|
| 13 |
+
2. **Random Measurement:** Bob measures each received photon using a randomly chosen basis.
|
| 14 |
+
3. **Basis Comparison:** Alice and Bob publicly compare the bases used for each photon and discard cases where Bob used the incorrect basis.
|
| 15 |
+
4. **Key Extraction:** The remaining bits form a shared secret key.
|
| 16 |
+
5. **Error Checking:** Alice and Bob verify key integrity by publicly comparing a subset of the bits. If errors exceed a threshold, they abort the protocol.
|
| 17 |
+
6. **Privacy Amplification:** If necessary, they apply classical error correction and privacy amplification techniques to refine the final secret key.
|
| 18 |
+
|
| 19 |
+
## Security
|
| 20 |
+
The security of BB84 is based on the no-cloning theorem, which prevents an adversary from perfectly copying an unknown quantum state. Any attempt by Eve to measure photons introduces detectable errors, allowing Alice and Bob to discard compromised keys.
|
| 21 |
+
|
| 22 |
+
## Applications
|
| 23 |
+
- Secure communication
|
| 24 |
+
- Quantum cryptography
|
| 25 |
+
- Future-proof encryption against quantum computing attacks
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# E91
|
| 30 |
+
|
| 31 |
+
## Overview
|
| 32 |
+
|
| 33 |
+
This project demonstrates how Alice and Bob can securely exchange a cryptographic key using the **E91 Quantum Key Distribution (QKD) Protocol**. The protocol, developed by **Artur Ekert in 1991**, leverages quantum entanglement and **Bell's theorem** to ensure that an eavesdropper, Eve, cannot gain any information about the key without detection.
|
| 34 |
+
|
| 35 |
+
## Encryption and the One-Time Pad
|
| 36 |
+
|
| 37 |
+
To ensure message confidentiality, Alice encrypts her message using the **one-time pad** technique. This method relies on the **exclusive OR (XOR) operation** to combine the plaintext and a randomly generated key:
|
| 38 |
+
|
| 39 |
+
$$ c_i = m_i \oplus k_i $$
|
| 40 |
+
|
| 41 |
+
where:
|
| 42 |
+
- \( m \) is the plaintext message,
|
| 43 |
+
- \( k \) is the secret key,
|
| 44 |
+
- \( c \) is the ciphertext.
|
| 45 |
+
|
| 46 |
+
Decryption is performed using the same XOR operation:
|
| 47 |
|
| 48 |
+
$$ m_i = c_i \oplus k_i $$
|
| 49 |
+
|
| 50 |
+
Since the security of the **one-time pad** depends on the secrecy of the key, the main challenge is securely distributing this key between Alice and Bob. This is where quantum mechanics comes into play.
|
| 51 |
+
|
| 52 |
+
## The E91 Quantum Key Distribution Protocol
|
| 53 |
+
|
| 54 |
+
The **E91 protocol** ensures secure key exchange using **quantum entanglement**. The steps are as follows:
|
| 55 |
+
|
| 56 |
+
### 1. Entangled Qubits Distribution
|
| 57 |
+
Charlie (a trusted third party) generates **N pairs of entangled qubits** in the singlet state:
|
| 58 |
+
|
| 59 |
+
$$ \lvert\psi_s\rangle = \frac{1}{\sqrt{2}}(\lvert01\rangle - \lvert10\rangle) $$
|
| 60 |
+
|
| 61 |
+
Charlie then sends **one qubit** from each entangled pair to Alice and the other to Bob over a **quantum channel**.
|
| 62 |
+
|
| 63 |
+
### 2. Measurement by Alice and Bob
|
| 64 |
+
- Alice and Bob independently choose random measurement bases and measure their received qubits.
|
| 65 |
+
- If they measure along the same basis, their results will be perfectly **anti-correlated** (i.e., opposite values).
|
| 66 |
+
|
| 67 |
+
### 3. Classical Communication
|
| 68 |
+
- Alice and Bob share their measurement choices over a **public classical channel**.
|
| 69 |
+
- They discard measurements where bases do not match.
|
| 70 |
+
- The remaining bits form the **raw key**.
|
| 71 |
+
|
| 72 |
+
### 4. Security Verification (Bell Test)
|
| 73 |
+
- Alice and Bob compute the **CHSH correlation value** to check for **Bell inequality violation**:
|
| 74 |
+
|
| 75 |
+
$$ C = \langle X \otimes W \rangle - \langle X \otimes V \rangle + \langle Z \otimes W \rangle + \langle Z \otimes V \rangle $$
|
| 76 |
+
|
| 77 |
+
- If the result exceeds the classical bound of **2** (e.g., \( C = -2\sqrt{2} \)), the key is confirmed to be **secure**.
|
| 78 |
+
- If Eve interfered, the Bell test would fail, alerting Alice and Bob to discard the key.
|
| 79 |
+
|
| 80 |
+
### 5. Key Extraction
|
| 81 |
+
After removing potentially compromised bits, Alice and Bob apply **error correction** and **privacy amplification** techniques to finalize the **secret key**.
|
| 82 |
+
|
| 83 |
+
## Why the E91 Protocol is Secure
|
| 84 |
+
- **Quantum Mechanics Guarantees Security**: Any attempt by Eve to measure the qubits **collapses their state**, altering results and revealing her presence.
|
| 85 |
+
- **Bell's Theorem and CHSH Inequality**: These ensure that no **local hidden variable theory** can explain the observed correlations, confirming true quantum entanglement.
|
| 86 |
+
|
| 87 |
+
## Applications
|
| 88 |
+
- **Quantum-Safe Encryption**: Protects against attacks from quantum computers.
|
| 89 |
+
- **Secure Communications**: Used in diplomatic and military communication systems.
|
| 90 |
+
- **Quantum Networks**: Forms the foundation for future **quantum internet** applications.
|
| 91 |
+
|
| 92 |
+
## Requirements
|
| 93 |
+
- Python (latest version recommended)
|
| 94 |
+
- Qiskit for quantum simulations
|
| 95 |
+
- Matplotlib for visualizing results
|
| 96 |
+
- NumPy for numerical computations
|
| 97 |
+
|
| 98 |
+
## References
|
| 99 |
+
- [One-Time Pad](https://en.wikipedia.org/wiki/One-time_pad)
|
| 100 |
+
- [E91 Quantum Key Distribution](https://en.wikipedia.org/wiki/E91_protocol)
|
| 101 |
+
- [Bell's Theorem](https://en.wikipedia.org/wiki/Bell's_theorem)
|
| 102 |
+
- [Qiskit Quantum Information](https://qiskit.org/documentation/tutorials/circuits/3_summary_of_quantum_operations.html)
|
| 103 |
+
|
| 104 |
+
---
|
| 105 |
+
This project demonstrates a secure method of quantum key distribution using entanglement and Bell's theorem, ensuring the highest level of encryption security.
|
app.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from src.bb84 import BB84Protocol
|
| 3 |
+
from src.e91 import E91Protocol
|
| 4 |
+
from src.circuit_viz import CircuitVisualizer
|
| 5 |
+
import numpy as np
|
| 6 |
+
import uuid
|
| 7 |
+
|
| 8 |
+
class QuantumCryptApp:
|
| 9 |
+
"""Interface gráfica para o QuantumCrypt usando Gradio."""
|
| 10 |
+
|
| 11 |
+
def __init__(self):
|
| 12 |
+
self.bb84 = BB84Protocol()
|
| 13 |
+
self.e91 = E91Protocol()
|
| 14 |
+
|
| 15 |
+
def create_interface(self):
|
| 16 |
+
"""Cria a interface Gradio."""
|
| 17 |
+
|
| 18 |
+
with gr.Blocks(title="QuantumCrypt", css="footer{display:none !important}") as interface:
|
| 19 |
+
gr.Markdown("# QuantumCrypt")
|
| 20 |
+
|
| 21 |
+
with gr.Tabs():
|
| 22 |
+
with gr.Tab("BB84"):
|
| 23 |
+
with gr.Row():
|
| 24 |
+
with gr.Column():
|
| 25 |
+
key_length = gr.Slider(
|
| 26 |
+
minimum=8, maximum=256, value=64,
|
| 27 |
+
label="Tamanho da Chave"
|
| 28 |
+
)
|
| 29 |
+
error_correction = gr.Checkbox(
|
| 30 |
+
label="Usar Correção de Erros",
|
| 31 |
+
visible=False
|
| 32 |
+
)
|
| 33 |
+
generate_btn = gr.Button("Gerar Chave BB84")
|
| 34 |
+
|
| 35 |
+
with gr.Column():
|
| 36 |
+
|
| 37 |
+
output_text = gr.TextArea(label="Resultado")
|
| 38 |
+
circuit_viz = gr.Image(label="Visualização do Circuito",
|
| 39 |
+
show_download_button=False,
|
| 40 |
+
show_fullscreen_button=False,
|
| 41 |
+
show_share_button=False)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
with gr.Tab("E91"):
|
| 45 |
+
with gr.Row():
|
| 46 |
+
with gr.Column():
|
| 47 |
+
key_length_e91 = gr.Slider(
|
| 48 |
+
minimum=8, maximum=256, value=64,
|
| 49 |
+
label="Tamanho da Chave"
|
| 50 |
+
)
|
| 51 |
+
error_correction_e91 = gr.Checkbox(
|
| 52 |
+
label="Usar Correção de Erros",
|
| 53 |
+
visible=False
|
| 54 |
+
)
|
| 55 |
+
generate_btn_e91 = gr.Button("Gerar Chave BB84")
|
| 56 |
+
|
| 57 |
+
with gr.Column():
|
| 58 |
+
|
| 59 |
+
output_text_e91 = gr.TextArea(label="Resultado")
|
| 60 |
+
circuit_viz_e91 = gr.Image(label="Visualização do Circuito",
|
| 61 |
+
show_download_button=False,
|
| 62 |
+
show_fullscreen_button=False,
|
| 63 |
+
show_share_button=False)
|
| 64 |
+
|
| 65 |
+
with gr.Accordion(label="About", open=False):
|
| 66 |
+
with open("README.md", "r") as readme_file:
|
| 67 |
+
gr.Markdown(
|
| 68 |
+
readme_file.read()
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
def generate_bb84(length, use_correction):
|
| 72 |
+
filename = f"data/{uuid.uuid4()}.png"
|
| 73 |
+
protocol = BB84Protocol(
|
| 74 |
+
key_length=length,
|
| 75 |
+
error_correction=use_correction
|
| 76 |
+
)
|
| 77 |
+
result = protocol.generate_key()
|
| 78 |
+
|
| 79 |
+
# Gerar visualização
|
| 80 |
+
circuit_img = CircuitVisualizer.draw_circuit(
|
| 81 |
+
protocol.current_circuit,
|
| 82 |
+
filename=filename
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
# Formatar resultado
|
| 86 |
+
output = (
|
| 87 |
+
f"Chave Alice: {''.join(map(str, result['alice']))}\n"
|
| 88 |
+
f"Chave Bob: {''.join(map(str, result['bob']))}\n"
|
| 89 |
+
f"Tamanho: {len(result['alice'])} bits\n"
|
| 90 |
+
f"Correção de Erros: {'Ativada' if use_correction else 'Desativada'}"
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
return output, filename
|
| 94 |
+
|
| 95 |
+
def generate_e91(length):
|
| 96 |
+
filename = f"data/{uuid.uuid4()}.png"
|
| 97 |
+
protocol = E91Protocol(
|
| 98 |
+
key_length=length
|
| 99 |
+
)
|
| 100 |
+
result = protocol.generate_key()
|
| 101 |
+
|
| 102 |
+
# Gerar visualização
|
| 103 |
+
circuit_img = CircuitVisualizer.draw_circuit(
|
| 104 |
+
protocol.current_circuit,
|
| 105 |
+
filename=filename
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
# Formatar resultado
|
| 109 |
+
output = (
|
| 110 |
+
f"Chave Alice: {''.join(map(str, result['alice']))}\n"
|
| 111 |
+
f"Chave Bob: {''.join(map(str, result['bob']))}\n"
|
| 112 |
+
f"Tamanho: {len(result['alice'])} bits\n"
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
return output, filename
|
| 116 |
+
|
| 117 |
+
generate_btn_e91.click(
|
| 118 |
+
generate_e91,
|
| 119 |
+
inputs=[key_length_e91],
|
| 120 |
+
outputs=[output_text_e91, circuit_viz_e91]
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
generate_btn.click(
|
| 124 |
+
generate_bb84,
|
| 125 |
+
inputs=[key_length, error_correction],
|
| 126 |
+
outputs=[output_text, circuit_viz]
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
return interface
|
| 130 |
+
|
| 131 |
+
# Exemplo de uso
|
| 132 |
+
if __name__ == "__main__":
|
| 133 |
+
app = QuantumCryptApp()
|
| 134 |
+
interface = app.create_interface()
|
| 135 |
+
interface.launch()
|
data/03bd51fa-e441-47dd-bd2e-ecc9fde0da3d.png
ADDED
|
data/2f47bf75-5546-44ee-815a-f408612230f4.png
ADDED
|
data/3a8ba655-50ed-4ddc-93ca-2eabee5a36b5.png
ADDED
|
data/3ed20c5a-74a1-4b16-bc33-ab745360536a.png
ADDED
|
requirements.txt
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiofiles==23.2.1
|
| 2 |
+
annotated-types==0.7.0
|
| 3 |
+
anyio==4.8.0
|
| 4 |
+
certifi==2025.1.31
|
| 5 |
+
charset-normalizer==3.4.1
|
| 6 |
+
click==8.1.8
|
| 7 |
+
contourpy==1.3.1
|
| 8 |
+
cycler==0.12.1
|
| 9 |
+
dill==0.3.9
|
| 10 |
+
exceptiongroup==1.2.2
|
| 11 |
+
fastapi==0.115.8
|
| 12 |
+
ffmpy==0.5.0
|
| 13 |
+
filelock==3.17.0
|
| 14 |
+
fonttools==4.56.0
|
| 15 |
+
fsspec==2025.2.0
|
| 16 |
+
gradio==5.17.1
|
| 17 |
+
gradio_client==1.7.1
|
| 18 |
+
h11==0.14.0
|
| 19 |
+
httpcore==1.0.7
|
| 20 |
+
httpx==0.28.1
|
| 21 |
+
huggingface-hub==0.29.1
|
| 22 |
+
idna==3.10
|
| 23 |
+
Jinja2==3.1.5
|
| 24 |
+
kiwisolver==1.4.8
|
| 25 |
+
markdown-it-py==3.0.0
|
| 26 |
+
MarkupSafe==2.1.5
|
| 27 |
+
matplotlib==3.10.0
|
| 28 |
+
mdurl==0.1.2
|
| 29 |
+
mpmath==1.3.0
|
| 30 |
+
numpy==2.2.3
|
| 31 |
+
orjson==3.10.15
|
| 32 |
+
packaging==24.2
|
| 33 |
+
pandas==2.2.3
|
| 34 |
+
pbr==6.1.1
|
| 35 |
+
pillow==11.1.0
|
| 36 |
+
psutil==7.0.0
|
| 37 |
+
pydantic==2.10.6
|
| 38 |
+
pydantic_core==2.27.2
|
| 39 |
+
pydub==0.25.1
|
| 40 |
+
Pygments==2.19.1
|
| 41 |
+
pylatexenc==2.10
|
| 42 |
+
pyparsing==3.2.1
|
| 43 |
+
python-dateutil==2.9.0.post0
|
| 44 |
+
python-multipart==0.0.20
|
| 45 |
+
pytz==2025.1
|
| 46 |
+
PyYAML==6.0.2
|
| 47 |
+
qiskit==1.4.0
|
| 48 |
+
qiskit-aer==0.16.1
|
| 49 |
+
requests==2.32.3
|
| 50 |
+
rich==13.9.4
|
| 51 |
+
ruff==0.9.7
|
| 52 |
+
rustworkx==0.16.0
|
| 53 |
+
safehttpx==0.1.6
|
| 54 |
+
scipy==1.15.2
|
| 55 |
+
semantic-version==2.10.0
|
| 56 |
+
shellingham==1.5.4
|
| 57 |
+
six==1.17.0
|
| 58 |
+
sniffio==1.3.1
|
| 59 |
+
starlette==0.45.3
|
| 60 |
+
stevedore==5.4.1
|
| 61 |
+
symengine==0.13.0
|
| 62 |
+
sympy==1.13.3
|
| 63 |
+
tomlkit==0.13.2
|
| 64 |
+
tqdm==4.67.1
|
| 65 |
+
typer==0.15.1
|
| 66 |
+
typing_extensions==4.12.2
|
| 67 |
+
tzdata==2025.1
|
| 68 |
+
urllib3==2.3.0
|
| 69 |
+
uvicorn==0.34.0
|
| 70 |
+
websockets==14.2
|
src/__pycache__/base.cpython-310.pyc
ADDED
|
Binary file (1.24 kB). View file
|
|
|
src/__pycache__/bb84.cpython-310.pyc
ADDED
|
Binary file (10.4 kB). View file
|
|
|
src/__pycache__/circuit_viz.cpython-310.pyc
ADDED
|
Binary file (900 Bytes). View file
|
|
|
src/__pycache__/e91.cpython-310.pyc
ADDED
|
Binary file (5.39 kB). View file
|
|
|
src/base.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from abc import ABC, abstractmethod
|
| 2 |
+
from typing import Dict, List, Tuple, Optional
|
| 3 |
+
import logging
|
| 4 |
+
|
| 5 |
+
class QuantumProtocol(ABC):
|
| 6 |
+
"""Classe base abstrata para protocolos de criptografia quântica."""
|
| 7 |
+
|
| 8 |
+
def __init__(self, key_length: int = 128):
|
| 9 |
+
self.key_length = key_length
|
| 10 |
+
self.logger = logging.getLogger(self.__class__.__name__)
|
| 11 |
+
|
| 12 |
+
@abstractmethod
|
| 13 |
+
def generate_key(self) -> Dict[str, List[int]]:
|
| 14 |
+
"""Gera uma chave usando o protocolo específico."""
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
@abstractmethod
|
| 18 |
+
def get_circuit_visualization(self) -> str:
|
| 19 |
+
"""Retorna a visualização do circuito quântico."""
|
| 20 |
+
pass
|
src/bb84.py
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
| 2 |
+
from qiskit.visualization import circuit_drawer
|
| 3 |
+
from qiskit_aer import Aer
|
| 4 |
+
import numpy as np
|
| 5 |
+
import random
|
| 6 |
+
from typing import Dict, List, Tuple, Optional
|
| 7 |
+
import logging
|
| 8 |
+
from .base import QuantumProtocol
|
| 9 |
+
|
| 10 |
+
class BB84Protocol(QuantumProtocol):
|
| 11 |
+
"""
|
| 12 |
+
Implementação do protocolo BB84 para distribuição quântica de chaves.
|
| 13 |
+
Herda da classe base QuantumProtocol e implementa correção de erros quânticos.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def __init__(self, key_length: int = 128, error_correction: bool = True):
|
| 17 |
+
"""
|
| 18 |
+
Inicializa o protocolo BB84.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
key_length (int): Tamanho desejado da chave final em bits
|
| 22 |
+
error_correction (bool): Se True, utiliza correção de erros quânticos
|
| 23 |
+
"""
|
| 24 |
+
super().__init__(key_length) # Chama o construtor da classe base
|
| 25 |
+
self.error_correction = error_correction
|
| 26 |
+
self.simulator = Aer.get_backend('qasm_simulator')
|
| 27 |
+
self.current_circuit = None
|
| 28 |
+
|
| 29 |
+
def _prepare_qubit(self, bit: int, basis: str) -> QuantumCircuit:
|
| 30 |
+
"""
|
| 31 |
+
Prepara um único qubit no estado e base especificados.
|
| 32 |
+
|
| 33 |
+
Args:
|
| 34 |
+
bit (int): Bit a ser codificado (0 ou 1)
|
| 35 |
+
basis (str): Base de medição ('Z' para rectilinear ou 'X' para diagonal)
|
| 36 |
+
|
| 37 |
+
Returns:
|
| 38 |
+
QuantumCircuit: Circuito quântico preparado
|
| 39 |
+
"""
|
| 40 |
+
if self.error_correction:
|
| 41 |
+
# Circuito com correção de erros (código de repetição de 3 qubits)
|
| 42 |
+
qr = QuantumRegister(3, 'q')
|
| 43 |
+
cr = ClassicalRegister(1, 'c')
|
| 44 |
+
qc = QuantumCircuit(qr, cr)
|
| 45 |
+
|
| 46 |
+
# Prepara o estado base
|
| 47 |
+
if bit == 1:
|
| 48 |
+
qc.x(qr[0])
|
| 49 |
+
|
| 50 |
+
# Aplica o código de repetição
|
| 51 |
+
qc.cx(qr[0], qr[1]) # CNOT para copiar o estado
|
| 52 |
+
qc.cx(qr[0], qr[2])
|
| 53 |
+
|
| 54 |
+
# Aplica a transformação de base se necessário
|
| 55 |
+
if basis == 'X':
|
| 56 |
+
qc.h(qr) # Aplica H em todos os qubits
|
| 57 |
+
else:
|
| 58 |
+
# Circuito simples sem correção
|
| 59 |
+
qr = QuantumRegister(1, 'q')
|
| 60 |
+
cr = ClassicalRegister(1, 'c')
|
| 61 |
+
qc = QuantumCircuit(qr, cr)
|
| 62 |
+
|
| 63 |
+
# Prepara o estado
|
| 64 |
+
if bit == 1:
|
| 65 |
+
qc.x(qr[0])
|
| 66 |
+
if basis == 'X':
|
| 67 |
+
qc.h(qr[0])
|
| 68 |
+
|
| 69 |
+
self.current_circuit = qc
|
| 70 |
+
return qc
|
| 71 |
+
|
| 72 |
+
def _measure_qubit(self, circuit: QuantumCircuit, basis: str) -> QuantumCircuit:
|
| 73 |
+
"""
|
| 74 |
+
Adiciona medição em uma base específica ao circuito.
|
| 75 |
+
|
| 76 |
+
Args:
|
| 77 |
+
circuit (QuantumCircuit): Circuito a ser medido
|
| 78 |
+
basis (str): Base de medição ('Z' ou 'X')
|
| 79 |
+
|
| 80 |
+
Returns:
|
| 81 |
+
QuantumCircuit: Circuito com medição adicionada
|
| 82 |
+
"""
|
| 83 |
+
if self.error_correction:
|
| 84 |
+
# Medição com correção de erros
|
| 85 |
+
if basis == 'X':
|
| 86 |
+
circuit.h(range(3)) # Aplica H em todos os qubits para base X
|
| 87 |
+
|
| 88 |
+
# Medição em todos os qubits
|
| 89 |
+
circuit.measure_all()
|
| 90 |
+
|
| 91 |
+
else:
|
| 92 |
+
# Medição simples
|
| 93 |
+
if basis == 'X':
|
| 94 |
+
circuit.h(0)
|
| 95 |
+
circuit.measure([0], [0])
|
| 96 |
+
|
| 97 |
+
return circuit
|
| 98 |
+
|
| 99 |
+
def _error_correction_decode(self, measurements: List[int]) -> int:
|
| 100 |
+
"""
|
| 101 |
+
Decodifica medições usando voto majoritário para correção de erros.
|
| 102 |
+
|
| 103 |
+
Args:
|
| 104 |
+
measurements (List[int]): Lista de medições dos qubits
|
| 105 |
+
|
| 106 |
+
Returns:
|
| 107 |
+
int: Bit decodificado
|
| 108 |
+
"""
|
| 109 |
+
return 1 if sum(measurements) > len(measurements)/2 else 0
|
| 110 |
+
|
| 111 |
+
def generate_random_bits(self, n: int) -> List[int]:
|
| 112 |
+
"""
|
| 113 |
+
Gera uma lista de bits aleatórios.
|
| 114 |
+
|
| 115 |
+
Args:
|
| 116 |
+
n (int): Número de bits a serem gerados
|
| 117 |
+
|
| 118 |
+
Returns:
|
| 119 |
+
List[int]: Lista de bits aleatórios
|
| 120 |
+
"""
|
| 121 |
+
return [random.randint(0, 1) for _ in range(n)]
|
| 122 |
+
|
| 123 |
+
def generate_random_bases(self, n: int) -> List[str]:
|
| 124 |
+
"""
|
| 125 |
+
Gera uma lista de bases aleatórias.
|
| 126 |
+
|
| 127 |
+
Args:
|
| 128 |
+
n (int): Número de bases a serem geradas
|
| 129 |
+
|
| 130 |
+
Returns:
|
| 131 |
+
List[str]: Lista de bases aleatórias ('Z' ou 'X')
|
| 132 |
+
"""
|
| 133 |
+
return [random.choice(['Z', 'X']) for _ in range(n)]
|
| 134 |
+
|
| 135 |
+
def simulate_transmission(self, bits: List[int], bases: List[str]) -> Tuple[List[int], List[str]]:
|
| 136 |
+
"""
|
| 137 |
+
Simula a transmissão dos qubits de Alice para Bob.
|
| 138 |
+
|
| 139 |
+
Args:
|
| 140 |
+
bits (List[int]): Bits a serem transmitidos
|
| 141 |
+
bases (List[str]): Bases usadas para codificação
|
| 142 |
+
|
| 143 |
+
Returns:
|
| 144 |
+
Tuple[List[int], List[str]]: Medições de Bob e bases escolhidas
|
| 145 |
+
"""
|
| 146 |
+
bob_bases = self.generate_random_bases(len(bits))
|
| 147 |
+
bob_measurements = []
|
| 148 |
+
|
| 149 |
+
for i in range(len(bits)):
|
| 150 |
+
# Alice prepara o qubit
|
| 151 |
+
circuit = self._prepare_qubit(bits[i], bases[i])
|
| 152 |
+
|
| 153 |
+
# Bob mede o qubit
|
| 154 |
+
circuit = self._measure_qubit(circuit, bob_bases[i])
|
| 155 |
+
|
| 156 |
+
# Executa a simulação
|
| 157 |
+
job = self.simulator.run(circuit, shots=1)
|
| 158 |
+
result = job.result()
|
| 159 |
+
counts = list(result.get_counts().keys())[0]
|
| 160 |
+
|
| 161 |
+
if self.error_correction:
|
| 162 |
+
# Decodifica as medições com correção de erros
|
| 163 |
+
measurements = [int(bit) for bit in counts]
|
| 164 |
+
measured_bit = self._error_correction_decode(measurements)
|
| 165 |
+
else:
|
| 166 |
+
measured_bit = int(counts)
|
| 167 |
+
|
| 168 |
+
bob_measurements.append(measured_bit)
|
| 169 |
+
|
| 170 |
+
return bob_measurements, bob_bases
|
| 171 |
+
|
| 172 |
+
def sift_key(self, alice_bits: List[int], alice_bases: List[str],
|
| 173 |
+
bob_measurements: List[int], bob_bases: List[str]) -> Tuple[List[int], List[int]]:
|
| 174 |
+
"""
|
| 175 |
+
Realiza o processo de peneiramento da chave.
|
| 176 |
+
|
| 177 |
+
Args:
|
| 178 |
+
alice_bits (List[int]): Bits originais de Alice
|
| 179 |
+
alice_bases (List[str]): Bases usadas por Alice
|
| 180 |
+
bob_measurements (List[int]): Medições de Bob
|
| 181 |
+
bob_bases (List[str]): Bases usadas por Bob
|
| 182 |
+
|
| 183 |
+
Returns:
|
| 184 |
+
Tuple[List[int], List[int]]: Chaves peneiradas de Alice e Bob
|
| 185 |
+
"""
|
| 186 |
+
alice_key = []
|
| 187 |
+
bob_key = []
|
| 188 |
+
|
| 189 |
+
for i in range(len(alice_bits)):
|
| 190 |
+
if alice_bases[i] == bob_bases[i]:
|
| 191 |
+
alice_key.append(alice_bits[i])
|
| 192 |
+
bob_key.append(bob_measurements[i])
|
| 193 |
+
|
| 194 |
+
return alice_key, bob_key
|
| 195 |
+
|
| 196 |
+
def check_eavesdropping(self, alice_key: List[int], bob_key: List[int],
|
| 197 |
+
sample_size: float = 0.25) -> bool:
|
| 198 |
+
"""
|
| 199 |
+
Verifica a presença de um espião comparando uma amostra das chaves.
|
| 200 |
+
|
| 201 |
+
Args:
|
| 202 |
+
alice_key (List[int]): Chave de Alice
|
| 203 |
+
bob_key (List[int]): Chave de Bob
|
| 204 |
+
sample_size (float): Proporção da chave a ser verificada
|
| 205 |
+
|
| 206 |
+
Returns:
|
| 207 |
+
bool: True se não houver evidência de espionagem, False caso contrário
|
| 208 |
+
"""
|
| 209 |
+
if len(alice_key) != len(bob_key):
|
| 210 |
+
return False
|
| 211 |
+
|
| 212 |
+
sample_length = int(len(alice_key) * sample_size)
|
| 213 |
+
indices = random.sample(range(len(alice_key)), sample_length)
|
| 214 |
+
|
| 215 |
+
differences = 0
|
| 216 |
+
for i in indices:
|
| 217 |
+
if alice_key[i] != bob_key[i]:
|
| 218 |
+
differences += 1
|
| 219 |
+
|
| 220 |
+
error_rate = differences / sample_length
|
| 221 |
+
self.logger.info(f"Taxa de erro na amostra: {error_rate:.2%}")
|
| 222 |
+
|
| 223 |
+
# Define um limite aceitável de erro (5%)
|
| 224 |
+
return error_rate < 0.05
|
| 225 |
+
|
| 226 |
+
def get_circuit_visualization(self) -> str:
|
| 227 |
+
"""
|
| 228 |
+
Implementação do método abstrato da classe base.
|
| 229 |
+
Retorna a visualização do circuito atual em ASCII.
|
| 230 |
+
|
| 231 |
+
Returns:
|
| 232 |
+
str: Representação ASCII do circuito
|
| 233 |
+
"""
|
| 234 |
+
if self.current_circuit:
|
| 235 |
+
return circuit_drawer(self.current_circuit, output='text')
|
| 236 |
+
return "Nenhum circuito disponível"
|
| 237 |
+
|
| 238 |
+
def generate_key(self) -> Dict[str, List[int]]:
|
| 239 |
+
"""
|
| 240 |
+
Implementação do método abstrato da classe base.
|
| 241 |
+
Executa o protocolo BB84 completo para gerar uma chave compartilhada.
|
| 242 |
+
|
| 243 |
+
Returns:
|
| 244 |
+
Dict[str, List[int]]: Dicionário contendo as chaves finais de Alice e Bob
|
| 245 |
+
"""
|
| 246 |
+
# Fase 1: Preparação
|
| 247 |
+
raw_bits = self.generate_random_bits(self.key_length * 4)
|
| 248 |
+
alice_bases = self.generate_random_bases(len(raw_bits))
|
| 249 |
+
|
| 250 |
+
self.logger.info(f"Iniciando protocolo BB84 para gerar chave de {self.key_length} bits")
|
| 251 |
+
self.logger.info(f"Correção de erros: {'Ativada' if self.error_correction else 'Desativada'}")
|
| 252 |
+
|
| 253 |
+
# Fase 2: Transmissão
|
| 254 |
+
bob_measurements, bob_bases = self.simulate_transmission(raw_bits, alice_bases)
|
| 255 |
+
|
| 256 |
+
# Fase 3: Peneiramento
|
| 257 |
+
alice_key, bob_key = self.sift_key(raw_bits, alice_bases, bob_measurements, bob_bases)
|
| 258 |
+
|
| 259 |
+
self.logger.info(f"Chave peneirada gerada com {len(alice_key)} bits")
|
| 260 |
+
|
| 261 |
+
# Fase 4: Detecção de espionagem
|
| 262 |
+
if not self.check_eavesdropping(alice_key, bob_key):
|
| 263 |
+
self.logger.error("Possível tentativa de espionagem detectada!")
|
| 264 |
+
return {"alice": [], "bob": []}
|
| 265 |
+
|
| 266 |
+
# Fase 5: Finalização
|
| 267 |
+
final_key_length = min(self.key_length, len(alice_key))
|
| 268 |
+
alice_final_key = alice_key[:final_key_length]
|
| 269 |
+
bob_final_key = bob_key[:final_key_length]
|
| 270 |
+
|
| 271 |
+
self.logger.info(f"Protocolo BB84 concluído com sucesso. "
|
| 272 |
+
f"Chave final de {final_key_length} bits gerada.")
|
| 273 |
+
|
| 274 |
+
return {
|
| 275 |
+
"alice": alice_final_key,
|
| 276 |
+
"bob": bob_final_key
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
def get_key_statistics(self, alice_key: List[int], bob_key: List[int]) -> Dict:
|
| 280 |
+
"""
|
| 281 |
+
Calcula estatísticas sobre as chaves geradas.
|
| 282 |
+
|
| 283 |
+
Args:
|
| 284 |
+
alice_key (List[int]): Chave de Alice
|
| 285 |
+
bob_key (List[int]): Chave de Bob
|
| 286 |
+
|
| 287 |
+
Returns:
|
| 288 |
+
Dict: Dicionário com estatísticas das chaves
|
| 289 |
+
"""
|
| 290 |
+
if not alice_key or not bob_key:
|
| 291 |
+
return {
|
| 292 |
+
"key_length": 0,
|
| 293 |
+
"error_rate": 1.0,
|
| 294 |
+
"matching_rate": 0.0,
|
| 295 |
+
"entropy": 0.0
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
differences = sum(a != b for a, b in zip(alice_key, bob_key))
|
| 299 |
+
error_rate = differences / len(alice_key)
|
| 300 |
+
|
| 301 |
+
# Calcula a entropia da chave
|
| 302 |
+
ones = sum(alice_key) / len(alice_key)
|
| 303 |
+
zeros = 1 - ones
|
| 304 |
+
if zeros == 0 or ones == 0:
|
| 305 |
+
entropy = 0
|
| 306 |
+
else:
|
| 307 |
+
entropy = -(ones * np.log2(ones) + zeros * np.log2(zeros))
|
| 308 |
+
|
| 309 |
+
return {
|
| 310 |
+
"key_length": len(alice_key),
|
| 311 |
+
"error_rate": error_rate,
|
| 312 |
+
"matching_rate": 1 - error_rate,
|
| 313 |
+
"entropy": entropy
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
def main():
|
| 317 |
+
"""Função principal para demonstração do protocolo."""
|
| 318 |
+
# Criar uma instância do protocolo
|
| 319 |
+
bb84 = BB84Protocol(key_length=64, error_correction=True)
|
| 320 |
+
|
| 321 |
+
# Gerar uma chave compartilhada
|
| 322 |
+
result = bb84.generate_key()
|
| 323 |
+
|
| 324 |
+
# Verificar se as chaves são idênticas
|
| 325 |
+
if result["alice"] and result["bob"]:
|
| 326 |
+
print("\nChave de Alice:", "".join(map(str, result["alice"])))
|
| 327 |
+
print("Chave de Bob: ", "".join(map(str, result["bob"])))
|
| 328 |
+
|
| 329 |
+
# Obter e mostrar estatísticas
|
| 330 |
+
stats = bb84.get_key_statistics(result["alice"], result["bob"])
|
| 331 |
+
print("\nEstatísticas da chave:")
|
| 332 |
+
print(f"Tamanho: {stats['key_length']} bits")
|
| 333 |
+
print(f"Taxa de erro: {stats['error_rate']:.2%}")
|
| 334 |
+
print(f"Taxa de correspondência: {stats['matching_rate']:.2%}")
|
| 335 |
+
print(f"Entropia: {stats['entropy']:.2f} bits")
|
| 336 |
+
|
| 337 |
+
# Mostrar visualização do último circuito
|
| 338 |
+
print("\nÚltimo circuito gerado:")
|
| 339 |
+
print(bb84.get_circuit_visualization())
|
| 340 |
+
else:
|
| 341 |
+
print("Falha na geração da chave - possível tentativa de espionagem detectada.")
|
src/circuit_viz.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from qiskit.visualization import circuit_drawer
|
| 2 |
+
from typing import Optional
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
|
| 5 |
+
class CircuitVisualizer:
|
| 6 |
+
"""Classe para visualização de circuitos quânticos."""
|
| 7 |
+
|
| 8 |
+
@staticmethod
|
| 9 |
+
def draw_circuit(circuit, filename: Optional[str] = None):
|
| 10 |
+
"""Desenha e opcionalmente salva o circuito."""
|
| 11 |
+
fig = plt.figure(figsize=(12, 8))
|
| 12 |
+
circuit_drawer(circuit, output='mpl')
|
| 13 |
+
if filename:
|
| 14 |
+
plt.savefig(filename)
|
| 15 |
+
plt.close()
|
src/e91.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .base import QuantumProtocol
|
| 2 |
+
from qiskit_aer import Aer
|
| 3 |
+
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
| 4 |
+
import numpy as np
|
| 5 |
+
import random
|
| 6 |
+
from typing import Dict, List, Tuple
|
| 7 |
+
from qiskit.visualization import circuit_drawer
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class E91Protocol(QuantumProtocol):
|
| 12 |
+
"""
|
| 13 |
+
Implementação do protocolo E91 (Ekert91) baseado em emaranhamento.
|
| 14 |
+
|
| 15 |
+
O protocolo E91 usa pares de qubits emaranhados e medições em diferentes ângulos
|
| 16 |
+
para estabelecer uma chave segura e verificar a presença de espionagem através
|
| 17 |
+
da violação das desigualdades de Bell.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
def __init__(self, key_length: int = 128):
|
| 21 |
+
super().__init__(key_length)
|
| 22 |
+
self.simulator = Aer.get_backend('qasm_simulator')
|
| 23 |
+
self.current_circuit = None
|
| 24 |
+
|
| 25 |
+
# Ângulos de medição para Alice e Bob
|
| 26 |
+
self.alice_angles = [0, np.pi/4, np.pi/2]
|
| 27 |
+
self.bob_angles = [np.pi/4, np.pi/2, 3*np.pi/4]
|
| 28 |
+
|
| 29 |
+
def _prepare_entangled_pair(self) -> QuantumCircuit:
|
| 30 |
+
"""
|
| 31 |
+
Prepara um par de qubits emaranhados no estado de Bell Φ+.
|
| 32 |
+
|
| 33 |
+
Returns:
|
| 34 |
+
QuantumCircuit: Circuito com o par emaranhado
|
| 35 |
+
"""
|
| 36 |
+
qr = QuantumRegister(2, 'q')
|
| 37 |
+
cr = ClassicalRegister(2, 'c')
|
| 38 |
+
qc = QuantumCircuit(qr, cr)
|
| 39 |
+
|
| 40 |
+
# Criar estado de Bell Φ+ = (|00⟩ + |11⟩)/√2
|
| 41 |
+
qc.h(qr[0])
|
| 42 |
+
qc.cx(qr[0], qr[1])
|
| 43 |
+
|
| 44 |
+
self.current_circuit = qc
|
| 45 |
+
return qc
|
| 46 |
+
|
| 47 |
+
def _measure_qubit(self, circuit: QuantumCircuit, angle: float, qubit: int) -> QuantumCircuit:
|
| 48 |
+
"""
|
| 49 |
+
Adiciona medição em um ângulo específico para um qubit.
|
| 50 |
+
|
| 51 |
+
Args:
|
| 52 |
+
circuit (QuantumCircuit): Circuito a ser medido
|
| 53 |
+
angle (float): Ângulo de medição
|
| 54 |
+
qubit (int): Índice do qubit a ser medido
|
| 55 |
+
|
| 56 |
+
Returns:
|
| 57 |
+
QuantumCircuit: Circuito com medição adicionada
|
| 58 |
+
"""
|
| 59 |
+
# Rotação para o ângulo de medição
|
| 60 |
+
circuit.ry(2*angle, qubit)
|
| 61 |
+
circuit.measure([qubit], [qubit])
|
| 62 |
+
return circuit
|
| 63 |
+
|
| 64 |
+
def _check_bell_inequality(self, correlations: List[float]) -> bool:
|
| 65 |
+
"""
|
| 66 |
+
Verifica a violação da desigualdade de CHSH.
|
| 67 |
+
|
| 68 |
+
Args:
|
| 69 |
+
correlations (List[float]): Lista de correlações medidas
|
| 70 |
+
|
| 71 |
+
Returns:
|
| 72 |
+
bool: True se a desigualdade for violada (indicando ausência de espião)
|
| 73 |
+
"""
|
| 74 |
+
# Cálculo do parâmetro S da desigualdade CHSH
|
| 75 |
+
S = abs(sum(correlations))
|
| 76 |
+
# O valor teórico máximo é 2√2 ≈ 2.82
|
| 77 |
+
# Um valor > 2 indica violação da desigualdade
|
| 78 |
+
return S > 2
|
| 79 |
+
|
| 80 |
+
def _calculate_correlation(self, alice_results: List[int],
|
| 81 |
+
bob_results: List[int]) -> float:
|
| 82 |
+
"""
|
| 83 |
+
Calcula a correlação entre as medições de Alice e Bob.
|
| 84 |
+
|
| 85 |
+
Args:
|
| 86 |
+
alice_results (List[int]): Resultados das medições de Alice
|
| 87 |
+
bob_results (List[int]): Resultados das medições de Bob
|
| 88 |
+
|
| 89 |
+
Returns:
|
| 90 |
+
float: Valor da correlação (-1 a 1)
|
| 91 |
+
"""
|
| 92 |
+
if not alice_results or not bob_results:
|
| 93 |
+
return 0
|
| 94 |
+
|
| 95 |
+
return np.mean([a == b for a, b in zip(alice_results, bob_results)])
|
| 96 |
+
|
| 97 |
+
def generate_key(self) -> Dict[str, List[int]]:
|
| 98 |
+
"""
|
| 99 |
+
Executa o protocolo E91 completo para gerar uma chave compartilhada.
|
| 100 |
+
|
| 101 |
+
Returns:
|
| 102 |
+
Dict[str, List[int]]: Dicionário contendo as chaves finais de Alice e Bob
|
| 103 |
+
"""
|
| 104 |
+
self.logger.info(f"Iniciando protocolo E91 para gerar chave de {self.key_length} bits")
|
| 105 |
+
|
| 106 |
+
alice_key = []
|
| 107 |
+
bob_key = []
|
| 108 |
+
correlations = []
|
| 109 |
+
|
| 110 |
+
# Precisamos de mais pares para compensar descartes
|
| 111 |
+
num_pairs = self.key_length * 4
|
| 112 |
+
|
| 113 |
+
for _ in range(num_pairs):
|
| 114 |
+
# Preparar par emaranhado
|
| 115 |
+
circuit = self._prepare_entangled_pair()
|
| 116 |
+
|
| 117 |
+
# Alice e Bob escolhem ângulos aleatoriamente
|
| 118 |
+
alice_angle = random.choice(self.alice_angles)
|
| 119 |
+
bob_angle = random.choice(self.bob_angles)
|
| 120 |
+
|
| 121 |
+
# Adicionar medições
|
| 122 |
+
circuit = self._measure_qubit(circuit, alice_angle, 0) # Alice
|
| 123 |
+
circuit = self._measure_qubit(circuit, bob_angle, 1) # Bob
|
| 124 |
+
|
| 125 |
+
# Executar circuito
|
| 126 |
+
job = self.simulator.run(circuit, shots=1)
|
| 127 |
+
result = job.result()
|
| 128 |
+
counts = list(result.get_counts().keys())[0]
|
| 129 |
+
alice_result = int(counts[0])
|
| 130 |
+
bob_result = int(counts[1])
|
| 131 |
+
|
| 132 |
+
# Verificar se os ângulos são compatíveis para a chave
|
| 133 |
+
if alice_angle == bob_angle:
|
| 134 |
+
alice_key.append(alice_result)
|
| 135 |
+
bob_key.append(bob_result)
|
| 136 |
+
else:
|
| 137 |
+
# Usar para teste de Bell
|
| 138 |
+
correlation = self._calculate_correlation([alice_result], [bob_result])
|
| 139 |
+
correlations.append(correlation)
|
| 140 |
+
|
| 141 |
+
# Verificar violação da desigualdade de Bell
|
| 142 |
+
if not self._check_bell_inequality(correlations):
|
| 143 |
+
self.logger.error("Possível espionagem detectada - violação de Bell não observada!")
|
| 144 |
+
return {"alice": [], "bob": []}
|
| 145 |
+
|
| 146 |
+
# Cortar para o tamanho desejado
|
| 147 |
+
alice_key = alice_key[:self.key_length]
|
| 148 |
+
bob_key = bob_key[:self.key_length]
|
| 149 |
+
|
| 150 |
+
self.logger.info(f"Protocolo E91 concluído com sucesso. "
|
| 151 |
+
f"Chave final de {len(alice_key)} bits gerada.")
|
| 152 |
+
|
| 153 |
+
return {
|
| 154 |
+
"alice": alice_key,
|
| 155 |
+
"bob": bob_key
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
def get_circuit_visualization(self) -> str:
|
| 159 |
+
"""
|
| 160 |
+
Retorna a visualização do circuito atual em ASCII.
|
| 161 |
+
|
| 162 |
+
Returns:
|
| 163 |
+
str: Representação ASCII do circuito
|
| 164 |
+
"""
|
| 165 |
+
if self.current_circuit:
|
| 166 |
+
return circuit_drawer(self.current_circuit, output='text')
|
| 167 |
+
return "Nenhum circuito disponível"
|
src/generate.py
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
| 2 |
+
from qiskit_aer import Aer
|
| 3 |
+
from qiskit.visualization import plot_histogram
|
| 4 |
+
import numpy as np
|
| 5 |
+
import random
|
| 6 |
+
from typing import List, Tuple, Dict
|
| 7 |
+
import logging
|
| 8 |
+
|
| 9 |
+
class BB84Protocol:
|
| 10 |
+
def __init__(self, key_length: int = 128):
|
| 11 |
+
"""
|
| 12 |
+
Inicializa o protocolo BB84 com o tamanho desejado da chave.
|
| 13 |
+
|
| 14 |
+
Args:
|
| 15 |
+
key_length (int): Tamanho desejado da chave final em bits
|
| 16 |
+
"""
|
| 17 |
+
self.key_length = key_length
|
| 18 |
+
self.simulator = Aer.get_backend('qasm_simulator')
|
| 19 |
+
|
| 20 |
+
# Configuração do logging
|
| 21 |
+
logging.basicConfig(level=logging.INFO)
|
| 22 |
+
self.logger = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
def _prepare_qubit(self, bit: int, basis: str) -> QuantumCircuit:
|
| 25 |
+
"""
|
| 26 |
+
Prepara um único qubit no estado e base especificados.
|
| 27 |
+
|
| 28 |
+
Args:
|
| 29 |
+
bit (int): Bit a ser codificado (0 ou 1)
|
| 30 |
+
basis (str): Base de medição ('Z' para rectilinear ou 'X' para diagonal)
|
| 31 |
+
|
| 32 |
+
Returns:
|
| 33 |
+
QuantumCircuit: Circuito quântico preparado
|
| 34 |
+
"""
|
| 35 |
+
qr = QuantumRegister(1)
|
| 36 |
+
cr = ClassicalRegister(1)
|
| 37 |
+
qc = QuantumCircuit(qr, cr)
|
| 38 |
+
|
| 39 |
+
# Prepara o estado do qubit
|
| 40 |
+
if bit == 1:
|
| 41 |
+
qc.x(qr[0])
|
| 42 |
+
|
| 43 |
+
# Aplica a transformação de base se necessário
|
| 44 |
+
if basis == 'X':
|
| 45 |
+
qc.h(qr[0])
|
| 46 |
+
|
| 47 |
+
return qc
|
| 48 |
+
|
| 49 |
+
def _measure_qubit(self, circuit: QuantumCircuit, basis: str) -> QuantumCircuit:
|
| 50 |
+
"""
|
| 51 |
+
Adiciona a medição em uma base específica ao circuito.
|
| 52 |
+
|
| 53 |
+
Args:
|
| 54 |
+
circuit (QuantumCircuit): Circuito a ser medido
|
| 55 |
+
basis (str): Base de medição ('Z' ou 'X')
|
| 56 |
+
|
| 57 |
+
Returns:
|
| 58 |
+
QuantumCircuit: Circuito com medição adicionada
|
| 59 |
+
"""
|
| 60 |
+
if basis == 'X':
|
| 61 |
+
circuit.h(0)
|
| 62 |
+
circuit.measure([0], [0])
|
| 63 |
+
return circuit
|
| 64 |
+
|
| 65 |
+
def generate_random_bits(self, n: int) -> List[int]:
|
| 66 |
+
"""
|
| 67 |
+
Gera uma lista de bits aleatórios.
|
| 68 |
+
|
| 69 |
+
Args:
|
| 70 |
+
n (int): Número de bits a serem gerados
|
| 71 |
+
|
| 72 |
+
Returns:
|
| 73 |
+
List[int]: Lista de bits aleatórios
|
| 74 |
+
"""
|
| 75 |
+
return [random.randint(0, 1) for _ in range(n)]
|
| 76 |
+
|
| 77 |
+
def generate_random_bases(self, n: int) -> List[str]:
|
| 78 |
+
"""
|
| 79 |
+
Gera uma lista de bases aleatórias.
|
| 80 |
+
|
| 81 |
+
Args:
|
| 82 |
+
n (int): Número de bases a serem geradas
|
| 83 |
+
|
| 84 |
+
Returns:
|
| 85 |
+
List[str]: Lista de bases aleatórias ('Z' ou 'X')
|
| 86 |
+
"""
|
| 87 |
+
return [random.choice(['Z', 'X']) for _ in range(n)]
|
| 88 |
+
|
| 89 |
+
def simulate_transmission(self, bits: List[int], bases: List[str]) -> Tuple[List[int], List[str]]:
|
| 90 |
+
"""
|
| 91 |
+
Simula a transmissão dos qubits de Alice para Bob.
|
| 92 |
+
|
| 93 |
+
Args:
|
| 94 |
+
bits (List[int]): Bits a serem transmitidos
|
| 95 |
+
bases (List[str]): Bases usadas para codificação
|
| 96 |
+
|
| 97 |
+
Returns:
|
| 98 |
+
Tuple[List[int], List[str]]: Medições de Bob e bases escolhidas
|
| 99 |
+
"""
|
| 100 |
+
bob_bases = self.generate_random_bases(len(bits))
|
| 101 |
+
bob_measurements = []
|
| 102 |
+
|
| 103 |
+
for i in range(len(bits)):
|
| 104 |
+
# Alice prepara o qubit
|
| 105 |
+
circuit = self._prepare_qubit(bits[i], bases[i])
|
| 106 |
+
|
| 107 |
+
# Bob mede o qubit
|
| 108 |
+
circuit = self._measure_qubit(circuit, bob_bases[i])
|
| 109 |
+
|
| 110 |
+
# Executa a simulação usando a nova API do Qiskit
|
| 111 |
+
job = self.simulator.run(circuit, shots=1)
|
| 112 |
+
result = job.result()
|
| 113 |
+
counts = result.get_counts()
|
| 114 |
+
measured_bit = int(list(counts.keys())[0])
|
| 115 |
+
bob_measurements.append(measured_bit)
|
| 116 |
+
|
| 117 |
+
return bob_measurements, bob_bases
|
| 118 |
+
|
| 119 |
+
def sift_key(self, alice_bits: List[int], alice_bases: List[str],
|
| 120 |
+
bob_measurements: List[int], bob_bases: List[str]) -> Tuple[List[int], List[int]]:
|
| 121 |
+
"""
|
| 122 |
+
Realiza o processo de peneiramento da chave.
|
| 123 |
+
|
| 124 |
+
Args:
|
| 125 |
+
alice_bits (List[int]): Bits originais de Alice
|
| 126 |
+
alice_bases (List[str]): Bases usadas por Alice
|
| 127 |
+
bob_measurements (List[int]): Medições de Bob
|
| 128 |
+
bob_bases (List[str]): Bases usadas por Bob
|
| 129 |
+
|
| 130 |
+
Returns:
|
| 131 |
+
Tuple[List[int], List[int]]: Chaves peneiradas de Alice e Bob
|
| 132 |
+
"""
|
| 133 |
+
alice_key = []
|
| 134 |
+
bob_key = []
|
| 135 |
+
|
| 136 |
+
for i in range(len(alice_bits)):
|
| 137 |
+
if alice_bases[i] == bob_bases[i]:
|
| 138 |
+
alice_key.append(alice_bits[i])
|
| 139 |
+
bob_key.append(bob_measurements[i])
|
| 140 |
+
|
| 141 |
+
return alice_key, bob_key
|
| 142 |
+
|
| 143 |
+
def check_eavesdropping(self, alice_key: List[int], bob_key: List[int],
|
| 144 |
+
sample_size: float = 0.25) -> bool:
|
| 145 |
+
"""
|
| 146 |
+
Verifica a presença de um espião comparando uma amostra das chaves.
|
| 147 |
+
|
| 148 |
+
Args:
|
| 149 |
+
alice_key (List[int]): Chave de Alice
|
| 150 |
+
bob_key (List[int]): Chave de Bob
|
| 151 |
+
sample_size (float): Proporção da chave a ser verificada
|
| 152 |
+
|
| 153 |
+
Returns:
|
| 154 |
+
bool: True se não houver evidência de espionagem, False caso contrário
|
| 155 |
+
"""
|
| 156 |
+
if len(alice_key) != len(bob_key):
|
| 157 |
+
return False
|
| 158 |
+
|
| 159 |
+
sample_length = int(len(alice_key) * sample_size)
|
| 160 |
+
indices = random.sample(range(len(alice_key)), sample_length)
|
| 161 |
+
|
| 162 |
+
differences = 0
|
| 163 |
+
for i in indices:
|
| 164 |
+
if alice_key[i] != bob_key[i]:
|
| 165 |
+
differences += 1
|
| 166 |
+
|
| 167 |
+
error_rate = differences / sample_length
|
| 168 |
+
self.logger.info(f"Taxa de erro na amostra: {error_rate:.2%}")
|
| 169 |
+
|
| 170 |
+
# Define um limite aceitável de erro (por exemplo, 5%)
|
| 171 |
+
return error_rate < 0.05
|
| 172 |
+
|
| 173 |
+
def generate_key(self) -> Dict[str, List[int]]:
|
| 174 |
+
"""
|
| 175 |
+
Executa o protocolo BB84 completo para gerar uma chave compartilhada.
|
| 176 |
+
|
| 177 |
+
Returns:
|
| 178 |
+
Dict[str, List[int]]: Dicionário contendo as chaves finais de Alice e Bob
|
| 179 |
+
"""
|
| 180 |
+
# Fase 1: Preparação
|
| 181 |
+
raw_bits = self.generate_random_bits(self.key_length * 4) # Geramos mais bits para compensar o peneiramento
|
| 182 |
+
alice_bases = self.generate_random_bases(len(raw_bits))
|
| 183 |
+
|
| 184 |
+
self.logger.info(f"Iniciando protocolo BB84 para gerar chave de {self.key_length} bits")
|
| 185 |
+
|
| 186 |
+
# Fase 2: Transmissão
|
| 187 |
+
bob_measurements, bob_bases = self.simulate_transmission(raw_bits, alice_bases)
|
| 188 |
+
|
| 189 |
+
# Fase 3: Peneiramento
|
| 190 |
+
alice_key, bob_key = self.sift_key(raw_bits, alice_bases, bob_measurements, bob_bases)
|
| 191 |
+
|
| 192 |
+
self.logger.info(f"Chave peneirada gerada com {len(alice_key)} bits")
|
| 193 |
+
|
| 194 |
+
# Fase 4: Detecção de espionagem
|
| 195 |
+
if not self.check_eavesdropping(alice_key, bob_key):
|
| 196 |
+
self.logger.error("Possível tentativa de espionagem detectada!")
|
| 197 |
+
return {"alice": [], "bob": []}
|
| 198 |
+
|
| 199 |
+
# Fase 5: Finalização
|
| 200 |
+
final_key_length = min(self.key_length, len(alice_key))
|
| 201 |
+
alice_final_key = alice_key[:final_key_length]
|
| 202 |
+
bob_final_key = bob_key[:final_key_length]
|
| 203 |
+
|
| 204 |
+
self.logger.info(f"Protocolo BB84 concluído com sucesso. Chave final de {final_key_length} bits gerada.")
|
| 205 |
+
|
| 206 |
+
return {
|
| 207 |
+
"alice": alice_final_key,
|
| 208 |
+
"bob": bob_final_key
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
# Exemplo de uso
|
| 212 |
+
if __name__ == "__main__":
|
| 213 |
+
# Criar uma instância do protocolo
|
| 214 |
+
bb84 = BB84Protocol(key_length=64)
|
| 215 |
+
|
| 216 |
+
# Gerar uma chave compartilhada
|
| 217 |
+
result = bb84.generate_key()
|
| 218 |
+
|
| 219 |
+
# Verificar se as chaves são idênticas
|
| 220 |
+
if result["alice"] and result["bob"]:
|
| 221 |
+
print("\nChave de Alice:", "".join(map(str, result["alice"])))
|
| 222 |
+
print("Chave de Bob: ", "".join(map(str, result["bob"])))
|
| 223 |
+
print("\nAs chaves são idênticas?", result["alice"] == result["bob"])
|
| 224 |
+
print("Tamanho da chave:", len(result["alice"]), "bits")
|
| 225 |
+
else:
|
| 226 |
+
print("Falha na geração da chave - possível tentativa de espionagem detectada.")
|
src/qec.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
|
| 3 |
+
class QuantumErrorCorrection:
|
| 4 |
+
"""Implementação de correção de erros quânticos."""
|
| 5 |
+
|
| 6 |
+
@staticmethod
|
| 7 |
+
def encode_message(bits: List[int]) -> List[int]:
|
| 8 |
+
"""Codifica uma mensagem usando código de repetição."""
|
| 9 |
+
encoded = []
|
| 10 |
+
for bit in bits:
|
| 11 |
+
# Implementa código de repetição de 3 qubits
|
| 12 |
+
encoded.extend([bit] * 3)
|
| 13 |
+
return encoded
|
| 14 |
+
|
| 15 |
+
@staticmethod
|
| 16 |
+
def decode_message(encoded_bits: List[int]) -> List[int]:
|
| 17 |
+
"""Decodifica uma mensagem usando voto majoritário."""
|
| 18 |
+
decoded = []
|
| 19 |
+
for i in range(0, len(encoded_bits), 3):
|
| 20 |
+
chunk = encoded_bits[i:i+3]
|
| 21 |
+
# Voto majoritário
|
| 22 |
+
bit = 1 if sum(chunk) > len(chunk)/2 else 0
|
| 23 |
+
decoded.append(bit)
|
| 24 |
+
return decoded
|