Los ordenadores cuánticos disponibles en el mercado pueden superar secp5k1. Todavía está a unos 2 órdenes de magnitud de distancia... Por ahora.
Steve Tippeconnic
Steve Tippeconnic27 jun 2025
Rompiendo una clave de curva elíptica de 5 bits con un ordenador ⚛️ cuántico de 133 qubits Este experimento rompe una clave criptográfica de curva elíptica de 5 bits utilizando el algoritmo de Shor. Ejecutado en el ibm_torino de 133 qubits de @IBM con @qiskit, un circuito de 15 qubits, compuesto por 10 qubits lógicos y 5 ancilla, interfiere sobre Z₃₂ para extraer el escalar secreto k de la relación de clave pública Q = kP, sin codificar nunca k directamente en el oráculo. A partir de 16.384 disparos, la interferencia cuántica revela una cresta diagonal en el espacio de resultados QFT de 32x32. El circuito cuántico, de más de 67.000 capas de profundidad, produjo patrones de interferencia válidos a pesar de la extrema profundidad del circuito, y el posprocesamiento clásico reveló k = 7 en los 100 primeros resultados invertibles. Tutorial de código 1. Codificación de grupo Restrinja la atención al subgrupo de orden 32 ⟨P⟩ de una curva elíptica sobre F_p. Asignar puntos a números enteros: 0P -> 0, 1P -> 1, ..., 31P -> 31. El derecho de grupo se convierte en una adición modular: (xP) + (yP) = ((x + y) mod 32))P. Este experimento utiliza una curva elíptica sobre F_p con un subgrupo cíclico de orden 32, mapeando P -> 1 y Q = 7P -> 23 en Z₃₂. El código asume la multiplicación escalar precalculada, abstrayendo las coordenadas explícitas. 2. Registros cuánticos Registro a: cinco qubits para el exponente a ∈ {0, ..., 31}. Registro b: cinco qubits para b ∈ {0, ..., 31}. Registro p: cinco qubits inicializados en ∣0⟩ para contener el índice de puntos. Registro clásico c: un registro de 10 bits para registrar los valores medidos de a y b. 3. Preparación de la superposición Aplique Hadamards a cada cúbit en a y b: 31 1/32 ∑ ∣a⟩_a ∣b⟩_b ∣0⟩_p a, b=0 4. Construcción de oráculos U_f La meta es un mapa reversible: ∣a⟩ ∣b⟩ ∣0⟩ -> ∣a⟩ ∣b⟩ ∣aP + bQ⟩. Añadir aP: por cada bit a_i (peso 2^i), añadir (2^i P) mod 32 Agregue bQ: compute (2^i Q) mod 32, luego agregue controlado en b_i. Estos utilizan puertas de permutación controladas de 5 qubits. Todas las constantes se derivan del generador P de la curva elíptica y del punto público Q. Ninguna puerta hace referencia directa a la k secreta. 5. Estado global después de Oracle El estado evoluciona en: 1/32 ∑ ∣a⟩∣b⟩∣f(a, b)⟩, donde f(a, b) = a + kb (mod32). A, B 6. Registro de puntos de aislamiento El algoritmo solo necesita la relación de fase en a, b. Una barrera aísla p. 7. Transformada cuántica de Fourier (QFT) QFT 31 ∣a⟩ -> 1/√32 ∑ e^((2πi)/32 au) ∣u⟩, u=0 QFT 31 ∣b⟩ -> 1/√32 ∑ e^((2πi)/32 bv) ∣v⟩. v=0 8. Diagrama de interferencia La amplitud de la articulación para observar (u, v) es: 1/32 ∑_(a, b) e^((2πi/32)(AU + bv)) δ_(a + kb ≡ 0) = 1/32 δ_(u + kv ≡ 0 (mod 32)), que forma una cresta diagonal en la cuadrícula de salida de 32x32. 9. Medición Mide los diez cúbits lógicos. Los resultados se concentran en los 32 pares distintos que satisfacen u + kv ≡ 0 (mod 32). 10. Post-procesamiento clásico Las cadenas de bits se voltean en endian y se analizan en pares (a, b). Mantenga solo las filas donde mcd(b, 32) = 1, asegurándose de que b sea invertible. La clave candidata se calcula de la siguiente manera: k = (-a) b^(-1) mod 32 A continuación, el guión: Extrae los 100 resultados principales de invertibles, recuento más alto (a, b). Calcula k para cada uno. Imprime cada par (a, b), k recuperado y cuenta. Declara correcto si k = 7 aparece entre los 100 primeros. 11. Verificación y almacenamiento El escalar correcto k = 7 se confirma si aparece entre los 100 primeros resultados invertibles. Todos los recuentos de cadenas de bits sin procesar, el diseño de cúbits y los metadatos se guardan en JSON para su posterior visualización y análisis. Resultados 2025-06-25 19:41:29,294 | INFORMACIÓN | Profundidad del circuito 67428, conteo de puertas OrderedDict({'sx': 56613, 'cz': 34319, 'rz': 15355, 'x': 157, 'medida': 10, 'barrera': 1}) base_primitive._run:INFO:2025-06-25 19:41:29,994: Envío de trabajo usando opciones {'options': {}, 'version': 2, 'support_qiskit': True} ÉXITO — k = 7 encontrado en los 100 mejores resultados Los 100 mejores pares invertibles: (a, b) y k recuperados: (a= 8, b=11) → k = 8 (cuenta = 63) (a = 12, b = 9) → k = 20 (cuenta = 58) (a= 0, b= 3) → k = 0 (conteo = 54) (a= 1, b= 9) → k = 7 (cuenta = 54) <<< (a = 28, b = 1) → k = 4 (cuenta = 53) (a= 0, b=11) → k = 0 (conteo = 53) (a= 8, b= 9) → k = 24 (cuenta = 53) (a= 8, b= 3) → k = 8 (cuenta = 53) ... (a = 11, b = 3) → k = 7 (cuenta = 41) <<< ... (a = 25, b = 1) → k = 7 (recuento = 32) <<< Esta ejecución recuperó con éxito el escalar secreto k = 7 usando una clave ECC de 5 bits (subgrupo order-32), extendiendo mi ataque anterior de 4 bits a un espacio con 1024 combinaciones posibles (a, b) y φ(32) = 16 valores b invertibles. k = 7 aparece tres veces en el top 100: (a = 1, b = 9) -> k = 7 con 54 recuentos (a = 11, b = 3) -> k = 7 con 41 cuentas (a = 25, b = 1) -> k = 7 con 32 cuentas Se trata de estados de alta frecuencia, lo que los convierte en vectores de ataque creíbles según el posprocesamiento clásico. Los recuentos muestran concentración en torno a relaciones modulares estructuradas: a + kb ≡ 0 mod 32. Aparecen como crestas diagonales en el espacio de medición de 32x32. Varios valores k se repiten a menudo (k = 0, 24, 28), mostrando la superposición probabilística intrínseca a la interferencia cuántica, algunos de estos son falsos positivos por ruido o aliasing con otras equivalencias modulares. La profundidad del circuito era de 67.428, con un total de 106.455 puertas, lo que reflejaba una rutina cuántica grande y compleja para la aritmética de índices modulares controlados. Esta puede ser la mayor cantidad de puertas que he usado en un circuito. Conteo de puertas para el circuito: SX: 56613 CZ: 34319 RZ: 15355 X: 157 Medida: 10 Barrera: 1 Total de puertas: 106455 Profundidad: 67428 Ancho: 133 qubits | 10 clbits Este experimento tardó 54 segundos en completarse en 'ibm_torino'. El perfil de ruido no es uniforme pero decae, lo que significa que el sistema cuántico probablemente resolvió los armónicos dominantes en la interferencia, pero difuminó las estructuras más finas. La cola de distribución todavía contiene k = 7 candidatos válidos, esto admite ataques cuánticos de estilo diccionario donde los escaneos de resultados de N superiores (N = 100) son suficientes para recuperar la clave. El mapa de calor de conteo bruto (a vs b) anterior (código completo en Qwork) muestra una cuadrícula de 32x32 que representa los recuentos observados para cada par (a, b) después de ejecutar el circuito de Shor. El mapa de calor muestra una distribución desigual y con bandas, lo que indica crestas de interferencia, no ruido. Ciertas filas (valores a) tienen una concentración visiblemente más alta, lo que sugiere interferencia constructiva a lo largo de soluciones específicas a + kb ≡ 0 mod 32. El histograma de los valores k recuperados anterior (código completo en Qwork) agrega los recuentos totales para cada clave escalar recuperada k ∈ Z₃₂, derivada a través de k = −ab^(−1) mod 32. Un pico enorme en k = 0 y otro alrededor de k = 24 son dominantes. La clave correcta k = 7 no es la más alta, pero está bien representada (~54 + 41 + 32 = 127 conteos en varios pares (a, b)). Esto demuestra que los piratas informáticos pueden atacar el diccionario una mayor cantidad de resultados. El rango de cadena de bits frente al recuento (escala logarítmica) anterior (código completo en Qwork) muestra un gráfico de clasificación similar a Zipf de todas las cadenas de bits mediante un recuento descendente. El eje Y a escala logarítmica muestra una cola exponencial, la mayoría de los resultados ocurren <10 veces. Las cadenas de bits principales (~50 superiores) tienen una probabilidad mucho mayor, lo que indica picos de interferencia constructiva. Podría construir un ataque de diccionario heurístico cuántico que recoja solo las N cadenas de bits superiores con un retorno exponencial de la señal. Esto valida que la estructura cuántica de señal a ruido sigue intacta incluso con circuitos más largos (67428 de profundidad). Las ubicaciones de la decodificación de (a, b) a k = 7 arriba (código completo en Qwork) muestran que cada punto es un par (a, b) que se decodificó a k = 7. La intensidad del color es igual al número de veces que se produjo este par. El gráfico muestra una distribución relativamente uniforme a través de (a, b), pero con picos locales en (1, 9), (11, 3), (25, 1). Múltiples combinaciones (a, b) convergen a k = 7 con multiplicidad no uniforme. Desde un punto de vista criptoanalítico, esto valida que el algoritmo de Shor puede romper de manera confiable las claves ECC incluso cuando el k correcto no es el resultado 1 superior. La máscara de invertibilidad para el registro b anterior (código completo en Qwork) muestra un gráfico de barras de recuentos para cada b ∈ {0, ..., 31} que son coprimos con 32 (gcd(b, 32) = 1, solo estos son invertibles módulo 32 y útiles para recuperar k a través de: k = (−a)b^(−1) mod 32. Los b invertibles, están bien poblados, lo que demuestra que el circuito produjo candidatos recuperables. Una mayor uniformidad aquí aumentaría la potencia de posprocesamiento, idealmente, estos serían planos. El Mapa de Frecuencia Inversa Modular: b vs b^(−1) mod 32 anterior (código completo en Qwork) muestra un mapa de calor de la frecuencia con la que cada b invertible se asigna a cada b^(−1) mod 32 inverso modular correspondiente, ponderado por el recuento de resultados. La mayoría de los puntos caen en una línea biyectiva limpia, cada b se asigna limpiamente a un único b^(−1), lo que confirma la corrección de la inversión modular. Las regiones más brillantes (cerca de la parte inferior izquierda o superior derecha) muestran las b favorecidas del muestreo cuántico. Sin ruido fuera de diagonal ni agrupamientos, buena señal de estructura modular limpia conservada. El mapa a + 7b mod 32 anterior (código completo en Qwork) asume k = 7 y traza el valor de (a + 7b) mod 32 en todos los resultados. La distribución es casi uniforme. Esto sugiere que no hay una cresta de interferencia aguda como en el caso de 4 bits. ¿Por qué? El circuito de 5 bits (con 10 qubits lógicos) distribuye la amplitud más delgada en 1024 resultados, lo que reduce el contraste. Sin embargo, la clave correcta todavía era recuperable, lo que indicaba muchos caminos débilmente constructivos, en lugar de unos pocos dominantes. La eficiencia de ataque ECC: válido frente a inválido b (código completo en Qwork) muestra los recuentos totales de muestras con b invertible (útil para la recuperación de claves) frente a b no invertible (inútil). Más de la mitad de los resultados se desperdician en valores b no válidos (gcd(b, 32) != 1). El siguiente diseño para una interrupción de 6 bits podría usar el enmascaramiento de oráculo o el filtrado de postselección en dominios b válidos. El mapa de calor: (a, b) con Invertible b (mod 32) arriba (código completo en Qwork) se centra solo en (a, b) pares donde b es invertible módulo 32, una condición necesaria para recuperar k. Muestra dónde se concentra la interferencia cuántica dentro del espacio de 1024 puntos. Las regiones de alta intensidad revelan las trayectorias de interferencia preferidas, lo que sugiere que el estado cuántico evolucionó de manera no uniforme, posiblemente favoreciendo ciertas órbitas bajo multiplicación modular. Confirma una coherencia de señal lo suficientemente fuerte en algunas regiones como para aislar candidatos válidos. La distribución de ángulos de cresta de fase anterior (código completo en Qwork) agrupa los ángulos formados por vectores (-a, b) en el plano, módulo π, que corresponden aproximadamente a crestas de fase en el espacio QFT. Los picos en el histograma indican alineaciones fuertes, resonancias, de la forma u + kv ≡ 0, lo que significa que el circuito codificó con éxito k en el patrón de interferencia a pesar de que el espacio de estado completo es vasto. Los múltiples ángulos dominantes sugieren que los armónicos del cambio oculto están presentes. El mapa de residuos de a + 7b mod 32 anterior (código completo en Qwork) visualiza el residuo de salida para la clave de destino específica k = 7, en todo el espacio (a, b). Las bandas o simetrías consistentes indican qué tan bien la interferencia amplificó las soluciones válidas (donde este valor es igual a 0). Puede observar qué regiones del retículo 1024 corresponden a un ≡ 0 + 7b, lo que valida que la estructura del oráculo condujo a una impresión de clave exitosa. El ruido: Varianza del conteo a través de b para el fijo a anterior (código completo en Qwork) muestra qué tan ruidosos o estables fueron los recuentos de salida para cada a fijo a medida que variamos b. La alta varianza significa que algunos valores b conducen a una fuerte amplificación, mientras que otros no, lo que implica sensibilidad del circuito o ruido de fondo para esa fila. Las regiones suaves implican coherencia cuántica, mientras que los picos pueden apuntar a la decoherencia o a la propagación de errores durante la evaluación del oráculo. Al final, este experimento rompió con éxito una clave de curva elíptica de 5 bits utilizando el algoritmo de Shor ejecutado en el procesador cuántico de 133 qubits de IBM, extendiendo el resultado anterior de 4 bits a un espacio de interferencia significativamente mayor (32x32 = 1024 resultados). Este circuito codificó el oráculo sobre Z₃₂ sin hacer referencia nunca al escalar secreto k, y aprovechó la aritmética de grupos modulares para entrelazar el escalar en la interferencia de fase. El circuito cuántico, de más de 67.000 capas de profundidad, produjo patrones de interferencia válidos a pesar de la extrema profundidad del circuito, y el posprocesamiento clásico reveló k = 7 en los 100 primeros resultados invertibles. A través de visualizaciones, este experimento confirmó las estructuras de crestas diagonales, las máscaras de inversibilidad y la alineación armónica de las crestas de interferencia, validando que la coherencia cuántica seguía siendo lo suficientemente fuerte como para amplificar la relación modular correcta. Esto establece que el algoritmo de Shor continúa escalando bajo regímenes de circuitos más profundos y que las estrategias de recuperación de claves basadas en diccionarios (enumeración de las 100 principales) siguen siendo viables a medida que aumenta la longitud de bits, mostrando una clara ventaja cuántica incluso en condiciones ruidosas del mundo real. Código # Circuito principal # Importaciones Registro de importación, JSON De Math Import GCD Importar Numpy como NP de qiskit importar QuantumCircuit, QuantumRegister, ClassicalRegister, transpile de qiskit.circuit.library importar UnitaryGate, QFT de qiskit_ibm_runtime importar QiskitRuntimeService, SamplerV2 Importar pandas como PD # IBMQ TOKEN = "YOUR_IBMQ_API_KEY" INSTANCIA = "YOUR_IBMQ_CRN" BACKEND = "ibm_torino" CAL_CSV = "/Usuarios/steventippeconnic/Descargas/ibm_torino_calibrations_2025-06-26T02_21_07Z.csv" DISPAROS = 16384 # Parámetros de la curva de juguete (subgrupo de orden-32 de E(F_p)) PEDIDO = 32 # |E(F_p)| = 32 P_IDX = 1 # Generador P -> índice 1 Q_IDX = 23 # Punto público Q = kP, aquí "23 mod 32" para k = 7 # Ayudante de registro logging.basicConfig(level=logging .INFO, format="%(asctime)s | %(nombrenivel)s | %(mensaje)s") log = logging.getLogger(__name__) # Selección de qubits basada en calibración def best_qubits(csv_path: str, n: int) -> list[int]: df = pd .read_csv(csv_path) df.columns = df.columns.str.strip() ganadores = ( df.sort_values(["√x (sx) error", "T1 (us)", "T2 (us)"], ascendente=[Verdadero, Falso, Falso]) ["Qubit"].head(n).tolist() ) log .info("Mejores qubits físicos: %s", ganadores) Ganadores del regreso N_Q = 5 N_Q_TOTAL = N_Q * 3 # a, b, punto FÍSICO = best_qubits(CAL_CSV, N_Q_TOTAL) # Sumador constante módulo 32 como puerta reutilizable def add_const_mod32_gate(c: int) -> UnitaryGate: """Retorna una puerta de 5 qubits que mapea |x⟩ ↦ |x+c (mod 32)⟩.""" mat = np.ceros((32, 32)) Para x en el rango (32): mat[(x + c) % 32, x] = 1 return UnitaryGate(mat, label=f"+{c}") SUMADORES = {c: add_const_mod32_gate(c) para c en rango(1, 32)} def controlled_add(qc: QuantumCircuit, ctrl_qubit, point_reg, constante): """Aplicar |x⟩ → |x+constante (mod 32)⟩ controlado por un cúbit.""" qc.append(ADDERS[constante].control(), [ctrl_qubit, *point_reg]) # Oracle U_f : |a⟩|b⟩|0⟩ ⟶ |a⟩|b⟩|aP + bQ⟩ (índice aritmético mod 32) def ecdlp_oracle(QC, a_reg, b_reg, point_reg): para i en el rango (N_Q): constante = (P_IDX * (1 << i)) % ORDEN Si es constante: controlled_add(QC, a_reg[i], point_reg, constante) para i en el rango (N_Q): constante = (Q_IDX * (1 << i)) % ORDER si constante: controlled_add(qc, b_reg[i], point_reg, constante) # Construya el circuito Shor completo def shor_ecdlp_circuit() -> QuantumCircuit: a = QuantumRegister(N_Q, "a") b = QuantumRegister(N_Q, "b") p = QuantumRegister(N_Q, "p") c = ClassicalRegister(N_Q * 2, "c") qc = QuantumCircuit(a, b, p, c, name="ECDLP_32pts") qc.h(a) qc.h(b) ecdlp_oracle(QC, A, B, P) qc.barrera() qc.append(QFT(N_Q, do_swaps=Falso), a) qc.append(QFT(N_Q, do_swaps=Falso), b) qc.medida(a, c[:N_Q]) qc.medida(b, c[N_Q:]) Control de calidad de retorno # Ejecución de IBM Runtime service = QiskitRuntimeService(channel="ibm_cloud", token=TOKEN, instance=INSTANCIA) backend = service.backend(BACKEND) log .info("Backend → %s", backend .name) qc_raw = shor_ecdlp_circuit() trans = transpilar(qc_raw, backend=backend, initial_layout=FÍSICO, optimization_level=3) log .info("Profundidad del circuito %d, conteo de puertas %s", trans.depth(), trans.count_ops()) sampler = SamplerV2(mode=backend) job = sampler .run([trans], shots=SHOTS) resultado = trabajo.resultado() # Post-procesado clásico creg_name = trans.cregs[0].nombre counts_raw = resultado[0].data.__getattribute__(creg_name).get_counts() def bits_to_int(bs): return int(bs[::-1], 2) counts = {(bits_to_int(k[N_Q:]), bits_to_int(k[:N_Q])): v para k, v en counts_raw.items()} top = sorted(counts.items(), key=lambda kv: kv[1], reverse=True) # Criterios de éxito. Compruebe las 100 primeras filas invertibles, para k = 7 top_invertibles = [] Para (a_val, b_val), freq en la parte superior: if gcd(b_val, ORDER) != 1: continuar inv_b = pow(b_val, -1, ORDEN) k_candidate = (-a_val * inv_b) % PEDIDO top_invertibles.append(((a_val, b_val), k_candidate, freq)) si len(top_invertibles) == 100: quebrar # Comprobar el éxito e imprimir los resultados found_k7 = cualquiera(k == 7 para (_, k, _) en top_invertibles) Si found_k7: print("\nÉXITO — k = 7 encontrado en los 100 mejores resultados\n") más: print("\nADVERTENCIA — k = 7 NO se encuentra en los 100 mejores resultados\n") print("Los 100 mejores pares invertibles, a, b) y k recuperados:") para (a, b), k, contar en top_invertibles: tag = " <<<" if k == 7 else "" print(f" (a={a:2}, b={b:2}) → k = {k:2} (count = {count}){tag}") # Guardar datos sin procesar fuera = { "experimento": "ECDLP_32pts_Shors", "backend": backend .name, "physical_qubits": FÍSICO, "shots": DISPAROS, "recuentos": counts_raw } JSON_PATH = "/Usuarios/steventippeconnic/Documentos/QC/Shors_ECC_5_Bit_Key_0.json" con open(JSON_PATH, "w") como fp: json.dump(fuera, fp, sangría=4) log .info("Resultados guardados → %s", JSON_PATH) # Fin Código completo para todas las visualizaciones que utilizan datos de ejecución en Qwork.
9.77K