
Este repositório contém o código e os detalhes de submissão para o desafio do prêmio QDay por https://www.projecteleven.com/
Solucionador quântico para o Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP), desenvolvido para o Q-Day Prize Challenge pela Project Eleven. O objetivo: recuperar chaves privadas ECC em hardware quântico real usando o algoritmo de Shor.
Todas as curvas do desafio usam y^2 = x^3 + 7 sobre F_p (a = 0, b = 7), coincidindo com a família secp256k1. O solucionador implementa a variante de dois registros do algoritmo de Shor para ECDLP:
A chave privada d é recuperada coletando múltiplas amostras (j, k) que satisfazem a mesma relação linear módulo a ordem do grupo n. O solucionador suporta seis estratégias de oráculo para as adições de pontos controladas, selecionadas automaticamente com base no tamanho da curva ou manualmente via --oracle.
Usada para curvas com ordem de grupo de até ~6 bits. Implementada em projecteleven.py.
Cada adição de ponto controlada "add S" é representada como uma matriz de permutação 2^(n+1) x 2^(n+1) aplicada via qc.unitary(). A matriz codifica a ação completa do grupo: o bloco superior esquerdo é a identidade (controle=0), o bloco inferior direito permuta os estados base de acordo com o mapa P -> P+S (controle=1).
Usada para curvas maiores. Implementada em quantum_arithmetic.py.
Em vez de construir matrizes densas, cada permutação "add S" é decomposta em transposições a partir de sua estrutura de ciclos. Cada transposição (troca de dois estados base |a> <-> |b>) é implementada com:
O MCX usa decomposição em cadeia-V com (n-2) qubits ancilla dedicados, resultando em portas Toffoli O(n) por MCX em vez de O(n^2) sem ancillas. Cada adição controlada é construída como um subcircuito isolado e anexada como uma única porta opaca, evitando o crescimento quadrático do DAG no Qiskit.
--oracle coordinate)Disponível para curvas de até ~6 bits. Implementada em quantum_oracle.py.
Em vez de codificar pontos como índices de grupo, o registro quântico mantém as coordenadas reais (x, y) dos elementos de campo em binário mais uma flag de identidade. O layout do registro de ponto é:
x_reg: f_bits qubits (f_bits = ceil(log2(p)))y_reg: f_bits qubitsid_flag: 1 qubit (1 = ponto no infinito)Cada "add S" controlada é computada a partir da fórmula de adição de curvas elípticas sobre todas as codificações de coordenadas válidas, produzindo uma permutação no registro de coordenadas. Essa permutação é decomposta em transposições usando a mesma infraestrutura de redução CNOT + MCX da Estratégia 2.
--oracle arithmetic)Estrutura para adição de pontos com escalonamento polinomial. Implementada em quantum_oracle.py e quantum_arithmetic.py.
Usa codificação por coordenadas (mesmo da Estratégia 3) com primitivas de aritmética modular baseadas em QFT como blocos de construção para uma adição de pontos totalmente aritmética. O código inclui implementações testadas de:
As primitivas aritméticas alcançam escalonamento O(n^3) por adição de ponto versus O(N*n) para a abordagem de permutação. No entanto, as operações baseadas em QFT carregam um fator constante ~150x maior, tornando a abordagem aritmética mais eficiente apenas para curvas acima de ~20 bits de ordem de grupo. Para os tamanhos atuais de desafio (até 12 bits), o somador baseado em permutação permanece mais rápido e é usado por padrão.
--oracle google)Implementada em google_semiclassical.py. Inspirada na técnica de estimação de fase com reciclagem de qubits de Griffiths & Niu (1996), aplicada em escala por Babbush et al. (2026) para estimativas de recursos do ECDLP secp256k1. O artigo de Babbush et al. foi publicado em 30 de março de 2026.
Substitui os dois registros de contagem multi-qubit (j, k) e a QFT inversa em massa por dois qubits reciclados únicos e correções de fase condicionadas classicamente. Cada bit do registro de contagem é processado sequencialmente: preparar em |+>, aplicar adição de ponto controlada, corrigir a fase com base em todos os bits previamente medidos e então medir. Os primitivos de circuitos dinâmicos reset + if_test no Qiskit permitem isso no hardware IBM Quantum.
O oráculo para adições de pontos controladas é delegado à infraestrutura existente (unitário denso para <= 6 bits, permutação eficiente para > 6 bits), portanto a economia de qubits vem inteiramente da eliminação dos registros de contagem.
--oracle ripple)Implementada em ripple_carry_shor.py. Usa somadores ripple-carry CDKM (Cuccaro et al. 2004) para as adições de pontos controladas, substituindo tanto as matrizes unitárias densas quanto os circuitos de transposição decompostos em ciclos.
Na codificação por índice de grupo, o ponto P = kG é representado por seu índice k no grupo cíclico. Adicionar S = sG torna-se adição modular da constante clássica s (mod n). A ideia central: cada adição de ponto controlada reduz-se a uma única adição modular controlada de uma constante conhecida, implementada via CDKMRippleCarryAdder e IntegerComparator do Qiskit.
O oráculo consiste em 2m adições modulares controladas (m por registro de contagem), onde cada adição modular controlada realiza:
Nenhum conhecimento da chave privada d é usado na construção do circuito. Os índices de grupo para potências de G são calculados como 2^i mod n (públicos). Os índices de grupo para potências de Q são derivados da enumeração pública do grupo cíclico gerado por G — o ponto Q é procurado nesta enumeração.
O código inclui blocos de construção de aritmética modular baseados em QFT (somadores de Beauregard/Draper, multiplicação modular quântico-quântico, inversão/negação modulares) como base para uma codificação por coordenadas totalmente aritmética em 256 bits. Essas primitivas foram verificadas como corretas via simulação Statevector para primos até p=13.
Chaves privadas recuperadas com sucesso em hardware IBM Quantum para curvas de desafio de até 17 bits:
Todas as execuções foram realizadas no plano de instância aberta da IBM Quantum, que concede 10 minutos de computação quântica gratuita por mês. Os logs completos de execução estão na pasta executions/.
A estratégia ripple-carry (Estratégia 6) permitiu um salto significativo: de 10 bits (40 qubits, 2M portas) para 17 bits (69 qubits, 112K portas) — um aumento de 7 bits no tamanho da chave com uma redução de 18x no número de portas de dois qubits. A estrutura de portas de vizinhança imediata do somador CDKM mapeia-se eficientemente para a topologia heavy-hex da IBM, mantendo o overhead de roteamento próximo a 1x.
A estratégia semiclássica (--oracle google) recuperou chaves com sucesso em 4, 6 e 7 bits usando circuitos dinâmicos (reset no meio do circuito, portas p condicionadas classicamente via if_test) em processadores IBM Heron r2. Em 7 bits, o circuito usa apenas 14 qubits (vs 26 para a abordagem de permutação padrão) enquanto produz contagens de portas 2Q comparáveis após a transpilação.
Em 8 bits e acima, a abordagem semiclássica torna-se impraticável no hardware IBM atual. Embora if_else e reset sejam suportados no Heron r2 (confirmado via inspeção do alvo do backend), cada ponto de feedback clássico requer uma sincronização completa da QPU — todos os 156 qubits físicos devem ficar ociosos enquanto o controlador clássico processa a condicional para os ~16 qubits ativos. Com ~295K portas CZ divididas em 16+ pontos de feedback, o overhead de execução por shot faz com que os jobs excedam o orçamento de tempo da QPU. A abordagem de permutação padrão, que executa a mesma contagem de portas em um único lote contínuo sem circuitos dinâmicos, completa-se com sucesso nessa escala.
Uma truncagem aproximada da QFT (parâmetro max_corrections) reduz o número de blocos if_else de O(n^2) para O(n), retendo apenas as k correções de fase mais próximas por etapa de medição (ângulos além de k contribuem com < pi/2^{k+1}, abaixo do piso de ruído do hardware). Com max_corrections=1, o circuito de 8 bits tem 16 blocos if_else — ainda suficiente para causar timeout no hardware IBM nessa contagem de portas.
Assumindo uma fidelidade típica de porta de dois qubits (CX) da IBM Quantum de ~99,5%, a fidelidade estimada do circuito decai exponencialmente com a contagem de portas:
A fidelidade do circuito é calculada como F ≈ (0,995)^{CX_count}. Para tudo além de 4 bits, a fidelidade estimada é astronomicamente pequena — a distribuição de saída é esmagadoramente ruído.
Para 8 bits e acima, cada shot produz uma sequência de bits quase única (8.128 resultados únicos em 8.192 shots em 8 bits; todos os 20.000 únicos em 16 e 17 bits). A saída é indistinguível de amostragem aleatória uniforme no nível da sequência de bits. No entanto, o algoritmo ainda recupera a chave privada correta.
A principal percepção é que o pós-processamento de Shor é robusto ao ruído de uma forma que a análise bruta de sequências de bits não é. Cada shot produz um tripleto de medição (j, k, r). A extração calcula d_cand = (r - j) · k^{-1} mod n e verifica via d_cand · G == Q. Apenas o verdadeiro d passa na verificação EC, portanto mesmo um único candidato correto entre milhares de shots ruidosos é suficiente.
Um tripleto (j, k, r) puramente aleatório produz o d_cand correto com probabilidade ~1/n. Com S shots, o número esperado de acertos verificados provenientes apenas de ruído é ~S/n. Em 17 bits (n=65.173, S=20.000), isso dá ~0,3 acertos de ruído esperados — qualquer recuperação bem-sucedida nessa escala fornece evidência de sinal quântico além do piso de ruído clássico.
Para curvas menores onde shots >> n (ex.: 10 bits com n=547 e 1.024 shots), o piso de ruído é ~1.024/547 ≈ 1,9 votos por candidato. Mesmo um punhado de shots portadores de sinal empurra o d correto acima do piso de ruído. Isso explica como o algoritmo é bem-sucedido apesar de fidelidades de circuito que pareceriam tornar o cálculo impossível.
Em escala de brinquedo, a etapa de verificação da extração (d_cand * G == Q) atua como um filtro que aceita apenas o verdadeiro d. Isso significa que mesmo tripletos (j, k, r) puramente aleatórios produzirão candidatos válidos a uma taxa de aproximadamente shots / n por execução. Quando shots >> n, o ruído aleatório sozinho pode recuperar d com alta probabilidade.
Para testar se o circuito quântico contribui com sinal além desse piso de ruído clássico, executamos o desafio de 6 bits (n=31) com apenas 8 shots (bem abaixo da ordem do grupo) 10 vezes no ibm_kingston:
Resultado: 4/10 sucessos (40%) vs uma linha de base de ruído clássico de ~20% (calculada via simulação de Monte Carlo: 8 sequências de bits aleatórias com (r-j)*k_inv mod 31 filtradas por verificação). Teste binomial unilateral: P(X >= 4 | n=10, p=0,20) = 0,121, indicando uma melhoria de 2x sobre o piso de ruído. Embora não seja individualmente significativo em p < 0,05 (o que exigiria 5+ sucessos), a taxa observada é consistente com um sinal quântico contribuindo com aproximadamente 1-2 pares (j, k) válidos adicionais por execução além do que o acaso fornece.
Este resultado situa-se entre o piso de ruído clássico e o regime teórico de vantagem quântica. Em tamanhos de curva maiores, onde n >> shots, a linha de base de ruído cai abaixo de 1% e qualquer recuperação bem-sucedida de chave torna-se forte evidência de computação quântica.
git clone https://github.com/GiancarloLelli/quantum.git cd quantum
python -m venv . Scripts\Activate.ps1 # For Windows only
pip install -r requirements.txt
### Como executar
Você precisa de uma conta [IBM Quantum](https://quantum.ibm.com/). Passe seu token de API na primeira execução e ele será salvo localmente:```bash
# Solve the 4-bit challenge curve:
python projecteleven.py --challenge 4 --token YOUR_IBM_TOKEN --backend ibm_marrakesh
# Subsequent runs (token already saved):
python projecteleven.py --challenge 4 --backend ibm_marrakesh
# Use the coordinate-based quantum oracle:
python projecteleven.py --challenge 4 --oracle coordinate --backend ibm_marrakesh
# Use the arithmetic oracle (coordinate encoding + QFT primitives):
python projecteleven.py --challenge 4 --oracle arithmetic --backend ibm_marrakesh
# Use ripple-carry modular addition (CDKM — best for 8-bit+):
python projecteleven.py --challenge 16 --oracle ripple --backend ibm_fez --shots 20000
# Use Google semiclassical phase estimation (qubit-recycled):
python projecteleven.py --challenge 4 --oracle google --backend ibm_marrakesh
# Use a specific IBM Quantum instance:
python projecteleven.py --challenge 4 --instance ibm-q/open/main --backend ibm_marrakesh
# Verify curve parameters without quantum execution:
python projecteleven.py --curve curve_4 --verify-only
projecteleven.py # Shor solver — dense unitary approach + CLI entry point quantum_arithmetic.py # Efficient permutation decomposition + QFT arithmetic primitives quantum_oracle.py # Coordinate-based oracle + arithmetic oracle framework google_semiclassical.py # Google semiclassical PE — qubit-recycled phase estimation ripple_carry_shor.py # Ripple-carry modular addition oracle (CDKM) — best for 8-bit+ input_curves.json # Challenge curves (4-bit to 30-bit) problem/curves.py # Curve generation utility requirements.txt # qiskit, qiskit-ibm-runtime
## Referências
- P. Shor, ["Algorithms for Quantum Computation: Discrete Logarithms and Factoring"](https://arxiv.org/abs/quant-ph/9508027) (1994)
- S. Beauregard, ["Circuit for Shor's algorithm using 2n+3 qubits"](https://arxiv.org/abs/quant-ph/0205095) (2003)
- S. A. Cuccaro, T. G. Draper, S. A. Kutin, D. P. Moulton, ["A new quantum ripple-carry addition circuit"](https://arxiv.org/abs/quant-ph/0410184) (2004)
- M. Roetteler, M. Naehrig, K. Svore, K. Lauter, ["Quantum resource estimates for computing elliptic curve discrete logarithms"](https://arxiv.org/abs/1706.06752) (2017)
- R. Griffiths, C.-S. Niu, ["Semiclassical Fourier Transform for Quantum Computation"](https://arxiv.org/abs/quant-ph/9511007) (1996)
- R. Babbush et al., ["Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities: Resource Estimates and Mitigations"](https://quantumai.google/static/site-assets/downloads/cryptocurrency-whitepaper.pdf) (2026)
## Licença
Este projeto é uma submissão ao Q-Day Prize Challenge lançado sob [LICENÇA MIT](https://github.com/giancarlolelli/quantum/blob/HEAD/LICENSE)
| Tamanho da curva | Qubits padrão | Qubits semiclássicos | Economia | Verificado em hardware |
|---|
| 4 bits (n=7) | 11 | 5 | 55% | Sim |
| 6 bits (n=31) | 17 | 7 | 59% | Sim |
| 7 bits (n=79) | 26 + anc | 14 | 46% | Sim |
| 8 bits (n=139) | 25 + anc | 10 + anc | 60% | Não (overhead de sincronização QPU) |
| 10 bits (n=547) | 31 + anc | 12 + anc | 61% | Não (overhead de sincronização QPU) |
| Tamanho da curva | Qubits | Portas 2Q (transpiladas) | Verificado em hardware |
|---|
| 4 bits (n=7) | 17 | 1.824 | Sim (simulação) |
| 8 bits (n=139) | 37 | 11.224 | — |
| 10 bits (n=547) | 45 | 17.204 | — |
| 12 bits (n=2143) | 53 | 24.304 | — |
| 16 bits (n=32497) | 65 | 98.049 | Sim |
| 17 bits (n=65173) | 69 | 111.816 | Sim |
| Métrica | Unitário Denso | Permutação Eficiente | Oráculo de Coordenadas | Oráculo Aritmético | Estimação de Fase Semiclássica | Ripple-Carry |
|---|
| Codificação do ponto | Índice de grupo | Índice de grupo | (x, y, id_flag) | (x, y, id_flag) | Índice de grupo | Índice de grupo |
| Escalonamento por adição | O(4^n) decomp. | O(N * n) | O(N * f_bits) | O(n^3) assintótico | O(N * n) | O(m^2) |
| Qubits (4 bits) | 11 | 13 | 24 | 24 | 5 | 17 |
| Qubits (6 bits) | 17 | 21 | 36 | 36 | 9 | 25 |
| Portas 2Q (4 bits) | 774 | ~1.200 | 6.449 | 6.449 | ~1.200 | 1.824 |
| Portas 2Q (6 bits) | 23.471 | ~38.000 | 95.254 | 95.254 | ~38.000 | 4.582 |
| Faixa prática | <= 6 bits | <= ~16 bits | <= 6 bits | >= 20 bits (futuro) | <= ~16 bits | <= ~20 bits |
| Desafio | p | n | Estratégia | Qubits | Portas 2Q | Profundidade transpilada | Shots | Backend | d recuperado | ID do Job |
|---|
| 4 bits | 13 | 7 | Unitário denso | 11 | 774 | 2.425 | 8.192 | ibm_torino | 6 | d73u28kvllmc73anvi90 |
| 4 bits | 13 | 7 | Oráculo de coordenadas | 24 | 6.449 | 13.125 | 8.192 | ibm_kingston | 6 | d74ht798qmgc73fm32c0 |
| 4 bits | 13 | 7 | Oráculo aritmético | 24 | 6.477 | 13.452 | 8.192 | ibm_torino | 6 | d75648lbjrds73ec0eng |
| 4 bits | 13 | 7 | Estimação de fase semicl. | 5 | 747 | 2.522 | 256 | ibm_kingston | 6 | d75p1ftbjrds73ecne3g |
| 6 bits | 43 | 31 | Unitário denso | 17 | 23.471 | 72.475 | 8.192 | ibm_torino | 18 | d73u2l5koquc73e24u8g |
| 6 bits | 43 | 31 | Oráculo de coordenadas | 36 | 95.254 | 169.766 | 8.192 | ibm_kingston | 18 | d74hu918qmgc73fm33g0 |
| 6 bits | 43 | 31 | Estimação de fase semicl. | 7 | 23.256 | 73.183 | 256 | ibm_kingston | 18 | d75p1unq1anc738cmr6g |
| 7 bits | 67 | 79 | Estimação de fase semicl. | 14 | 127.918 | 266.122 | 256 | ibm_kingston | 56 | d75p3sq3qcgc73fs2fpg |
| 8 bits | 163 | 139 | Permutação eficiente | 32 | 294.628 | 599.517 | 8.192 | ibm_kingston | 103 | d73ui15koquc73e25e4g |
| 9 bits | 349 | 313 | Permutação eficiente | 36 | 887.544 | 1.764.266 | 8.192 | ibm_torino | 135 | d73ua2h8qmgc73flei9g |
| 10 bits | 547 | 547 | Permutação eficiente | 40 | 2.049.138 | 3.948.250 | 1.024 | ibm_torino | 165 | d752vfu8faus73evhovg |
| 16 bits | 32.803 | 32.497 | Ripple-carry | 65 | 98.049 | 202.994 | 20.000 | ibm_fez | 20.248 | d790j2hq1efs73d2979g |
| 17 bits | 65.647 | 65.173 | Ripple-carry | 69 | 111.816 | 231.475 | 20.000 | ibm_fez | 1.441 | d790krrc6das739idasg |
| Desafio | Estratégia | Portas 2Q | Fidelidade Est. do Circuito | Resultados Únicos | Shots Totais | Regime de Sinal |
|---|
| 4 bits | Denso | 774 | ~2,1% | 1.869 / 2.048 | 8.192 | Sinal fraco |
| 6 bits | Denso | 23.471 | ~10^{-51} | 3.776 / 131.072 | 8.192 | Dominado por ruído |
| 8 bits | Permutação | 294.628 | ~10^{-644} | 8.128 / 4.3B | 8.192 | Dominado por ruído |
| 9 bits | Permutação | 887.544 | ~10^{-1.939} | 8.168 / 68.7B | 8.192 | Dominado por ruído |
| 10 bits | Permutação | 2.049.138 | ~10^{-4.477} | 1.024 / 1.1T | 1.024 | Dominado por ruído |
| 16 bits | Ripple-carry | 98.049 | ~10^{-214} | 20.000 / 2^65 | 20.000 | Dominado por ruído |
| 17 bits | Ripple-carry | 111.816 | ~10^{-244} | 20.000 / 2^69 | 20.000 | Dominado por ruído |
| Execução | ID do Job | Resultado |
|---|
| 1 | d75qrrq3qcgc73fs4hn0 | FALHA |
| 2 | d75qs3e8faus73f0ep6g | FALHA |
| 3 | d75qsafq1anc738coujg | FALHA |
| 4 | d75qsie8faus73f0eplg | d = 18 |
| 5 | d75qsq23qcgc73fs4ing | d = 18 |
| 6 | d75qt168faus73f0eq50 | FALHA |
| 7 | d75qt7vq1anc738covf0 | d = 18 |
| 8 | d75qthu8faus73f0eqmg | FALHA |
| 9 | d75qtodbjrds73ecpk80 | d = 18 |
| 10 | d75qtvi3qcgc73fs4jsg | FALHA |
| Bandeira | Descrição | Padrão |
|---|
--challenge N | Resolver a curva de desafio de N bits de input_curves.json | — |
--curve NAME | Usar uma curva de teste interna (curve_4) | — |
--token TOKEN | Token da API IBM Quantum (salvo localmente no primeiro uso) | — |
--backend NAME | Backend IBM Quantum | ibm_marrakesh |
--instance ID | Instância IBM Quantum | open-instance |
--shots N | Número de disparos de medição | 8192 |
--oracle TYPE | Estratégia de oráculo: dense, permutation, coordinate, arithmetic, google ou ripple | auto |
--optimization-level N | Nível de otimização de transcompilação do Qiskit (0-3) | 3 |
--d N | Chave secreta conhecida para teste (com --curve) | — |
--verify-only | Validar parâmetros da curva e sair | — |