Spaces:
Sleeping
Sleeping
| from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister | |
| from qiskit.visualization import circuit_drawer | |
| from qiskit_aer import Aer | |
| import numpy as np | |
| import random | |
| from typing import Dict, List, Tuple, Optional | |
| import logging | |
| from .base import QuantumProtocol | |
| class BB84Protocol(QuantumProtocol): | |
| """ | |
| Implementação do protocolo BB84 para distribuição quântica de chaves. | |
| Herda da classe base QuantumProtocol e implementa correção de erros quânticos. | |
| """ | |
| def __init__(self, key_length: int = 128, error_correction: bool = True): | |
| """ | |
| Inicializa o protocolo BB84. | |
| Args: | |
| key_length (int): Tamanho desejado da chave final em bits | |
| error_correction (bool): Se True, utiliza correção de erros quânticos | |
| """ | |
| super().__init__(key_length) # Chama o construtor da classe base | |
| self.error_correction = error_correction | |
| self.simulator = Aer.get_backend('qasm_simulator') | |
| self.current_circuit = None | |
| def _prepare_qubit(self, bit: int, basis: str) -> QuantumCircuit: | |
| """ | |
| Prepara um único qubit no estado e base especificados. | |
| Args: | |
| bit (int): Bit a ser codificado (0 ou 1) | |
| basis (str): Base de medição ('Z' para rectilinear ou 'X' para diagonal) | |
| Returns: | |
| QuantumCircuit: Circuito quântico preparado | |
| """ | |
| if self.error_correction: | |
| # Circuito com correção de erros (código de repetição de 3 qubits) | |
| qr = QuantumRegister(3, 'q') | |
| cr = ClassicalRegister(1, 'c') | |
| qc = QuantumCircuit(qr, cr) | |
| # Prepara o estado base | |
| if bit == 1: | |
| qc.x(qr[0]) | |
| # Aplica o código de repetição | |
| qc.cx(qr[0], qr[1]) # CNOT para copiar o estado | |
| qc.cx(qr[0], qr[2]) | |
| # Aplica a transformação de base se necessário | |
| if basis == 'X': | |
| qc.h(qr) # Aplica H em todos os qubits | |
| else: | |
| # Circuito simples sem correção | |
| qr = QuantumRegister(1, 'q') | |
| cr = ClassicalRegister(1, 'c') | |
| qc = QuantumCircuit(qr, cr) | |
| # Prepara o estado | |
| if bit == 1: | |
| qc.x(qr[0]) | |
| if basis == 'X': | |
| qc.h(qr[0]) | |
| self.current_circuit = qc | |
| return qc | |
| def _measure_qubit(self, circuit: QuantumCircuit, basis: str) -> QuantumCircuit: | |
| """ | |
| Adiciona medição em uma base específica ao circuito. | |
| Args: | |
| circuit (QuantumCircuit): Circuito a ser medido | |
| basis (str): Base de medição ('Z' ou 'X') | |
| Returns: | |
| QuantumCircuit: Circuito com medição adicionada | |
| """ | |
| if self.error_correction: | |
| # Medição com correção de erros | |
| if basis == 'X': | |
| circuit.h(range(3)) # Aplica H em todos os qubits para base X | |
| # Medição em todos os qubits | |
| circuit.measure_all() | |
| else: | |
| # Medição simples | |
| if basis == 'X': | |
| circuit.h(0) | |
| circuit.measure([0], [0]) | |
| return circuit | |
| def _error_correction_decode(self, measurements: List[int]) -> int: | |
| """ | |
| Decodifica medições usando voto majoritário para correção de erros. | |
| Args: | |
| measurements (List[int]): Lista de medições dos qubits | |
| Returns: | |
| int: Bit decodificado | |
| """ | |
| return 1 if sum(measurements) > len(measurements)/2 else 0 | |
| def generate_random_bits(self, n: int) -> List[int]: | |
| """ | |
| Gera uma lista de bits aleatórios. | |
| Args: | |
| n (int): Número de bits a serem gerados | |
| Returns: | |
| List[int]: Lista de bits aleatórios | |
| """ | |
| return [random.randint(0, 1) for _ in range(n)] | |
| def generate_random_bases(self, n: int) -> List[str]: | |
| """ | |
| Gera uma lista de bases aleatórias. | |
| Args: | |
| n (int): Número de bases a serem geradas | |
| Returns: | |
| List[str]: Lista de bases aleatórias ('Z' ou 'X') | |
| """ | |
| return [random.choice(['Z', 'X']) for _ in range(n)] | |
| def simulate_transmission(self, bits: List[int], bases: List[str]) -> Tuple[List[int], List[str]]: | |
| """ | |
| Simula a transmissão dos qubits de Alice para Bob. | |
| Args: | |
| bits (List[int]): Bits a serem transmitidos | |
| bases (List[str]): Bases usadas para codificação | |
| Returns: | |
| Tuple[List[int], List[str]]: Medições de Bob e bases escolhidas | |
| """ | |
| bob_bases = self.generate_random_bases(len(bits)) | |
| bob_measurements = [] | |
| for i in range(len(bits)): | |
| # Alice prepara o qubit | |
| circuit = self._prepare_qubit(bits[i], bases[i]) | |
| # Bob mede o qubit | |
| circuit = self._measure_qubit(circuit, bob_bases[i]) | |
| # Executa a simulação | |
| job = self.simulator.run(circuit, shots=1) | |
| result = job.result() | |
| counts = list(result.get_counts().keys())[0] | |
| if self.error_correction: | |
| # Decodifica as medições com correção de erros | |
| measurements = [int(bit) for bit in counts] | |
| measured_bit = self._error_correction_decode(measurements) | |
| else: | |
| measured_bit = int(counts) | |
| bob_measurements.append(measured_bit) | |
| return bob_measurements, bob_bases | |
| def sift_key(self, alice_bits: List[int], alice_bases: List[str], | |
| bob_measurements: List[int], bob_bases: List[str]) -> Tuple[List[int], List[int]]: | |
| """ | |
| Realiza o processo de peneiramento da chave. | |
| Args: | |
| alice_bits (List[int]): Bits originais de Alice | |
| alice_bases (List[str]): Bases usadas por Alice | |
| bob_measurements (List[int]): Medições de Bob | |
| bob_bases (List[str]): Bases usadas por Bob | |
| Returns: | |
| Tuple[List[int], List[int]]: Chaves peneiradas de Alice e Bob | |
| """ | |
| alice_key = [] | |
| bob_key = [] | |
| for i in range(len(alice_bits)): | |
| if alice_bases[i] == bob_bases[i]: | |
| alice_key.append(alice_bits[i]) | |
| bob_key.append(bob_measurements[i]) | |
| return alice_key, bob_key | |
| def check_eavesdropping(self, alice_key: List[int], bob_key: List[int], | |
| sample_size: float = 0.25) -> bool: | |
| """ | |
| Verifica a presença de um espião comparando uma amostra das chaves. | |
| Args: | |
| alice_key (List[int]): Chave de Alice | |
| bob_key (List[int]): Chave de Bob | |
| sample_size (float): Proporção da chave a ser verificada | |
| Returns: | |
| bool: True se não houver evidência de espionagem, False caso contrário | |
| """ | |
| if len(alice_key) != len(bob_key): | |
| return False | |
| sample_length = int(len(alice_key) * sample_size) | |
| indices = random.sample(range(len(alice_key)), sample_length) | |
| differences = 0 | |
| for i in indices: | |
| if alice_key[i] != bob_key[i]: | |
| differences += 1 | |
| error_rate = differences / sample_length | |
| self.logger.info(f"Taxa de erro na amostra: {error_rate:.2%}") | |
| # Define um limite aceitável de erro (5%) | |
| return error_rate < 0.05 | |
| def get_circuit_visualization(self) -> str: | |
| """ | |
| Implementação do método abstrato da classe base. | |
| 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" | |
| def generate_key(self) -> Dict[str, List[int]]: | |
| """ | |
| Implementação do método abstrato da classe base. | |
| Executa o protocolo BB84 completo para gerar uma chave compartilhada. | |
| Returns: | |
| Dict[str, List[int]]: Dicionário contendo as chaves finais de Alice e Bob | |
| """ | |
| # Fase 1: Preparação | |
| raw_bits = self.generate_random_bits(self.key_length * 4) | |
| alice_bases = self.generate_random_bases(len(raw_bits)) | |
| self.logger.info(f"Iniciando protocolo BB84 para gerar chave de {self.key_length} bits") | |
| self.logger.info(f"Correção de erros: {'Ativada' if self.error_correction else 'Desativada'}") | |
| # Fase 2: Transmissão | |
| bob_measurements, bob_bases = self.simulate_transmission(raw_bits, alice_bases) | |
| # Fase 3: Peneiramento | |
| alice_key, bob_key = self.sift_key(raw_bits, alice_bases, bob_measurements, bob_bases) | |
| self.logger.info(f"Chave peneirada gerada com {len(alice_key)} bits") | |
| # Fase 4: Detecção de espionagem | |
| if not self.check_eavesdropping(alice_key, bob_key): | |
| self.logger.error("Possível tentativa de espionagem detectada!") | |
| return {"alice": [], "bob": []} | |
| # Fase 5: Finalização | |
| final_key_length = min(self.key_length, len(alice_key)) | |
| alice_final_key = alice_key[:final_key_length] | |
| bob_final_key = bob_key[:final_key_length] | |
| self.logger.info(f"Protocolo BB84 concluído com sucesso. " | |
| f"Chave final de {final_key_length} bits gerada.") | |
| return { | |
| "alice": alice_final_key, | |
| "bob": bob_final_key | |
| } | |
| def get_key_statistics(self, alice_key: List[int], bob_key: List[int]) -> Dict: | |
| """ | |
| Calcula estatísticas sobre as chaves geradas. | |
| Args: | |
| alice_key (List[int]): Chave de Alice | |
| bob_key (List[int]): Chave de Bob | |
| Returns: | |
| Dict: Dicionário com estatísticas das chaves | |
| """ | |
| if not alice_key or not bob_key: | |
| return { | |
| "key_length": 0, | |
| "error_rate": 1.0, | |
| "matching_rate": 0.0, | |
| "entropy": 0.0 | |
| } | |
| differences = sum(a != b for a, b in zip(alice_key, bob_key)) | |
| error_rate = differences / len(alice_key) | |
| # Calcula a entropia da chave | |
| ones = sum(alice_key) / len(alice_key) | |
| zeros = 1 - ones | |
| if zeros == 0 or ones == 0: | |
| entropy = 0 | |
| else: | |
| entropy = -(ones * np.log2(ones) + zeros * np.log2(zeros)) | |
| return { | |
| "key_length": len(alice_key), | |
| "error_rate": error_rate, | |
| "matching_rate": 1 - error_rate, | |
| "entropy": entropy | |
| } | |
| def main(): | |
| """Função principal para demonstração do protocolo.""" | |
| # Criar uma instância do protocolo | |
| bb84 = BB84Protocol(key_length=64, error_correction=True) | |
| # Gerar uma chave compartilhada | |
| result = bb84.generate_key() | |
| # Verificar se as chaves são idênticas | |
| if result["alice"] and result["bob"]: | |
| print("\nChave de Alice:", "".join(map(str, result["alice"]))) | |
| print("Chave de Bob: ", "".join(map(str, result["bob"]))) | |
| # Obter e mostrar estatísticas | |
| stats = bb84.get_key_statistics(result["alice"], result["bob"]) | |
| print("\nEstatísticas da chave:") | |
| print(f"Tamanho: {stats['key_length']} bits") | |
| print(f"Taxa de erro: {stats['error_rate']:.2%}") | |
| print(f"Taxa de correspondência: {stats['matching_rate']:.2%}") | |
| print(f"Entropia: {stats['entropy']:.2f} bits") | |
| # Mostrar visualização do último circuito | |
| print("\nÚltimo circuito gerado:") | |
| print(bb84.get_circuit_visualization()) | |
| else: | |
| print("Falha na geração da chave - possível tentativa de espionagem detectada.") | |