File size: 6,075 Bytes
0173bbf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from .base import QuantumProtocol
from qiskit_aer import Aer
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
import numpy as np
import random
from typing import Dict, List, Tuple
from qiskit.visualization import circuit_drawer



class E91Protocol(QuantumProtocol):
    """
    Implementação do protocolo E91 (Ekert91) baseado em emaranhamento.
    
    O protocolo E91 usa pares de qubits emaranhados e medições em diferentes ângulos
    para estabelecer uma chave segura e verificar a presença de espionagem através
    da violação das desigualdades de Bell.
    """
    
    def __init__(self, key_length: int = 128):
        super().__init__(key_length)
        self.simulator = Aer.get_backend('qasm_simulator')
        self.current_circuit = None
        
        # Ângulos de medição para Alice e Bob
        self.alice_angles = [0, np.pi/4, np.pi/2]
        self.bob_angles = [np.pi/4, np.pi/2, 3*np.pi/4]
    
    def _prepare_entangled_pair(self) -> QuantumCircuit:
        """
        Prepara um par de qubits emaranhados no estado de Bell Φ+.
        
        Returns:
            QuantumCircuit: Circuito com o par emaranhado
        """
        qr = QuantumRegister(2, 'q')
        cr = ClassicalRegister(2, 'c')
        qc = QuantumCircuit(qr, cr)
        
        # Criar estado de Bell Φ+ = (|00⟩ + |11⟩)/√2
        qc.h(qr[0])
        qc.cx(qr[0], qr[1])
        
        self.current_circuit = qc
        return qc
    
    def _measure_qubit(self, circuit: QuantumCircuit, angle: float, qubit: int) -> QuantumCircuit:
        """
        Adiciona medição em um ângulo específico para um qubit.
        
        Args:
            circuit (QuantumCircuit): Circuito a ser medido
            angle (float): Ângulo de medição
            qubit (int): Índice do qubit a ser medido
            
        Returns:
            QuantumCircuit: Circuito com medição adicionada
        """
        # Rotação para o ângulo de medição
        circuit.ry(2*angle, qubit)
        circuit.measure([qubit], [qubit])
        return circuit

    def _check_bell_inequality(self, correlations: List[float]) -> bool:
        """
        Verifica a violação da desigualdade de CHSH.
        
        Args:
            correlations (List[float]): Lista de correlações medidas
            
        Returns:
            bool: True se a desigualdade for violada (indicando ausência de espião)
        """
        # Cálculo do parâmetro S da desigualdade CHSH
        S = abs(sum(correlations))
        # O valor teórico máximo é 2√2 ≈ 2.82
        # Um valor > 2 indica violação da desigualdade
        return S > 2
    
    def _calculate_correlation(self, alice_results: List[int], 
                             bob_results: List[int]) -> float:
        """
        Calcula a correlação entre as medições de Alice e Bob.
        
        Args:
            alice_results (List[int]): Resultados das medições de Alice
            bob_results (List[int]): Resultados das medições de Bob
            
        Returns:
            float: Valor da correlação (-1 a 1)
        """
        if not alice_results or not bob_results:
            return 0
        
        return np.mean([a == b for a, b in zip(alice_results, bob_results)])

    def generate_key(self) -> Dict[str, List[int]]:
        """
        Executa o protocolo E91 completo para gerar uma chave compartilhada.
        
        Returns:
            Dict[str, List[int]]: Dicionário contendo as chaves finais de Alice e Bob
        """
        self.logger.info(f"Iniciando protocolo E91 para gerar chave de {self.key_length} bits")
        
        alice_key = []
        bob_key = []
        correlations = []
        
        # Precisamos de mais pares para compensar descartes
        num_pairs = self.key_length * 4
        
        for _ in range(num_pairs):
            # Preparar par emaranhado
            circuit = self._prepare_entangled_pair()
            
            # Alice e Bob escolhem ângulos aleatoriamente
            alice_angle = random.choice(self.alice_angles)
            bob_angle = random.choice(self.bob_angles)
            
            # Adicionar medições
            circuit = self._measure_qubit(circuit, alice_angle, 0)  # Alice
            circuit = self._measure_qubit(circuit, bob_angle, 1)    # Bob
            
            # Executar circuito
            job = self.simulator.run(circuit, shots=1)
            result = job.result()
            counts = list(result.get_counts().keys())[0]
            alice_result = int(counts[0])
            bob_result = int(counts[1])
            
            # Verificar se os ângulos são compatíveis para a chave
            if alice_angle == bob_angle:
                alice_key.append(alice_result)
                bob_key.append(bob_result)
            else:
                # Usar para teste de Bell
                correlation = self._calculate_correlation([alice_result], [bob_result])
                correlations.append(correlation)
        
        # Verificar violação da desigualdade de Bell
        if not self._check_bell_inequality(correlations):
            self.logger.error("Possível espionagem detectada - violação de Bell não observada!")
            return {"alice": [], "bob": []}
        
        # Cortar para o tamanho desejado
        alice_key = alice_key[:self.key_length]
        bob_key = bob_key[:self.key_length]
        
        self.logger.info(f"Protocolo E91 concluído com sucesso. "
                        f"Chave final de {len(alice_key)} bits gerada.")
        
        return {
            "alice": alice_key,
            "bob": bob_key
        }

    def get_circuit_visualization(self) -> str:
        """
        Retorna a visualização do circuito atual em ASCII.
        
        Returns:
            str: Representação ASCII do circuito
        """
        if self.current_circuit:
            return circuit_drawer(self.current_circuit, output='text')
        return "Nenhum circuito disponível"