<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cryptography on kenji.blog</title><link>http://kenji.blog/pt/categories/cryptography/</link><description>Recent content in Cryptography on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/categories/cryptography/index.xml" rel="self" type="application/rss+xml"/><item><title>Fundamentos e Implementação da Criptografia usando o Pequeno Teorema de Fermat</title><link>http://kenji.blog/pt/p/fermats-little-theorem-cryptography-implementation/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/fermats-little-theorem-cryptography-implementation/</guid><description>&lt;img src="http://kenji.blog/p/fermats-little-theorem-cryptography-implementation/img/eyecatch.jpg" alt="Featured image of post Fundamentos e Implementação da Criptografia usando o Pequeno Teorema de Fermat" />&lt;h2 id="1-introdução-o-mistério-matemático-que-sustenta-a-criptografia-moderna">1. Introdução: O mistério matemático que sustenta a criptografia moderna
&lt;/h2>&lt;p>Na sociedade digital moderna, especialmente nas comunicações via Internet, a &amp;ldquo;criptografia&amp;rdquo; tornou-se uma tecnologia fundamental indispensável. O fato de podermos navegar na web de forma segura via HTTPS em nossos navegadores, realizar transações financeiras no internet banking e trocar mensagens privadas em aplicativos de mensagens é possível devido aos protocolos criptográficos apoiados por teorias matemáticas avançadas que operam nos bastidores. Entre eles, o sistema de &amp;ldquo;criptografia de chave pública&amp;rdquo; desempenha um papel particularmente importante, e seu principal representante é a &lt;strong>Criptografia RSA&lt;/strong>.&lt;/p>
&lt;p>A segurança e a validade de muitos algoritmos criptográficos, incluindo o RSA, dependem fortemente de um teorema muito belo e poderoso descoberto pelo matemático francês do século 17, Pierre de Fermat. Esse é o &lt;strong>Pequeno Teorema de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>. Além disso, o teorema de Leonhard Euler, que generaliza isso, também desempenha um papel decisivo na teoria da criptografia.&lt;/p>
&lt;p>Neste artigo, explicaremos detalhadamente desde o básico como a descoberta do Pequeno Teorema de Fermat, na matemática pura, é aplicada às tecnologias de criptografia práticas modernas, em particular ao &amp;ldquo;teste de primalidade&amp;rdquo; e à &amp;ldquo;criptografia RSA&amp;rdquo;. Este será um guia técnico muito detalhado que cobre provas matemáticas, os mecanismos de criptografia e descriptografia, e implementações de algoritmos específicos em C++ e Python.&lt;/p>
&lt;hr>
&lt;h2 id="2-fundamentos-de-congruências-e-aritmética-modular">2. Fundamentos de Congruências e Aritmética Modular
&lt;/h2>&lt;p>Para entender o Pequeno Teorema de Fermat, primeiro precisamos nos familiarizar com o conceito matemático de &amp;ldquo;aritmética modular (congruências)&amp;rdquo;. A aritmética modular é um sistema de cálculo que foca no &amp;ldquo;resto&amp;rdquo; quando dividido por um número fixo (chamado de módulo). Por ser um cálculo parecido com o mostrador de um relógio (que dá uma volta em 12 horas), também é chamada de &amp;ldquo;matemática do relógio&amp;rdquo;.&lt;/p>
&lt;p>Quando o resto da divisão dos inteiros $a$ e $b$ por um inteiro positivo $n$ é igual, matematicamente, descrevemos da seguinte forma:&lt;/p>
$$
a \equiv b \pmod n
$$
&lt;p>Isso é lido como &amp;ldquo;$a$ e $b$ são congruentes módulo $n$&amp;rdquo;. Por exemplo, o resto da divisão de 17 por 5 é 2, e o resto da divisão de 12 por 5 também é 2. Portanto, podemos escrever:&lt;/p>
$$
17 \equiv 12 \pmod 5 \equiv 2 \pmod 5
$$
&lt;p>Na aritmética modular, as quatro operações aritméticas normais (adição, subtração e multiplicação) valem como são:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adição&lt;/strong>: Se $a \equiv b \pmod n$ e $c \equiv d \pmod n$, então $a + c \equiv b + d \pmod n$&lt;/li>
&lt;li>&lt;strong>Subtração&lt;/strong>: Se $a \equiv b \pmod n$ e $c \equiv d \pmod n$, então $a - c \equiv b - d \pmod n$&lt;/li>
&lt;li>&lt;strong>Multiplicação&lt;/strong>: Se $a \equiv b \pmod n$ e $c \equiv d \pmod n$, então $a \times c \equiv b \times d \pmod n$&lt;/li>
&lt;li>&lt;strong>Exponenciação&lt;/strong>: Se $a \equiv b \pmod n$, então para qualquer número natural $k$, $a^k \equiv b^k \pmod n$&lt;/li>
&lt;/ol>
&lt;p>No entanto, é necessário ter cuidado com a &lt;strong>divisão&lt;/strong>. Em geral, o fato de que $a \times c \equiv b \times c \pmod n$ não significa que podemos dividir ambos os lados por $c$ para obter $a \equiv b \pmod n$. Isso só é verdadeiro se $c$ e $n$ forem coprimos (o máximo divisor comum for 1). Esse conceito de &amp;ldquo;inverso modular&amp;rdquo; torna-se extremamente importante na geração de chaves da criptografia RSA descrita mais adiante.&lt;/p>
&lt;hr>
&lt;h2 id="3-fundamentação-matemática-e-prova-do-pequeno-teorema-de-fermat">3. Fundamentação Matemática e Prova do Pequeno Teorema de Fermat
&lt;/h2>&lt;p>Agora que entendemos os fundamentos da aritmética modular, vamos analisar o assunto principal: o Pequeno Teorema de Fermat.&lt;/p>
&lt;h3 id="31-definição-do-teorema">3.1 Definição do Teorema
&lt;/h3>&lt;p>O Pequeno Teorema de Fermat é formulado da seguinte maneira:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Pequeno Teorema de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>
Seja $p$ um número primo e $a$ um número inteiro que não seja um múltiplo de $p$ (ou seja, $a$ e $p$ são coprimos). Então, a seguinte congruência é válida:
&lt;/p>
$$ a^{p-1} \equiv 1 \pmod p $$
&lt;/blockquote>
&lt;p>Também é comum expressá-lo de uma forma que seja válida para todos os inteiros $a$, removendo a condição &amp;ldquo;se $a$ não for múltiplo de $p$&amp;rdquo;. Nesse caso, multiplicando ambos os lados por $a$, temos:&lt;/p>
$$
a^p \equiv a \pmod p
$$
&lt;h3 id="32-confirmação-com-exemplos-específicos">3.2 Confirmação com Exemplos Específicos
&lt;/h3>&lt;p>Vamos confirmar se o teorema é realmente válido usando números específicos.
Seja o número primo $p = 5$. Então $p-1 = 4$. Escolheremos um número inteiro $a$ que não seja um múltiplo de $p$.&lt;/p>
&lt;ul>
&lt;li>Para $a = 2$: $2^{5-1} = 2^4 = 16$. $16 \div 5 = 3$ com resto $1$. Portanto, $16 \equiv 1 \pmod 5$. (Válido)&lt;/li>
&lt;li>Para $a = 3$: $3^{5-1} = 3^4 = 81$. $81 \div 5 = 16$ com resto $1$. Portanto, $81 \equiv 1 \pmod 5$. (Válido)&lt;/li>
&lt;li>Para $a = 4$: $4^{5-1} = 4^4 = 256$. $256 \div 5 = 51$ com resto $1$. Portanto, $256 \equiv 1 \pmod 5$. (Válido)&lt;/li>
&lt;/ul>
&lt;p>Como podemos ver, qualquer $a$ que escolhermos (desde que não seja um múltiplo de 5), o resto após elevá-lo à quarta potência e dividi-lo por 5 será sempre 1. Parece magia, mas isso se origina das belas propriedades que os números primos possuem.&lt;/p>
&lt;h3 id="33-prova-matemática-do-teorema">3.3 Prova Matemática do Teorema
&lt;/h3>&lt;p>Por que isso acontece? Aqui apresentamos uma prova elegante usando conjuntos de classes de resíduos.&lt;/p>
&lt;p>Considere o conjunto $S = \{1, 2, 3, \dots, p-1\}$. Estes são os representantes dos números inteiros cujos restos da divisão por $p$ são de $1$ a $p-1$.
Agora, considere um novo conjunto $T$, formado pela multiplicação de cada elemento por um inteiro $a$, coprimo com $p$.
&lt;/p>
$$ T = \{1a, 2a, 3a, \dots, (p-1)a\} $$
&lt;p>Vamos considerar o resto de cada elemento desse conjunto $T$ quando dividido por $p$. Surpreendentemente, esses restos, embora a ordem possa mudar, coincidem perfeitamente com o conjunto de elementos do conjunto original $S$.
Por que:&lt;/p>
&lt;ol>
&lt;li>Nenhum elemento de $T$ será múltiplo de $p$ (porque nem $a$ nem os elementos originais são múltiplos de $p$).&lt;/li>
&lt;li>Não existem dois elementos diferentes em $T$ que sejam congruentes módulo $p$. Se houvesse $ia \equiv ja \pmod p$ ($i \neq j$), já que $a$ e $p$ são coprimos, poderíamos dividir por $a$ e obter $i \equiv j \pmod p$, o que é uma contradição.&lt;/li>
&lt;/ol>
&lt;p>Portanto, o produto de todos os elementos de $S$ e o produto de todos os elementos de $T$ são congruentes módulo $p$.&lt;/p>
$$
(1a) \times (2a) \times \dots \times ((p-1)a) \equiv 1 \times 2 \times \dots \times (p-1) \pmod p
$$
&lt;p>Organizando o lado esquerdo, como temos $p-1$ fatores $a$, obtemos:&lt;/p>
$$
a^{p-1} \cdot (p-1)! \equiv (p-1)! \pmod p
$$
&lt;p>Como $(p-1)!$ e $p$ são coprimos, podemos dividir ambos os lados por $(p-1)!$, o que nos leva finalmente ao seguinte teorema:&lt;/p>
$$
a^{p-1} \equiv 1 \pmod p
$$
&lt;p>Esta é a prova do Pequeno Teorema de Fermat.&lt;/p>
&lt;hr>
&lt;h2 id="4-a-função-totiente-de-euler-e-o-teorema-de-euler">4. A Função Totiente de Euler e o Teorema de Euler
&lt;/h2>&lt;p>O Pequeno Teorema de Fermat é um teorema sobre um &amp;ldquo;número primo $p$&amp;rdquo;, mas quem o generalizou para &amp;ldquo;qualquer inteiro positivo $n$&amp;rdquo; foi Leonhard Euler. Essa extensão é essencial para compreender a criptografia RSA.&lt;/p>
&lt;h3 id="41-função-totiente-de-euler-phin">4.1 Função Totiente de Euler $\phi(n)$
&lt;/h3>&lt;p>A função totiente de Euler (ou função $\phi$ de Euler) $\phi(n)$ é uma função que representa &amp;ldquo;a quantidade de inteiros de $1$ a $n$ que são coprimos com $n$&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>Para um número primo $p$, como todos os inteiros de $1$ a $p-1$ são coprimos com $p$, temos $\phi(p) = p - 1$.&lt;/li>
&lt;li>Para dois números primos distintos $p$ e $q$, o valor de $\phi(n)$ para o seu produto $n = p \times q$ pode ser calculado com uma fórmula muito simples:
$$ \phi(p \times q) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$&lt;/li>
&lt;/ul>
&lt;p>Esta propriedade é a lógica central na geração de chaves da criptografia RSA.&lt;/p>
&lt;h3 id="42-teorema-de-euler">4.2 Teorema de Euler
&lt;/h3>&lt;p>Euler generalizou o Pequeno Teorema de Fermat da seguinte maneira:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Teorema de Euler (Euler&amp;rsquo;s Theorem)&lt;/strong>
Para qualquer inteiro positivo $n$ e um inteiro $a$ coprimo com ele, é válido que:
&lt;/p>
$$ a^{\phi(n)} \equiv 1 \pmod n $$
&lt;/blockquote>
&lt;p>Se $n$ for um número primo $p$, então $\phi(p) = p - 1$, o que o torna exatamente o Pequeno Teorema de Fermat ($a^{p-1} \equiv 1 \pmod p$). Em outras palavras, o Pequeno Teorema de Fermat não passa de um caso especial do Teorema de Euler.&lt;/p>
&lt;hr>
&lt;h2 id="5-encontrando-números-primos-gigantescos-o-teste-de-primalidade-de-fermat">5. Encontrando Números Primos Gigantescos: O Teste de Primalidade de Fermat
&lt;/h2>&lt;p>Na tecnologia criptográfica (como a criptografia RSA e a troca de chaves Diffie-Hellman), é necessário encontrar &amp;ldquo;números primos gigantescos&amp;rdquo; de centenas de dígitos em alta velocidade. No entanto, para testar se um número gigante $N$ é primo através da &amp;ldquo;divisão por tentativa&amp;rdquo; (testando a divisibilidade por todos os números de $2$ a $\sqrt{N}$), levaria tanto tempo quanto a idade do universo.&lt;/p>
&lt;p>Aqui entra o &lt;strong>Teste de Primalidade de Fermat (Fermat Primality Test)&lt;/strong>, um &amp;ldquo;teste de primalidade probabilístico&amp;rdquo; que usa o Pequeno Teorema de Fermat.&lt;/p>
&lt;h3 id="51-o-que-é-um-teste-de-primalidade-probabilístico">5.1 O que é um Teste de Primalidade Probabilístico?
&lt;/h3>&lt;p>De acordo com o Pequeno Teorema de Fermat, se $p$ for um número primo, então, para qualquer $a$ ($1 &lt; a &lt; p$), $a^{p-1} \equiv 1 \pmod p$ é sempre válido.
Tomando a contrapositiva: &amp;ldquo;Se houver algum $a$ para o qual $a^{p-1} \not\equiv 1 \pmod p$, então $p$ &lt;strong>absolutamente não é um número primo (é um número composto)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Portanto, se quisermos testar se $N$ é um número primo, escolhemos aleatoriamente alguns valores para $a$, calculamos $a^{N-1} \pmod N$ e verificamos se o resultado é $1$. Se obtivermos uma resposta diferente de $1$ mesmo que seja apenas uma vez, concluímos que $N$ é um número composto. Se o resultado for sempre $1$, independentemente de quantas vezes testarmos, podemos julgar com alta probabilidade que $N$ &amp;ldquo;provavelmente é primo&amp;rdquo;.&lt;/p>
&lt;h3 id="52-explicação-do-algoritmo-e-fluxograma">5.2 Explicação do Algoritmo e Fluxograma
&lt;/h3>&lt;p>O algoritmo do teste de Fermat é o seguinte.&lt;/p>
&lt;div class="mermaid">flowchart TD
Start["Início"] --> Input["Inserir o número a testar p e o número de testes k"]
Input --> LoopStart["Loop de i = 0 até k-1"]
LoopStart --> Condition{"i &lt; k ?"}
Condition -- "Sim" --> RandomA["Escolher um inteiro aleatório a no intervalo 1 &lt; a &lt; p-1"]
RandomA --> Calc["Calcular a exponenciação modular a^(p-1) mod p"]
Calc --> CheckPrime{"O resultado é 1 ?"}
CheckPrime -- "Não" --> ReturnComposite["p é um número composto (Definitivo)"]
CheckPrime -- "Sim" --> Increment["Incrementar i"]
Increment --> Condition
Condition -- "Não" --> ReturnPrime["p é provavelmente primo (Probabilístico)"]
ReturnComposite --> End["Fim"]
ReturnPrime --> End&lt;/div>
&lt;h3 id="53-a-armadilha-dos-números-de-carmichael-pseudoprimos">5.3 A Armadilha dos Números de Carmichael (Pseudoprimos)
&lt;/h3>&lt;p>O teste de Fermat é extremamente rápido, mas tem uma desvantagem séria. Existem números maldosos que, apesar de serem compostos, satisfazem $a^{N-1} \equiv 1 \pmod N$ para todos os valores de $a$. Estes são chamados de &lt;strong>Números de Carmichael (Carmichael numbers)&lt;/strong>. O menor número de Carmichael é $561$ ($3 \times 11 \times 17$).&lt;/p>
&lt;p>Devido à existência dos números de Carmichael, não se pode realizar um teste de primalidade absoluto usando apenas o teste puro de Fermat. Por esta razão, em sistemas criptográficos reais (como o OpenSSL), o &lt;strong>Teste de Primalidade de Miller-Rabin&lt;/strong>, que é um aprimoramento do teste de Fermat, é usado como padrão. O teste de Miller-Rabin consegue detectar os números de Carmichael, reduzindo a probabilidade de falso julgamento praticamente a zero.&lt;/p>
&lt;h3 id="54-exponenciação-modular-rápida-método-de-exponenciação-binária">5.4 Exponenciação Modular Rápida (Método de Exponenciação Binária)
&lt;/h3>&lt;p>No algoritmo de teste de primalidade, precisamos calcular $a^{N-1} \pmod N$, mas se $N$ for enorme, $a^{N-1}$ terá uma quantidade astronômica de dígitos e não caberá na memória do computador.
O que resolve esse problema é a &lt;strong>Exponenciação Binária (Exponentiation by Squaring)&lt;/strong> ou exponenciação modular. Ao aplicar o módulo (mod N) a cada etapa do cálculo, o valor é mantido sempre inferior a $N$, permitindo um cálculo muito rápido (complexidade $O(\log N)$).&lt;/p>
&lt;hr>
&lt;h2 id="6-implementação-do-teste-de-primalidade-e-exponenciação-modular">6. Implementação do Teste de Primalidade e Exponenciação Modular
&lt;/h2>&lt;p>Agora, vamos implementar o teste de primalidade de Fermat e o método de exponenciação binária em C++ e Python.&lt;/p>
&lt;h3 id="61-implementação-em-c">6.1 Implementação em C++
&lt;/h3>&lt;p>Em C++, os tipos de inteiros padrão tendem a transbordar, exigindo bibliotecas de inteiros de precisão arbitrária (como GMP) para lidar com números enormes, mas aqui mostramos uma implementação dentro do limite de um inteiro de 64 bits (&lt;code>unsigned long long&lt;/code>) para entender o algoritmo.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;random&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Exponenciação modular rápida (a^b mod m) - Método de exponenciação binária
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Se o bit menos significativo de b for 1, multiplica o resultado por a
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Extensão para 128 bits para evitar transbordamento
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Eleva a ao quadrado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">__int128&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Desloca b para a direita (divide por 2)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Teste de primalidade de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">random_device&lt;/span> &lt;span class="n">rd&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mt19937_64&lt;/span> &lt;span class="n">gen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rd&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uniform_int_distribution&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gen&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Se a^(p-1) mod p não for 1, é um número composto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">power_mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Provavelmente primo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">unsigned&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000000007&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Número primo conhecido
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is probably prime.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; is composite.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-implementação-em-python">6.2 Implementação em Python
&lt;/h3>&lt;p>O tipo inteiro padrão do Python suporta precisão arbitrária nativamente, de modo que não há necessidade de se preocupar com estouro de dígitos. Além disso, a função interna do Python &lt;code>pow(a, b, m)&lt;/code> usa internamente o método de exponenciação binária, tornando-a muito rápida.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">iterations&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Teste de primalidade probabilístico usando o Teste de Primalidade de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterations&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Escolhe um número aleatório a entre 2 e p-2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calcula a^(p-1) mod p. A função interna pow é rápida.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># Definitivamente composto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># Provavelmente primo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Teste&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">number_to_test&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">104729&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">fermat_is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> é provavelmente primo.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">number_to_test&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> é composto.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-aplicação-na-criptografia-rsa-onde-fermat-e-euler-dão-frutos">7. Aplicação na Criptografia RSA: Onde Fermat e Euler dão Frutos
&lt;/h2>&lt;p>A maior aplicação do Pequeno Teorema de Fermat (e do Teorema de Euler) é a &lt;strong>Criptografia RSA&lt;/strong>, desenvolvida por Rivest, Shamir e Adleman em 1977.
A criptografia RSA é um sistema revolucionário de &amp;ldquo;criptografia de chave pública&amp;rdquo;, que consegue um mecanismo onde a chave para criptografar (a chave pública) é revelada a todo o mundo, enquanto a chave para descriptografar (a chave privada) é conhecida apenas pelo destinatário pretendido.&lt;/p>
&lt;p>Essa assimetria é baseada na segurança computacional proporcionada pelo fato de que &amp;ldquo;a fatoração de um número composto gigantesco é extremamente difícil&amp;rdquo;.&lt;/p>
&lt;h3 id="71-como-funciona-a-criptografia-rsa-geração-de-chaves-criptografia-descriptografia">7.1 Como Funciona a Criptografia RSA (Geração de Chaves, Criptografia, Descriptografia)
&lt;/h3>&lt;p>Vamos ver o fluxo geral de comunicação da criptografia RSA com um diagrama de sequência Mermaid.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice["Alice (Destinatário)"]
participant Bob["Bob (Remetente)"]
Alice->>Alice: "Gera os primos gigantescos p e q"
Alice->>Alice: "Calcula N = p * q, φ(N) = (p-1)(q-1)"
Alice->>Alice: "Calcula a chave pública e e a chave privada d (e*d ≡ 1 mod φ(N))"
Alice->>Bob: "Envia a chave pública (N, e)"
Note over Bob: "Prepara o texto simples M (M &lt; N)"
Bob->>Bob: "Calcula o texto cifrado C = M^e mod N"
Bob->>Alice: "Envia o texto cifrado C"
Alice->>Alice: "Calcula o texto simples M = C^d mod N para descriptografar"&lt;/div>
&lt;p>Abaixo, explicaremos os passos matemáticos detalhados.&lt;/p>
&lt;h4 id="passo-1-geração-de-chaves-tarefa-da-destinatária-alice">Passo 1: Geração de Chaves (Tarefa da destinatária Alice)
&lt;/h4>&lt;ol>
&lt;li>Gera dois números primos gigantescos aleatórios $p$ e $q$ (o método de teste de primalidade descrito acima é usado aqui).&lt;/li>
&lt;li>Calcula o seu produto $N = p \times q$. Este $N$ torna-se público.&lt;/li>
&lt;li>Usando a função totiente de Euler, calcula $\phi(N) = (p-1)(q-1)$.&lt;/li>
&lt;li>Escolhe um número inteiro $e$ (expoente público) que seja coprimo com $\phi(N)$ (geralmente $e = 65537$ é usado).&lt;/li>
&lt;li>Calcula o inverso modular $d$ (expoente privado) de $e$. Ou seja, encontra $d$ que satisfaça o seguinte:
$$ e \cdot d \equiv 1 \pmod{\phi(N)} $$
Para esse cálculo, o &lt;strong>Algoritmo de Euclides Estendido&lt;/strong> é usado.&lt;/li>
&lt;/ol>
&lt;p>Com isso, a &lt;strong>chave pública é $(N, e)$&lt;/strong> e a &lt;strong>chave privada é $(N, d)$&lt;/strong>. (Eles descartam imediatamente ou ocultam estritamente $p, q, \phi(N)$).&lt;/p>
&lt;h4 id="passo-2-criptografia-tarefa-do-remetente-bob">Passo 2: Criptografia (Tarefa do remetente Bob)
&lt;/h4>&lt;p>Suponha que Bob queira enviar a mensagem $M$ para Alice ($M$ é uma representação numérica de caracteres, onde $0 \le M &lt; N$).
Bob usa a chave pública de Alice $(N, e)$ para realizar o seguinte cálculo e criar o texto cifrado $C$.&lt;/p>
$$
C \equiv M^e \pmod N
$$
&lt;p>Este $C$ é então enviado para Alice pela rede.&lt;/p>
&lt;h4 id="passo-3-descriptografia-tarefa-da-destinatária-alice">Passo 3: Descriptografia (Tarefa da destinatária Alice)
&lt;/h4>&lt;p>Ao receber o texto cifrado $C$, Alice realiza o seguinte cálculo usando a chave privada $d$ que apenas ela conhece.&lt;/p>
$$
M' \equiv C^d \pmod N
$$
&lt;p>Surpreendentemente, o resultado desse cálculo, $M'$, é exatamente igual à mensagem original $M$.&lt;/p>
&lt;h3 id="72-por-que-pode-ser-descriptografado-prova-matemática">7.2 Por que pode ser Descriptografado? (Prova Matemática)
&lt;/h3>&lt;p>É aqui que o Pequeno Teorema de Fermat (Teorema de Euler) mostra seu verdadeiro valor. Por que $C^d \pmod N$ retorna a $M$?&lt;/p>
&lt;p>Vamos expandir a equação de descriptografia.
Como $C \equiv M^e \pmod N$,
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>No passo de geração da chave, $d$ foi escolhido para que $e \cdot d \equiv 1 \pmod{\phi(N)}$. Isso significa que existe um número inteiro $k$ tal que:
&lt;/p>
$$ e \cdot d = 1 + k \cdot \phi(N) $$
&lt;p>Substituindo isso na equação acima:
&lt;/p>
$$ M^{ed} = M^{1 + k \cdot \phi(N)} = M \cdot M^{k \cdot \phi(N)} = M \cdot (M^{\phi(N)})^k \pmod N $$
&lt;p>Aqui, entra o &lt;strong>Teorema de Euler&lt;/strong> ($M^{\phi(N)} \equiv 1 \pmod N$). (&lt;em>Rigorosamente, $M$ e $N$ precisam ser coprimos, mas em RSA, a probabilidade de que $M$ e $N$ não sejam coprimos é astronomicamente baixa, e pelo Teorema Chinês do Resto, pode-se provar que é válido mesmo se não forem coprimos&lt;/em>).&lt;/p>
&lt;p>Aplicando o Teorema de Euler, como $M^{\phi(N)} \equiv 1$, temos:
&lt;/p>
$$ M \cdot (1)^k \equiv M \pmod N $$
&lt;p>$M$ foi perfeitamente restaurado! As propriedades dos números que Fermat e Euler descobriram há centenas de anos garantem perfeitamente a confidencialidade das comunicações digitais modernas.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementação-da-criptografia-rsa-de-brinquedo-python">8. Implementação da Criptografia RSA de Brinquedo (Python)
&lt;/h2>&lt;p>Uma vez que é difícil ter uma noção de como isso funciona baseando-se apenas na teoria, vamos usar o Python para implementar o processo de geração de chaves, criptografia e descriptografia da criptografia RSA na prática. Esta é uma &amp;ldquo;implementação de brinquedo&amp;rdquo; educacional, mas a matemática subjacente é exatamente a mesma.&lt;/p>
&lt;p>O &amp;ldquo;Algoritmo de Euclides Estendido&amp;rdquo; para encontrar o inverso modular $d$ também será incluído na implementação.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Encontrar o máximo divisor comum&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Algoritmo de Euclides Estendido (encontra x e y para ax + by = gcd(a,b))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Usado para encontrar d para e*d ≡ 1 (mod φ(N))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">extended_gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;O inverso não existe&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Função de geração de primos (Versão simples: gera números primos pequenos)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getrandbits&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Substitui o teste de Fermat acima por um teste simplificado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">p&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Geração de par de chaves RSA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Evita que p e q sejam iguais&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e costuma usar um número primo como 65537, mas vamos escolher aleatoriamente aqui&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cálculo da chave privada d&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Chave pública (e, n), chave privada (d, n)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calcula plaintext^e mod n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cipher&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">plaintext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cipher&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Calcula cipher^d mod n e reverte para um caractere&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">plain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">chr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">ciphertext&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plain&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo de execução&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- Implementação da Criptografia RSA de Brinquedo ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">private_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_keypair&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bits&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Usa um número primo de 12 bits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Chave pública (e, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Chave privada (d, n): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello Math!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Mensagem original: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Criptografia&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">encrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">public_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">encrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Descriptografia&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted_msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">decrypt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">private_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">encrypted_msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Mensagem descriptografada: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_msg&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Quando você executa este código, você pode confirmar como a matriz de caracteres é convertida em um array de números estranhos (texto cifrado), e como isso é restaurado perfeitamente para a string original através da chave privada.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusão-a-intersecção-entre-a-beleza-da-matemática-e-a-praticidade">9. Conclusão: A Intersecção entre a Beleza da Matemática e a Praticidade
&lt;/h2>&lt;p>Quando Pierre de Fermat descobriu este &amp;ldquo;pequeno teorema&amp;rdquo; no século 17, ninguém pensou que isso pudesse ser útil de alguma forma. O próprio Fermat conduziu suas pesquisas em teoria dos números com curiosidade puramente matemática.&lt;/p>
&lt;p>No entanto, nos anos 1970, cerca de 300 anos depois, nos primórdios das redes de computadores, o teorema de Fermat fez um retorno dramático como uma tecnologia de criptografia essencial para estabelecer protocolos de comunicação seguros. A tecnologia do teste de primalidade baseada no Pequeno Teorema de Fermat e a Criptografia RSA, com base no Teorema de Euler, sustentam literalmente a infraestrutura moderna da internet.&lt;/p>
&lt;p>Até mesmo a mensagem no LINE que enviamos casualmente todos os dias e nossas compras na Amazon, estão todas dançando no topo desta simples e bela fórmula: $a^{p-1} \equiv 1 \pmod p$. O Pequeno Teorema de Fermat nos ensina que, não importa o quão abstrata seja a matemática, o momento em que ela for útil para a humanidade sem dúvida chegará algum dia.&lt;/p>
&lt;p>Ao aprender programação e teoria criptográfica, compreender a estrutura matemática em seus fundamentos será uma grande arma para o profundo entendimento do comportamento das bibliotecas fornecidas como caixas-pretas e para o design de sistemas mais seguros.&lt;/p></description></item><item><title>A intuição matemática da criptografia baseada em reticulados (Lattice-based cryptography)</title><link>http://kenji.blog/pt/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/lattice-based-cryptography-math-intuition/</guid><description>&lt;img src="http://kenji.blog/p/lattice-based-cryptography-math-intuition/img/eyecatch.jpg" alt="Featured image of post A intuição matemática da criptografia baseada em reticulados (Lattice-based cryptography)" />&lt;h1 id="1-introdução-o-alvorecer-da-criptografia-pós-quântica-pqc-e-a-ascensão-da-criptografia-baseada-em-reticulados">1. Introdução: O alvorecer da Criptografia Pós-Quântica (PQC) e a ascensão da criptografia baseada em reticulados
&lt;/h1>&lt;p>A infraestrutura digital da sociedade moderna é sustentada por tecnologias de criptografia de chave pública, como a criptografia RSA e a Criptografia de Curva Elíptica (ECC). Esses métodos criptográficos baseiam sua segurança na dificuldade matemática de problemas como o &amp;ldquo;Problema de Fatoração de Inteiros&amp;rdquo; e o &amp;ldquo;Problema do Logaritmo Discreto&amp;rdquo;, que se acredita não poderem ser resolvidos eficientemente (exigindo tempo exponencial) pelos computadores clássicos convencionais.&lt;/p>
&lt;p>No entanto, o &amp;ldquo;Algoritmo de Shor&amp;rdquo;, publicado por Peter Shor em 1994, enviou ondas de choque através do mundo da criptografia. Este algoritmo provou matematicamente que, uma vez realizados computadores quânticos de grande escala, problemas de fatoração de inteiros e logaritmos discretos serão resolvidos em tempo polinomial. Isso significa que a criptografia de chave pública amplamente utilizada hoje se tornará completamente decifrável no futuro.&lt;/p>
&lt;p>Para combater essa &amp;ldquo;Ameaça Quântica (Quantum Threat)&amp;rdquo;, a pesquisa em novos métodos criptográficos que sejam difíceis de quebrar, mesmo usando computadores quânticos, tornou-se uma questão urgente. Este é o campo conhecido como &amp;ldquo;Criptografia Pós-Quântica (Post-Quantum Cryptography: PQC)&amp;rdquo; ou &amp;ldquo;Criptografia resistente a quantum&amp;rdquo;.&lt;/p>
&lt;p>Existem vários candidatos fortes para PQC. Estes incluem criptografia baseada em hash, criptografia baseada em código, criptografia polinomial multivariada e criptografia baseada em isogenia. Entre eles, o que atualmente atrai mais atenção e é fundamental para o processo de padronização PQC do NIST (Instituto Nacional de Padrões e Tecnologia dos EUA) é a &amp;ldquo;Criptografia baseada em reticulados (Lattice-based cryptography)&amp;rdquo;. Em comparação com outros métodos, a criptografia baseada em reticulados possui velocidades de criptografia e descriptografia extremamente rápidas e exibe uma característica notável em sua prova de segurança: uma redução da &amp;ldquo;complexidade do pior caso (Worst-case complexity)&amp;rdquo; para a &amp;ldquo;complexidade do caso médio (Average-case complexity)&amp;rdquo;, que é extremamente poderosa na teoria criptográfica.&lt;/p>
&lt;p>Neste artigo, começaremos pela definição matemática fundamental de um &amp;ldquo;Reticulado (Lattice)&amp;rdquo;, que é a base da criptografia baseada em reticulados, e explicaremos profundamente problemas difíceis em reticulados como SVP (Problema do Vetor Mais Curto) e CVP (Problema do Vetor Mais Próximo), e o núcleo da criptografia de reticulados moderna, o &amp;ldquo;Problema LWE (Learning With Errors)&amp;rdquo;, usando fórmulas, intuição geométrica e exemplos numéricos concretos.&lt;/p>
&lt;h1 id="2-definição-matemática-e-intuição-geométrica-do-reticulado-lattice">2. Definição Matemática e Intuição Geométrica do Reticulado (Lattice)
&lt;/h1>&lt;h2 id="21-espaço-vetorial-e-reticulados">2.1 Espaço Vetorial e Reticulados
&lt;/h2>&lt;p>Em matemática, um &amp;ldquo;Reticulado (Lattice)&amp;rdquo; é um conjunto de pontos discretos dispostos regularmente em um espaço vetorial real de dimensão $n$, $\mathbb{R}^n$. É semelhante a um espaço vetorial (Vector Space) aprendido em álgebra linear, mas há uma diferença crucial. Enquanto um espaço vetorial é um espaço contínuo representado por combinações lineares com &amp;ldquo;coeficientes reais&amp;rdquo; dos vetores de base, um reticulado é um espaço discreto representado por combinações lineares com &amp;ldquo;coeficientes inteiros&amp;rdquo; dos vetores de base.&lt;/p>
&lt;p>Vamos dar uma definição matemática rigorosa. Considere $n$ vetores linearmente independentes ($n \le m$) $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$ em um espaço vetorial real de dimensão $m$, $\mathbb{R}^m$. Considere uma matriz cujos vetores coluna são esses vetores: $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$. Esta $B$ é chamada de &amp;ldquo;Base (Basis)&amp;rdquo; do reticulado.&lt;/p>
&lt;p>O reticulado $\mathcal{L}(B)$ gerado por esta base $B$ é definido da seguinte forma:&lt;/p>
$$
\mathcal{L}(B) = \left\{ \sum_{i=1}^{n} x_i \mathbf{b}_i \mathrel{\bigg|} x_i \in \mathbb{Z} \right\} = \{ B \mathbf{x} \mid \mathbf{x} \in \mathbb{Z}^n \}
$$
&lt;p>O ponto importante aqui é que os coeficientes $x_i$ são restritos a inteiros $\mathbb{Z}$, e não a números reais $\mathbb{R}$. Isso forma um &amp;ldquo;conjunto de pontos discretos&amp;rdquo; semelhante a cruzamentos espaçados uniformemente, em vez dos infinitos pontos contínuos no espaço.&lt;/p>
&lt;h2 id="22-imagem-geométrica">2.2 Imagem Geométrica
&lt;/h2>&lt;p>Vamos considerar um exemplo em um plano bidimensional $\mathbb{R}^2$. Se escolhermos $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ e $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$ como vetores de base, o reticulado gerado por eles será o conjunto de todas as coordenadas inteiras $(x, y) \in \mathbb{Z}^2$ no plano cartesiano. Este é o &amp;ldquo;reticulado quadrado&amp;rdquo; mais simples.&lt;/p>
&lt;p>No entanto, reticulados nem sempre são ortogonais. Por exemplo, considerando a base $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ e $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$, os pontos gerados serão como as interseções de uma malha distorcida diagonalmente.&lt;/p>
&lt;h2 id="23-não-unicidade-da-base-e-transformação-unimodular">2.3 Não Unicidade da Base e Transformação Unimodular
&lt;/h2>&lt;p>Há uma propriedade importante relacionada ao núcleo da segurança da criptografia baseada em reticulados. É que &amp;ldquo;existem infinitas bases que geram o mesmo reticulado&amp;rdquo;.&lt;/p>
&lt;p>Por exemplo, a base anterior $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ que gera o reticulado $\mathbb{Z}^2$ também gerará exatamente o mesmo reticulado $\mathbb{Z}^2$ se usarmos a base $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$.&lt;/p>
&lt;p>A condição necessária e suficiente para uma certa base $B$ e outra base $B'$ gerarem o mesmo reticulado é que exista uma matriz com componentes inteiros $U \in \mathbb{Z}^{n \times n}$ tal que seu determinante seja $\det(U) = \pm 1$, e possa ser expressa como:
&lt;/p>
$$ B' = B U $$
&lt;p>
Tal matriz $U$ é chamada de &amp;ldquo;matriz unimodular (Unimodular matrix)&amp;rdquo;.&lt;/p>
&lt;p>A ideia básica em aplicações criptográficas é usar uma &amp;ldquo;boa base (uma base próxima de ser ortogonal, consistindo de vetores curtos)&amp;rdquo; como chave privada, e uma &amp;ldquo;base ruim (uma base consistindo de vetores extremamente oblíquos entre si e muito longos)&amp;rdquo; como chave pública. Calcular uma boa base a partir de uma base ruim torna-se extremamente difícil à medida que a dimensão aumenta. Esta é a intuição básica da criptografia baseada em reticulados.&lt;/p>
&lt;h1 id="3-problemas-computacionalmente-difíceis-em-reticulados">3. Problemas Computacionalmente Difíceis em Reticulados
&lt;/h1>&lt;p>A segurança da criptografia baseada em reticulados depende da dificuldade de resolver certos problemas matemáticos sobre reticulados. Aqui, introduziremos os dois problemas mais fundamentais e famosos.&lt;/p>
&lt;h2 id="31-problema-do-vetor-mais-curto-shortest-vector-problem-svp">3.1 Problema do Vetor Mais Curto (Shortest Vector Problem: SVP)
&lt;/h2>&lt;p>SVP é o problema mais clássico e famoso na teoria dos reticulados.&lt;/p>
&lt;p>&lt;strong>Definição (SVP):&lt;/strong>
Dada qualquer base de reticulado $B$, encontre o vetor não nulo $\mathbf{v}$ pertencente ao reticulado $\mathcal{L}(B)$ cuja norma euclidiana (comprimento) seja mínima.&lt;/p>
&lt;p>Expressando em fórmula, é o problema de encontrar $\mathbf{v}$ tal que $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$. Este comprimento mínimo é denotado como $\lambda_1(\mathcal{L})$ e é chamado de &amp;ldquo;Primeiro mínimo sucessivo (First successive minimum)&amp;rdquo; do reticulado.&lt;/p>
&lt;p>Em dimensões baixas, como 2D ou 3D, você pode desenhar uma figura e encontrar visualmente o vetor mais curto. Alternativamente, algoritmos de redução de base de Gauss podem resolvê-lo eficientemente. No entanto, sabe-se que em altas dimensões (por exemplo, dimensão $n$ na casa das centenas a milhares), resolver o SVP de forma exata é NP-difícil.&lt;/p>
&lt;p>Em criptografia do mundo real, em vez do vetor mais curto exato, é usado o SVP aproximado ($\gamma$-SVP) para encontrar um &amp;ldquo;vetor aproximadamente curto&amp;rdquo;. Se o fator de aproximação $\gamma$ for de tamanho polinomial, este problema ainda é considerado extremamente difícil.&lt;/p>
&lt;h2 id="32-problema-do-vetor-mais-próximo-closest-vector-problem-cvp">3.2 Problema do Vetor Mais Próximo (Closest Vector Problem: CVP)
&lt;/h2>&lt;p>CVP também é um problema extremamente importante na criptografia baseada em reticulados.&lt;/p>
&lt;p>&lt;strong>Definição (CVP):&lt;/strong>
Dada qualquer base de reticulado $B$ e qualquer vetor alvo no espaço $\mathbf{t} \in \mathbb{R}^m$ (não necessariamente um ponto do reticulado), encontre o ponto do reticulado $\mathbf{v} \in \mathcal{L}(B)$ que seja o mais próximo de $\mathbf{t}$.&lt;/p>
&lt;p>Expressando em fórmula, é o problema de procurar o ponto do reticulado $\mathbf{v}$ que resulta em $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$.&lt;/p>
&lt;p>O CVP também é NP-difícil em altas dimensões, semelhante ao SVP. Do ponto de vista das aplicações criptográficas, o problema LWE, descrito posteriormente, está intimamente relacionado a uma variante especial do CVP (Bounded Distance Decoding: BDD).&lt;/p>
&lt;h2 id="33-por-que-não-pode-ser-resolvido-em-altas-dimensões-os-limites-do-lll-e-bkz">3.3 Por que não pode ser resolvido em altas dimensões? (Os Limites do LLL e BKZ)
&lt;/h2>&lt;p>Um algoritmo famoso para resolver problemas de reticulados em altas dimensões é o algoritmo LLL (algoritmo de Lenstra-Lenstra-Lovász). O algoritmo LLL opera em tempo polinomial e pode reduzir a base do reticulado a uma &amp;ldquo;boa base&amp;rdquo; em certa medida. No entanto, o vetor mais curto encontrado pelo algoritmo LLL tem um fator de aproximação exponencial ($2^{\mathcal{O}(n)}$) em relação ao comprimento do vetor mais curto verdadeiro, portanto, não chega ao ponto de quebrar a segurança criptográfica.&lt;/p>
&lt;p>Usar algoritmos de redução de base mais poderosos como o algoritmo BKZ (Block Korkine-Zolotarev), que é uma melhoria do LLL, permite encontrar vetores mais curtos, mas seu tempo de computação aumenta exponencialmente em relação ao tamanho do bloco. Na criptografia baseada em reticulados, parâmetros seguros (como o tamanho da dimensão $n$) são determinados estimando o tempo de execução deste algoritmo BKZ. Nos parâmetros padrão atuais da PQC, são escolhidos valores entre 500 e 1000 ou mais para a dimensão $n$, e estima-se que levaria mais tempo do que a idade do universo para decifrá-los, mesmo com supercomputadores ou computadores quânticos futuros.&lt;/p>
&lt;h1 id="4-formulação-matemática-do-problema-lwe-learning-with-errors">4. Formulação Matemática do Problema LWE (Learning With Errors)
&lt;/h1>&lt;p>A maior parte da criptografia moderna baseada em reticulados é baseada no &amp;ldquo;Problema LWE (Learning With Errors)&amp;rdquo;, proposto por Oded Regev em 2005. A beleza do problema LWE reside na simplicidade de sua formulação e em ter uma prova matemática poderosa: a &amp;ldquo;redução da complexidade do pior caso para a complexidade do caso médio&amp;rdquo;.&lt;/p>
&lt;h2 id="41-equações-lineares-simultâneas-sem-ruído">4.1 Equações lineares simultâneas sem ruído
&lt;/h2>&lt;p>Para entender o problema LWE, vamos primeiro considerar equações lineares simultâneas simples sem ruído.
Suponha que haja um vetor secreto desconhecido $\mathbf{s} \in \mathbb{Z}_q^n$ (cada componente é um número inteiro de $0$ a $q-1$). Aqui, $q$ é considerado um número primo.&lt;/p>
&lt;p>Escolhemos vetores de coeficientes aleatórios $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$, e calculamos seu produto escalar com o vetor secreto $\mathbf{s}$ módulo $q$.
$b_1 = \langle \mathbf{a}_1, \mathbf{s} \rangle \pmod q$
$b_2 = \langle \mathbf{a}_2, \mathbf{s} \rangle \pmod q$
$\vdots$&lt;/p>
&lt;p>Se nos derem um número suficiente (pelo menos $n$) de pares $(\mathbf{a}_i, b_i)$, podemos restaurar facilmente o vetor secreto $\mathbf{s}$ usando a &amp;ldquo;Eliminação Gaussiana (Gaussian elimination)&amp;rdquo; em álgebra linear. Este é um problema que pode ser resolvido facilmente em tempo polinomial.&lt;/p>
&lt;h2 id="42-definição-do-problema-lwe-adicionando-ruído">4.2 Definição do problema LWE: Adicionando Ruído
&lt;/h2>&lt;p>Então, o que acontece se adicionarmos um pouco de &amp;ldquo;ruído (erro)&amp;rdquo; a este problema?
Esta é a essência do problema LWE.&lt;/p>
&lt;p>Para o vetor secreto desconhecido $\mathbf{s} \in \mathbb{Z}_q^n$, adicionamos um pequeno erro $e_i \in \mathbb{Z}_q$ ao resultado de cada equação.
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>Aqui, $e_i$ é um número inteiro pequeno com média 0 e desvio padrão relativamente pequeno (por exemplo, retirado de uma distribuição Gaussiana discreta, como uma distribuição normal).
A informação fornecida é uma lista de pares do vetor aleatório $\mathbf{a}_i$ e $b_i$ calculado adicionando o erro.
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>Expressar isso em forma de matriz o torna muito claro.
Usando uma matriz aleatória $A \in \mathbb{Z}_q^{m \times n}$, um vetor secreto $\mathbf{s} \in \mathbb{Z}_q^n$, e um vetor de erro $\mathbf{e} \in \mathbb{Z}_q^m$,
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
pode ser escrito. Apenas $A$ e $\mathbf{b}$ são fornecidos. Encontrar $\mathbf{s}$ a partir disso é o &amp;ldquo;Problema de busca LWE (Search LWE problem)&amp;rdquo;.&lt;/p>
&lt;p>Como o erro $e_i$ está incluído, ao tentar usar a eliminação gaussiana, o erro será amplificado exponencialmente durante o processo de adição e subtração de equações, tornando impossível chegar à resposta correta. À primeira vista, parecem equações lineares simultâneas simples, mas apenas adicionando esse pequeno ruído, o nível de dificuldade do problema salta para um nível NP-difícil.&lt;/p>
&lt;h2 id="43-problema-lwe-de-decisão-decision-lwe">4.3 Problema LWE de decisão (Decision LWE)
&lt;/h2>&lt;p>O que é frequentemente usado em provas na teoria criptográfica é uma variação do problema de busca LWE chamado de &amp;ldquo;Problema LWE de decisão (Decision LWE problem)&amp;rdquo;.&lt;/p>
&lt;p>O problema de decisão LWE é o problema de determinar de qual de duas distribuições uma lista de amostras fornecida se origina.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Distribuição LWE&lt;/strong>: Intencionalmente calculada $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$&lt;/li>
&lt;li>&lt;strong>Distribuição aleatória uniforme&lt;/strong>: $(A, \mathbf{u})$ que consiste em uma matriz completamente escolhida aleatoriamente $A$ e vetor $\mathbf{u}$&lt;/li>
&lt;/ol>
&lt;p>Surpreendentemente, se os parâmetros do problema LWE forem escolhidos de forma apropriada, pares de dados da distribuição LWE tornam-se &amp;ldquo;computacionalmente indistinguíveis (Computationally Indistinguishable)&amp;rdquo; de pares de dados completamente aleatórios. Esta propriedade é a base pela qual os cifradores baseados em LWE podem gerar &amp;ldquo;textos cifrados indistinguíveis de números aleatórios&amp;rdquo;.&lt;/p>
&lt;h2 id="44-redução-da-complexidade-do-pior-caso-para-a-complexidade-do-caso-médio-teorema-de-regev">4.4 Redução da complexidade do pior caso para a complexidade do caso médio (Teorema de Regev)
&lt;/h2>&lt;p>A maior conquista de Oded Regev foi ter vinculado matematicamente a dificuldade deste problema LWE à dificuldade dos problemas de reticulados (SVP e CVP) mencionados acima.&lt;/p>
&lt;p>Ele usou a redução quântica (Quantum reduction) para provar que &amp;ldquo;Se existe um algoritmo de tempo polinomial que pode resolver o problema LWE na média (para $A$ e $\mathbf{e}$ escolhidos aleatoriamente), então existe um algoritmo quântico de tempo polinomial que pode resolver o Gap-SVP no pior caso (o caso mais difícil) para qualquer reticulado&amp;rdquo;. (Mais tarde, Peikert e outros também mostraram a redução clássica).&lt;/p>
&lt;p>Esta é uma propriedade dos sonhos na teoria criptográfica. Porque dissipa a preocupação de que &amp;ldquo;a criptografia possa ser quebrada porque por acaso escolhemos uma chave fraca (uma parte do caso médio)&amp;rdquo; e nos dá a poderosa garantia de que &amp;ldquo;Se o LWE médio puder ser resolvido, todos os problemas difíceis do reticulado poderão ser resolvidos (portanto, o LWE é absolutamente difícil)&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Problemas de Reticulado de Pior Caso (Gap-SVP, SIVP)"] -->|Redução Quântica/Clássica| B["Problema LWE de Caso Médio"]
B -->|Construção Criptográfica| C["Sistemas Criptográficos baseados em LWE (PKE, KEM, FHE)"]
style A fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#000
style B fill:#ccffcc,stroke:#00aa00,stroke-width:2px,color:#000
style C fill:#ccccff,stroke:#0000ff,stroke-width:2px,color:#000&lt;/div>
&lt;h1 id="5-construção-do-cifrador-de-chave-pública-usando-lwe-cifrador-regev">5. Construção do Cifrador de Chave Pública usando LWE (Cifrador Regev)
&lt;/h1>&lt;p>Agora que entendemos a dificuldade do problema LWE, vamos ver a criptografia de chave pública básica proposta por Oded Regev para ver como ela é usada para criptografia e descriptografia. Aqui, explicaremos o mecanismo mais básico para criptografar uma mensagem de 1 bit $M \in \{0, 1\}$.&lt;/p>
&lt;h2 id="51-geração-de-chaves-key-generation">5.1 Geração de chaves (Key Generation)
&lt;/h2>&lt;ol>
&lt;li>Determine o módulo primo $q$, a dimensão $n$, e o número de equações $m$ ($m > n \log q$) como parâmetros do sistema.&lt;/li>
&lt;li>Como uma chave privada, escolha um vetor $\mathbf{s} \in \mathbb{Z}_q^n$ aleatoriamente.&lt;/li>
&lt;li>Gere uma matriz aleatória $A \in \mathbb{Z}_q^{m \times n}$.&lt;/li>
&lt;li>Escolha um vetor de erro pequeno $\mathbf{e} \in \mathbb{Z}_q^m$ a partir de uma distribuição de erro como a distribuição gaussiana discreta.&lt;/li>
&lt;li>Calcule o vetor $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$.&lt;/li>
&lt;li>A chave pública (Public Key) será $(A, \mathbf{b})$.&lt;/li>
&lt;li>A chave privada (Secret Key) será $\mathbf{s}$.&lt;/li>
&lt;/ol>
&lt;p>A chave pública é exatamente a &amp;ldquo;instância do problema LWE&amp;rdquo; em si. Uma vez que encontrar a chave privada $\mathbf{s}$ a partir da chave pública $(A, \mathbf{b})$ é equivalente a resolver o problema de busca LWE, a segurança é garantida.&lt;/p>
&lt;h2 id="52-criptografia-encryption">5.2 Criptografia (Encryption)
&lt;/h2>&lt;p>Alice usa a chave pública de Bob $(A, \mathbf{b})$ para criptografar a mensagem de 1 bit $M \in \{0, 1\}$.&lt;/p>
&lt;ol>
&lt;li>Escolha um vetor binário aleatório (composto de zeros ou uns) $\mathbf{r} \in \{0, 1\}^m$.&lt;/li>
&lt;li>Como a primeira metade do texto cifrado, calcule o vetor $\mathbf{u} = A^T \mathbf{r} \pmod q$. ($A^T$ é a matriz transposta de $A$. Em outras palavras, está somando as linhas de $A$ onde os componentes de $\mathbf{r}$ são 1).&lt;/li>
&lt;li>Como a segunda metade do texto cifrado, calcule o escalar $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$.
(Se a mensagem $M$ for 0, nada é adicionado; se for $1$, é adicionado o valor exatamente da metade de $q$, $\lfloor \frac{q}{2} \rfloor$).&lt;/li>
&lt;li>O texto cifrado (Ciphertext) será $(\mathbf{u}, v)$.&lt;/li>
&lt;/ol>
&lt;p>O significado intuitivo da criptografia é pegar a &amp;ldquo;soma de um subconjunto aleatório&amp;rdquo; para a matriz de chave pública $A$ e o vetor $\mathbf{b}$. Devido à dificuldade do problema LWE de decisão, esse texto cifrado $(\mathbf{u}, v)$ parece indistinguível de um vetor completamente aleatório e um número aleatório uniforme (Segurança semântica: Semantic Security).&lt;/p>
&lt;div class="mermaid">flowchart LR
M["Mensagem M em {0,1}"] --> Enc
PK["Chave Pública (A, b)"] --> Enc
r["Vetor binário aleatório r"] --> Enc
subgraph Enc ["Processo de Criptografia"]
direction TB
u_calc["u = A^T * r mod q"]
v_calc["v = b^T * r + M * floor(q/2) mod q"]
end
Enc --> CT["Texto Cifrado (u, v)"]&lt;/div>
&lt;h2 id="53-descriptografia-decryption">5.3 Descriptografia (Decryption)
&lt;/h2>&lt;p>Bob descriptografa o texto cifrado $(\mathbf{u}, v)$ usando a chave secreta $\mathbf{s}$.&lt;/p>
&lt;ol>
&lt;li>Calcule o seguinte valor: $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>Se o resultado calculado estiver mais próximo de $0$, a saída é $M=0$; se estiver mais próximo de $\lfloor \frac{q}{2} \rfloor$, a saída é $M=1$.&lt;/li>
&lt;/ol>
&lt;p>Vamos expandir matematicamente para ver por que isso permite a descriptografia.
Lembre-se de que $\mathbf{b} = A \mathbf{s} + \mathbf{e}$.&lt;/p>
$$
\begin{aligned}
v - \mathbf{s}^T \mathbf{u} &amp;= (\mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T (A^T \mathbf{r}) \\
&amp;= ((A \mathbf{s} + \mathbf{e})^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= (\mathbf{s}^T A^T \mathbf{r} + \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor) - \mathbf{s}^T A^T \mathbf{r} \\
&amp;= \mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q
\end{aligned}
$$
&lt;p>Aqui, $\mathbf{s}^T A^T \mathbf{r}$ foi perfeitamente cancelado e desapareceu da fórmula!
O que restou foi $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$.&lt;/p>
&lt;p>$\mathbf{e}$ é um vetor de ruído cujos componentes são extremamente pequenos, e $\mathbf{r}$ é um vetor binário cujos componentes são 0 ou 1. Portanto, o produto escalar deles, $\mathbf{e}^T \mathbf{r}$, também permanece em um valor relativamente pequeno (se os parâmetros forem escolhidos apropriadamente).&lt;/p>
&lt;ul>
&lt;li>Se $M=0$, o resultado é $\mathbf{e}^T \mathbf{r}$, o que será um valor pequeno próximo de $0$.&lt;/li>
&lt;li>Se $M=1$, o resultado é $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$, o qual ficará próximo da metade do valor de $q$, $\lfloor \frac{q}{2} \rfloor$.&lt;/li>
&lt;/ul>
&lt;p>Se os parâmetros forem desenhados para que o valor absoluto do erro $\mathbf{e}^T \mathbf{r}$ fique abaixo de $\frac{q}{4}$, Bob pode determinar (descriptografar) com precisão a mensagem $M$ apenas olhando se o resultado do cálculo está mais próximo de $0$ ou $\lfloor \frac{q}{2} \rfloor$. Este é o belo mecanismo pelo qual os cifradores baseados em LWE funcionam.&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["Texto Cifrado (u, v)"] --> Dec
SK["Chave Secreta s"] --> Dec
subgraph Dec ["Processo de Descriptografia"]
direction TB
calc["Calcular D = v - s^T * u mod q"]
check["Verificar se D está mais próximo de 0 ou q/2"]
end
calc --> check
Dec --> M_out["Mensagem Recuperada M"]&lt;/div>
&lt;h1 id="6-exemplo-prático-toy-example-de-criptografia-lwe-com-valores-numéricos-específicos">6. Exemplo Prático (Toy Example) de Criptografia LWE com Valores Numéricos Específicos
&lt;/h1>&lt;p>Pode ser difícil ter uma noção apenas listando equações, então vamos tentar definir parâmetros numéricos muito pequenos e seguir o cálculo desde a criptografia até a descriptografia.
(*Em sistemas criptográficos do mundo real, são utilizados valores para $n$ superiores a 500 e $q$ superiores a milhares para garantir a segurança.)&lt;/p>
&lt;p>&lt;strong>[Configuração de Parâmetros]&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Módulo $q = 17$ (Número primo. Assim, os valores variam de $0$ a $16$)&lt;/li>
&lt;li>Dimensão $n = 2$&lt;/li>
&lt;li>Número de equações $m = 4$&lt;/li>
&lt;li>Suponha que vamos criptografar a mensagem $M = 1$.&lt;/li>
&lt;li>Quantidade de deslocamento da mensagem: $\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[1. Fase de Geração de Chaves]&lt;/strong>
Bob seleciona a chave privada $\mathbf{s}$, a matriz $A$ e o vetor de erro $\mathbf{e}$ aleatoriamente.
&lt;/p>
$$ \mathbf{s} = \begin{pmatrix} 3 \\ 4 \end{pmatrix} \in \mathbb{Z}_{17}^2 $$
$$ A = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \in \mathbb{Z}_{17}^{4 \times 2} $$
$$ \mathbf{e} = \begin{pmatrix} 1 \\ -1 \\ 0 \\ 2 \end{pmatrix} \equiv \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} \pmod{17} $$
&lt;p>Em seguida, ele calcula a chave pública $\mathbf{b}$.
&lt;/p>
$$ A \mathbf{s} = \begin{pmatrix} 2 &amp; 15 \\ 1 &amp; 8 \\ 14 &amp; 5 \\ 9 &amp; 10 \end{pmatrix} \begin{pmatrix} 3 \\ 4 \end{pmatrix} = \begin{pmatrix} 2\times 3 + 15\times 4 \\ 1\times 3 + 8\times 4 \\ 14\times 3 + 5\times 4 \\ 9\times 3 + 10\times 4 \end{pmatrix} = \begin{pmatrix} 6 + 60 \\ 3 + 32 \\ 42 + 20 \\ 27 + 40 \end{pmatrix} = \begin{pmatrix} 66 \\ 35 \\ 62 \\ 67 \end{pmatrix} $$
&lt;p>
Calculando isto no módulo 17 (por exemplo, $66 = 17 \times 3 + 15$):
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
Adicionando o vetor de erro $\mathbf{e}$:
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} + \begin{pmatrix} 1 \\ 16 \\ 0 \\ 2 \end{pmatrix} = \begin{pmatrix} 16 \\ 17 \\ 11 \\ 18 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 0 \\ 11 \\ 1 \end{pmatrix} \pmod{17} $$
&lt;p>A chave pública será $A$ e $\mathbf{b} = (16, 0, 11, 1)^T$.&lt;/p>
&lt;p>&lt;strong>[2. Fase de Criptografia]&lt;/strong>
Alice criptografa a mensagem $M = 1$.
Ela escolhe um vetor aleatório $\mathbf{r}$. Aqui, assumiremos $\mathbf{r} = (1, 0, 1, 0)^T$.&lt;/p>
&lt;p>Calculando $\mathbf{u}$:
&lt;/p>
$$ \mathbf{u} = A^T \mathbf{r} = \begin{pmatrix} 2 &amp; 1 &amp; 14 &amp; 9 \\ 15 &amp; 8 &amp; 5 &amp; 10 \end{pmatrix} \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = \begin{pmatrix} 2 \times 1 + 14 \times 1 \\ 15 \times 1 + 5 \times 1 \end{pmatrix} = \begin{pmatrix} 16 \\ 20 \end{pmatrix} \equiv \begin{pmatrix} 16 \\ 3 \end{pmatrix} \pmod{17} $$
&lt;p>Calculando $v$:
&lt;/p>
$$ \mathbf{b}^T \mathbf{r} = (16, 0, 11, 1) \begin{pmatrix} 1 \\ 0 \\ 1 \\ 0 \end{pmatrix} = 16 \times 1 + 11 \times 1 = 27 \equiv 10 \pmod{17} $$
&lt;p>
Ela adiciona o valor $\lfloor 17/2 \rfloor = 8$ correspondente à mensagem $M=1$.
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>Alice envia o texto cifrado $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ para Bob.&lt;/p>
&lt;p>&lt;strong>[3. Fase de Descriptografia]&lt;/strong>
Ao receber o texto cifrado, Bob descriptografa usando a chave secreta $\mathbf{s} = (3, 4)^T$.
Fórmula do processo de descriptografia: Ele calcula $D = v - \mathbf{s}^T \mathbf{u} \pmod{17}$.&lt;/p>
$$ \mathbf{s}^T \mathbf{u} = (3, 4) \begin{pmatrix} 16 \\ 3 \end{pmatrix} = 3 \times 16 + 4 \times 3 = 48 + 12 = 60 \equiv 9 \pmod{17} $$
$$ D = v - \mathbf{s}^T \mathbf{u} = 1 - 9 = -8 \pmod{17} $$
&lt;p>Aqui, no mundo de módulo 17, $-8$ é equivalente a $9$ ($-8 + 17 = 9$).
Ele verifica se o valor obtido $D = 9$ está mais próximo de $0$ ou $8$ ($\lfloor 17/2 \rfloor$).
Uma vez que $9$ é claramente mais próximo de $8$ do que de $0$, Bob conseguiu recuperar corretamente $M = 1$!&lt;/p>
&lt;p>Por que se tornou $9$? Lembre-se da prova anterior.
A parte do erro é $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$.
Portanto, o resultado do cálculo é $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$, confirmando que o valor teórico foi calculado.&lt;/p>
&lt;h1 id="7-evolução-para-a-prática-ring-lwe-e-module-lwe">7. Evolução para a Prática: Ring-LWE e Module-LWE
&lt;/h1>&lt;p>O problema LWE Padrão (Standard LWE) explicado até agora possui provas de segurança muito fortes, mas tem uma fraqueza fatal na prática. Esta é o &amp;ldquo;tamanho da chave torna-se enorme&amp;rdquo; e &amp;ldquo;os custos de computação são elevados&amp;rdquo;.&lt;/p>
&lt;p>No Standard LWE, a chave pública contém uma matriz enorme $A \in \mathbb{Z}_q^{m \times n}$. Quando o parâmetro $n$ atinge centenas ou milhares, o tamanho dessa matriz chega a vários megabytes, o que a torna muito pesada para transmissão através de protocolos de comunicação na internet (como TLS) todas as vezes. Além disso, a multiplicação entre matrizes e vetores requer complexidade computacional de $\mathcal{O}(n^2)$.&lt;/p>
&lt;p>Para resolver esse problema, &amp;ldquo;Ring-LWE (RLWE)&amp;rdquo; e &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; foram introduzidos, incorporando a estrutura algébrica dos anéis de polinômios (Polynomial rings) aos reticulados.&lt;/p>
&lt;h2 id="71-a-intuição-do-ring-lwe">7.1 A Intuição do Ring-LWE
&lt;/h2>&lt;p>No Ring-LWE, vetores e matrizes são substituídos por elementos (polinômios) em um anel de polinômios $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$. (Aqui, $n$ é escolhido como uma potência de 2).&lt;/p>
&lt;p>Enquanto a chave pública no LWE Padrão era uma matriz $A$, o Ring-LWE usa um único polinômio $a(x)$. A chave privada $s(x)$ e o erro $e(x)$ também se tornam polinômios.
A equação fica assim:
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Por ser uma multiplicação polinomial, ao usar a &amp;ldquo;Transformada Numérica de Teoria (Number Theoretic Transform: NTT)&amp;rdquo;, que é análoga à Transformada Rápida de Fourier (FFT), o custo computacional pode ser drasticamente reduzido para $\mathcal{O}(n \log n)$. Além disso, dado que o tamanho da chave pública é reduzido de uma matriz para um único polinômio, o tamanho dos dados é reduzido para $\mathcal{O}(n)$. Isso traz uma vantagem esmagadora na largura de banda de comunicação.&lt;/p>
&lt;p>Matematicamente falando, o Ring-LWE não é sobre reticulados gerais, mas reduz-se a problemas em um reticulado especial simétrico chamado &amp;ldquo;Reticulado Ideal (Ideal Lattice)&amp;rdquo;.&lt;/p>
&lt;h2 id="72-module-lwe-e-a-padronização-do-nist-kyber--ml-kem">7.2 Module-LWE e a Padronização do NIST (Kyber / ML-KEM)
&lt;/h2>&lt;p>Embora o Ring-LWE seja eficiente, houve alguma preocupação de que a estrutura algébrica especial dos reticulados ideais pudesse se tornar a base para ataques futuros. Portanto, foi criado o &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; para obter &amp;ldquo;o melhor dos dois mundos&amp;rdquo;, combinando a segurança conservadora do LWE Padrão com a eficiência do Ring-LWE.&lt;/p>
&lt;p>No Module-LWE, consideramos pequenos vetores e matrizes cujos elementos são polinômios. Ou seja, lidamos com módulos (modules) sobre um anel.
Atualmente, o &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; (nome padronizado: ML-KEM), selecionado pelo NIST como o padrão para algoritmos de compartilhamento de chaves (KEM) da PQC, é construído exatamente sobre a dificuldade desse problema Module-LWE.&lt;/p>
&lt;h1 id="8-por-que-é-seguro-contra-computadores-quânticos">8. Por que é seguro contra computadores quânticos?
&lt;/h1>&lt;p>Por fim, tocaremos na questão central: &amp;ldquo;Por que se acredita que a criptografia baseada em reticulados não pode ser decifrada nem mesmo por computadores quânticos?&amp;rdquo;.&lt;/p>
&lt;p>O algoritmo de Shor, que permite aos computadores quânticos quebrar a criptografia RSA ou a criptografia de curvas elípticas, é essencialmente um algoritmo para resolver o &amp;ldquo;Problema do Subgrupo Oculto (Hidden Subgroup Problem: HSP)&amp;rdquo;. As estruturas matemáticas subjacentes à RSA e à ECC (grupos abelianos finitos) possuem periodicidade, e usando a operação específica de algoritmos quânticos chamada Transformada de Fourier Quântica (QFT), esse período (subgrupo oculto) pode ser extraído de uma vez.&lt;/p>
&lt;p>Contudo, os problemas de reticulados são fundamentalmente diferentes. Embora os reticulados também tenham periodicidade, o que é requerido em problemas como SVP e CVP são propriedades geométricas não-lineares, como &amp;ldquo;a distância mais curta&amp;rdquo; e &amp;ldquo;a remoção de ruído&amp;rdquo;. Mesmo que se aplique a &amp;ldquo;transformada de Fourier quântica sobre grupos abelianos&amp;rdquo; como no algoritmo de Shor diretamente, informações úteis que poderiam ser a resposta a problemas de reticulados não podem ser extraídas eficientemente. Até o momento, não foram descobertos algoritmos quânticos que resolvam SVP ou LWE em tempo polinomial e acredita-se amplamente que, mesmo com a capacidade de computação paralela dos computadores quânticos, não exista meio eficaz além de uma busca por força bruta (com uma aceleração na raiz quadrada pelo algoritmo de Grover).&lt;/p>
&lt;h1 id="9-conclusão">9. Conclusão
&lt;/h1>&lt;p>Neste artigo, explicamos em detalhes a intuição matemática da criptografia baseada em reticulados, começando pela definição geométrica de um reticulado, a formulação do problema LWE e culminando na construção da criptografia de chave pública.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Reticulado (Lattice)&lt;/strong> é um espaço discreto expresso por uma combinação linear com coeficientes inteiros de vetores de base, e em dimensões altas, torna-se difícil encontrar uma &amp;ldquo;boa base&amp;rdquo; quase ortogonal (SVP).&lt;/li>
&lt;li>O &lt;strong>Problema LWE (Learning With Errors)&lt;/strong> é o problema de resolver um sistema de equações lineares com ruído, e por estar vinculado à dificuldade do caso mais difícil dos problemas de reticulados, oferece uma poderosa garantia de segurança.&lt;/li>
&lt;li>Ao usar o problema LWE, a criptografia e descriptografia (&lt;strong>Cifrador Regev&lt;/strong>) são alcançadas através de um mecanismo inteligente de adição e cancelamento intencional de ruídos.&lt;/li>
&lt;li>Em protocolos do mundo real, o &lt;strong>Ring-LWE&lt;/strong> e o &lt;strong>Module-LWE&lt;/strong> usando anéis de polinômios são adotados para aumentar a eficiência de comunicação e velocidade computacional, formando a base do padrão NIST &lt;strong>ML-KEM&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;p>À medida que nos aproximamos de uma mudança de paradigma computacional sem precedentes chamada computador quântico, é uma história muito romântica que a &amp;ldquo;Criptografia baseada em reticulados&amp;rdquo;, nascida das profundezas da álgebra linear clássica e da teoria dos números, apoiará a fundação da segurança da internet no futuro. A matemática que fundamenta a criptografia de reticulados não é excessivamente complexa, e com conhecimentos básicos de álgebra linear e probabilidade, pode-se entender completamente sua bela estrutura. Esperamos que este artigo ajude na compreensão da criptografia baseada em reticulados, que é o cerne da PQC.&lt;/p></description></item><item><title>O Funcionamento das Provas de Conhecimento Zero (ZKP) e as Últimas Aplicações em Web3 e Segurança</title><link>http://kenji.blog/pt/p/zero-knowledge-proofs-zkp-web3-security/</link><pubDate>Fri, 11 Sep 2026 19:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/zero-knowledge-proofs-zkp-web3-security/</guid><description>&lt;img src="http://kenji.blog/p/zero-knowledge-proofs-zkp-web3-security/img/eyecatch.jpg" alt="Featured image of post O Funcionamento das Provas de Conhecimento Zero (ZKP) e as Últimas Aplicações em Web3 e Segurança" />&lt;h2 id="introdução">Introdução
&lt;/h2>&lt;p>Na sociedade digital moderna, a privacidade de dados e a escalabilidade tornaram-se dois dos desafios mais importantes. Com o aumento do risco de vazamento de informações pessoais e uso não autorizado, há uma forte demanda por tecnologias que permitam &amp;ldquo;provar que você possui determinada informação sem revelá-la à outra parte&amp;rdquo;. Isso é alcançado pela &lt;strong>Prova de Conhecimento Zero (Zero-Knowledge Proof: ZKP)&lt;/strong>.&lt;/p>
&lt;p>A Prova de Conhecimento Zero é um conceito de teoria criptográfica proposto pela primeira vez na década de 1980 por Shafi Goldwasser, Silvio Micali e Charles Rackoff, mas que permaneceu restrito à pesquisa teórica por um longo tempo. No entanto, com a ascensão da tecnologia blockchain e da Web3, a situação mudou drasticamente. A ZKP ganhou destaque repentino como a &amp;ldquo;varinha mágica&amp;rdquo; para resolver simultaneamente o problema de escalabilidade (limites de capacidade de processamento) e o problema de privacidade (todas as transações sendo públicas) enfrentados por blockchains públicas como o Ethereum.&lt;/p>
&lt;p>Neste artigo, exploraremos detalhadamente e tecnicamente desde os conceitos fundamentais das Provas de Conhecimento Zero, os profundos mecanismos matemáticos e criptográficos dos atualmente populares &lt;strong>zk-SNARKs&lt;/strong> e &lt;strong>zk-STARKs&lt;/strong>, até os exemplos mais recentes de aplicações em Web3 e segurança, como ZK-Rollups e Identidade Descentralizada (DID).&lt;/p>
&lt;hr>
&lt;h2 id="o-que-é-uma-prova-de-conhecimento-zero-zkp">O que é uma Prova de Conhecimento Zero (ZKP)?
&lt;/h2>&lt;p>Uma Prova de Conhecimento Zero (ZKP) refere-se a um protocolo onde, ao provar que uma certa proposição é verdadeira, um provador (Prover) não transmite nenhuma informação a um verificador (Verifier) &amp;ldquo;além do fato de que a proposição é verdadeira&amp;rdquo;.&lt;/p>
&lt;h3 id="3-requisitos-que-a-zkp-deve-satisfazer">3 Requisitos que a ZKP Deve Satisfazer
&lt;/h3>&lt;p>Para ser estabelecida como uma ZKP, os três seguintes atributos devem ser estritamente atendidos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Completude (Completeness)&lt;/strong>
Se a proposição for verdadeira e tanto o provador quanto o verificador seguirem o protocolo corretamente, o verificador deve aceitar (Accept) a prova com uma probabilidade esmagadora.&lt;/li>
&lt;li>&lt;strong>Solidez (Soundness)&lt;/strong>
Se a proposição for falsa, mesmo o provador mais malicioso e com grande poder computacional não poderá enganar o verificador para aceitar a prova (exceto por uma probabilidade insignificantemente pequena).&lt;/li>
&lt;li>&lt;strong>Conhecimento Zero (Zero-Knowledge)&lt;/strong>
Se a proposição for verdadeira, o verificador não pode obter do processo de prova nenhuma informação além do fato de que &amp;ldquo;a proposição é verdadeira&amp;rdquo;. Do ponto de vista do verificador, prova-se por definição matemática que é possível simular o processo de prova (existe um simulador).&lt;/li>
&lt;/ol>
&lt;h3 id="provas-interativas-e-não-interativas">Provas Interativas e Não Interativas
&lt;/h3>&lt;p>Existem dois tipos de ZKP: &lt;strong>provas interativas (Interactive ZKP)&lt;/strong>, onde o provador e o verificador se comunicam múltiplas vezes, e &lt;strong>provas não interativas (Non-Interactive ZKP)&lt;/strong>, onde o provador envia os dados da prova apenas uma vez e finaliza.&lt;/p>
&lt;h4 id="provas-interativas-interactive-zkp">Provas Interativas (Interactive ZKP)
&lt;/h4>&lt;p>As primeiras ZKPs foram projetadas como protocolos interativos. A famosa alegoria da &amp;ldquo;Caverna de Ali Babá&amp;rdquo; enquadra-se nisso. O fluxo geral do protocolo é o seguinte:&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Prover as "Prover (Provador)"
participant Verifier as "Verifier (Verificador)"
Note over Prover, Verifier: "Fluxo básico do protocolo de prova interativa"
Prover->>Verifier: "1. Enviar compromisso (Commitment)"
Verifier->>Prover: "2. Enviar desafio aleatório (Challenge)"
Prover->>Verifier: "3. Calcular e enviar resposta (Response)"
Note over Verifier: "Verificar a resposta (Verification)"
Verifier-->>Prover: "4. Aceitar ou rejeitar (Accept / Reject)"
Note over Prover, Verifier: "※Para aumentar a certeza, isso é repetido dezenas de vezes"&lt;/div>
&lt;p>Este método é poderoso, mas o verificador deve estar online, o que o torna inconveniente para aplicação em sistemas distribuídos assíncronos como blockchain. Em uma blockchain, qualquer pessoa deve ser capaz de verificar provas passadas a qualquer momento.&lt;/p>
&lt;h4 id="transformação-de-fiat-shamir-fiat-shamir-heuristic-e-não-interatividade">Transformação de Fiat-Shamir (Fiat-Shamir Heuristic) e Não Interatividade
&lt;/h4>&lt;p>A &lt;strong>Transformação de Fiat-Shamir&lt;/strong> é um método inovador para converter uma prova interativa em uma prova não interativa (Non-Interactive Zero-Knowledge Proof: NIZK).&lt;/p>
&lt;p>Em vez do &amp;ldquo;desafio aleatório&amp;rdquo; enviado pelo verificador, o provador autogera um &amp;ldquo;desafio pseudoaleatório&amp;rdquo; usando seu próprio compromisso e o valor de hash das informações públicas. Assumindo que uma função de hash criptográfica (como SHA-256 ou Keccak) funcione como um oráculo aleatório, o provador não pode prever ou manipular o desafio antecipadamente e pode completar a prova com um único envio de mensagem, mantendo a mesma segurança de uma prova interativa.&lt;/p>
&lt;hr>
&lt;h2 id="detalhes-técnicos-de-zk-snarks">Detalhes Técnicos de zk-SNARKs
&lt;/h2>&lt;p>Atualmente, a ZKP mais amplamente utilizada é o &lt;strong>zk-SNARKs&lt;/strong> (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge). Como o nome sugere, é um argumento de conhecimento (Argument of Knowledge) que possui conhecimento zero (zk), tamanho de prova muito pequeno e verificação rápida (Succinct) e é não interativo (Non-Interactive).&lt;/p>
&lt;p>A base do zk-SNARKs é a geometria algébrica avançada e a teoria criptográfica. Ele converte a execução ou cálculo de um programa na verificação de uma equação polinomial específica.&lt;/p>
&lt;h3 id="1-conversão-para-circuitos-aritméticos-e-r1cs-rank-1-constraint-system">1. Conversão para Circuitos Aritméticos e R1CS (Rank-1 Constraint System)
&lt;/h3>&lt;p>Primeiro, qualquer cálculo a ser provado (um algoritmo ou lógica de contrato inteligente) é convertido em um &lt;strong>circuito aritmético (Arithmetic Circuit)&lt;/strong> que consiste em portas de adição e portas de multiplicação.&lt;/p>
&lt;p>Em seguida, este circuito aritmético é convertido em um conjunto de equações de matriz chamado &lt;strong>R1CS (Rank-1 Constraint System)&lt;/strong>. O R1CS é o problema de encontrar matrizes $A, B, C$ que satisfaçam a seguinte restrição para um vetor de variáveis $x$:&lt;/p>
$$ (A \cdot x) \circ (B \cdot x) = C \cdot x $$
&lt;p>Aqui, $\circ$ representa o produto de Hadamard (produto elemento a elemento). Essa restrição garante que todas as portas lógicas do circuito (especialmente as portas de multiplicação) sejam calculadas corretamente.&lt;/p>
&lt;h3 id="2-conversão-para-qap-quadratic-arithmetic-program">2. Conversão para QAP (Quadratic Arithmetic Program)
&lt;/h3>&lt;p>Como existem inúmeras restrições de matriz do R1CS, verificá-las individualmente é muito ineficiente. Portanto, usando a interpolação de Lagrange, essas restrições são comprimidas em uma única equação polinomial. Isso é o &lt;strong>QAP (Quadratic Arithmetic Program)&lt;/strong>.&lt;/p>
&lt;p>Ao converter para QAP, o problema a ser provado se reduz ao problema de &amp;ldquo;Pode um polinômio específico $P(x)$ ser divisível por outro polinômio conhecido $Z(x)$?&amp;rdquo;.&lt;/p>
$$ P(x) = L(x) \cdot R(x) - O(x) $$
&lt;p>Aqui, $L(x), R(x), O(x)$ são combinações dos polinômios correspondentes a cada linha das matrizes $A, B, C$, respectivamente. Se o provador souber a solução correta (Witness), o valor em cada raiz (ponto de avaliação) de $P(x)$ será 0, portanto, $P(x)$ terá o polinômio alvo $Z(x)$ como um fator. Ou seja, existe um polinômio $H(x)$ e a seguinte equação se mantém:&lt;/p>
$$ P(x) = H(x) \cdot Z(x) $$
&lt;p>O verificador pode verificar instantaneamente se todo o cálculo foi realizado corretamente apenas verificando se esta equação $P(s) = H(s) \cdot Z(s)$ se mantém em um ponto secreto aleatório $s$. Esse é o segredo da &amp;ldquo;Sucintez (Succinctness)&amp;rdquo;.&lt;/p>
&lt;h3 id="3-criptografia-de-curva-elíptica-e-emparelhamentos-bilinear-pairings">3. Criptografia de Curva Elíptica e Emparelhamentos (Bilinear Pairings)
&lt;/h3>&lt;p>No entanto, se o verificador souber o ponto secreto $s$, o provador poderá forjar um polinômio falso para satisfazer a equação (quebra da solidez). Portanto, é necessário realizar o cálculo mantendo $s$ criptografado (usando criptografia homomórfica) para que ninguém o conheça.&lt;/p>
&lt;p>Isto é alcançado pelos &lt;strong>emparelhamentos de curva elíptica (Bilinear Pairings)&lt;/strong>.
Um emparelhamento $e$ é uma função especial que pode calcular um valor equivalente à criptografia de seu produto a partir de dois valores criptografados.&lt;/p>
$$ e(g_1^a, g_2^b) = e(g_1, g_2)^{ab} $$
&lt;p>O provador pode calcular os valores criptografados dos polinômios $P(s)$ e $H(s)$ usando o valor criptografado da potência de $s$ (chamado de CRS: Common Reference String), mesmo sem conhecer o próprio $s$. O verificador utiliza a função de emparelhamento para verificar se a relação $P(s) = H(s) \cdot Z(s)$ é mantida enquanto os valores permanecem criptografados.&lt;/p>
&lt;h3 id="4-configuração-confiável-trusted-setup">4. Configuração Confiável (Trusted Setup)
&lt;/h3>&lt;p>A maior fraqueza dos zk-SNARKs (especialmente os iniciais como o Groth16) é que eles requerem um processo para gerar o ponto secreto $s$, chamado de &lt;strong>Configuração Confiável (Trusted Setup)&lt;/strong>. Se o criador do $s$ mantiver o valor em vez de destruí-lo, ele poderá gerar qualquer prova falsa (problema do Lixo Tóxico / Toxic Waste).&lt;/p>
&lt;p>Para prevenir isso, é realizada uma cerimônia chamada &amp;ldquo;Ceremony&amp;rdquo;, que utiliza Computação Multipartidária (MPC). Vários participantes colaboram para fornecer aleatoriedade, e se pelo menos um participante destruir honestamente seu próprio valor aleatório, a segurança de todo o sistema é mantida. No entanto, pesquisas para eliminar essa dependência vêm sendo conduzidas há muitos anos.&lt;/p>
&lt;hr>
&lt;h2 id="detalhes-técnicos-de-zk-starks">Detalhes Técnicos de zk-STARKs
&lt;/h2>&lt;p>Como resposta à dependência da Configuração Confiável e ao risco de decodificação da criptografia de curva elíptica por computadores quânticos, surgiram os &lt;strong>zk-STARKs&lt;/strong> (Zero-Knowledge Scalable Transparent Argument of Knowledge).&lt;/p>
&lt;p>Desenvolvido por Eli Ben-Sasson e outros, o STARKs não requer nenhuma Configuração Confiável (Trusted Setup), como o nome &amp;ldquo;Transparente (Transparent)&amp;rdquo; sugere, e tem a característica de que o tamanho da prova e o tempo de verificação são mantidos eficientes mesmo se o volume de cálculo aumentar, como sugere o nome &amp;ldquo;Escalável (Scalable)&amp;rdquo;.&lt;/p>
&lt;h3 id="1-compromisso-polinomial-e-protocolo-fri">1. Compromisso Polinomial e Protocolo FRI
&lt;/h3>&lt;p>Os zk-STARKs não dependem de criptografia de curva elíptica, mas ancoram a sua segurança &lt;strong>apenas em funções hash&lt;/strong>. Portanto, eles possuem propriedades de criptografia pós-quântica (Post-Quantum Cryptography).&lt;/p>
&lt;p>A verificação do cálculo é realizada convertendo-o num formato chamado AIR (Algebraic Intermediate Representation) e, em seguida, utilizando as propriedades dos polinómios unidimensionais ou multidimensionais. O núcleo do STARKs está no protocolo &lt;strong>FRI (Fast Reed-Solomon Interactive Oracle Proof of Proximity)&lt;/strong>.&lt;/p>
&lt;p>O protocolo FRI é uma tecnologia para verificar &amp;ldquo;se uma determinada função está suficientemente próxima de um polinômio de um grau específico (Proximity)&amp;rdquo;. O provador compromete os valores do polinômio como folhas de uma árvore de Merkle (Merkle Tree) (compromisso polinomial).&lt;/p>
&lt;div class="mermaid">graph TD
Root["Merkle Root (Compromisso)"] --> Node0["Nó 0"]
Root --> Node1["Nó 1"]
Node0 --> Leaf0["P(x_0)"]
Node0 --> Leaf1["P(x_1)"]
Node1 --> Leaf2["P(x_2)"]
Node1 --> Leaf3["P(x_3)"]&lt;/div>
&lt;p>O verificador exige a revelação de alguns pontos aleatórios e utiliza provas de Merkle (Merkle Proofs) para confirmar que estão incluídos no compromisso. Ao repetir isso recursivamente, garante-se com probabilidade esmagadora que o grau do polinômio original é realmente baixo.&lt;/p>
&lt;h3 id="comparação-entre-zk-snarks-e-zk-starks">Comparação entre zk-SNARKs e zk-STARKs
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Característica&lt;/th>
&lt;th style="text-align:left">zk-SNARKs&lt;/th>
&lt;th style="text-align:left">zk-STARKs&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Suposições Criptográficas&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Curvas elípticas, Emparelhamentos&lt;/td>
&lt;td style="text-align:left">Funções hash resistentes a colisões&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Configuração Confiável&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Necessária (Plonk etc. são universais)&lt;/td>
&lt;td style="text-align:left">Não necessária (Transparente)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Resistência Quântica&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Não&lt;/td>
&lt;td style="text-align:left">Sim&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Tamanho da Prova&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Muito pequeno (~200 Byte)&lt;/td>
&lt;td style="text-align:left">Um pouco maior (dezenas de KB)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Custo Computacional da Geração da Prova&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Alto&lt;/td>
&lt;td style="text-align:left">Relativamente menor que SNARKs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Custo de Verificação (Taxa de Gas)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Muito baixo (constante)&lt;/td>
&lt;td style="text-align:left">Baixo (aumenta logaritmicamente)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Nos últimos anos, surgiram SNARKs que &amp;ldquo;não requerem Configuração Confiável, ou precisam de apenas uma vez&amp;rdquo;, como Plonk e Halo2, e a fronteira entre SNARKs e STARKs está gradualmente se tornando tênue, mas a diferença fundamental na abordagem matemática é importante.&lt;/p>
&lt;hr>
&lt;h2 id="as-últimas-aplicações-de-provas-de-conhecimento-zero-na-web3-e-segurança">As Últimas Aplicações de Provas de Conhecimento Zero na Web3 e Segurança
&lt;/h2>&lt;p>A ZKP, que passou da teoria à prática, está atualmente causando uma revolução na vanguarda da Web3 e da segurança cibernética.&lt;/p>
&lt;h3 id="1-dimensionamento-extremo-do-ethereum-por-zk-rollups">1. Dimensionamento Extremo do Ethereum por ZK-Rollups
&lt;/h3>&lt;p>As blockchains de camada 1 (L1) como o Ethereum enfrentam grandes limitações de escalabilidade (o trilema) porque enfatizam a descentralização e a segurança. A solução definitiva de camada 2 (L2) para resolver isso é o &lt;strong>ZK-Rollups&lt;/strong>.&lt;/p>
&lt;p>No ZK-Rollup, milhares de transações são executadas e processadas off-chain (L2), e uma única &amp;ldquo;ZKP (Validity Proof)&amp;rdquo; é gerada para mostrar que todas foram executadas corretamente. O contrato inteligente na cadeia L1 só precisa verificar esta prova.&lt;/p>
&lt;div class="mermaid">flowchart LR
Users["Users (Envio de Tx)"] --> Sequencer["Sequencer (Coleta e Execução de Tx)"]
Sequencer --> Prover["Prover (Geração de ZKP)"]
Sequencer --> L1Contract["L1 Smart Contract (Publicação de Dados de Tx)"]
Prover --> L1Contract["Submissão de ZKP (Prova)"]
L1Contract --> Verify["Verificação &amp; Atualização de Estado"]&lt;/div>
&lt;p>A maior vantagem do ZK-Rollups é que, diferentemente do Optimistic Rollups (como Arbitrum ou Optimism), não há necessidade de um período de contestação (geralmente 7 dias) para provas de fraude (Fraud Proof). Como a correção é garantida criptograficamente, a retirada de fundos (Finality) para a L1 é concluída no momento em que a prova é verificada. Atualmente, projetos como zkSync, Starknet, Scroll e Polygon zkEVM estão em intensa competição de desenvolvimento, e a realização do &lt;strong>zkEVM&lt;/strong>, que é compatível com o EVM (Ethereum Virtual Machine), está impulsionando o rápido crescimento do ecossistema.&lt;/p>
&lt;h3 id="2-identidade-com-preservação-de-privacidade-zkp-for-identity">2. Identidade com Preservação de Privacidade (ZKP for Identity)
&lt;/h3>&lt;p>A forma como a autenticação pessoal funciona no mundo digital também mudará fundamentalmente com a ZKP.
Por exemplo, para a pergunta &amp;ldquo;Você tem 18 anos ou mais?&amp;rdquo;, os sistemas tradicionais exigiam a apresentação de uma carteira de motorista ou passaporte, entregando informações pessoais desnecessárias como nome e endereço à outra parte.&lt;/p>
&lt;p>Usando ZKP, é possível provar &lt;strong>apenas o fato matematicamente&lt;/strong> de que &amp;ldquo;com base na minha data de nascimento, tenho 18 anos ou mais na data atual&amp;rdquo; utilizando certificados digitais emitidos por órgãos governamentais (Verifiable Credential). O verificador só precisa validar a assinatura do certificado e a ZKP, e não pode saber a data de nascimento ou a identidade do usuário.&lt;/p>
&lt;p>Projetos de Prova de Humanidade (Proof of Personhood) como o Worldcoin também não armazenam ou compartilham diretamente os dados da íris, mas usam a ZKP para implementar um sistema que comprova &amp;ldquo;apenas ser um ser humano único&amp;rdquo;.&lt;/p>
&lt;h3 id="3-contratos-inteligentes-confidenciais-e-uso-corporativo">3. Contratos Inteligentes Confidenciais e Uso Corporativo
&lt;/h3>&lt;p>A natureza de &amp;ldquo;todos os dados serem públicos&amp;rdquo; nas blockchains públicas sempre foi uma barreira importante para as empresas lidarem com transações confidenciais ou informações da cadeia de suprimentos na blockchain.&lt;/p>
&lt;p>Utilizando a tecnologia ZKP (por exemplo, redes focadas em privacidade como Aleo e Aztec), é possível registrar na blockchain pública apenas a validade da atualização do estado, mantendo os valores de entrada e saída das transações e até mesmo a própria lógica do contrato inteligente executado criptografados. Isto possibilita prevenir o front-running (MEV) em DeFi (Finanças Descentralizadas) e construir redes de consórcio confidenciais entre empresas, enquanto se desfruta da alta segurança da blockchain pública.&lt;/p>
&lt;hr>
&lt;h2 id="desafios-futuros-e-perspectivas-da-zkp">Desafios Futuros e Perspectivas da ZKP
&lt;/h2>&lt;p>A ZKP é inegavelmente uma tecnologia fundamental da próxima geração, mas ainda restam alguns desafios.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Custo Computacional da Geração de Provas e Aceleração de Hardware&lt;/strong>
A geração da ZKP requer enormes cálculos de polinômios, FFT (Transformada Rápida de Fourier) e MSM (Multiplicação Multi-Escalar). Atualmente, a pesquisa em hardware especializado (FPGA e ASIC) para acelerar essa geração de provas, conhecida como &lt;strong>Mineração ZKP&lt;/strong> (Prover Network), está avançando rapidamente.&lt;/li>
&lt;li>&lt;strong>Padronização e Melhoria da Experiência do Desenvolvedor (DX)&lt;/strong>
Múltiplas linguagens dedicadas para escrever circuitos ZKP, como Circom, Cairo, Noir, Leo, estão proliferando. O padrão que as unifica e a maturidade de compiladores que gerem automaticamente circuitos ZKP a partir de Rust ou C++ existentes serão a chave para a adoção da ZKP por engenheiros de software comuns.&lt;/li>
&lt;/ol>
&lt;h2 id="conclusão">Conclusão
&lt;/h2>&lt;p>As Provas de Conhecimento Zero (ZKP) evoluíram de ser apenas uma &amp;ldquo;tecnologia para aumentar o anonimato das criptomoedas&amp;rdquo; para uma &amp;ldquo;tecnologia de propósito geral que redefine a confiança (trust) de toda a Internet&amp;rdquo;. As pequenas provas calculadas nas profundezas da matemática e da teoria da criptografia expandem infinitamente a escalabilidade da blockchain e funcionam como um forte escudo para proteger nossa privacidade.&lt;/p>
&lt;p>Rumo à verdadeira adoção em massa da Web3 e à construção de uma Internet de próxima geração segura e privada, as Provas de Conhecimento Zero continuarão a funcionar como a peça mais importante. Não podemos tirar os olhos da futura evolução da tecnologia ZKP.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Referências e Links Relacionados&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Groth, J. (2016). &amp;ldquo;On the Size of Pairing-based Non-interactive Arguments&amp;rdquo;&lt;/li>
&lt;li>Ben-Sasson, E., et al. (2018). &amp;ldquo;Scalable, transparent, and post-quantum secure computational integrity&amp;rdquo;&lt;/li>
&lt;li>Vitalik Buterin&amp;rsquo;s blog on zk-SNARKs and zk-STARKs&lt;/li>
&lt;/ul></description></item><item><title>A Hipótese de Riemann e a Distribuição dos Números Primos: A Profunda Relação com a Criptografia Moderna</title><link>http://kenji.blog/pt/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/riemann-hypothesis-prime-distribution-cryptography/</guid><description>&lt;img src="http://kenji.blog/p/riemann-hypothesis-prime-distribution-cryptography/img/eyecatch.jpg" alt="Featured image of post A Hipótese de Riemann e a Distribuição dos Números Primos: A Profunda Relação com a Criptografia Moderna" />&lt;h1 id="1-introdução-o-mistério-cósmico-dos-números-primos-e-a-hipótese-de-riemann">1. Introdução: O Mistério Cósmico dos Números Primos e a Hipótese de Riemann
&lt;/h1>&lt;p>Os &amp;ldquo;Números Primos&amp;rdquo; (Prime Numbers) são números naturais divisíveis apenas por 1 e por si mesmos, sendo frequentemente chamados de &amp;ldquo;átomos&amp;rdquo; do mundo da matemática. Essa sequência que segue como 2, 3, 5, 7, 11, 13&amp;hellip; parece, à primeira vista, desordenada e aleatória. Desde que o matemático grego antigo Euclides provou que &amp;ldquo;os números primos são infinitos&amp;rdquo;, incontáveis matemáticos têm tentado desvendar os padrões ocultos nessa disposição de primos.&lt;/p>
&lt;p>Aquele que chegou mais perto de desvendar esse mistério dos números primos foi o matemático alemão Bernhard Riemann, que propôs a &lt;strong>&amp;ldquo;Hipótese de Riemann&amp;rdquo; (Riemann Hypothesis)&lt;/strong> em 1859. A Hipótese de Riemann é um dos problemas mais importantes e não resolvidos da matemática moderna, com um prêmio de 1 milhão de dólares oferecido pelo Instituto de Matemática Clay como um dos Problemas do Prêmio Millennium.&lt;/p>
&lt;p>À primeira vista, pode parecer que esse problema formidável da matemática pura sobre a distribuição de números primos não tenha relação com o nosso dia a dia. No entanto, a segurança da internet, que sustenta a infraestrutura da sociedade moderna, especialmente as &lt;strong>tecnologias de criptografia modernas como a criptografia RSA e a criptografia de curva elíptica (ECC)&lt;/strong>, depende profundamente das propriedades de números primos gigantescos.&lt;/p>
&lt;p>Neste artigo, faremos uma jornada matemática partindo da distribuição dos números primos até o Teorema dos Números Primos, a função zeta de Riemann e o núcleo da Hipótese de Riemann, explorando de forma extremamente detalhada e profunda como isso se conecta com a criptografia moderna e o que aconteceria com o mundo se a Hipótese de Riemann fosse provada.&lt;/p>
&lt;hr>
&lt;h1 id="2-o-teorema-dos-números-primos-e-a-distribuição-de-primos-a-descoberta-de-gauss">2. O Teorema dos Números Primos e a Distribuição de Primos: A Descoberta de Gauss
&lt;/h1>&lt;p>Para entender como os números primos estão distribuídos, os matemáticos conceberam a &lt;strong>função de contagem de números primos (Prime-counting function)&lt;/strong> $\pi(x)$, que representa &amp;ldquo;quantos números primos existem menores ou iguais a um dado número $x$&amp;rdquo;.&lt;/p>
&lt;p>Por exemplo:&lt;/p>
&lt;ul>
&lt;li>$\pi(10) = 4$ (2, 3, 5, 7)&lt;/li>
&lt;li>$\pi(100) = 25$&lt;/li>
&lt;li>$\pi(1000) = 168$&lt;/li>
&lt;/ul>
&lt;p>O gênio matemático de 15 anos, Carl Friedrich Gauss, calculou extensas tabelas de números primos e descobriu que a frequência de aparecimento dos números primos diminui de forma inversamente proporcional ao logaritmo natural $\ln x$. Em outras palavras, ele conjecturou que a probabilidade de encontrar um número primo perto de um número $x$ é de aproximadamente $\frac{1}{\ln x}$.&lt;/p>
&lt;p>Expressando isso por meio de uma integral, obtemos o &lt;strong>logaritmo integral (Logarithmic integral)&lt;/strong> $\text{Li}(x)$.&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>A conjectura de Gauss foi posteriormente provada de forma independente por Jacques Hadamard e Charles Jean de la Vallée Poussin em 1896, estabelecendo-se como o &lt;strong>Teorema dos Números Primos (Prime Number Theorem, PNT)&lt;/strong>.&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>Ou, de forma aproximada, pode ser expresso como:&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>Este teorema mostrou que, de uma perspectiva macroscópica, os números primos têm uma distribuição muito suave e previsível. No entanto, microscopicamente, sempre existe um &amp;ldquo;erro&amp;rdquo;, ou seja, uma &amp;ldquo;flutuação&amp;rdquo; entre $\pi(x)$ e $\text{Li}(x)$. A verdadeira natureza dessa flutuação é exatamente o maior mistério que a Hipótese de Riemann tenta desvendar.&lt;/p>
&lt;hr>
&lt;h1 id="3-a-função-zeta-de-riemann-e-o-produto-de-euler">3. A Função Zeta de Riemann e o Produto de Euler
&lt;/h1>&lt;p>A arma mais poderosa para analisar a distribuição dos números primos é a &lt;strong>Função Zeta de Riemann (Riemann Zeta Function)&lt;/strong>. Originalmente, era uma série infinita definida por Leonhard Euler para números reais $s > 1$.&lt;/p>
$$ \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s} = 1 + \frac{1}{2^s} + \frac{1}{3^s} + \frac{1}{4^s} + \dots $$
&lt;p>Uma das maiores conquistas de Euler foi provar que esta série infinita pode ser expressa como um produto infinito sobre todos os números primos $p$. Este é o &lt;strong>Produto de Euler (Euler Product Formula)&lt;/strong>.&lt;/p>
$$ \zeta(s) = \prod_{p \text{ prime}} \frac{1}{1 - p^{-s}} = \left( \frac{1}{1 - 2^{-s}} \right) \left( \frac{1}{1 - 3^{-s}} \right) \left( \frac{1}{1 - 5^{-s}} \right) \dots $$
&lt;p>Uma compreensão intuitiva da prova é que, se expandirmos cada termo do lado direito como uma série geométrica e os multiplicarmos, o Teorema Fundamental da Aritmética (que afirma que todo número natural pode ser expresso de forma única como um produto de primos) reconstrói perfeitamente a soma dos recíprocos dos números naturais no lado esquerdo.&lt;/p>
&lt;p>&lt;strong>Essa única equação se tornou a ponte que liga a análise (séries infinitas, funções contínuas) à teoria dos números (números primos, números discretos).&lt;/strong> Estudar a função zeta é sinônimo de estudar a distribuição dos números primos.&lt;/p>
&lt;hr>
&lt;h1 id="4-continuação-analítica-e-a-extensão-para-o-plano-complexo">4. Continuação Analítica e a Extensão para o Plano Complexo
&lt;/h1>&lt;p>A genialidade de Riemann reside no fato de ele ter estendido a variável $s$ de $\zeta(s)$, que Euler considerava apenas para números reais, para &lt;strong>números complexos $s = \sigma + it$ ($\sigma$ é a parte real e $t$ é a parte imaginária)&lt;/strong>.&lt;/p>
&lt;p>A série infinita original converge apenas para $\sigma > 1$, mas Riemann usou um método chamado &amp;ldquo;Continuação Analítica (Analytic Continuation)&amp;rdquo; para estender a definição de modo que $\zeta(s)$ fizesse sentido em todo o plano complexo, com exceção do polo em $s = 1$.&lt;/p>
&lt;p>Ele também derivou uma bela equação funcional (Functional equation) que a função zeta satisfaz.&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>Aqui, $\Gamma(x)$ é a função gama. Com esta equação, podemos conhecer as propriedades do semiplano esquerdo a partir das propriedades do semiplano direito.&lt;/p>
&lt;h3 id="zeros-zeros-of-the-zeta-function">Zeros (Zeros of the Zeta Function)
&lt;/h3>&lt;p>Os números complexos $s$ para os quais o valor da função zeta se torna 0 são chamados de &amp;ldquo;zeros&amp;rdquo;.
A partir da equação funcional, quando $s$ é um número par negativo ($-2, -4, -6, \dots$), $\sin(\pi s / 2)$ torna-se 0, resultando em $\zeta(s) = 0$. Estes são chamados de &lt;strong>zeros triviais (Trivial zeros)&lt;/strong>.&lt;/p>
&lt;p>No entanto, o que importa para a distribuição dos números primos são os outros zeros, ou seja, os &lt;strong>zeros não triviais (Non-trivial zeros)&lt;/strong>, que existem na &amp;ldquo;faixa crítica (Critical strip)&amp;rdquo; onde $0 \le \sigma \le 1$.&lt;/p>
&lt;hr>
&lt;h1 id="5-o-núcleo-da-hipótese-de-riemann-e-a-fórmula-explícita">5. O Núcleo da Hipótese de Riemann e a Fórmula Explícita
&lt;/h1>&lt;p>Riemann calculou alguns zeros e formulou uma conjectura surpreendente. Esta é a &lt;strong>Hipótese de Riemann&lt;/strong>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Hipótese de Riemann (Riemann Hypothesis)&lt;/strong>
Todos os zeros não triviais da função zeta de Riemann $\zeta(s)$ encontram-se na linha reta onde a parte real é igual a $1/2$ ($\text{Re}(s) = 1/2$).&lt;/p>
&lt;/blockquote>
&lt;p>Esta reta onde a parte real é 1/2 é chamada de &amp;ldquo;linha crítica (Critical line)&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Função Zeta de Riemann ζ(s)"] --> B["Extensão para o plano complexo via continuação analítica"]
B --> C["Zeros triviais (s = -2, -4, -6 ...)"]
B --> D["Zeros não triviais (0 &lt;= Re(s) &lt;= 1)"]
D --> E["Hipótese de Riemann"]
E --> F["Todos os zeros não triviais estão em Re(s) = 1/2"]
F --> G["Para a prova do limite do termo de erro da distribuição de primos"]&lt;/div>
&lt;p>Por que a Hipótese de Riemann é tão importante? Porque os zeros da função zeta determinam &lt;strong>completamente&lt;/strong> a distribuição dos números primos.&lt;/p>
&lt;p>Riemann e o matemático posterior von Mangoldt derivaram a &amp;ldquo;Fórmula Explícita (Explicit formula)&amp;rdquo;, que descreve com precisão a distribuição dos números primos. Usando a função de Chebyshev $\psi(x)$, ela pode ser expressa da seguinte forma:&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>Aqui, a soma é sobre todos os zeros não triviais $\rho$ da função zeta.
O termo principal é $x$ (o que corresponde ao Teorema dos Números Primos), e ao adicionar e subtrair termos ondulatórios que dependem dos zeros $\rho$, a distribuição exata em forma de degraus dos números primos é restaurada. Pode-se dizer que os zeros não triviais representam as &amp;ldquo;frequências (ondas)&amp;rdquo; da distribuição dos números primos.&lt;/p>
&lt;p>Se a Hipótese de Riemann estiver correta e a parte real de todos os zeros não triviais $\rho$ for exatamente $1/2$, o termo de erro do Teorema dos Números Primos ficará dentro da menor margem teoricamente possível.&lt;/p>
$$ |\pi(x) - \text{Li}(x)| \le \frac{1}{8\pi} \sqrt{x} \ln x \quad \text{for} \quad x \ge 2657 $$
&lt;p>Em outras palavras, &lt;strong>se a Hipótese de Riemann for verdadeira, fica provado que os números primos estão distribuídos da forma mais &amp;ldquo;ordenada e bela&amp;rdquo; que possamos imaginar&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="6-a-relação-inseparável-entre-a-criptografia-moderna-e-os-números-primos">6. A Relação Inseparável entre a Criptografia Moderna e os Números Primos
&lt;/h1>&lt;p>Até aqui estivemos no mundo profundo da matemática pura, mas essas propriedades dos números primos sustentam fundamentalmente a sociedade digital moderna. O exemplo mais representativo são os sistemas de criptografia de chave pública, como a &lt;strong>criptografia RSA&lt;/strong>.&lt;/p>
&lt;p>A segurança de todas as comunicações, como pagamentos com cartão de crédito na internet, transmissão de senhas e assinaturas digitais em blockchain, depende dos &amp;ldquo;números primos&amp;rdquo;.&lt;/p>
&lt;h3 id="como-funciona-a-criptografia-rsa">Como funciona a Criptografia RSA
&lt;/h3>&lt;p>A segurança da criptografia RSA é baseada no fato matemático (o problema de fatoração de inteiros) de que &amp;ldquo;a fatoração de um número composto com muitos dígitos é extremamente difícil&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Geração de Chaves&lt;/strong>:
Escolhem-se aleatoriamente dois números primos gigantescos $p$ e $q$ (por exemplo, de 2048 bits cada).
Multiplicam-se ambos para calcular $N = p \times q$. Este $N$ se torna parte da chave pública.
Usando a função totiente de Euler $\phi(N) = (p-1)(q-1)$, gera-se a chave privada $d$.&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Criptografia e Descriptografia&lt;/strong>:
O texto plano (plaintext) $M$ é convertido em um texto cifrado (ciphertext) $C$ usando a chave pública $e, N$.
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
Apenas aquele que possui a chave privada $d$ pode descriptografar.
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Texto plano (Plaintext)"] --> B["Criptografado com a chave pública (e, N)"]
B --> C["Texto cifrado (Ciphertext)"]
C --> D["Descriptografado com a chave privada (d)"]
D --> E["Texto plano original"]
F["Atacante (Attacker)"] -- "Tenta fatorar N" --> C
F -.-> G["Sem saber p e q, d é incalculável"]&lt;/div>
&lt;p>Para quebrar a criptografia RSA, é necessário encontrar os números primos originais $p$ e $q$ a partir do gigantesco $N$ (fatoração de primos). Mesmo usando os algoritmos predominantes atuais (como o Crivo do Corpo de Números Generalizado: GNFS), diz-se que fatorar um número de centenas de dígitos levaria um tempo que excede muito a idade do universo, mesmo utilizando supercomputadores.&lt;/p>
&lt;hr>
&lt;h1 id="7-o-impacto-da-hipótese-de-riemann-na-criptografia">7. O Impacto da Hipótese de Riemann na Criptografia
&lt;/h1>&lt;p>Então, como a &amp;ldquo;Hipótese de Riemann&amp;rdquo;, que está no ápice da matemática pura, cruza-se com a &amp;ldquo;criptografia&amp;rdquo;?&lt;/p>
&lt;h3 id="71-algoritmos-de-geração-de-números-primos-teste-de-primalidade-e-a-hipótese-generalizada-de-riemann-grh">7.1. Algoritmos de Geração de Números Primos (Teste de Primalidade) e a Hipótese Generalizada de Riemann (GRH)
&lt;/h3>&lt;p>Para operar a criptografia RSA, primeiro é necessário gerar os gigantescos números primos $p$ e $q$. No entanto, determinar de forma confiável e rápida &amp;ldquo;se um determinado número é primo&amp;rdquo; não é algo simples.&lt;/p>
&lt;p>Atualmente, o que é utilizado de forma prática é um algoritmo probabilístico chamado &lt;strong>teste de primalidade de Miller-Rabin (Miller-Rabin primality test)&lt;/strong>. Esse algoritmo é rápido, mas carrega o risco de classificar incorretamente, com uma probabilidade extremamente baixa, um número composto como primo, um chamado &amp;ldquo;pseudoprimo&amp;rdquo;.&lt;/p>
&lt;p>No entanto, assumindo que a &lt;strong>&amp;ldquo;Hipótese Generalizada de Riemann (Generalized Riemann Hypothesis, GRH)&amp;rdquo;&lt;/strong>, que estende a Hipótese de Riemann às funções L de Dirichlet, é verdadeira, a história muda drasticamente.&lt;/p>
&lt;p>Se a GRH for verdadeira, o limite superior do número de testes no teste de Miller-Rabin será matematicamente garantido, elevando-o de um algoritmo probabilístico para um &lt;strong>&amp;ldquo;algoritmo de tempo polinomial determinístico&amp;rdquo;&lt;/strong> (este era um fato crucial já conhecido antes da descoberta do teste de primalidade AKS).&lt;/p>
&lt;p>Em outras palavras, a Hipótese de Riemann (e sua generalização) desempenha o papel de dar uma garantia direta para a base da criptografia: &amp;ldquo;é possível gerar números primos gigantescos de forma rápida e com absoluta confiança?&amp;rdquo;.&lt;/p>
&lt;h3 id="72-relação-com-os-algoritmos-de-fatoração">7.2. Relação com os Algoritmos de Fatoração
&lt;/h3>&lt;p>Ao avaliar a complexidade computacional dos algoritmos usados para decifrar códigos (como o Crivo do Corpo de Números Generalizado), o conhecimento sobre a distribuição dos números primos também é indispensável. A maioria dos algoritmos de fatoração depende da distribuição de &amp;ldquo;números lisos (Smooth numbers: números que possuem apenas pequenos fatores primos)&amp;rdquo;.&lt;/p>
&lt;p>Para avaliar rigorosamente a frequência com que números lisos aparecem, é necessária uma profunda compreensão da distribuição dos números primos, e aqui também são plenamente utilizadas técnicas de teoria analítica dos números que se conectam diretamente à função zeta e à Hipótese de Riemann. Se a Hipótese de Riemann for provada e o erro na distribuição de primos for completamente determinado, será possível discernir os limites de desempenho dos algoritmos de fatoração de forma mais precisa.&lt;/p>
&lt;hr>
&lt;h1 id="8-se-a-hipótese-de-riemann-for-provada-a-criptografia-será-quebrada">8. Se a Hipótese de Riemann for Provada, a Criptografia será Quebrada?
&lt;/h1>&lt;p>Assim como uma lenda urbana, às vezes se diz que &amp;ldquo;se a Hipótese de Riemann for resolvida, a criptografia RSA desmoronará em um instante&amp;rdquo;, mas &lt;strong>isso é matematicamente impreciso&lt;/strong>.&lt;/p>
&lt;p>A prova da Hipótese de Riemann, por si só, não produzirá imediatamente um algoritmo mágico que acelera drasticamente a fatoração. Isso porque a Hipótese de Riemann é, em última análise, um teorema sobre os &amp;ldquo;padrões de distribuição macroscópicos&amp;rdquo; dos números primos, e não nos diz diretamente por quais números primos um número específico $N$ é divisível (uma propriedade local).&lt;/p>
&lt;p>No entanto, o impacto não é zero.
Isso porque é extremamente provável que, no processo de provar a Hipótese de Riemann, &lt;strong>&amp;ldquo;novas ferramentas matemáticas&amp;rdquo; e &amp;ldquo;métodos analíticos desconhecidos&amp;rdquo; sejam descobertos&lt;/strong>. Olhando para a história, quando o Último Teorema de Fermat ou a Conjectura de Poincaré foram provados, as novas teorias desenvolvidas no processo impulsionaram significativamente a matemática como um todo.&lt;/p>
&lt;p>Se for estabelecido um método desconhecido de geometria algébrica ou de geometria não-comutativa capaz de manipular completamente as propriedades dos zeros da função zeta de Riemann, não se pode negar a possibilidade de que isso leve à descoberta de um algoritmo de fatoração revolucionário (por exemplo, um algoritmo clássico que reduz a complexidade para o tempo polinomial). Nesse sentido, os criptógrafos nunca podem tirar os olhos dos desenvolvimentos da Hipótese de Riemann.&lt;/p>
&lt;h3 id="computadores-quânticos-e-o-algoritmo-de-shor">Computadores Quânticos e o Algoritmo de Shor
&lt;/h3>&lt;p>Uma ameaça mais direta e realista à criptografia não é a prova da Hipótese de Riemann, mas os &lt;strong>computadores quânticos&lt;/strong>. O &amp;ldquo;Algoritmo de Shor&amp;rdquo;, anunciado por Peter Shor em 1994, provou que, com um computador quântico de capacidade suficiente, a fatoração pode ser resolvida em tempo polinomial. Isso fundamentalmente quebraria a criptografia RSA e a criptografia de curva elíptica.&lt;/p>
&lt;p>Atualmente, ao redor do mundo, há uma transição em andamento para a &amp;ldquo;Criptografia Pós-Quântica (Post-Quantum Cryptography, PQC)&amp;rdquo; (como a criptografia baseada em reticulados), que não pode ser decifrada nem por computadores quânticos. As tecnologias de criptografia baseadas em números primos podem, de certa forma, estar encerrando sua era de ouro, mas o valor matemático dos números primos em si nunca se perderá.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusão-o-cruzamento-entre-a-abstração-da-matemática-e-o-mundo-real">9. Conclusão: O Cruzamento entre a Abstração da Matemática e o Mundo Real
&lt;/h1>&lt;div class="mermaid">graph TD
A["Exploração da matemática pura"] --> B["Esclarecimento da Hipótese de Riemann"]
B --> C["Compreensão completa da distribuição de números primos"]
C --> D["Avanço rápido na teoria dos números e geometria algébrica"]
D -.-> E["Possibilidade de novos algoritmos de fatoração"]
E -.-> F["Atualização na avaliação de segurança da criptografia"]
A --> G["Matemática aplicada e ciência da computação"]
G --> H["Eficiência no teste de primalidade e geração de códigos"]
H --> F&lt;/div>
&lt;p>A exploração insaciável dos números primos, que remonta à Grécia Antiga, foi sublimada por um gênio chamado Riemann em uma bela sinfonia no plano complexo (os zeros da função zeta). E, surpreendentemente, esse cristal de matemática pura e inocente foi aplicado séculos depois como o escudo mais forte para garantir a segurança da sociedade da internet.&lt;/p>
&lt;p>A Hipótese de Riemann é uma entidade que simboliza, simultaneamente, a &amp;ldquo;beleza abstrata&amp;rdquo; e a &amp;ldquo;incrível aplicabilidade ao mundo físico e à sociedade real&amp;rdquo; que a matemática possui.&lt;/p>
&lt;p>Quando esta montanha colossal da matemática, cujo cume ninguém ainda alcançou, for um dia conquistada, compreenderemos completamente a verdade cósmica dos números primos, e também ganharemos uma nova perspectiva sobre os alicerces da sociedade da informação. Estudar criptografia é, por si só, uma jornada pela história da sabedoria humana.&lt;/p></description></item><item><title>A História da Criptografia: Da Cifra de César à Criptografia Pós-Quântica (PQC)</title><link>http://kenji.blog/pt/p/history-of-cryptography-caesar-to-pqc/</link><pubDate>Fri, 11 Sep 2026 15:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/history-of-cryptography-caesar-to-pqc/</guid><description>&lt;img src="http://kenji.blog/p/history-of-cryptography-caesar-to-pqc/img/eyecatch.jpg" alt="Featured image of post A História da Criptografia: Da Cifra de César à Criptografia Pós-Quântica (PQC)" />&lt;h1 id="1-introdução-o-que-é-criptografia">1. Introdução: O que é Criptografia?
&lt;/h1>&lt;p>A criptografia (Cryptography) é uma tecnologia para preservar o sigilo das informações e tem evoluído junto com a história da humanidade. Desde a transmissão de comandos secretos em guerras antigas até a proteção de informações de cartão de crédito na internet moderna, o propósito da criptografia tem sido consistente. Consiste em &amp;ldquo;garantir que apenas os destinatários pretendidos possam entender as informações e que terceiros não consigam decifrá-las&amp;rdquo;.&lt;/p>
&lt;p>Na segurança da informação moderna, a tecnologia criptográfica não se limita apenas ao &amp;ldquo;sigilo da informação (Confidencialidade: Confidentiality)&amp;rdquo;, mas desempenha papéis cruciais como a &amp;ldquo;Integridade (Integrity)&amp;rdquo; dos dados, a &amp;ldquo;Autenticação (Authentication)&amp;rdquo; e o &amp;ldquo;Não-repúdio (Non-repudiation)&amp;rdquo;.&lt;/p>
&lt;p>Neste artigo, desvendaremos detalhadamente a história da evolução da tecnologia criptográfica a partir de uma perspectiva técnica e matemática, começando pelas simples cifras de substituição antigas, passando pelas cifras mecânicas, as modernas criptografias de chave simétrica e chave pública, e chegando à era da &amp;ldquo;Criptografia Pós-Quântica (PQC)&amp;rdquo; que surge com o uso prático dos computadores quânticos.&lt;/p>
&lt;hr>
&lt;h1 id="2-a-era-da-criptografia-clássica-substituição-e-transposição-de-letras">2. A Era da Criptografia Clássica: Substituição e Transposição de Letras
&lt;/h1>&lt;p>As origens da criptografia remontam antes de Cristo. As primeiras cifras consistiam principalmente em duas abordagens: &amp;ldquo;Transposição (reordenação)&amp;rdquo; e &amp;ldquo;Substituição (troca)&amp;rdquo;.&lt;/p>
&lt;h2 id="cifra-de-cítala-cifra-de-transposição">Cifra de Cítala (Cifra de Transposição)
&lt;/h2>&lt;p>O &amp;ldquo;Cítala (Scytale)&amp;rdquo;, usado em Esparta na Grécia Antiga no século V a.C., é um dos mais antigos instrumentos de criptografia. Uma tira longa e estreita de pergaminho era enrolada em um bastão de madeira de uma espessura específica, e a mensagem era escrita horizontalmente. Ao desenrolar a tira, as letras ficavam ordenadas de forma sem sentido, mas um destinatário com um bastão da mesma espessura poderia enrolar a tira novamente e ler a mensagem original.&lt;/p>
&lt;h2 id="cifra-de-césar-cifra-de-substituição-simples">Cifra de César (Cifra de Substituição Simples)
&lt;/h2>&lt;p>Diz-se que o herói romano antigo Júlio César usou a &amp;ldquo;Cifra de César&amp;rdquo; no século I a.C. Esta é uma cifra de substituição simples (Monoalphabetic substitution) onde o alfabeto é deslocado por um número fixo (geralmente 3 letras).&lt;/p>
&lt;p>Matematicamente, tratando as letras como números de $0$ a $25$ e o número de deslocamentos como $K$, a conversão do texto claro $P$ para o texto cifrado $C$ é expressa pela seguinte equação de congruência:&lt;/p>
$$C \equiv P + K \pmod{26}$$
&lt;p>A decodificação realiza a operação inversa.&lt;/p>
$$P \equiv C - K \pmod{26}$$
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo simples de implementação da Cifra de César em Python&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;encrypt&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">mode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;decrypt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">shift&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">shift&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isalpha&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isupper&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cálculo do deslocamento&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="nb">chr&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">base&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">26&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">char&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo de execução&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">plaintext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;HELLO WORLD&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plaintext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;encrypt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># KHOOR ZRUOG&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="análise-de-frequência-e-cifra-de-vigenère">Análise de Frequência e Cifra de Vigenère
&lt;/h2>&lt;p>As cifras de substituição simples tornaram-se facilmente decifráveis através da &amp;ldquo;Análise de Frequência (Frequency Analysis)&amp;rdquo;, inventada pelo estudioso árabe Al-Kindi no século IX. Ela se aproveita das propriedades estatísticas da linguagem, onde letras como &amp;ldquo;E&amp;rdquo; ou &amp;ldquo;T&amp;rdquo; aparecem com frequência, no caso do inglês.&lt;/p>
&lt;p>Para combater isso, a &amp;ldquo;Cifra de Vigenère (Vigenère cipher)&amp;rdquo; foi concebida no século XVI. Esta é uma cifra de substituição polialfabética (Polyalphabetic substitution) que usa múltiplos deslocamentos (chaves) alternados periodicamente e foi chamada de &amp;ldquo;cifra indecifrável (Le Chiffre Indéchiffrable)&amp;rdquo; por cerca de 300 anos.&lt;/p>
&lt;p>Matematicamente, a $i$-ésima letra do texto claro $P_i$ e a $i$-ésima letra da chave repetida $K_i$ são usadas para criptografar da seguinte forma:&lt;/p>
$$C_i \equiv P_i + K_i \pmod{26}$$
&lt;p>Essa cifra também veio a ser decifrada no século XIX por Charles Babbage e Friedrich Kasiski, através da descoberta do &amp;ldquo;Exame de Kasiski (Kasiski examination)&amp;rdquo;, que determina o tamanho da chave a partir de padrões repetitivos no texto cifrado.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Classificação da Criptografia Clássica"
A["Criptografia Clássica"] --> B["Cifra de Transposição"]
A --> C["Cifra de Substituição"]
B --> D["Cifra de Cítala"]
C --> E["Substituição Simples"]
C --> F["Substituição Polialfabética"]
E --> G["Cifra de César"]
F --> H["Cifra de Vigenère"]
end&lt;/div>
&lt;hr>
&lt;h1 id="3-criptografia-mecânica-e-as-guerras-mundiais-enigma-e-sua-decodificação">3. Criptografia Mecânica e as Guerras Mundiais: Enigma e sua Decodificação
&lt;/h1>&lt;p>Ao entrarmos no século XX, os meios de comunicação mudaram das cartas para o telégrafo e o rádio, passando a exigir velocidade e complexidade na criptografia. Foi aqui que surgiu a &amp;ldquo;criptografia mecânica&amp;rdquo;, combinando rotores (discos rotativos).&lt;/p>
&lt;h2 id="a-ameaça-da-enigma-enigma">A Ameaça da Enigma (Enigma)
&lt;/h2>&lt;p>A &amp;ldquo;Enigma&amp;rdquo;, usada pela Alemanha Nazista durante a Segunda Guerra Mundial, é a máquina de criptografia mais famosa na história da tecnologia criptográfica. A Enigma consistia em múltiplos rotores (geralmente de 3 a 4), um painel de conexões (Steckerbrett) para trocar o cabeamento das letras, e um refletor (rotor reverso).&lt;/p>
&lt;p>Como o rotor girava a cada vez que uma letra era digitada no teclado, mesmo que a mesma letra fosse digitada consecutivamente, um caractere cifrado diferente era produzido (o auge da criptografia polialfabética). O seu espaço de chaves (combinações de configurações) chegava a cerca de $1.58 \times 10^{19}$ (aproximadamente 15,8 quintilhões), e com a tecnologia da época, a decodificação por força bruta era considerada impossível.&lt;/p>
&lt;h2 id="alan-turing-e-a-bombe-bombe">Alan Turing e a &amp;ldquo;Bombe (Bombe)&amp;rdquo;
&lt;/h2>&lt;p>A equipe de decodificação de códigos de Bletchley Park, no Reino Unido, que se baseou nos resultados iniciais do matemático polonês Marian Rejewski e outros, desafiou essa Enigma inexpugnável.&lt;/p>
&lt;p>Particularmente, Alan Turing usou a suposição de texto claro (Crib) correspondente a parte do texto cifrado e desenvolveu a máquina de decodificação eletromecânica &amp;ldquo;Bombe&amp;rdquo;. A Bombe detectava rapidamente contradições lógicas e eliminava configurações impossíveis de rotores uma após a outra, obtendo sucesso na decodificação da Enigma. Diz-se que essa grande conquista adiantou a vitória dos Aliados em vários anos.&lt;/p>
&lt;hr>
&lt;h1 id="4-o-início-da-criptografia-moderna-criptografia-de-chave-simétrica-des-e-aes">4. O Início da Criptografia Moderna: Criptografia de Chave Simétrica (DES e AES)
&lt;/h1>&lt;p>No pós-guerra, com o advento dos computadores, a criptografia passou por uma mudança drástica de paradigma, da manipulação de &amp;ldquo;letras&amp;rdquo; para a manipulação de &amp;ldquo;bits (0 e 1)&amp;rdquo;.&lt;/p>
&lt;h2 id="claude-shannon-e-a-teoria-da-informação">Claude Shannon e a Teoria da Informação
&lt;/h2>&lt;p>Em 1949, Claude Shannon publicou o artigo &amp;ldquo;Teoria da Comunicação de Sistemas Secretos&amp;rdquo;, estabelecendo os fundamentos matemáticos da criptografia moderna. Ele propôs a &amp;ldquo;Confusão (Confusion)&amp;rdquo; e a &amp;ldquo;Difusão (Diffusion)&amp;rdquo; como princípios para um design criptográfico seguro.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Confusão (Confusion)&lt;/strong>: Tornar a relação entre a chave e o texto cifrado o mais complexa possível. (Realizado por substituição / S-boxes)&lt;/li>
&lt;li>&lt;strong>Difusão (Diffusion)&lt;/strong>: Fazer com que a alteração de 1 bit do texto claro afete muitos bits do texto cifrado. (Realizado por transposição / permutação)&lt;/li>
&lt;/ul>
&lt;h2 id="des-data-encryption-standard">DES (Data Encryption Standard)
&lt;/h2>&lt;p>Em 1977, o Instituto Nacional de Padrões e Tecnologia dos EUA (NIST, então NBS) estabeleceu o &amp;ldquo;DES&amp;rdquo;, baseado no design da IBM, como o padrão de criptografia.
O DES adota uma arquitetura chamada &amp;ldquo;Rede de Feistel (Feistel Network)&amp;rdquo;, possuindo um tamanho de bloco de 64 bits e um tamanho de chave de 56 bits. Havia uma vantagem na implementação onde o algoritmo de criptografia e decodificação possuíam quase a mesma estrutura.&lt;/p>
&lt;p>No entanto, à medida que o poder de computação melhorava, tornou-se claro que um tamanho de chave de 56 bits (cerca de $7.2 \times 10^{16}$ possibilidades) era insuficiente. Em 1998, a Electronic Frontier Foundation (EFF) desenvolveu uma máquina dedicada, a &amp;ldquo;Deep Crack&amp;rdquo;, e demonstrou a quebra do DES em poucos dias.&lt;/p>
&lt;h2 id="aes-advanced-encryption-standard">AES (Advanced Encryption Standard)
&lt;/h2>&lt;p>Como um novo padrão para substituir o DES, o &amp;ldquo;AES&amp;rdquo; foi estabelecido em 2001. O algoritmo &amp;ldquo;Rijndael&amp;rdquo;, criado por criptógrafos belgas selecionado através de um concurso público, foi adotado.&lt;/p>
&lt;p>O AES não utiliza a Rede de Feistel, mas sim a &amp;ldquo;Estrutura SPN (Substitution-Permutation Network)&amp;rdquo;, e utiliza operações matemáticas sobre o Campo de Galois (campo finito) $GF(2^8)$. O tamanho da chave pode ser selecionado entre 128, 192 e 256 bits, e ainda hoje é amplamente utilizado como o padrão de criptografia de chave simétrica em todo o mundo.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Processo de 1 round do AES (Estrutura SPN)"
A["Estado de entrada (128-bit)"] --> B("SubBytes (Substituição de bytes / S-Box)")
B --> C("ShiftRows (Deslocamento de linhas)")
C --> D("MixColumns (Mistura de colunas / Multiplicação em GF(2^8))")
D --> E("AddRoundKey (XOR com a chave da rodada)")
E --> F["Para a próxima rodada"]
end&lt;/div>
&lt;hr>
&lt;h1 id="5-a-revolução-da-criptografia-de-chave-pública-de-diffie-hellman-a-rsa">5. A Revolução da Criptografia de Chave Pública: De Diffie-Hellman a RSA
&lt;/h1>&lt;p>A criptografia de chave simétrica possuía uma fraqueza decisiva. Trata-se do &amp;ldquo;Problema de Distribuição de Chaves (Key Distribution Problem)&amp;rdquo;. É o problema de como compartilhar de forma segura uma &amp;ldquo;chave comum&amp;rdquo; com uma parte distante antes de iniciar a comunicação criptografada. Este problema foi resolvido pela &amp;ldquo;Criptografia de Chave Pública&amp;rdquo;, nascida na década de 1970.&lt;/p>
&lt;h2 id="troca-de-chaves-de-diffie-hellman">Troca de Chaves de Diffie-Hellman
&lt;/h2>&lt;p>Em 1976, Whitfield Diffie e Martin Hellman publicaram o artigo revolucionário &amp;ldquo;New Directions in Cryptography&amp;rdquo;. Eles utilizaram a dificuldade matemática chamada &amp;ldquo;Problema do Logaritmo Discreto (Discrete Logarithm Problem)&amp;rdquo; e propuseram um método para compartilhar chaves de forma segura, mesmo em canais de comunicação interceptados.&lt;/p>
&lt;ol>
&lt;li>Um número primo grande $p$ e um gerador $g$ são tornados públicos.&lt;/li>
&lt;li>Alice escolhe um valor secreto $a$ e envia $A = g^a \pmod{p}$ para Bob.&lt;/li>
&lt;li>Bob escolhe um valor secreto $b$ e envia $B = g^b \pmod{p}$ para Alice.&lt;/li>
&lt;li>Alice calcula $K = B^a \pmod{p}$, e Bob calcula $K = A^b \pmod{p}$.&lt;/li>
&lt;li>Pelas leis dos expoentes, $K = (g^b)^a = (g^a)^b = g^{ab} \pmod{p}$, e assim, de forma brilhante, eles podem compartilhar a mesma chave $K$.&lt;/li>
&lt;/ol>
&lt;h2 id="criptografia-rsa">Criptografia RSA
&lt;/h2>&lt;p>No ano seguinte, em 1977, a &amp;ldquo;Criptografia RSA&amp;rdquo; foi concebida por Ron Rivest, Adi Shamir e Leonard Adleman. Ela baseia-se na propriedade de que &amp;ldquo;a fatoração de números compostos gigantes é difícil&amp;rdquo;.&lt;/p>
&lt;p>&lt;strong>Mecanismo matemático do RSA:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Escolhem-se 2 números primos gigantes $p$ e $q$, e calcula-se $n = p \times q$.&lt;/li>
&lt;li>Calcula-se a função totiente de Euler $\phi(n) = (p-1)(q-1)$.&lt;/li>
&lt;li>Escolhe-se um número inteiro $e$ (chave pública) que seja coprimo de $\phi(n)$.&lt;/li>
&lt;li>Calcula-se um número inteiro $d$ (chave privada) tal que $e \times d \equiv 1 \pmod{\phi(n)}$.&lt;/li>
&lt;/ol>
&lt;p>Criptografia: Para o texto claro $M$, $C \equiv M^e \pmod{n}$
Decodificação: Para o texto cifrado $C$, $M \equiv C^d \pmod{n}$&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Código Python demonstrando o conceito da criptografia RSA (não para uso prático)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cálculo do inverso modular pelo algoritmo de Euclides estendido&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">g&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">rsa_example&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Exemplo usando números primos pequenos&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">61&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">53&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">17&lt;/span> &lt;span class="c1"># Valor coprimo de phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Chave pública: (e=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, n=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">)&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Chave privada: (d=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, n=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">)&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Criptografia e decodificação de uma mensagem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">65&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto claro: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; Texto cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; Após decodificação: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">rsa_example&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h1 id="6-a-ascensão-da-criptografia-de-curva-elíptica-ecc">6. A Ascensão da Criptografia de Curva Elíptica (ECC)
&lt;/h1>&lt;p>A criptografia RSA é forte, mas com a melhoria no desempenho dos computadores, tornou-se necessário aumentar o tamanho da chave para manter a segurança (atualmente 2048 bits ou 3072 bits), o que gerou o problema do aumento do custo computacional.&lt;/p>
&lt;p>Portanto, em 1985 foi proposta a &amp;ldquo;Criptografia de Curva Elíptica (Elliptic Curve Cryptography: ECC)&amp;rdquo;. Isso utiliza a adição de pontos em uma curva elíptica sobre um campo finito (geralmente na forma de $y^2 = x^3 + ax + b$).&lt;/p>
&lt;p>Sabe-se que o Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP) é ainda mais difícil de resolver do que o problema da fatoração de primos, e &lt;strong>o ECC pode alcançar a mesma segurança que o RSA de 3072 bits com um tamanho de chave de apenas 256 bits&lt;/strong>. Isso possibilitou uma comunicação criptografada de alta velocidade e segurança (como ECDSA e ECDH) até mesmo em ambientes com recursos computacionais limitados, como smartphones e dispositivos IoT.&lt;/p>
&lt;hr>
&lt;h1 id="7-a-ameaça-dos-computadores-quânticos-e-a-criptografia-pós-quântica-pqc">7. A Ameaça dos Computadores Quânticos e a Criptografia Pós-Quântica (PQC)
&lt;/h1>&lt;p>A tecnologia criptográfica parecia sólida, mas em 1994, o &amp;ldquo;Algoritmo de Shor&amp;rdquo; publicado por Peter Shor causou um grande impacto.&lt;/p>
&lt;p>Os computadores quânticos realizam cálculos utilizando as propriedades da mecânica quântica de &amp;ldquo;superposição&amp;rdquo; e &amp;ldquo;emaranhamento quântico&amp;rdquo;. Foi matematicamente provado que a execução do algoritmo de Shor em um computador quântico de desempenho suficiente pode resolver o problema de fatoração de primos e o problema do logaritmo discreto em &amp;ldquo;tempo polinomial&amp;rdquo;. Ou seja, no dia em que um computador quântico prático for concluído (Q-Day), as criptografias de chave pública usadas atualmente, como RSA e ECC, serão corrompidas instantaneamente.&lt;/p>
&lt;h2 id="o-surgimento-da-pqc-post-quantum-cryptography">O Surgimento da PQC (Post-Quantum Cryptography)
&lt;/h2>&lt;p>Em preparação para esta ameaça sem precedentes, pesquisas em &amp;ldquo;Criptografia Pós-Quântica (PQC)&amp;rdquo;, baseada em novos problemas matemáticos difíceis de resolver mesmo para computadores quânticos, estão avançando a passos largos. O NIST (Instituto Nacional de Padrões e Tecnologia dos EUA) tem conduzido um processo de padronização da PQC ao longo de muitos anos, e as seguintes abordagens matemáticas são consideradas as mais promissoras.&lt;/p>
&lt;h3 id="1-criptografia-baseada-em-reticulados-lattice-based-cryptography">1. Criptografia Baseada em Reticulados (Lattice-based Cryptography)
&lt;/h3>&lt;p>Atualmente é a abordagem mais promissora, sendo também adotada nos algoritmos de padronização do NIST (ML-KEM / Kyber, ML-DSA / Dilithium). Ela baseia-se na dificuldade de encontrar pontos específicos (como o Problema do Vetor Mais Curto: SVP) em &amp;ldquo;reticulados (Lattice)&amp;rdquo; no espaço multidimensional e no problema LWE (Learning With Errors: Aprendizado Com Erros).&lt;/p>
&lt;p>O conceito do problema LWE aproveita a propriedade de que se um &amp;ldquo;pequeno ruído (erro)&amp;rdquo; for adicionado intencionalmente a um sistema de equações lineares simultâneas, de repente torna-se difícil encontrar a solução.
Sistema de equações: $\mathbf{A}\mathbf{s} + \mathbf{e} \equiv \mathbf{b} \pmod{q}$
($\mathbf{A}$ e $\mathbf{b}$ são públicos, $\mathbf{s}$ é a chave privada, $\mathbf{e}$ é o ruído minúsculo)&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pseudo-código conceitual do problema LWE (Para fins educacionais)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span> &lt;span class="c1"># Dimensão&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3329&lt;/span> &lt;span class="c1"># Módulo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">512&lt;/span> &lt;span class="c1"># Número de equações&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Chave privada s e pequeno erro e&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Matriz pública A e vetor público b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">A&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">A&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">s&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Mesmo utilizando um computador quântico, é considerado extremamente difícil recuperar s a partir de A e b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-criptografia-baseada-em-hash-hash-based-cryptography">2. Criptografia Baseada em Hash (Hash-based Cryptography)
&lt;/h3>&lt;p>É um esquema de assinatura digital que baseia a sua segurança unicamente na resistência a colisões de funções hash. Por não possuir uma estrutura matemática, é forte contra ataques quânticos, mas tende a ter tamanhos de assinatura grandes (como SPHINCS+).&lt;/p>
&lt;h3 id="3-criptografia-baseada-em-código-code-based-cryptography">3. Criptografia Baseada em Código (Code-based Cryptography)
&lt;/h3>&lt;p>É um sistema criptográfico baseado na teoria de códigos de correção de erros. A Criptografia de McEliece, proposta em 1978, é famosa; possui uma longa história e uma segurança estabelecida, mas tem o desafio de que o tamanho da chave pública é extremamente grande (podendo chegar a vários megabytes).&lt;/p>
&lt;div class="mermaid">timeline
title "História da Evolução da Criptografia e dos Computadores"
"Antiguidade - Idade Média" : "Cifra de César" : "Cifra de Vigenère" : "Nascimento da Análise de Frequência"
"Anos 1930 - 1940" : "Operação e Decodificação da Enigma" : "Máquina de Turing - Desenvolvimento da Bombe"
"Anos 1970" : "Padronização do DES (1977)" : "Troca de Chaves de Diffie-Hellman (1976)" : "Nascimento da Criptografia RSA (1977)"
"Anos 1980 - 1990" : "Proposta da Criptografia de Curva Elíptica (ECC)" : "Publicação do Algoritmo de Shor (1994)"
"Anos 2000" : "Padronização do AES (2001)"
"Anos 2010 - Atualidade" : "Aceleração da Pesquisa em Computadores Quânticos" : "Início do Projeto de Padronização PQC pelo NIST"
"Futuro Próximo (Q-Day)" : "Realização do Computador Quântico em Larga Escala?" : "Transição Completa para PQC (ML-KEM/ML-DSA)"&lt;/div>
&lt;hr>
&lt;h1 id="8-conclusão-uma-batalha-interminável-de-escudos-e-lanças">8. Conclusão: Uma Batalha Interminável de Escudos e Lanças
&lt;/h1>&lt;p>A história da tecnologia criptográfica é a história de uma batalha interminável entre a invenção de novos esquemas de criptografia (escudos) e os novos métodos de decodificação que os quebram (lanças).&lt;/p>
&lt;p>A Cifra de César foi derrotada pela análise de frequência, e a outrora invencível Enigma foi derrotada pelo gênio de Turing e o poder das máquinas. E agora, as fortes criptografias como RSA e ECC, que sustentam as bases da sociedade moderna da internet, estão sob a ameaça da nova &amp;ldquo;lança&amp;rdquo;, que é o computador quântico.&lt;/p>
&lt;p>No entanto, a humanidade já vislumbra o futuro e está se preparando para o novo &amp;ldquo;escudo&amp;rdquo;, a Criptografia Pós-Quântica (PQC). Atualmente, as preparações para a transição (Garantia de Agilidade Criptográfica - Crypto Agility) das criptografias de chave pública existentes para a PQC em infraestruturas de TI ao redor do mundo são uma questão de urgência.&lt;/p>
&lt;p>A tecnologia criptográfica não é apenas um quebra-cabeça matemático obscuro, mas sim a barreira mais forte para proteger nossa privacidade, nossas propriedades e as próprias infraestruturas da sociedade.&lt;/p></description></item><item><title>【Explicação de Matemática】Explicando o mecanismo da criptografia RSA para que até alunos do ensino médio entendam</title><link>http://kenji.blog/pt/p/rsa-encryption-math-explained-for-beginners/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/rsa-encryption-math-explained-for-beginners/</guid><description>&lt;img src="http://kenji.blog/p/rsa-encryption-math-explained-for-beginners/img/eyecatch.jpg" alt="Featured image of post 【Explicação de Matemática】Explicando o mecanismo da criptografia RSA para que até alunos do ensino médio entendam" />&lt;p>Uma das tecnologias que sustenta a segurança da nossa sociedade baseada na internet desde a sua base é a &amp;ldquo;Criptografia RSA&amp;rdquo;. Muitas das comunicações que usamos casualmente todos os dias, como pagamentos com cartão de crédito em compras online, troca de mensagens em redes sociais com amigos, ou o envio e recebimento de informações confidenciais de empresas, são protegidas pela criptografia RSA e suas tecnologias sucessoras.&lt;/p>
&lt;p>No entanto, ao ouvir a palavra &amp;ldquo;criptografia&amp;rdquo;, você pode imaginar máquinas de cifra complexas como as que aparecem em filmes de espionagem, ou uma matemática super avançada que apenas alguns gênios conseguem entender. É verdade que a teoria criptográfica moderna é baseada em matemática avançada, mas &lt;strong>o mecanismo fundamental da criptografia RSA pode ser plenamente compreendido com o conhecimento de matemática ensinado no ensino médio (propriedades de números inteiros, números primos, congruências, etc.)&lt;/strong>.&lt;/p>
&lt;p>Neste artigo, usaremos o conhecimento da matemática do ensino médio como ponto de partida para explicar passo a passo e de forma aprofundada os princípios matemáticos pelos quais a criptografia RSA funciona e por que é tão difícil de quebrar. Explicarei cuidadosamente usando exemplos concretos para que mesmo aqueles que têm um pouco de dificuldade com matemática possam entender.&lt;/p>
&lt;hr>
&lt;h2 id="1-criptografia-de-chave-simétrica-e-criptografia-de-chave-pública">1. Criptografia de Chave Simétrica e Criptografia de Chave Pública
&lt;/h2>&lt;p>Antes de mergulhar no mecanismo matemático da criptografia RSA, vamos primeiro revisar a ideia básica de criptografia. Os métodos criptográficos podem ser amplamente divididos em dois tipos: &amp;ldquo;Criptografia de chave simétrica&amp;rdquo; e &amp;ldquo;Criptografia de chave pública&amp;rdquo;.&lt;/p>
&lt;h3 id="11-limitações-da-criptografia-de-chave-simétrica">1.1 Limitações da Criptografia de Chave Simétrica
&lt;/h3>&lt;p>Muitos dos métodos de criptografia usados há muito tempo são chamados de &amp;ldquo;Criptografia de chave simétrica&amp;rdquo;. Este é um método em que &lt;strong>a mesma chave é usada tanto para &amp;ldquo;criptografia&amp;rdquo; (converter uma mensagem em um texto cifrado secreto) quanto para &amp;ldquo;descriptografia&amp;rdquo; (retornar o texto cifrado à mensagem original)&lt;/strong>.&lt;/p>
&lt;p>Por exemplo, suponha que a Alice vá enviar uma carta secreta ao Bob. A Alice coloca a carta em uma caixa e a tranca usando um cadeado (chave simétrica). Para o Bob abrir essa caixa, ele precisará ter a mesma chave que a Alice usou.&lt;/p>
&lt;p>Este método tem um grande problema: o &amp;ldquo;Problema de distribuição de chaves&amp;rdquo;. Quando Alice e Bob, que estão distantes, se comunicam pela primeira vez, como eles poderiam compartilhar a chave sem serem interceptados? Se a chave for roubada por terceiros enquanto é enviada por correio, toda a comunicação criptografada subsequente ficará totalmente exposta.&lt;/p>
&lt;h3 id="12-uma-invenção-revolucionária-criptografia-de-chave-pública">1.2 Uma Invenção Revolucionária: &amp;ldquo;Criptografia de Chave Pública&amp;rdquo;
&lt;/h3>&lt;p>A &amp;ldquo;Criptografia de chave pública&amp;rdquo; foi idealizada para resolver esse problema de distribuição de chaves. A criptografia RSA é um tipo deste sistema.&lt;/p>
&lt;p>Na criptografia de chave pública, usamos &lt;strong>duas chaves diferentes: uma &amp;ldquo;chave para criptografar (chave pública)&amp;rdquo; e uma &amp;ldquo;chave para descriptografar (chave privada)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>O destinatário, Bob, cria um par de &amp;ldquo;chave pública&amp;rdquo; e &amp;ldquo;chave privada&amp;rdquo;.&lt;/li>
&lt;li>Bob publica a &amp;ldquo;chave pública&amp;rdquo; para todo o mundo (não importa quem a obtenha).&lt;/li>
&lt;li>A remetente, Alice, criptografa a mensagem usando a &amp;ldquo;chave pública&amp;rdquo; de Bob e a envia.&lt;/li>
&lt;li>A mensagem criptografada só pode ser descriptografada com a &amp;ldquo;chave privada&amp;rdquo; que apenas Bob possui.&lt;/li>
&lt;/ol>
&lt;p>Comparando isso com o exemplo do cadeado: Bob cria vários &amp;ldquo;cadeados abertos (chaves públicas)&amp;rdquo; e os distribui pelo mundo. Alice coloca sua mensagem destinada a Bob em uma caixa e a tranca fechando um dos cadeados que encontrou pertencente a Bob. Uma vez que o cadeado é fechado, ele só pode ser aberto com a &amp;ldquo;chave mestra (chave privada)&amp;rdquo; que Bob possui. Mesmo que alguém roube a caixa no meio do caminho, essa pessoa não conseguirá abri-la porque não tem a chave mestra.&lt;/p>
&lt;div class="mermaid">graph TD
A["Alice (Remetente)"] --> B["Texto Plano (Mensagem)"]
B --> C["Processo de Criptografia"]
D["Chave Pública do Bob (Disponível para qualquer um)"] --> C
C --> E["Enviado via Internet: Texto Cifrado"]
E --> F["Processo de Descriptografia"]
G["Chave Privada do Bob (Mantida apenas pelo Bob)"] --> F
F --> H["Texto Plano Restaurado (Mensagem)"]
H --> I["Bob (Destinatário)"]&lt;/div>
&lt;p>Para implementar este sistema revolucionário, é necessária algum tipo de &lt;strong>&amp;ldquo;função unidirecional (um quebra-cabeça matemático de mão única)&amp;rdquo;&lt;/strong>, que significa que &amp;ldquo;é fácil criptografar com a chave pública, mas é absolutamente impossível descriptografar sem a chave privada&amp;rdquo;. Como peça para esse quebra-cabeça, a atenção se voltou para os &amp;ldquo;números primos&amp;rdquo;, algo que conhecemos bem.&lt;/p>
&lt;hr>
&lt;h2 id="2-base-matemática-1-sustentando-a-criptografia-rsa-números-primos-e-fatoração-em-números-primos">2. Base Matemática 1 Sustentando a Criptografia RSA: Números Primos e Fatoração em Números Primos
&lt;/h2>&lt;p>A segurança da criptografia RSA é baseada no fato matemático de que &lt;strong>&amp;ldquo;a fatoração de números gigantes em números primos é extremamente difícil&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="21-o-que-são-números-primos">2.1 O que são Números Primos?
&lt;/h3>&lt;p>Os números primos são &amp;ldquo;números naturais maiores que 1 que só podem ser divididos por 1 e por si mesmos&amp;rdquo;.
Exemplo: $2, 3, 5, 7, 11, 13, 17, 19, 23...$&lt;/p>
&lt;p>Os números primos são como &amp;ldquo;átomos&amp;rdquo; para todos os números inteiros. Qualquer número natural pode ser decomposto na forma de uma multiplicação de números primos. Isso é chamado de &lt;strong>fatoração em números primos&lt;/strong>. Por exemplo, como em $60 = 2^2 \times 3 \times 5$, ignorando a ordem, o fato de que pode ser fatorado em números primos de apenas uma única forma é conhecido como o &amp;ldquo;Teorema Fundamental da Aritmética&amp;rdquo;.&lt;/p>
&lt;h3 id="22-a-dificuldade-da-fatoração-em-números-primos-função-unidirecional">2.2 A Dificuldade da Fatoração em Números Primos (Função Unidirecional)
&lt;/h3>&lt;p>O importante aqui é a assimetria: &lt;strong>&amp;ldquo;A multiplicação é fácil, mas a fatoração em números primos é difícil&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Por exemplo, tente calcular de cabeça a multiplicação destes dois números primos:
$11 \times 13 = ?$
Isto é fácil. A resposta é $143$.&lt;/p>
&lt;p>Então, que tal o próximo número?
Por favor, fatore $323$ em números primos.
E então? Deve demorar um pouco. (A resposta é $17 \times 19$).&lt;/p>
&lt;p>Quando os números são pequenos, até humanos conseguem calcular de alguma forma, mas quando os números ficam grandes, o cálculo se torna explosivamente difícil, mesmo usando computadores. Na criptografia RSA moderna, usamos um número $N = p \times q$ obtido pela multiplicação de números primos incrivelmente gigantes $p$ e $q$ de 2048 bits (cerca de 600 dígitos decimais).&lt;/p>
&lt;p>Quando fornecidos dois números primos gigantes $p$ e $q$, calcular $N$ leva apenas um instante (menos de um milissegundo) para um computador. No entanto, reversamente, receber apenas $N$ e encontrar os $p$ e $q$ originais leva tanto tempo que não seria resolvido mesmo rodando os supercomputadores mais rápidos da atualidade por trilhões de anos.&lt;/p>
&lt;p>Essa &lt;strong>&amp;ldquo;assimetria computacional (um caminho é fácil, o caminho inverso é difícil)&amp;rdquo;&lt;/strong> é a base que cria o relacionamento entre a chave pública e a chave privada.&lt;/p>
&lt;hr>
&lt;h2 id="3-base-matemática-2-sustentando-a-criptografia-rsa-congruência-aritmética-modular">3. Base Matemática 2 Sustentando a Criptografia RSA: Congruência (Aritmética Modular)
&lt;/h2>&lt;p>Os cálculos da criptografia RSA não são realizados com adição e multiplicação onde os números ficam infinitamente grandes, como costumamos usar, mas sim no mundo dos &amp;ldquo;restos&amp;rdquo; quando divididos por um certo número. Isso é chamado de &lt;strong>congruência (aritmética modular)&lt;/strong>.&lt;/p>
&lt;h3 id="31-a-matemática-do-relógio">3.1 A Matemática do Relógio
&lt;/h3>&lt;p>A aritmética modular é frequentemente comparada com a &amp;ldquo;matemática do relógio&amp;rdquo;. Supondo que agora são 10 horas, que horas serão daqui a 5 horas? $10 + 5 = 15$ horas, mas em um relógio normal de 12 horas, respondemos &amp;ldquo;3 horas&amp;rdquo;. Isso ocorre porque o resto de 15 dividido por 12 é 3.&lt;/p>
&lt;p>No mundo da matemática, isso é escrito da seguinte forma:
&lt;/p>
$$ 15 \equiv 3 \pmod{12} $$
&lt;p>
Lê-se &amp;ldquo;15 e 3 são congruentes módulo 12 (os restos quando divididos por 12 são iguais)&amp;rdquo;.&lt;/p>
&lt;h3 id="32-propriedades-básicas-da-congruência">3.2 Propriedades Básicas da Congruência
&lt;/h3>&lt;p>A congruência possui propriedades muito úteis e semelhantes a equações (igualdades $=$). Vamos assumir que o módulo (número pelo qual dividimos) é $N$.
Quando $a \equiv b \pmod N$ e $c \equiv d \pmod N$, o seguinte é verdadeiro:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adição:&lt;/strong> $a + c \equiv b + d \pmod N$&lt;/li>
&lt;li>&lt;strong>Subtração:&lt;/strong> $a - c \equiv b - d \pmod N$&lt;/li>
&lt;li>&lt;strong>Multiplicação:&lt;/strong> $a \times c \equiv b \times d \pmod N$&lt;/li>
&lt;li>&lt;strong>Exponenciação:&lt;/strong> $a^k \equiv b^k \pmod N$ ($k$ é um número natural)&lt;/li>
&lt;/ol>
&lt;p>Particularmente importante é a propriedade da &amp;ldquo;exponenciação&amp;rdquo;. Isso significa que &lt;strong>&amp;ldquo;o resto de uma potência é igual à potência do resto&amp;rdquo;&lt;/strong>.
Por exemplo, imagine que você queira encontrar o resto de $7^{100}$ dividido por $5$. Seria muito difícil multiplicar o $7$ por ele mesmo 100 vezes e depois dividir por $5$, mas se usarmos a propriedade da congruência, como $7 \equiv 2 \pmod 5$, então $7^{100} \equiv 2^{100} \pmod 5$, permitindo simplificar drasticamente o cálculo. No mundo da criptografia lidamos com potências de números extremamente grandes, então essa propriedade é indispensável.&lt;/p>
&lt;hr>
&lt;h2 id="4-base-matemática-3-sustentando-a-criptografia-rsa-função-de-euler-e-teorema-de-euler">4. Base Matemática 3 Sustentando a Criptografia RSA: Função de Euler e Teorema de Euler
&lt;/h2>&lt;p>A partir daqui, entra a matemática mágica que forma o núcleo da criptografia RSA. Apresentamos o &amp;ldquo;Teorema de Euler&amp;rdquo;, que é uma generalização do &amp;ldquo;Pequeno Teorema de Fermat&amp;rdquo;.&lt;/p>
&lt;h3 id="41-a-função-totiente-de-euler-phin">4.1 A Função Totiente de Euler $\phi(N)$
&lt;/h3>&lt;p>A função totiente de Euler (função $\phi$) é uma função que, para um determinado número natural $N$, retorna &lt;strong>&amp;ldquo;a quantidade de números naturais de 1 até $N$ que são coprimos de $N$ (ou seja, seu máximo divisor comum é 1)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Vamos olhar alguns exemplos.&lt;/p>
&lt;ul>
&lt;li>$\phi(5)$: Dentre 1, 2, 3, 4, 5, os números coprimos de 5 são 1, 2, 3, 4; ou seja, 4 números. Portanto, $\phi(5) = 4$.&lt;/li>
&lt;li>$\phi(6)$: Dentre 1, 2, 3, 4, 5, 6, os números coprimos de 6 são 1, 5; ou seja, 2 números. Portanto, $\phi(6) = 2$.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Propriedade especial no caso de números primos]&lt;/strong>
Quando $p$ é um número primo, todos os números de 1 até $p-1$ são coprimos de $p$. Logo,
&lt;/p>
$$ \phi(p) = p - 1 $$
&lt;p>&lt;strong>[Propriedade especial no caso de um produto de números primos]&lt;/strong>
Para dois números primos distintos $p$ e $q$, quando se estabelece que $N = p \times q$, $\phi(N)$ pode ser facilmente obtido pelo seguinte cálculo:
&lt;/p>
$$ \phi(N) = \phi(p) \times \phi(q) = (p - 1)(q - 1) $$
&lt;p>
Essa propriedade funciona como a &amp;ldquo;porta dos fundos secreta (alçapão)&amp;rdquo; na criptografia RSA. Alguém que conhece $p$ e $q$ (o criador das chaves) pode calcular $\phi(N)$ em um instante, mas um terceiro que conhece apenas $N$ não pode determinar $\phi(N)$ a menos que fatore $N$ em números primos.&lt;/p>
&lt;h3 id="42-teorema-de-euler">4.2 Teorema de Euler
&lt;/h3>&lt;p>Leonhard Euler usou esse $\phi(N)$ para provar o seguinte belo teorema.&lt;/p>
&lt;p>&lt;strong>Teorema de Euler:&lt;/strong>
Quando um inteiro $a$ e $N$ são coprimos, a seguinte congruência é verdadeira:
&lt;/p>
$$ a^{\phi(N)} \equiv 1 \pmod N $$
&lt;p>Isso é uma propriedade surpreendente que diz: &amp;ldquo;quando você multiplica um certo número $a$ por ele mesmo $\phi(N)$ vezes e divide por $N$, o resto será sempre $1$&amp;rdquo;. (Se $N$ for um número primo $p$, torna-se $a^{p-1} \equiv 1 \pmod p$, que é chamado de Pequeno Teorema de Fermat).&lt;/p>
&lt;p>Vamos transformar este Teorema de Euler. Multiplicamos ambos os lados por $a$ mais uma vez.
&lt;/p>
$$ a^{\phi(N) + 1} \equiv a \pmod N $$
&lt;p>Além disso, para qualquer número inteiro $k$, $a^{k \cdot \phi(N)}$ também será $1^k = 1$, de modo que a seguinte fórmula é válida:
&lt;/p>
$$ a^{k \cdot \phi(N) + 1} \equiv a \pmod N $$
&lt;p>Esta exata equação é o princípio fundamental que faz com que a mágica da criptografia RSA de &lt;strong>&amp;ldquo;retornar ao original quando descriptografada após criptografar&amp;rdquo;&lt;/strong> funcione.&lt;/p>
&lt;hr>
&lt;h2 id="5-algoritmo-da-criptografia-rsa-passos-para-geração-de-chaves-criptografia-e-descriptografia">5. Algoritmo da Criptografia RSA: Passos para Geração de Chaves, Criptografia e Descriptografia
&lt;/h2>&lt;p>Agora que temos o conhecimento básico, vamos olhar para os passos concretos da criptografia RSA. A criptografia RSA é dividida principalmente em três fases: &amp;ldquo;1. Geração de Chaves&amp;rdquo;, &amp;ldquo;2. Criptografia&amp;rdquo; e &amp;ldquo;3. Descriptografia&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Escolher os primos p, q"] --> A2["Calcular N = p × q"]
A1 --> A3["Calcular φ(N) = (p-1)(q-1)"]
A3 --> A4["Escolher e coprimo de φ(N)"]
A3 --> A5["Calcular d tal que e × d ≡ 1 (mod φ(N))"]
A2 --> A6["Chave Pública (N, e)"]
A4 --> A6
A5 --> A7["Chave Privada d"]
B1["2. Mensagem em Texto Plano M"] --> B2["Calcular C ≡ M^e (mod N)"]
A6 -.-> B2
B2 --> B3["Enviar Texto Cifrado C"]
B3 --> C1["3. Receber Texto Cifrado C"]
C1 --> C2["Calcular M ≡ C^d (mod N)"]
A7 -.-> C2
C2 --> C3["Obter a Mensagem em Texto Plano original M"]&lt;/div>
&lt;h3 id="51-geração-de-chaves-key-generation">5.1 Geração de Chaves (Key Generation)
&lt;/h3>&lt;p>Bob, o destinatário, gera sua &amp;ldquo;chave pública&amp;rdquo; e &amp;ldquo;chave privada&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Seleção dos primos:&lt;/strong> Ele escolhe dois grandes números primos $p$ e $q$ aleatoriamente.&lt;/li>
&lt;li>&lt;strong>Cálculo do módulo $N$:&lt;/strong> Ele calcula $N = p \times q$. Este $N$ é tornado público.&lt;/li>
&lt;li>&lt;strong>Cálculo de $\phi(N)$:&lt;/strong> Ele calcula a função de Euler $\phi(N) = (p - 1)(q - 1)$. Este número é um segredo apenas do Bob.&lt;/li>
&lt;li>&lt;strong>Seleção da chave pública $e$:&lt;/strong> Ele escolhe um inteiro $e$ tal que $1 &lt; e &lt; \phi(N)$ e que $e$ seja coprimo de $\phi(N)$.&lt;/li>
&lt;li>&lt;strong>Cálculo da chave privada $d$:&lt;/strong> Ele encontra um inteiro $d$ que satisfaça a seguinte condição:
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
Isso significa &amp;ldquo;um número $d$ tal que, quando $e \times d$ é dividido por $\phi(N)$, o resto é $1$&amp;rdquo;.&lt;/li>
&lt;/ol>
&lt;p>Com isso, as chaves estão prontas.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Chave Pública:&lt;/strong> O par $(N, e)$. Publicado para todo o mundo.&lt;/li>
&lt;li>&lt;strong>Chave Privada:&lt;/strong> $d$. Jamais revelado a ninguém.&lt;/li>
&lt;/ul>
&lt;h3 id="52-criptografia-encryption">5.2 Criptografia (Encryption)
&lt;/h3>&lt;p>Suponha que Alice queira enviar uma mensagem secreta $M$ para Bob. (Assumimos que $M$ é um texto convertido em valor numérico, e que $0 \le M &lt; N$). Alice usa a chave pública do Bob, $(N, e)$, para fazer o seguinte cálculo:&lt;/p>
$$ C \equiv M^e \pmod N $$
&lt;p>Ela calcula &amp;ldquo;o resto $C$ obtido após elevar a mensagem $M$ à potência de $e$, e dividir por $N$&amp;rdquo;. Esse $C$ é o texto cifrado.&lt;/p>
&lt;h3 id="53-descriptografia-decryption">5.3 Descriptografia (Decryption)
&lt;/h3>&lt;p>Bob recebe o texto cifrado $C$. Bob usa sua chave privada $d$ para calcular o seguinte:&lt;/p>
$$ M \equiv C^d \pmod N $$
&lt;p>Ao calcular &amp;ldquo;o resto de elevar o texto cifrado $C$ à potência de $d$, e dividir por $N$&amp;rdquo;, incrivelmente a mensagem original $M$ é restaurada!&lt;/p>
&lt;hr>
&lt;h2 id="6-por-que-retorna-ao-original-na-descriptografia-prova-matemática">6. Por que retorna ao original na descriptografia? (Prova Matemática)
&lt;/h2>&lt;p>Você pode se perguntar: &amp;ldquo;Por que simplesmente elevar $C$ à potência de $d$ retorna ao $M$ original?&amp;rdquo;. Aqui, o &amp;ldquo;Teorema de Euler&amp;rdquo; mencionado anteriormente mostra o seu poder.&lt;/p>
&lt;p>Vamos substituir a equação de criptografia $C = M^e$ na equação de descriptografia $C^d \pmod N$.
&lt;/p>
$$ C^d \equiv (M^e)^d \equiv M^{ed} \pmod N $$
&lt;p>Aqui, lembre-se do Passo 5 da Geração de Chaves. Ao criar $d$, Bob o escolheu de forma que $e \times d \equiv 1 \pmod{\phi(N)}$. Isso significa que &amp;ldquo;$ed$ é um múltiplo de $\phi(N)$ somado a $1$&amp;rdquo;. Podemos escrevê-lo da seguinte maneira, utilizando um inteiro $k$:
&lt;/p>
$$ ed = k \cdot \phi(N) + 1 $$
&lt;p>Substituímos isso no expoente e o decompomos usando as leis dos expoentes:
&lt;/p>
$$ M^{ed} = M^{k \cdot \phi(N) + 1} = M^{k \cdot \phi(N)} \times M^1 = (M^{\phi(N)})^k \times M $$
&lt;p>Aqui, assumindo que a mensagem $M$ e $N$ são coprimos, a partir do &lt;strong>Teorema de Euler&lt;/strong>, temos $M^{\phi(N)} \equiv 1 \pmod N$.
&lt;/p>
$$ (M^{\phi(N)})^k \times M \equiv 1^k \times M \equiv M \pmod N $$
&lt;p>Portanto, a seguinte equação é perfeitamente estabelecida:
&lt;/p>
$$ C^d \equiv M \pmod N $$
&lt;p>Como a Alice não conhece $d$, e o espião também não conhece $d$, apenas Bob, que possui $d$, consegue extrair o $M$ a partir de $C$.&lt;/p>
&lt;hr>
&lt;h2 id="7-exemplo-concreto-vamos-vivenciar-o-rsa-calculando-à-mão-usando-pequenos-números-primos">7. Exemplo Concreto: Vamos vivenciar o RSA calculando à mão usando pequenos números primos
&lt;/h2>&lt;p>Vamos tentar enviar uma comunicação criptografada de Alice para Bob usando números pequenos (números primos) de fato.&lt;/p>
&lt;p>&lt;strong>[Fase de Geração de Chaves do Bob]&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Escolhe-se dois números primos $p=11$, $q=13$.&lt;/li>
&lt;li>Calcula-se $N = 11 \times 13 = 143$.&lt;/li>
&lt;li>Calcula-se $\phi(N) = (11 - 1) \times (13 - 1) = 10 \times 12 = 120$.&lt;/li>
&lt;li>Escolhe-se uma chave pública $e$ coprima de $\phi(N)=120$. Aqui usaremos $e=7$.&lt;/li>
&lt;li>Calcula-se a chave privada $d$. Buscamos um $d$ que satisfaça $7 \times d \equiv 1 \pmod{120}$.
Na equação $7d = 120k + 1$, quando $k=6$, temos $721$, e $721 \div 7 = 103$.
Portanto, $d = 103$.&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>Chave Pública: $(N=143, e=7)$&lt;/li>
&lt;li>Chave Privada: $d=103$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[Fase de Criptografia da Alice]&lt;/strong>
Suponha que ela queira enviar a mensagem $M = 9$.
Fórmula: $C \equiv 9^7 \pmod{143}$
$9^7 = 4.782.969$. Dividindo isso por 143, dá $33447$ com resto $48$.
O texto cifrado se tornou $C = 48$.&lt;/p>
&lt;p>&lt;strong>[Fase de Descriptografia do Bob]&lt;/strong>
Bob recebe o texto cifrado $C = 48$ e o descriptografa usando a chave privada $d = 103$.
Fórmula: $M \equiv 48^{103} \pmod{143}$
Se executarmos &lt;code>(48 ** 103) % 143&lt;/code> na calculadora, brilhantemente o resultado será &amp;ldquo;&lt;strong>9&lt;/strong>&amp;rdquo;! A mensagem original foi recebida com sucesso.&lt;/p>
&lt;hr>
&lt;h2 id="8-como-encontrar-a-chave-privada-d-algoritmo-de-euclides-estendido">8. Como encontrar a Chave Privada $d$: Algoritmo de Euclides Estendido
&lt;/h2>&lt;p>No exemplo calculado à mão, adivinhamos o valor de $k$ para encontrar $d=103$, mas quando o número atinge centenas de dígitos, esse método se torna impossível. Nos programas reais usamos um algoritmo chamado &lt;strong>&amp;ldquo;Algoritmo de Euclides Estendido&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Resolver $7d \equiv 1 \pmod{120}$ é o mesmo que encontrar inteiros $d, y$ que satisfaçam $7d + 120y = 1$. Ao realizar os passos do Algoritmo de Euclides ao reverso, podemos encontrar isso mecanicamente.&lt;/p>
&lt;ol>
&lt;li>$120 \div 7 = 17$ com resto $1$&lt;/li>
&lt;li>Rearranjando isso, temos $1 = 120 - 17 \times 7$&lt;/li>
&lt;li>Em outras palavras, $-17 \times 7 \equiv 1 \pmod{120}$&lt;/li>
&lt;/ol>
&lt;p>No mundo do módulo $120$, $-17$ tem o mesmo significado que $120 - 17 = 103$. Assim, o $d = 103$ pode ser encontrado em um instante. Este método consegue calcular de forma extremamente rápida por mais gigante que o número seja.&lt;/p>
&lt;hr>
&lt;h2 id="9-outra-face-da-criptografia-rsa-assinatura-digital">9. Outra Face da Criptografia RSA: Assinatura Digital
&lt;/h2>&lt;p>A parte fantástica da criptografia RSA é que, se invertermos as funções da chave pública e chave privada, ela também pode ser usada como uma &lt;strong>&amp;ldquo;Assinatura Digital&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Na criptografia os passos eram: &amp;ldquo;Criptografar com a chave pública $\Rightarrow$ Descriptografar com a chave privada&amp;rdquo;,
Mas na assinatura digital seguimos os passos: &amp;ldquo;Criptografar com a chave privada $\Rightarrow$ Descriptografar com a chave pública&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">flowchart TD
A1["1. Alice cria a assinatura com a chave privada"] --> A2["S ≡ M^d (mod N)"]
A2 --> A3["Envia a mensagem M e a assinatura S"]
A3 --> B1["2. Bob verifica a assinatura com a chave pública"]
B1 --> B2["Calcula M' ≡ S^e (mod N)"]
B2 --> B3["Verifica se M' e M coincidem"]&lt;/div>
&lt;p>A Alice transforma a mensagem usando sua própria chave privada $d$ (essa será a assinatura $S$) e envia ao Bob. O Bob faz o cálculo de verificação usando a chave pública de Alice, $e$. Se o resultado do cálculo for igual à mensagem original, isso prova simultaneamente que &amp;ldquo;os dados só poderiam ter sido criados pela chave privada da Alice&amp;rdquo; e que &amp;ldquo;a mensagem não foi adulterada no meio do caminho&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="10-sentindo-a-criptografia-rsa-na-prática-com-código">10. Sentindo a Criptografia RSA na Prática com Código
&lt;/h2>&lt;p>O cálculo de potências que seria difícil de fazer à mão pode ser implementado muito facilmente usando Python. A seguir, um código Python para você experienciar a lógica central da criptografia RSA.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Calcular o máximo divisor comum&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Encontrar a chave privada d (usando a função embutida a partir do Python 3.8)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Geração de chaves&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">13&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">N&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod_inverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Chave Pública: (N=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, e=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">), Chave Privada: d=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Criptografia&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">9&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto Cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Descriptografia&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">decrypted_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Mensagem Descriptografada: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted_message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Como a função &lt;code>pow(base, exp, mod)&lt;/code> do Python usa internamente um algoritmo rápido chamado &amp;ldquo;exponenciação binária (ou método das multiplicações repetidas)&amp;rdquo;, o cálculo termina em um instante mesmo para números com centenas de dígitos.&lt;/p>
&lt;hr>
&lt;h2 id="11-conclusão-e-futuro-das-tecnologias-de-criptografia">11. Conclusão e Futuro das Tecnologias de Criptografia
&lt;/h2>&lt;p>Nós desvendamos o mecanismo da criptografia RSA tendo como base a matemática do ensino médio.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>A dificuldade da fatoração em números primos:&lt;/strong> É fácil calcular $p \times q = N$, mas é extremamente difícil encontrar $p, q$ a partir de $N$.&lt;/li>
&lt;li>&lt;strong>Congruências e Teorema de Euler:&lt;/strong> Devido à regra $a^{\phi(N)} \equiv 1 \pmod N$, completa-se o mágico alçapão onde &amp;ldquo;a exponenciação por um certo número retorna ao estado original&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Chave Pública e Chave Privada:&lt;/strong> Qualquer um pode criptografar, mas apenas o destinatário legítimo consegue descriptografar.&lt;/li>
&lt;/ol>
&lt;p>O $N$ da criptografia RSA usada atualmente possui mais de 600 dígitos, e mesmo que todos os supercomputadores do mundo se juntassem para faturar esse número em primos, levaria um tempo maior do que a idade do universo. No entanto, se o &amp;ldquo;computador quântico&amp;rdquo;, que vem sendo pesquisado ativamente nos últimos anos, se tornar prático no futuro, essa fatoração poderá ser resolvida em instantes pelo &amp;ldquo;Algoritmo de Shor&amp;rdquo;. Por esse motivo, criptografias &amp;ldquo;resistentes a computadores quânticos&amp;rdquo;, que não poderiam ser quebradas nem mesmo por eles, estão sendo desenvolvidas a um ritmo acelerado pelo mundo todo.&lt;/p>
&lt;p>A matemática avançada que costumamos considerar &amp;ldquo;inútil&amp;rdquo;, na verdade, protege nosso dia a dia na sua essência mais profunda. A criptografia RSA é um excelente material didático que nos ensina essa profundidade e beleza da matemática. Ficaria muito feliz se através deste artigo você pudesse sentir um pouco do fascínio da criptografia e da matemática.&lt;/p></description></item><item><title>O que é a Criptografia Totalmente Homomórfica (FHE)? Explicando a essência da segurança de próxima geração</title><link>http://kenji.blog/pt/p/fully-homomorphic-encryption-fhe-explained/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/fully-homomorphic-encryption-fhe-explained/</guid><description>&lt;img src="http://kenji.blog/p/fully-homomorphic-encryption-fhe-explained/img/eyecatch.jpg" alt="Featured image of post O que é a Criptografia Totalmente Homomórfica (FHE)? Explicando a essência da segurança de próxima geração" />&lt;p>À medida que a computação em nuvem e a tecnologia de IA se estabelecem como base da sociedade, o trade-off entre a &amp;ldquo;privacidade de dados&amp;rdquo; e a &amp;ldquo;utilização de dados&amp;rdquo; tornou-se um dos desafios mais importantes. Embora haja uma demanda crescente por ter IAs analisando dados altamente sensíveis na nuvem — como dados médicos, informações financeiras e dados biométricos pessoais —, muitas empresas hesitam em enviar dados externamente por questões de segurança.&lt;/p>
&lt;p>Tecnologias de criptografia tradicionais (como AES e RSA) são excelentes em proteger dados armazenados em disco (Data at Rest) ou dados transmitidos pela rede (Data in Transit). No entanto, quando o servidor executa &lt;strong>processamentos (cálculos) nos dados, como pesquisas ou aprendizado de máquina (Data in Use), é necessário descriptografar a cifra e retorná-la a texto plano primeiro&lt;/strong>. Se o servidor for hackeado exatamente no momento em que os dados estão descriptografados, ou se um administrador interno mal-intencionado visualizar os dados, isso levará diretamente a um vazamento de informações.&lt;/p>
&lt;p>A tecnologia dos sonhos que supera essa fraqueza fundamental da &amp;ldquo;descriptografia durante o processamento&amp;rdquo; é a &lt;strong>Criptografia Totalmente Homomórfica (Fully Homomorphic Encryption: FHE)&lt;/strong>. Ao usar a FHE, torna-se possível realizar cálculos nos dados enquanto eles permanecem criptografados, sem qualquer descriptografia, e retornar apenas o texto cifrado do resultado para o cliente.&lt;/p>
&lt;p>Neste artigo, explicaremos profundamente a FHE, o pilar da segurança da próxima geração, desde os seus conceitos até a história, o avanço revolucionário de Craig Gentry, a base matemática (como Ring-LWE), o maior desafio do &amp;ldquo;ruído&amp;rdquo; e sua solução (bootstrapping), chegando até as bibliotecas de implementação mais recentes.&lt;/p>
&lt;hr>
&lt;h2 id="1-o-que-é-a-criptografia-homomórfica-conceitos-básicos">1. O que é a Criptografia Homomórfica? Conceitos Básicos
&lt;/h2>&lt;p>&amp;ldquo;Homomorfismo&amp;rdquo; é um termo da álgebra que se refere à propriedade de mapeamento entre conjuntos que possuem uma determinada estrutura, preservando a estrutura de suas operações. A &amp;ldquo;propriedade homomórfica&amp;rdquo; na teoria da criptografia é a característica onde &lt;strong>as operações no espaço de texto plano correspondem às operações no espaço de texto cifrado&lt;/strong>.&lt;/p>
&lt;p>Expressado em uma fórmula simples, considere que a função de criptografia para os textos planos $m_1$ e $m_2$ seja $E(\cdot)$ e a função de descriptografia seja $D(\cdot)$. Sendo $\circ$ a operação sobre os textos planos (como adição ou multiplicação) e $\diamond$ a operação sobre os textos cifrados, a seguinte relação é mantida:&lt;/p>
$$ D(E(m_1) \diamond E(m_2)) = m_1 \circ m_2 $$
&lt;p>Em outras palavras, ao descriptografar o resultado da aplicação de alguma operação $\diamond$ nos textos cifrados $E(m_1)$ e $E(m_2)$, obteremos o mesmo resultado da operação $\circ$ feita nos textos planos originais.&lt;/p>
&lt;h3 id="fluxo-de-dados-na-computação-em-nuvem">Fluxo de Dados na Computação em Nuvem
&lt;/h3>&lt;p>A arquitetura de processamento em nuvem usando a FHE é completamente diferente da arquitetura tradicional. O diagrama a seguir ilustra o fluxo de processamento seguro de dados utilizando a FHE.&lt;/p>
&lt;div class="mermaid">graph TD
A["Cliente (Possui a chave secreta)"] -->|1. Criptografar texto plano x: E(x)| B["Servidor em Nuvem (Apenas dados criptografados)"]
B -->|2. Aplicar função f no texto cifrado: E(f(x))| B
B -->|3. Texto cifrado do resultado calculado E(y)| A
A -->|4. Descriptografar com chave secreta: y = f(x)| A
style A fill:#d4edda,stroke:#28a745
style B fill:#f8d7da,stroke:#dc3545&lt;/div>
&lt;p>O servidor recebe os dados criptografados $E(x)$, mas como ele não possui a chave secreta, ele é absolutamente incapaz de saber o conteúdo dos dados. No entanto, explorando as propriedades da FHE, é possível aplicar a função $f$ (por exemplo, um modelo de inferência de aprendizado de máquina) ao texto cifrado e gerar $E(f(x))$. O cliente recebe isso e, descriptografando-o com sua própria chave secreta, obtém o resultado desejado $y = f(x)$.&lt;/p>
&lt;hr>
&lt;h2 id="2-a-história-da-evolução-da-criptografia-homomórfica-phe-she-fhe">2. A História da Evolução da Criptografia Homomórfica: PHE, SHE, FHE
&lt;/h2>&lt;p>A criptografia homomórfica não atingiu sua forma &amp;ldquo;totalmente&amp;rdquo; atual de uma só vez. Ela é amplamente classificada em três estágios dependendo dos tipos e da quantidade de operações que podem ser realizadas.&lt;/p>
&lt;h3 id="partially-homomorphic-encryption-phe-criptografia-parcialmente-homomórfica">Partially Homomorphic Encryption (PHE: Criptografia Parcialmente Homomórfica)
&lt;/h3>&lt;p>A PHE é um método de criptografia que permite que &lt;strong>apenas uma das operações&lt;/strong> (ou adição ou multiplicação) seja executada um número ilimitado de vezes. Na verdade, criptografias com essa propriedade existem há muito tempo.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Criptografia RSA (Homomorfismo para multiplicação)&lt;/strong>
A criptografia RSA obteve inadvertidamente propriedade homomórfica multiplicativa. Dados os textos planos $m_1, m_2$ e a chave pública $(e, N)$:
$$ E(m_1) = m_1^e \pmod N $$
$$ E(m_2) = m_2^e \pmod N $$
Ao multiplicá-los:
$$ E(m_1) \times E(m_2) = (m_1 \cdot m_2)^e \pmod N = E(m_1 \times m_2) $$
Assim, a multiplicação dos textos cifrados corresponde à multiplicação dos textos planos.&lt;/li>
&lt;li>&lt;strong>Criptografia Paillier (Homomorfismo para adição)&lt;/strong>
A criptografia Paillier, inventada em 1999, possui propriedade homomórfica para a adição. Tem sido implementada na prática em sistemas como o voto eletrônico (onde os votos criptografados são agregados e apenas o resultado final é descriptografado).&lt;/li>
&lt;/ul>
&lt;h3 id="somewhat-homomorphic-encryption-she-criptografia-homomórfica-limitada">Somewhat Homomorphic Encryption (SHE: Criptografia Homomórfica Limitada)
&lt;/h3>&lt;p>Este método pode executar &lt;strong>tanto a adição quanto a multiplicação&lt;/strong>, mas há &lt;strong>um limite no número de vezes (a profundidade do circuito)&lt;/strong> em que as operações podem ser realizadas. Devido ao acúmulo de &amp;ldquo;ruído&amp;rdquo; discutido mais adiante, após realizar mais do que um certo número de multiplicações, a descriptografia se torna impossível. A criptografia BGN (Boneh-Goh-Nissim) de 2005 entra nessa categoria, mas tinha limites quando se tentava cálculos complexos práticos (como o deep learning).&lt;/p>
&lt;h3 id="fully-homomorphic-encryption-fhe-criptografia-totalmente-homomórfica">Fully Homomorphic Encryption (FHE: Criptografia Totalmente Homomórfica)
&lt;/h3>&lt;p>Um esquema de criptografia no qual tanto a adição quanto a multiplicação podem ser realizadas &lt;strong>um número ilimitado de vezes&lt;/strong>. Semelhante à completude de Turing na teoria da informação, se a adição (correspondente a XOR) e a multiplicação (correspondente a AND) puderem ser combinadas infinitamente, significa que, em princípio, qualquer função ou algoritmo computável pode ser executado enquanto os dados permanecem criptografados.&lt;/p>
&lt;p>Por muito tempo, a FHE foi chamada de o &amp;ldquo;Santo Graal do mundo da criptografia&amp;rdquo; e muitos pensavam ser impossível. No entanto, em 2009, &lt;strong>Craig Gentry&lt;/strong>, que estava em um programa de doutorado na Universidade de Stanford na época, propôs o primeiro esquema de FHE usando Reticulados Ideais (Ideal Lattices), chocando o mundo.&lt;/p>
&lt;hr>
&lt;h2 id="3-a-base-matemática-da-fhe-o-problema-lwe-e-ring-lwe">3. A Base Matemática da FHE: O Problema LWE e Ring-LWE
&lt;/h2>&lt;p>Muitos esquemas modernos de FHE baseiam-se no &lt;strong>problema LWE (Learning With Errors)&lt;/strong>, um difícil problema matemático da &amp;ldquo;Criptografia baseada em Reticulados (Lattice-based Cryptography)&amp;rdquo;, também conhecida como Criptografia Pós-Quântica (Post-Quantum Cryptography).&lt;/p>
&lt;h3 id="entendimento-intuitivo-do-problema-lwe">Entendimento Intuitivo do Problema LWE
&lt;/h3>&lt;p>Resolver um sistema de equações lineares é fácil usando métodos como a eliminação de Gauss.&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 \equiv 12 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 \equiv 8 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>No entanto, o que acontece se adicionarmos um pequeno &amp;ldquo;erro aleatório (ruído)&amp;rdquo; $e$ ao resultado destas equações?&lt;/p>
$$ \begin{cases} 3s_1 + 4s_2 + 2s_3 + e_1 \equiv 13 \pmod{17} \\ 1s_1 + 9s_2 + 5s_3 + e_2 \equiv 7 \pmod{17} \\ \vdots \end{cases} $$
&lt;p>Ao apenas adicionar esse erro $e$, o problema de descobrir o vetor de variáveis secretas $\vec{s}$ se transforma em um problema NP-difícil, extremamente complicado de ser decifrado mesmo utilizando os supercomputadores ou computadores quânticos de hoje. Esse é o problema LWE.&lt;/p>
&lt;h3 id="problema-ring-lwe-rlwe">Problema Ring-LWE (RLWE)
&lt;/h3>&lt;p>Como o problema LWE padrão envolve operações com matrizes, ele sofria da desvantagem de possuir tamanhos de chave extremamente grandes (às vezes chegando à escala de gigabytes) e de ter baixa eficiência computacional. O &lt;strong>problema Ring-LWE (RLWE)&lt;/strong>, que utiliza operações sobre um anel polinomial, foi introduzido para resolver esse problema.&lt;/p>
&lt;p>No RLWE, os elementos pertencem a um anel polinomial $R_q = \mathbb{Z}_q[x] / (x^N + 1)$ (onde $N$ é uma potência de 2, e $q$ é um número primo para o módulo).
Se a chave secreta for o polinômio $s(x)$, um polinômio aleatório for $a(x)$, e um polinômio de ruído pequeno for $e(x)$, o par de chaves públicas será:&lt;/p>
$$ (a(x), b(x)) \quad \text{where} \quad b(x) = -a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>No momento da criptografia, a propriedade desse polinômio é usada para codificar o texto plano $m(x)$ e gerar o texto cifrado.&lt;/p>
&lt;hr>
&lt;h2 id="4-a-maior-barreira-ruído-e-o-bootstrapping-de-gentry">4. A Maior Barreira: &amp;ldquo;Ruído&amp;rdquo; e o Bootstrapping de Gentry
&lt;/h2>&lt;p>O conceito mais importante no entendimento da FHE é &lt;strong>&amp;ldquo;a gestão do ruído&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Em criptografias baseadas em LWE/RLWE, pequenos &amp;ldquo;ruídos (erros)&amp;rdquo; são intencionalmente incluídos para garantir a segurança.
O processo de descriptografia do texto cifrado $c$ do texto plano $m$ pode ser expresso em termos gerais pela seguinte fórmula:&lt;/p>
$$ D(c) = (c \cdot s) \pmod q = m + \text{noise} $$
&lt;p>Durante a descriptografia, o texto plano $m$ correto é obtido pela remoção desse &lt;code>noise&lt;/code> por meio de processos como o arredondamento. Contudo, ao realizar operações homomórficas (especialmente a multiplicação) nos textos cifrados, esse ruído se amplifica drasticamente.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Adição homomórfica&lt;/strong>: O ruído aumenta aditivamente ($e_1 + e_2$). É um aumento relativamente suave.&lt;/li>
&lt;li>&lt;strong>Expressão matemática da propriedade homomórfica com adição homomórfica&lt;/strong>:
$$ E(m_1) \oplus E(m_2) = E(m_1 + m_2) $$&lt;/li>
&lt;li>&lt;strong>Multiplicação homomórfica&lt;/strong>: O ruído explode multiplicativamente (pois envolve fatores como $e_1 \times e_2$). Apenas multiplicando algumas vezes, o ruído pode exceder o limiar $q/2$, impossibilitando o arredondamento correto e levando à falha da descriptografia.&lt;/li>
&lt;li>&lt;strong>Expressão matemática da propriedade homomórfica com multiplicação homomórfica&lt;/strong>:
$$ E(m_1) \otimes E(m_2) = E(m_1 \times m_2) $$&lt;/li>
&lt;/ul>
&lt;p>É por isso que a FHE permaneceu sem ser concretizada por um longo tempo, restrita a SHE (limitada em número de operações).&lt;/p>
&lt;h3 id="a-magia-do-bootstrapping">A Magia do Bootstrapping
&lt;/h3>&lt;p>A contribuição genial de Craig Gentry foi a invenção da técnica de redução de ruído chamada &lt;strong>&amp;ldquo;bootstrapping&amp;rdquo;&lt;/strong>. Essa foi uma mudança de paradigma na criptografia.&lt;/p>
&lt;p>Intuitivamente, é o processo de &amp;ldquo;&amp;lsquo;descriptografar&amp;rsquo; o texto cifrado dentro do seu estado criptografado para limpá-lo, antes que ele se torne tão repleto de ruído que quebre, e então colocá-lo em um novo texto cifrado&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>Suponha que temos um texto cifrado $C_{noisy}$ com muito ruído.&lt;/li>
&lt;li>O cliente fornece antecipadamente ao servidor sua chave secreta $sk$ &amp;ldquo;criptografada com a chave pública&amp;rdquo;, ou seja, $E_{pk}(sk)$ (isto é chamado de chave de bootstrapping).&lt;/li>
&lt;li>O servidor executa homomorficamente o &lt;strong>Circuito de Descriptografia (Decryption Circuit)&lt;/strong> sobre $C_{noisy}$.&lt;/li>
&lt;li>Especificamente, ele realiza uma &amp;ldquo;descriptografia dentro do espaço criptografado&amp;rdquo; aplicando $E_{pk}(sk)$ em $E_{pk}(C_{noisy})$.&lt;/li>
&lt;li>Como este circuito de descriptografia é em si mesmo uma operação homomórfica, ele gerará um novo ruído, mas o ruído do novo texto cifrado gerado, $C_{fresh}$, é redefinido para um &amp;ldquo;nível fixo&amp;rdquo; constante.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Texto cifrado com alto ruído C_noisy"] --> B["Circuito de descriptografia homomórfica (Eval_Dec)"]
C["Chave secreta criptografada E(sk)"] --> B
B --> D["Texto cifrado com baixo ruído C_fresh"]
style B fill:#ffeeba,stroke:#ffc107&lt;/div>
&lt;p>Ao executar este bootstrapping periodicamente no meio dos cálculos, tornou-se teoricamente possível calcular circuitos de profundidade infinita (atingindo a FHE). No entanto, no esquema inicial de Gentry, o custo computacional para esse processo de bootstrapping era desesperadamente alto, levando de dezenas de minutos a horas para ser executado uma única vez.&lt;/p>
&lt;hr>
&lt;h2 id="5-gerações-de-fhe-e-a-evolução-dos-principais-esquemas">5. Gerações de FHE e a Evolução dos Principais Esquemas
&lt;/h2>&lt;p>Para tornar a FHE viável na prática, criptógrafos de todo o mundo vêm competindo para aprimorar os algoritmos. Atualmente, a FHE é amplamente categorizada em quatro gerações ou famílias.&lt;/p>
&lt;h3 id="segunda-geração-aritmética-exata-de-inteiros-bgv-bfv">Segunda Geração: Aritmética Exata de Inteiros (BGV, BFV)
&lt;/h3>&lt;p>Surgidos entre 2011 e 2012, os esquemas &lt;strong>BGV (Brakerski-Gentry-Vaikuntanathan)&lt;/strong> e &lt;strong>BFV (Brakerski/Fan-Vercauteren)&lt;/strong>. Baseados no RLWE, eles são apropriados para a aritmética modular com números inteiros (cálculos exatos).
Eles têm como característica o suporte a técnicas de loteamento (Batching) como SIMD (Single Instruction, Multiple Data), que permite acomodar milhares de slots de dados em um único texto cifrado de polinômio gigante, possibilitando cálculos paralelos de uma só vez.&lt;/p>
&lt;h3 id="terceira-geração-aceleração-do-bootstrapping-gsw-fhew-tfhe">Terceira Geração: Aceleração do Bootstrapping (GSW, FHEW, TFHE)
&lt;/h3>&lt;p>O esquema &lt;strong>GSW (Gentry-Sahai-Waters)&lt;/strong> de 2013 simplificou a estrutura da FHE. Isso então evoluiu para o &lt;strong>TFHE (Fast Fully Homomorphic Encryption over the Torus)&lt;/strong>, que é um dos métodos predominantes hoje em dia.
A característica do TFHE é que o seu bootstrapping é extremamente rápido (na ordem de milissegundos). Ele é robusto no processamento ao nível de portas (circuitos lógicos como AND, XOR) e possui um tamanho de texto cifrado relativamente pequeno, tornando-o ideal para avaliar rapidamente circuitos lógicos arbitrários.&lt;/p>
&lt;h3 id="quarta-geração-especialização-para-cálculo-aproximado-e-aprendizado-de-máquina-ckks">Quarta Geração: Especialização para Cálculo Aproximado e Aprendizado de Máquina (CKKS)
&lt;/h3>&lt;p>O esquema &lt;strong>CKKS (Cheon-Kim-Kim-Song)&lt;/strong>, proposto por Cheon et al. em 2017, pode ser considerado a tecnologia definitiva na proteção da privacidade para a IA e aprendizado de máquina modernos.
Enquanto as versões anteriores da FHE focavam em &amp;ldquo;cálculos com números inteiros exatos&amp;rdquo;, o CKKS suporta homomorficamente &lt;strong>&amp;ldquo;cálculos aproximados com números de ponto flutuante&amp;rdquo;&lt;/strong>. Ele demonstra um desempenho avassalador em cálculos com números reais onde pequenas margens de erro são toleradas, como no treinamento e inferência de redes neurais.&lt;/p>
&lt;p>A tabela abaixo resume como escolher os esquemas conforme a finalidade:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Nome do Esquema&lt;/th>
&lt;th style="text-align:left">Tipo de Dados Adequado&lt;/th>
&lt;th style="text-align:left">Casos de Uso Recomendados&lt;/th>
&lt;th style="text-align:left">Características&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>BFV / BGV&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Inteiros (Integer)&lt;/td>
&lt;td style="text-align:left">Cálculos estatísticos exatos, agregação de dados financeiros, buscas em DB&lt;/td>
&lt;td style="text-align:left">Alto rendimento via loteamento SIMD&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>CKKS&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Números Reais (Real/Complex)&lt;/td>
&lt;td style="text-align:left">Aprendizado de Máquina (DNN, regressão logística), processamento de sinais&lt;/td>
&lt;td style="text-align:left">Aceleração via cálculo aproximado, reescalonamento&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>TFHE&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Valores Booleanos (Boolean)&lt;/td>
&lt;td style="text-align:left">Circuitos lógicos arbitrários, buscas por strings, avaliação de funções não lineares&lt;/td>
&lt;td style="text-align:left">Bootstrapping super-rápido (escala de milissegundos)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="6-prática-bibliotecas-de-fhe-e-código-conceitual">6. Prática: Bibliotecas de FHE e Código Conceitual
&lt;/h2>&lt;p>Atualmente, existem inúmeras bibliotecas de código aberto que permitem usar a FHE sem necessitar de conhecimento profundo em criptografia.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Microsoft SEAL (Simple Encrypted Arithmetic Library)&lt;/strong>: Biblioteca em C++ com suporte para os esquemas BFV, BGV e CKKS. É um dos padrões da indústria. O &lt;strong>TenSEAL&lt;/strong>, seu wrapper em Python, é popular entre engenheiros de IA.&lt;/li>
&lt;li>&lt;strong>Zama (Concrete)&lt;/strong>: Framework baseado em TFHE. Pode ser codificado em Rust/Python e oferece recursos (Concrete ML) para compilar modelos PyTorch existentes para executá-los em FHE.&lt;/li>
&lt;li>&lt;strong>OpenFHE&lt;/strong>: O sucessor do PALISADE, é uma biblioteca C++ abrangente que suporta todos os esquemas principais.&lt;/li>
&lt;/ul>
&lt;h3 id="exemplo-de-programação-fhe-usando-python-tenseal">Exemplo de Programação FHE usando Python (TenSEAL)
&lt;/h3>&lt;p>Abaixo, mostramos um exemplo conceitual em Python usando o esquema CKKS, em que vetores de números reais são somados e multiplicados enquanto permanecem criptografados.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">tenseal&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">ts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Configuração do contexto (incluindo a geração das chaves)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Usando o esquema CKKS e configurando o grau do polinômio para 8192&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SCHEME_TYPE&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CKKS&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">poly_modulus_degree&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8192&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coeff_mod_bit_sizes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_galois_keys&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">context&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">global_scale&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="mi">40&lt;/span> &lt;span class="c1"># Fator de escala para números reais&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Lado do cliente: Criptografia dos dados&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">1.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">2.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.5&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">vector2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mf">2.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">3.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">4.0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Convertendo o vetor em texto plano para um texto cifrado (Originalmente executado no cliente)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_v2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ckks_vector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">vector2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Lado do servidor: Operações no estado criptografado (Proteção do Data in Use)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># O servidor não conhece os textos planos, mas consegue realizar a adição e a multiplicação&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">enc_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_v1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">enc_v2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Lado do cliente: Descriptografia do resultado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Apenas o cliente que possui a chave secreta consegue ver o resultado&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_add&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_add&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res_mul&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enc_mul&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decrypt&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Resultado da adição descriptografado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_add&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo de saída: [3.5000001, 5.5000001, 7.5000002] (Uma pequena margem de erro por causa dos cálculos aproximados)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Resultado da multiplicação descriptografado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">res_mul&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemplo de saída: [3.0000002, 7.5000005, 14.0000003]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Como pode ser visto no código acima, operações normais de operadores de Python como &lt;code>enc_v1 + enc_v2&lt;/code> podem ser sobrecarregadas para expressar cálculos entre textos cifrados de maneira intuitiva. No lado do servidor, as operações vetoriais são completadas sem que se conheça o conteúdo do vetor.&lt;/p>
&lt;hr>
&lt;h2 id="7-desafios-da-fhe-desempenho-e-aceleração-por-hardware">7. Desafios da FHE: Desempenho e Aceleração por Hardware
&lt;/h2>&lt;p>Embora a FHE forneça uma segurança teoricamente perfeita, o maior desafio na sua aplicação prática é a &lt;strong>&amp;ldquo;sobrecarga (overhead) de desempenho&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Sobrecarga computacional&lt;/strong>: Comparado ao cálculo em texto plano, o cálculo sobre um texto cifrado na CPU é milhares a dezenas de milhares de vezes mais lento. Multiplicar polinômios e realizar bootstrapping exige cálculos computacionais imensos, como FFT (Transformada Rápida de Fourier) e NTT (Transformada da Teoria dos Números).&lt;/li>
&lt;li>&lt;strong>Expansão de Dados (Ciphertext Expansion)&lt;/strong>: Um texto plano de alguns bytes, quando criptografado, pode aumentar de tamanho para alguns megabytes. Isso exerce forte pressão sobre a largura de banda de memória e da rede.&lt;/li>
&lt;/ol>
&lt;h3 id="abordagens-de-resolução-através-de-hardware">Abordagens de Resolução Através de Hardware
&lt;/h3>&lt;p>Para superar essa sobrecarga, esforços estão em andamento em todo o mundo para desenvolver aceleradores de hardware dedicados à FHE (suporte a ASIC, FPGA e GPU).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Aceleração com GPU&lt;/strong>: Esforços para usar as potentes GPUs (como as da NVIDIA) a fim de paralelizar os cálculos de NTT ou o bootstrapping estão progredindo e relatam velocidades que são dezenas de vezes mais rápidas em comparação com as implementações baseadas em software (ex.: 100x.ai, o backend CUDA TFHE-rs da Zama).&lt;/li>
&lt;li>&lt;strong>Projeto DARPA DPRIVE&lt;/strong>: A Defense Advanced Research Projects Agency (DARPA) dos EUA, está conduzindo o &amp;ldquo;DPRIVE (Data Protection in Virtual Environments)&amp;rdquo;, um projeto focado no desenvolvimento de hardware exclusivo projetado para elevar a velocidade do cálculo da FHE a uma capacidade equivalente à velocidade de execução em texto plano (com overhead dentro de 10x), que conta com parceiros como Intel, Microsoft, Intellectual Ventures e afins.&lt;/li>
&lt;li>&lt;strong>O Surgimento da FPU (FHE Processing Unit)&lt;/strong>: Startups como Cornami e Optalysys têm se empenhado em construir chips dedicados à FHE usando arquiteturas de silício especiais ou tecnologias de computação óptica.&lt;/li>
&lt;/ul>
&lt;p>Num futuro próximo, poderemos presenciar a era em que as FPUs estejam incluídas como padrão em infraestruturas de servidores ou na nuvem, da mesma forma que as NPUs (Neural Processing Units) ocorrem na IA.&lt;/p>
&lt;hr>
&lt;h2 id="8-casos-de-uso-esperados">8. Casos de Uso Esperados
&lt;/h2>&lt;p>Hoje em dia, onde a FHE está alcançando uma velocidade em níveis práticos, são aguardadas inovações disruptivas nos seguintes campos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Proteção à privacidade em análises genômicas e médicas&lt;/strong>:
Informações biológicas (dados de DNA) ou laudos e exames provindos de muitos hospitais diferentes poderão receber modelos de IA em conjunto pelas nuvens sob formatação FHE de estado permanente cifrado, o qual atende inteiramente os limites impostos pelas leis legislativas de conformidade (como a LGPD, HIPAA e GDPR). Esses esforços proporcionarão construções avançadas com diagnóstico e produção em tratamentos farmacêuticos precisos sobre patologias de tumores cancerosos e desenvolvimento de novas medicações sem riscos.&lt;/li>
&lt;li>&lt;strong>Verificação antifraude nas Instituições Financeiras e PLD (Prevenção à Lavagem de Dinheiro)&lt;/strong>:
Instituições financeiras em concorrência poderão verificar em mútuo auxílio o quadro dos extratos ou as referências transacionais de cada cliente sob encriptação, contendo integridade não visível para apontar enormes cadeias criminosas de fraude que praticam remessas desonestas entre bancos nas transferências. O que possibilita executar a chamada avaliação multi-bancos.&lt;/li>
&lt;li>&lt;strong>APIs de IA Seguras de Inferências Pessoais (MaaS: Model as a Service)&lt;/strong>:
Usuários usarão chaves particulares próprias (mensagens digitadas de comandos/prompt, rostos, fotos, imagens de íris, gravações da sua fala) e repassarão elas de maneira cifrada e inacessível a uma determinada aplicação de Inteligência Artificial para Inferência de Modelos de Linguagem (a exemplo de um modelo LLM igual o ChatGPT ou congêneres da tecnologia de processamento natural humano). O Fornecedor provedor detentor da IA despacha e fabrica formulações conclusivas não sabendo jamais qual era o dado ali originário de partida; remetendo sua solução redigida na total cifra. Desse modo erradica o abalo de &amp;ldquo;permitir o espião no treinamento indevido sob rastros dos detalhes expostos pelo indivíduo na internet privada e sensível&amp;rdquo;.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="9-conclusão-o-futuro-da-criptografia-em-direção-ao-cálculo-invisível">9. Conclusão: O Futuro da Criptografia em Direção ao &amp;ldquo;Cálculo Invisível&amp;rdquo;
&lt;/h2>&lt;p>Assim como a invenção da criptografia de chave pública (como a RSA) na década de 1970 possibilitou a comunicação segura pela internet (como no HTTPS), a invenção da FHE por Craig Gentry é um dos marcos mais cruciais em toda a história criptográfica da humanidade.&lt;/p>
&lt;p>No presente, a Criptografia Totalmente Homomórfica (FHE) deu um salto dos laboratórios teóricos para o mundo real, entrando agora na etapa pela qual as corporações da Microsoft, IBM, Intel, Google, assim como uma quantidade de startups lutam firmemente em direção ao estado da comercialização tangível no sistema prático. O problema da quantidade do peso do tamanho expansível nos dados codificados ainda está contido no rol de entraves e desafios a transpor, mas à luz do requinte arquitetônico dos modelos e softwares matemáticos de algoritmo em sincronia contínua de aperfeiçoamento nos hardwares superacelerados tecnológicos, sua capacidade de melhoria atinge avanços velozes cujas expectativas superam a Lei de Moore.&lt;/p>
&lt;p>Daqui a poucos anos, a frase &amp;ldquo;processar e calcular enquanto os dados se encontram em criptografia resguardada&amp;rdquo; será desprovida da sensação da complexidade esotérica especial e rara e deve vir a ser consolidada na prática essencialmente como base obrigatória generalizada do mercado na segurança protetora das soluções da arquitetura pela nuvem de serviços mundiais atuais. Afinal, no palco dessa presente comunidade conectada (data-driven) embasada globalmente via bases contínuas digitais, a &lt;strong>FHE (Criptografia Totalmente Homomórfica)&lt;/strong> assume sua titularidade do suporte principal absoluto para a segurança nas próximas fronteiras do amanhã que concretiza a conciliação unânime final das realidades — da máxima e rigorosa preservação do resguardo íntimo da &lt;strong>privacidade e paralelamente de suas inúmeras flexibilidades promissoras no uso interconectado nos dados&lt;/strong>.&lt;/p></description></item><item><title>Fundamentos Matemáticos da Criptografia de Curva Elíptica (ECC) e sua Implementação em C++</title><link>http://kenji.blog/pt/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post Fundamentos Matemáticos da Criptografia de Curva Elíptica (ECC) e sua Implementação em C++" />&lt;h1 id="fundamentos-matemáticos-da-criptografia-de-curva-elíptica-ecc-e-sua-implementação-em-c">Fundamentos Matemáticos da Criptografia de Curva Elíptica (ECC) e sua Implementação em C++
&lt;/h1>&lt;p>Na tecnologia criptográfica moderna, a &lt;strong>Criptografia de Curva Elíptica (Elliptic Curve Cryptography: ECC)&lt;/strong> desempenha um papel extremamente importante. Desde nossas comunicações diárias na internet (HTTPS/TLS), até o enclave seguro dos smartphones, autenticação de servidores via SSH, autenticação sem senha como FIDO e, além disso, criptoativos como Bitcoin e Ethereum, não é exagero dizer que a base de confiança da sociedade digital moderna é sustentada pela ECC.&lt;/p>
&lt;p>Neste artigo, explicaremos de forma exaustiva e com um volume impressionante como essa criptografia de curva elíptica funciona, partindo da teoria matemática bela e complexa por trás dela (geometria algébrica em corpos finitos), passando pelo método de implementação real usando C++, até as técnicas de codificação segura para evitar ataques de canal lateral (ataques de tempo).&lt;/p>
&lt;hr>
&lt;h2 id="1-por-que-a-criptografia-de-curva-elíptica-comparação-com-rsa">1. Por que a Criptografia de Curva Elíptica? (Comparação com RSA)
&lt;/h2>&lt;p>Por muito tempo, o sinônimo de criptografia de chave pública foi a &lt;strong>Criptografia RSA&lt;/strong>. A criptografia RSA baseia a sua segurança na &amp;ldquo;dificuldade de fatoração de números compostos gigantes&amp;rdquo;. No entanto, com o aumento da capacidade de cálculo dos computadores, surgiu a necessidade de aumentar continuamente o tamanho da chave RSA (o número de bits do módulo) para manter a segurança. Atualmente, recomenda-se um tamanho de chave de no mínimo 2048 bits, ou 3072 bits e 4096 bits para maior segurança.&lt;/p>
&lt;p>Por outro lado, a criptografia de curva elíptica (ECC) baseia a sua segurança em outra dificuldade matemática chamada &lt;strong>&amp;ldquo;Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP)&amp;rdquo;&lt;/strong>. Até o momento, nenhum algoritmo eficiente (como algoritmos de tempo subexponencial) foi descoberto para resolver o ECDLP, e mesmo os métodos de ataque mais eficientes conhecidos requerem tempo exponencial.&lt;/p>
&lt;p>Devido a essa propriedade, a ECC possui a vantagem decisiva de &lt;strong>alcançar uma força de segurança equivalente à do RSA com um tamanho de chave muito menor&lt;/strong>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Força de Segurança (bits)&lt;/th>
&lt;th style="text-align:center">Tamanho da Chave RSA (bits)&lt;/th>
&lt;th style="text-align:center">Tamanho da Chave de Curva Elíptica (bits)&lt;/th>
&lt;th style="text-align:center">Proporção do Tamanho da Chave&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Como a tabela acima mostra, para obter uma força de segurança de 128 bits (o padrão atual), o RSA requer uma chave de 3072 bits, mas a ECC requer apenas 256 bits. Isso permite a redução da quantidade de cálculos, a diminuição do uso de memória e a economia de largura de banda de rede, apresentando uma vantagem esmagadora, especialmente em ambientes com recursos limitados como dispositivos IoT e cartões inteligentes.&lt;/p>
&lt;hr>
&lt;h2 id="2-preparação-matemática-teoria-dos-grupos-e-corpos-finitos">2. Preparação Matemática: Teoria dos Grupos e Corpos Finitos
&lt;/h2>&lt;p>Para entender verdadeiramente a criptografia de curva elíptica, é necessário compreender os conceitos básicos de álgebra abstrata (teoria dos grupos e teoria dos corpos). Aqui, resumiremos os conhecimentos prévios para construir a ECC.&lt;/p>
&lt;h3 id="21-grupos-group-e-grupos-abelianos">2.1. Grupos (Group) e Grupos Abelianos
&lt;/h3>&lt;p>Um &lt;strong>Grupo (Group)&lt;/strong> é um conjunto de um dado conjunto $G$ com uma operação binária nesse conjunto (aqui será a adição $+$), $(G, +)$, que satisfaz os 4 axiomas a seguir.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Fechamento (Closure)&lt;/strong>: Para quaisquer $a, b \in G$, $a + b \in G$.&lt;/li>
&lt;li>&lt;strong>Associatividade (Associativity)&lt;/strong>: Para quaisquer $a, b, c \in G$, $(a + b) + c = a + (b + c)$ é válido.&lt;/li>
&lt;li>&lt;strong>Existência do Elemento Neutro (Identity element)&lt;/strong>: Existe um elemento $e \in G$ tal que para qualquer $a \in G$, $a + e = e + a = a$. No caso de grupos aditivos, este elemento neutro é normalmente denotado como $0$ ou $\mathcal{O}$.&lt;/li>
&lt;li>&lt;strong>Existência do Elemento Inverso (Inverse element)&lt;/strong>: Para qualquer $a \in G$, existe um elemento $b \in G$ tal que $a + b = b + a = e$. Esse $b$ é denotado como $-a$.&lt;/li>
&lt;/ol>
&lt;p>Além disso, um grupo que não altera o resultado mesmo mudando a ordem da operação, ou seja, que satisfaz a seguinte condição, é chamado de &lt;strong>Grupo Abeliano (Grupo Comutativo)&lt;/strong>.&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>Comutatividade (Commutativity)&lt;/strong>: Para quaisquer $a, b \in G$, $a + b = b + a$ é válido.&lt;/li>
&lt;/ol>
&lt;p>O conjunto de pontos em uma curva elíptica forma este &lt;strong>grupo abeliano&lt;/strong> pela definição de uma regra de adição específica.&lt;/p>
&lt;h3 id="22-corpos-finitos-finite-field">2.2. Corpos Finitos (Finite Field)
&lt;/h3>&lt;p>Na teoria criptográfica, em vez de corpos contínuos com infinitos elementos como os números reais ou complexos, usamos &lt;strong>Corpos Finitos (Finite Field)&lt;/strong> ou Corpos de Galois, onde o número de elementos é finito.&lt;/p>
&lt;p>O corpo finito mais básico é o &lt;strong>corpo primo $\mathbb{F}_p$&lt;/strong> que usa o número primo $p$. Ele é a definição das quatro operações aritméticas (adição, subtração, multiplicação e divisão) em módulo $p$ (resto da divisão por $p$) no conjunto de inteiros $\{0, 1, 2, \dots, p-1\}$.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Adição&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Subtração&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Multiplicação&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Divisão&lt;/strong>: $a \times b^{-1} \pmod p$ (onde $b^{-1}$ é o inverso multiplicativo de $b$ módulo $p$)&lt;/li>
&lt;/ul>
&lt;p>O cálculo do &lt;strong>Inverso Multiplicativo Modular (Modular Multiplicative Inverse)&lt;/strong> é extremamente importante nas implementações criptográficas. Para encontrar o $b^{-1}$ que satisfaz $b \times b^{-1} \equiv 1 \pmod p$, são utilizados principalmente os 2 algoritmos a seguir.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Algoritmo de Euclides Estendido (Extended Euclidean Algorithm)&lt;/strong>: Rápido, mas dependendo da implementação, o tempo de processamento depende do valor de entrada, o que representa um risco de ataques de tempo.&lt;/li>
&lt;li>&lt;strong>Pequeno Teorema de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>: Quando $p$ é um número primo e $b \neq 0$, $b^{p-1} \equiv 1 \pmod p$ é válido. Dividindo ambos os lados por $b$, obtemos $b^{p-2} \equiv b^{-1} \pmod p$. Em outras palavras, o inverso é encontrado calculando $b$ elevado a $p-2$. A operação de exponenciação é fácil de implementar em tempo constante, por isso é a preferida em implementações criptográficas.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-equação-da-curva-elíptica-e-geometria">3. Equação da Curva Elíptica e Geometria
&lt;/h2>&lt;h3 id="31-forma-normal-de-weierstrass">3.1. Forma Normal de Weierstrass
&lt;/h3>&lt;p>Uma &lt;strong>Curva Elíptica (Elliptic Curve)&lt;/strong> é geralmente uma curva plana definida pela equação chamada de &lt;strong>Forma normal de Weierstrass (Weierstrass normal form)&lt;/strong> a seguir.&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>Aqui, $a$ e $b$ são constantes, e como condição para que a curva não possua singularidades (autointerseção ou cúspides) (para que seja uma curva suave), exige-se que o &lt;strong>Discriminante (Discriminant) $\Delta$&lt;/strong> a seguir não seja zero.&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>Como as curvas com singularidades comprometem a segurança criptográfica, coeficientes $a, b$ que satisfaçam essa condição são sempre escolhidos.&lt;/p>
&lt;h3 id="32-ponto-no-infinito-point-at-infinity">3.2. Ponto no Infinito (Point at Infinity)
&lt;/h3>&lt;p>Para transformar a curva elíptica em um grupo matematicamente perfeito, além dos pontos no plano, introduzimos um ponto virtual chamado &lt;strong>&amp;ldquo;Ponto no Infinito (Point at Infinity)&amp;rdquo;&lt;/strong>. Ele é denotado como $\mathcal{O}$ (O).&lt;/p>
&lt;p>O ponto no infinito $\mathcal{O}$ é definido como o ponto onde todas as linhas verticais se cruzam no infinito. Na teoria dos grupos, este ponto no infinito $\mathcal{O}$ funciona como o &lt;strong>elemento neutro na adição&lt;/strong> (zero).&lt;/p>
&lt;p>Ou seja, para qualquer ponto $P$ na curva, vale o seguinte:
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>Além disso, o inverso $-P$ do ponto $P = (x, y)$ é definido como o ponto simétrico em relação ao eixo x $(x, -y)$. Portanto:
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;p>
é obtido.&lt;/p>
&lt;hr>
&lt;h2 id="4-operações-de-grupo-em-curvas-elípticas-adição-de-pontos-e-dobro">4. Operações de Grupo em Curvas Elípticas (Adição de Pontos e Dobro)
&lt;/h2>&lt;p>O núcleo da criptografia de curva elíptica é a operação de &lt;strong>&amp;ldquo;Adição (Addition)&amp;rdquo;&lt;/strong> entre pontos na curva. Diferente da adição normal de inteiros, ela é baseada em operações geométricas.&lt;/p>
&lt;h3 id="41-adição-geométrica-tangent-and-chord-method">4.1. Adição Geométrica (Tangent and Chord Method)
&lt;/h3>&lt;p>O procedimento para somar 2 pontos diferentes $P$ e $Q$ na curva para encontrar um novo ponto $R$ ($R = P + Q$) é o seguinte.&lt;/p>
&lt;ol>
&lt;li>Trace uma reta (corda) passando pelo ponto $P$ e pelo ponto $Q$.&lt;/li>
&lt;li>Esta reta sempre cruzará a curva elíptica em um terceiro ponto (vamos chamá-lo de $-R$). (*Pelo teorema da geometria algébrica)&lt;/li>
&lt;li>O ponto simétrico de $-R$ em relação ao eixo x (o ponto com o sinal da coordenada y invertido) será o ponto $R$ desejado.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["Traçar uma reta ligando P(x1, y1) e Q(x2, y2)"] --> Step2["Encontrar o terceiro ponto de interseção -R com a curva"]
Step2 --> Step3["Refletir -R no eixo x para obter R(x3, y3)"]
Step3 -.-> Result["Este é R = P + Q"]&lt;/div>
&lt;h3 id="42-dobro-de-um-ponto-point-doubling">4.2. Dobro de um Ponto (Point Doubling)
&lt;/h3>&lt;p>Quando somamos o ponto $P$ ao próprio ponto $P$ ($P + P = 2P$), não podemos traçar uma reta que passe por 2 pontos. Neste caso, traçamos a &lt;strong>tangente (Tangent) à curva no ponto $P$&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Trace a tangente à curva no ponto $P$.&lt;/li>
&lt;li>Esta tangente cruzará a curva em outro ponto $-R$.&lt;/li>
&lt;li>O ponto simétrico desse cruzamento em relação ao eixo x será o ponto $R = 2P$ desejado.&lt;/li>
&lt;/ol>
&lt;h3 id="43-fórmulas-de-cálculo-algébrico">4.3. Fórmulas de Cálculo Algébrico
&lt;/h3>&lt;p>As operações geométricas são convertidas em fórmulas algébricas para que possam ser calculadas por computadores.
As operações são todas feitas no &lt;strong>corpo finito $\mathbb{F}_p$ (módulo $p$)&lt;/strong>.&lt;/p>
&lt;p>Sejam os pontos $P = (x_1, y_1)$ e $Q = (x_2, y_2)$.
Além disso, seja o ponto do resultado do cálculo $R = P + Q = (x_3, y_3)$.&lt;/p>
&lt;p>Seja $\lambda$ (lambda) a inclinação da reta.&lt;/p>
&lt;p>&lt;strong>[Caso 1: Quando $P \neq Q$ (Adição de Pontos)]&lt;/strong>
A inclinação $\lambda$ é a taxa de variação entre os 2 pontos.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>Usando esse $\lambda$, $x_3, y_3$ são calculados da seguinte forma.
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>[Caso 2: Quando $P = Q$ (Dobro de Ponto)]&lt;/strong>
A inclinação $\lambda$ será a inclinação da tangente, encontrada pela derivada. (Diferenciação implícita de $y^2 = x^3 + ax + b$)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
Portanto,
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>As equações de $x_3, y_3$ têm o mesmo formato da adição, mas como $x_2 = x_1$, ficam assim:
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
Estas fórmulas contêm &lt;strong>divisões (cálculo do inverso modular)&lt;/strong> como $(x_2 - x_1)^{-1}$ e $(2y_1)^{-1}$. O cálculo do inverso modular tem um custo computacional muito alto, então em implementações reais, geralmente se usa um sistema de coordenadas projetivas, como o &lt;strong>&amp;ldquo;Sistema de Coordenadas Jacobiano (Jacobian Coordinates)&amp;rdquo;&lt;/strong>, que adia a divisão.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-multiplicação-escalar-e-o-problema-do-logaritmo-discreto-em-curvas-elípticas-ecdlp">5. Multiplicação Escalar e o Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP)
&lt;/h2>&lt;p>Na criptografia de curva elíptica, a operação de maior complexidade computacional e que forma o núcleo da segurança é a &lt;strong>Multiplicação Escalar (Scalar Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="51-o-que-é-a-multiplicação-escalar">5.1. O que é a Multiplicação Escalar
&lt;/h3>&lt;p>A operação de somar um ponto $P$ a ele mesmo $k$ vezes é chamada de multiplicação escalar e denotada como $kP$.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{ vezes}} $$
&lt;p>Aqui, $k$ é um inteiro muito grande (por exemplo, um número inteiro de 256 bits).&lt;/p>
&lt;h3 id="52-problema-do-logaritmo-discreto-em-curvas-elípticas-ecdlp">5.2. Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP)
&lt;/h3>&lt;p>A segurança da criptografia de curva elíptica depende da dificuldade do seguinte problema.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Problema do Logaritmo Discreto em Curvas Elípticas (Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
Dado um ponto conhecido $P$ (ponto base) e um ponto de resultado do cálculo $Q$, encontre o escalar $k$ que satisfaz $Q = kP$.&lt;/p>
&lt;/blockquote>
&lt;p>É fácil (em tempo polinomial) calcular $Q$ a partir de $k$ e $P$ (direção direta) usando os algoritmos que serão mencionados depois, mas calcular inversamente $k$ a partir de $P$ e $Q$ (direção inversa) é virtualmente impossível sem usar uma busca exaustiva (força bruta), tornando-a uma função de via única.
Nos protocolos criptográficos, &lt;strong>$k$ corresponde à &amp;ldquo;chave privada&amp;rdquo; e $Q$ corresponde à &amp;ldquo;chave pública&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="53-algoritmo-double-and-add">5.3. Algoritmo Double-and-Add
&lt;/h3>&lt;p>Quando $k$ é um número gigante (ex: $2^{256}$), a adição direta de $P$ por $k$ vezes não terminaria nem com o fim da vida do universo. Assim, para realizar a multiplicação escalar rapidamente, usa-se o &lt;strong>método Double-and-Add (Método Binário)&lt;/strong>.&lt;/p>
&lt;p>Esta é a versão em curva elíptica da &amp;ldquo;exponenciação modular rápida&amp;rdquo; para calcular rapidamente potências de números inteiros. Ele expressa o escalar $k$ em binário e o processa a partir do bit mais significativo.&lt;/p>
&lt;ol>
&lt;li>Inicialize o ponto $R$, que guardará o resultado, como $\mathcal{O}$.&lt;/li>
&lt;li>Repita do bit mais significativo até o bit menos significativo de $k$:
&lt;ul>
&lt;li>Dobre $R$ (Point Doubling: $R = 2R$)&lt;/li>
&lt;li>Se o bit atual for &lt;code>1&lt;/code>, adicione $P$ a $R$ (Point Addition: $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Com este algoritmo, a complexidade computacional é drasticamente reduzida de $O(k)$ para $O(\log_2 k)$, tornando o cálculo possível em tempo realista (na ordem de milissegundos).&lt;/p>
&lt;hr>
&lt;h2 id="6-troca-de-chaves-diffie-hellman-em-curva-elíptica-ecdh">6. Troca de Chaves Diffie-Hellman em Curva Elíptica (ECDH)
&lt;/h2>&lt;p>Aqui explicaremos o funcionamento do protocolo mais representativo de aplicação da ECC, o &lt;strong>protocolo de troca de chaves ECDH (Elliptic Curve Diffie-Hellman)&lt;/strong>. O ECDH é um mecanismo que permite que Alice e Bob gerem e compartilhem de forma segura uma chave secreta comum (chave de sessão) sobre um canal de comunicação sujeito a interceptação (é o núcleo do handshake TLS).&lt;/p>
&lt;p>&lt;strong>[Parâmetros Prévios (Parâmetros de Domínio)]&lt;/strong>
As duas partes compartilham com antecedência a curva elíptica $E$ a ser usada, um número primo $p$, e um ponto base $G$. (Exemplos incluem NIST P-256 e secp256k1)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice"
participant Bob as "Bob"
Note over Alice,Bob: "Parâmetros Públicos: Curva E, Ponto base G, Primo p"
Alice->>Alice: "Gerar chave privada d_A (inteiro aleatório)"
Alice->>Alice: "Calcular chave pública Q_A = d_A * G"
Bob->>Bob: "Gerar chave privada d_B (inteiro aleatório)"
Bob->>Bob: "Calcular chave pública Q_B = d_B * G"
Alice->>Bob: "Enviar chave pública Q_A (texto claro)"
Bob->>Alice: "Enviar chave pública Q_B (texto claro)"
Alice->>Alice: "Calcular segredo compartilhado S = d_A * Q_B"
Bob->>Bob: "Calcular segredo compartilhado S = d_B * Q_A"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "O resultado do cálculo S de ambos é perfeitamente idêntico!"&lt;/div>
&lt;p>Um interceptador (Eve) pode capturar $G$, $Q_A$ e $Q_B$ que fluem na via de comunicação, mas devido à dificuldade do ECDLP, não pode deduzir a chave privada $d_A$ de Alice a partir de $Q_A = d_A \cdot G$. Além disso, multiplicar $Q_A$ e $Q_B$ não resulta na chave compartilhada $S$, de forma que o interceptador não pode calcular $S$.&lt;/p>
&lt;hr>
&lt;h2 id="7-armadilhas-de-implementação-ataques-de-canal-lateral-e-contramedidas">7. Armadilhas de Implementação: Ataques de Canal Lateral e Contramedidas
&lt;/h2>&lt;p>Mesmo que seja um algoritmo de criptografia teoricamente perfeito, vulnerabilidades podem surgir no processo de implementá-lo como um programa. Isso é conhecido como &lt;strong>&amp;ldquo;Ataque de Canal Lateral (Side-Channel Attack)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="71-ataques-de-tempo-timing-attack">7.1. Ataques de Tempo (Timing Attack)
&lt;/h3>&lt;p>Vamos rever o algoritmo Double-and-Add mencionado anteriormente.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pseudocódigo vulnerável de Double-and-Add
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Sempre executado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Executado apenas quando o bit é 1!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Esta implementação tem uma falha fatal. Como a Adição de Pontos (Point Addition) é executada quando o bit é &lt;code>1&lt;/code>, o &lt;strong>tempo de cálculo é ligeiramente maior&lt;/strong> do que quando o bit é &lt;code>0&lt;/code>. Além disso, o comportamento da previsão de ramificação do processador e da memória cache também muda.
Observando estatisticamente essas diferenças microscópicas no tempo de computação (ou consumo de energia) milhares de vezes, um atacante pode &lt;strong>restaurar a sequência de bits da chave secreta $k$ completamente, bit a bit&lt;/strong>. Esse é o ataque de tempo.&lt;/p>
&lt;h3 id="72-implementação-em-tempo-constante-constant-time-montgomery-ladder">7.2. Implementação em Tempo Constante (Constant-Time): Montgomery Ladder
&lt;/h3>&lt;p>Para prevenir ataques de tempo, é necessário adotar um algoritmo em que &lt;strong>a sequência de instruções executadas e o tempo de computação sejam sempre constantes (Constant-Time), independentemente do valor do bit da chave secreta&lt;/strong>.&lt;/p>
&lt;p>Um exemplo representativo disso é a &lt;strong>Escada de Montgomery (Montgomery Ladder)&lt;/strong>.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Inicialização: R0 = O, R1 = P"] --> LoopStart["Para cada bit i (a partir do mais significativo)"]
LoopStart --> Cond{"Qual é o valor de k_i?"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["Ir para o próximo bit"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"Todos os bits concluídos"| End["Término: R0 é o resultado (kP)"]&lt;/div>
&lt;p>A beleza da Montgomery Ladder é que, seja o bit &lt;code>0&lt;/code> ou &lt;code>1&lt;/code>, &lt;strong>&amp;ldquo;sempre 1 Point Addition e 1 Point Doubling&amp;rdquo;&lt;/strong> são executados. Isto elimina completamente a dependência de dados no tempo de computação.&lt;/p>
&lt;p>No entanto, se a própria ramificação (&lt;code>if (k_i == 0)&lt;/code>) existir, haverá um risco de variação no tempo de execução devido à otimização do compilador e à previsão de ramificação da CPU. Portanto, nas implementações em Tempo Constante reais, as ramificações condicionais (comandos &lt;code>if&lt;/code>) são eliminadas e usa-se a &lt;strong>troca condicional (Conditional Swap) usando operações de bit&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementação-da-criptografia-de-curva-elíptica-em-c">8. Implementação da Criptografia de Curva Elíptica em C++
&lt;/h2>&lt;p>A partir daqui, transformaremos a teoria em código C++. Bibliotecas de criptografia práticas (como OpenSSL e libsodium) usam otimizações avançadas em Assembly e o sistema de coordenadas jacobiano, mas aqui mostraremos a estrutura de uma &lt;strong>implementação de tempo constante simples usando coordenadas afins&lt;/strong>, para aprofundar a compreensão matemática.&lt;/p>
&lt;p>Supõe-se que será usado &lt;code>boost::multiprecision::cpp_int&lt;/code> para operações com números inteiros enormes.&lt;/p>
&lt;h3 id="81-aritmética-modular-e-inverso">8.1. Aritmética Modular e Inverso
&lt;/h3>&lt;p>Primeiro, vamos definir as funções auxiliares de cálculo sobre o corpo finito. Vamos implementar o cálculo do inverso com base no pequeno teorema de Fermat.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Exemplo: primo p e parâmetros da secp256k1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Aritmética modular retornando resto positivo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Cálculo de exponenciação modular (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Inverso modular usando o Pequeno Teorema de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Pressupondo que m seja primo: n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-representação-dos-pontos-e-operações-de-grupo-adição-e-dobro">8.2. Representação dos Pontos e Operações de Grupo (Adição e Dobro)
&lt;/h3>&lt;p>Vamos implementar a estrutura &lt;code>Point&lt;/code> para gerenciar o ponto no infinito por meio de uma flag e a fórmula de adição.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Geração do ponto no infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Geração de um ponto normal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Adição de pontos em uma curva elíptica (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = ponto no infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (Quando P = Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (Quando P != Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-implementação-da-troca-condicional-em-tempo-constante-constant-time-conditional-swap">8.3. Implementação da Troca Condicional em Tempo Constante (Constant-Time Conditional Swap)
&lt;/h3>&lt;p>Ao trocar o conteúdo de variáveis com base no valor do bit da chave privada, efetuamos a troca apenas com operações de bit (máscaras) sem usar o comando &lt;code>if&lt;/code>. Deste modo, o caminho de execução se torna estritamente constante.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
Em implementações reais, classes de números inteiros de múltipla precisão dinamicamente alocadas, como &lt;code>cpp_int&lt;/code>, não são adequadas para processamento em Tempo Constante (Constant-Time). Isso ocorre porque informações de temporização vazam por causa de alocações de memória e mudanças de tamanho de vetor. Em bibliotecas de produção, representamos números inteiros de tamanho fixo (por exemplo, arrays de 4 elementos uint64_t) e implementamos processamento de máscara a nível de bit. A seguir, está um exemplo conceitual.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Constant-Time Swap Conceitual (assumindo números inteiros de tamanho fixo)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Se bit for 1, troca P1 e P2; se for 0, não troca
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit é 0 ou 1. A máscara é todos os bits 1 (0xFF..) se bit=1 e todos 0 se for 0.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (Aqui, para explicação, assumimos cada palavra da classe BigInt de tamanho fixo como w)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // As coordenadas y e as flags isInfinity também são processadas da mesma forma
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ※ É difícil realizar uma troca de tempo constante perfeita usando boost::multiprecision,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// então, aqui nos limitaremos a simular a ramificação para entender a lógica.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-multiplicação-escalar-pela-escada-de-montgomery-montgomery-ladder">8.4. Multiplicação Escalar pela Escada de Montgomery (Montgomery Ladder)
&lt;/h3>&lt;p>Combinando os comandos &lt;code>pointAdd&lt;/code> e &lt;code>cswap&lt;/code> acima mencionados, implementaremos uma multiplicação escalar segura.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Multiplicação escalar k * P (método Montgomery Ladder)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Ponto no infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtém o comprimento em bits de k (256 bits se secp256k1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtém o valor do bit i (0 ou 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Se bit == 1, faz swap entre R0 e R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Executa sempre a mesma operação (Point Addition e Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Se bit == 1, faz o swap novamente para retornar ao estado original
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Por essa lógica de implementação, se cada bit do escalar $k$ é &lt;code>0&lt;/code> ou &lt;code>1&lt;/code>, as operações executadas em cada iteração de loop (&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>) seguem exatamente o mesmo fluxo, e é possível prevenir vigorosamente o vazamento de informações secretas através das diferenças de temporização ou padrões de acesso ao cache.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusão">9. Conclusão
&lt;/h2>&lt;p>À primeira vista, a criptografia de curva elíptica (ECC) pode parecer estranha: &amp;ldquo;Por que uma operação geométrica de traçar retas e dobrar interseções resulta em criptografia?&amp;rdquo;. No entanto, é o produto da fusão milagrosa da matemática e da criptografia que permite que uma brilhante função de via única (o problema do logaritmo discreto) seja estruturada por meio do mapeamento do mundo discreto dos corpos finitos.&lt;/p>
&lt;p>Este artigo abordou os seguintes pontos cruciais.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Superioridade em relação ao RSA&lt;/strong>: Fornece segurança poderosa com comprimentos de chave muito curtos, sendo a mais adequada para as eras móveis e IoT contemporâneas.&lt;/li>
&lt;li>&lt;strong>Bases da Teoria dos Grupos e Corpos Finitos&lt;/strong>: As estruturas matemáticas subjacentes da ECC.&lt;/li>
&lt;li>&lt;strong>Fórmulas de Adição e Dobro&lt;/strong>: O método para implementar operações algébricas de grupo usando equações de Weierstrass.&lt;/li>
&lt;li>&lt;strong>Ameaça de Ataques de Canal Lateral&lt;/strong>: As ramificações condicionais dependentes de bit da chave privada causam vulnerabilidades fatais.&lt;/li>
&lt;li>&lt;strong>Implementação de Tempo Constante (Constant-Time)&lt;/strong>: Técnicas de codificação em C++ para evitar ataques através de comportamentos unificados de nível de hardware usando Escada de Montgomery (Montgomery Ladder) e Troca Condicional (Conditional Swap).&lt;/li>
&lt;/ol>
&lt;p>Não é recomendado (&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;) criar suas próprias bibliotecas criptográficas que operem efetivamente no ambiente de produção, uma vez que o risco de segurança é extremamente alto. No entanto, compreender a fundo o seu algoritmo interno e o contexto matemático que operem lá dentro deveria ser uma arma indubitavelmente forte para qualquer engenheiro que queira criar e operar um sistema ainda mais seguro e com maior desempenho.&lt;/p>
&lt;p>No próximo artigo, aprofundaremos um pouco mais sobre o mecanismo do &lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong>, um algoritmo de assinatura digital que usa essas curvas elípticas, bem como a &lt;strong>Assinatura de Schnorr&lt;/strong> usada no Bitcoin.&lt;/p></description></item><item><title>Existe algum algoritmo além do GNFS (Crivo Geral dos Campos de Números)?</title><link>http://kenji.blog/pt/p/beyond-gnfs-integer-factorization-algorithms/</link><pubDate>Fri, 11 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/beyond-gnfs-integer-factorization-algorithms/</guid><description>&lt;img src="http://kenji.blog/p/beyond-gnfs-integer-factorization-algorithms/img/eyecatch.jpg" alt="Featured image of post Existe algum algoritmo além do GNFS (Crivo Geral dos Campos de Números)?" />&lt;h2 id="1-introdução-a-fatoração-de-inteiros-e-a-base-da-criptografia-moderna">1. Introdução: A Fatoração de Inteiros e a Base da Criptografia Moderna
&lt;/h2>&lt;p>A segurança das comunicações na Internet na sociedade moderna depende fortemente da segurança da criptografia de chave pública RSA. A segurança do RSA baseia-se na suposição matemática da &amp;ldquo;dificuldade de fatorar números compostos gigantes&amp;rdquo;. Se um algoritmo de fatoração extremamente eficiente for descoberto, a infraestrutura de comunicação em todo o mundo desmoronaria desde a sua base.&lt;/p>
&lt;p>Atualmente, o &lt;strong>Crivo Geral dos Campos de Números (GNFS - General Number Field Sieve)&lt;/strong> reina como o algoritmo mais rápido e poderoso para a fatoração de números inteiros gigantes utilizando computadores clássicos. O GNFS nasceu como uma extensão do Crivo Especial dos Campos de Números (SNFS), proposto no final da década de 1980, e estabeleceu recordes de fatoração para números compostos enormes como o RSA-768 e RSA-250 até os dias de hoje.&lt;/p>
&lt;p>No entanto, criptógrafos e matemáticos sempre se fazem as seguintes perguntas: &amp;ldquo;Existe algum algoritmo clássico que supere o GNFS?&amp;rdquo; &amp;ldquo;Onde está o limite dos computadores clássicos?&amp;rdquo; e &amp;ldquo;Como os computadores quânticos irão contornar essa situação?&amp;rdquo;&lt;/p>
&lt;p>Neste artigo, dissecaremos exaustivamente as profundas estruturas matemáticas por trás do GNFS e conduziremos uma análise técnica detalhada da seleção de polinômios, processo de crivagem e etapas de álgebra linear usando o método de Block Wiedemann. Além disso, consideraremos métodos de extensão para GNFS, como as melhorias de Coppersmith, e compararemos e explicaremos as diferenças cruciais entre os algoritmos clássicos de tempo subexponencial (Sub-exponential time) e os algoritmos quânticos de tempo polinomial a partir de uma perspectiva matemática.&lt;/p>
&lt;hr>
&lt;h2 id="2-complexidade-assintótica-e-notação-l-l-notation">2. Complexidade Assintótica e Notação L (L-notation)
&lt;/h2>&lt;p>Ao avaliar a complexidade de algoritmos de fatoração, a &lt;strong>Notação L (L-notation)&lt;/strong> é usada para expressar o tempo subexponencial relativo ao número de dígitos da entrada $n$, ao invés da notação padrão de tempo polinomial (como $O(n^k)$). A notação L é definida da seguinte forma:&lt;/p>
$$
L_n[\alpha, c] = \exp \left( (c + o(1)) (\ln n)^\alpha (\ln \ln n)^{1-\alpha} \right)
$$
&lt;p>Aqui, $n$ é o número inteiro a ser fatorado e $\ln n$ é o logaritmo natural, o qual é proporcional ao comprimento em bits de $n$.&lt;/p>
&lt;ul>
&lt;li>Quando $\alpha = 0$: $L_n[0, c] = \exp(c \ln \ln n) = (\ln n)^c$, representando um &lt;strong>tempo polinomial (Polynomial time)&lt;/strong> em relação ao comprimento em bits.&lt;/li>
&lt;li>Quando $\alpha = 1$: $L_n[1, c] = \exp(c \ln n) = n^c$, representando um &lt;strong>tempo exponencial (Exponential time)&lt;/strong> em relação ao comprimento em bits.&lt;/li>
&lt;li>Quando $0 &lt; \alpha &lt; 1$: Representa um &lt;strong>tempo subexponencial (Sub-exponential time)&lt;/strong> localizado entre o tempo polinomial e o tempo exponencial.&lt;/li>
&lt;/ul>
&lt;p>A evolução dos algoritmos de fatoração no passado tem sido a história de reduzir gradualmente o valor desse $\alpha$.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fração Contínua (CFRAC) e Crivo Quadrático de Múltiplos Polinômios (MPQS)&lt;/strong>: Pertencem à classe $\alpha = 1/2$ e a complexidade de cálculo é de cerca de $L_n[1/2, 1]$.&lt;/li>
&lt;li>&lt;strong>Crivo Geral dos Campos de Números (GNFS)&lt;/strong>: Alcançou $\alpha = 1/3$ e ostenta a complexidade computacional mais rápida de $L_n[1/3, (64/9)^{1/3}]$ entre os algoritmos clássicos conhecidos atualmente.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-visão-geral-do-algoritmo-gnfs-e-estrutura-matemática">3. Visão Geral do Algoritmo GNFS e Estrutura Matemática
&lt;/h2>&lt;p>O GNFS possui uma base matemática muito complexa e avançada. A ideia básica é uma extensão do Pequeno Teorema de Fermat e do Crivo Quadrático (QS), consistindo em encontrar um par não-trivial $(X, Y)$ que satisfaça a congruência $X^2 \equiv Y^2 \pmod n$ e $X \not\equiv \pm Y \pmod n$, para assim derivar um fator $\gcd(X-Y, n)$ de $n$.&lt;/p>
&lt;p>No entanto, a verdadeira essência do GNFS não é fazer isso apenas no corpo dos números racionais $\mathbb{Q}$, mas sim buscar simultaneamente por &amp;ldquo;números suaves (Smooth numbers)&amp;rdquo; tanto em uma extensão de corpo chamada Corpo de Números Algébricos (Algebraic Number Field) $\mathbb{Q}(\alpha)$ quanto no corpo dos números racionais, e construir uma relação de congruência por meio de um homomorfismo.&lt;/p>
&lt;p>O processo do GNFS é amplamente dividido em 5 fases.&lt;/p>
&lt;div class="mermaid">graph TD
A["Problema de fatoração de inteiros (entrada n)"] --> B["1. Seleção de polinômios (Polynomial Selection)"]
B --> C["2. Processo de crivagem (Sieving Phase)"]
C --> D["3. Filtragem (Filtering Phase)"]
D --> E["4. Álgebra Linear (Linear Algebra Phase)"]
E --> F["5. Raiz quadrada (Square Root Phase)"]
F --> G["Saída dos fatores primos p, q"]&lt;/div>
&lt;h3 id="31-fase-1-seleção-de-polinômios-polynomial-selection">3.1 Fase 1: Seleção de polinômios (Polynomial Selection)
&lt;/h3>&lt;p>O sucesso do GNFS depende fortemente da seleção adequada dos polinômios. O objetivo é encontrar dois polinômios irredutíveis $f_1(x)$ (lado racional) e $f_2(x)$ (lado algébrico) que compartilham uma raiz comum $m$. Ou seja,
$f_1(m) \equiv f_2(m) \equiv 0 \pmod n$
satisfazendo.&lt;/p>
&lt;p>Normalmente, um polinômio linear $f_1(x) = x - m$ é escolhido para o lado racional, e um polinômio mônico $f_2(x)$ de grau $d$ (tipicamente 5 ou 6) é escolhido para o lado algébrico. A abordagem mais clássica é o &lt;strong>Método de base $m$ (Base-$m$ method)&lt;/strong>.
Escolhe-se um inteiro $m = \lfloor n^{1/(d+1)} \rfloor$ próximo à raiz $1/(d+1)$ de $n$ e expande-se $n$ na base $m$.
$n = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0$
Com isso, obtemos o polinômio $f_2(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_0$. Claramente, $f_2(m) = n \equiv 0 \pmod n$.&lt;/p>
&lt;p>Entretanto, em implementações modernas o &lt;strong>Algoritmo de Kleinjung&lt;/strong> é utilizado. Ele busca polinômios cujos coeficientes não se tornem extremamente grandes (otimização de Skewness) enquanto otimiza propriedades algébricas (valor $E$ de Murphy e valor $\alpha$), facilitando a geração de números suaves durante o processo de crivagem. Esta etapa por si só requer uma enorme quantidade de recursos computacionais.&lt;/p>
&lt;h3 id="32-fase-2-processo-de-crivagem-sieving-phase">3.2 Fase 2: Processo de crivagem (Sieving Phase)
&lt;/h3>&lt;p>Uma vez que os polinômios são determinados, entra-se na fase de &amp;ldquo;Crivagem (Sieving)&amp;rdquo;, que é a fase mais exigente do ponto de vista computacional do algoritmo. Aqui, buscamos pares $(a, b)$. Este par deve ser coprimo entre si e é requerido que os dois valores seguintes sejam simultaneamente &amp;ldquo;suaves (Smooth)&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Norma do lado racional&lt;/strong>: $F_1(a, b) = b \cdot f_1(a/b) = a - bm$&lt;/li>
&lt;li>&lt;strong>Norma do lado algébrico&lt;/strong>: $F_2(a, b) = b^d \cdot f_2(a/b)$&lt;/li>
&lt;/ol>
&lt;p>&amp;ldquo;Suave&amp;rdquo; significa que o valor pode ser fatorado apenas por números primos menores ou iguais a um limite especificado (Sieve bound). Uma base de fatores (Factor base) para o lado racional e outra para o lado algébrico são preparadas, e números suaves são encontrados eficientemente em um enorme espaço de busca utilizando uma técnica semelhante ao Crivo de Eratóstenes.
Hoje, uma técnica chamada &lt;strong>Crivo em Reticulado (Lattice Sieving)&lt;/strong> é dominante, onde se fixa um número primo específico $q$ e realiza-se a crivagem apenas em pares $(a, b)$ em um sub-reticulado no qual tanto o lado racional quanto o algébrico são múltiplos de $q$, alcançando assim uma eficiência extremamente alta.&lt;/p>
&lt;h3 id="33-fase-3-filtragem-filtering-phase">3.3 Fase 3: Filtragem (Filtering Phase)
&lt;/h3>&lt;p>O número de relações suaves (relations) encontradas no processo de crivagem chega a centenas de milhões, ou até bilhões. No entanto, muitas destas contêm informações inúteis.
O objetivo da filtragem é construir uma enorme matriz esparsa (Sparse Matrix) ao mesmo tempo que reduz a sua dimensionalidade ao máximo possível.&lt;/p>
&lt;p>Especificamente, realizam-se as seguintes operações:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Remoção de singletons (Singleton removal)&lt;/strong>: Excluir as relações que contêm fatores primos que aparecem apenas uma vez.&lt;/li>
&lt;li>&lt;strong>Remoção de cliques / Mesclagem (Clique removal / Merging)&lt;/strong>: Multiplicar relações que possuem fatores primos que aparecem duas ou mais vezes, eliminando variáveis para reduzir para um sistema de equações de maior densidade, porém menor dimensionalidade.&lt;/li>
&lt;/ul>
&lt;p>Com isso, uma matriz com bilhões de linhas é comprimida em uma enorme matriz esparsa $\mathbf{A}$ (com elementos 0 e 1 sobre o corpo $\mathbb{F}_2$) de nível de dezenas de milhões de linhas.&lt;/p>
&lt;h3 id="34-fase-4-álgebra-linear-linear-algebra-phase">3.4 Fase 4: Álgebra Linear (Linear Algebra Phase)
&lt;/h3>&lt;p>Aqui, buscamos um vetor de solução não trivial $\mathbf{x}$ para a equação $\mathbf{A} \mathbf{x} \equiv \mathbf{0} \pmod 2$. Ou seja, é o problema de encontrar o espaço nulo à esquerda (Left Nullspace) de uma enorme matriz esparsa.&lt;/p>
&lt;p>Devido ao tamanho extremo da matriz, é totalmente inviável calcular com a eliminação gaussiana padrão ($O(N^3)$). Portanto, utilizam-se métodos iterativos, que são um tipo de método de subespaço de Krylov. Historicamente, o &lt;strong>Método Block Lanczos&lt;/strong> tem sido utilizado, mas em ambientes modernos de computação distribuída o &lt;strong>Algoritmo de Block Wiedemann&lt;/strong>, que pode reduzir drasticamente a sobrecarga de comunicação, é o dominante.&lt;/p>
&lt;p>O método Block Wiedemann calcula o polinômio mínimo a partir da matriz $\mathbf{A}$ e de sequências de vetores e constrói a base do espaço nulo utilizando o algoritmo de Berlekamp-Massey. Esse passo é extremamente difícil de paralelizar, o que exige redes de comunicação estreitamente acopladas em supercomputadores ou grandes clusters, sendo um dos maiores gargalos do GNFS.&lt;/p>
&lt;h3 id="35-fase-5-raiz-quadrada-square-root-phase">3.5 Fase 5: Raiz quadrada (Square Root Phase)
&lt;/h3>&lt;p>A partir das soluções da álgebra linear, constrói-se um produto que é um &amp;ldquo;quadrado perfeito&amp;rdquo; em ambos os lados, o racional e o algébrico.
No lado racional, $\prod (a-bm)$ torna-se o quadrado $X^2$ de um determinado inteiro $X$, enquanto no lado algébrico o produto dos ideais correspondentes torna-se um quadrado perfeito $\gamma^2$ no corpo de números algébricos.
Ao calcular esse $\gamma$ no corpo de números algébricos e aplicar o homomorfismo ao anel dos inteiros racionais $\phi: \alpha \mapsto m \pmod n$, obtemos a congruência:
$X^2 \equiv \phi(\gamma)^2 \equiv Y^2 \pmod n$
obtém-se.&lt;/p>
&lt;p>O cálculo da raiz quadrada no corpo de números algébricos utiliza algoritmos complexos, como o &lt;strong>Método de Montgomery&lt;/strong>, exigindo um profundo conhecimento em teoria algébrica dos números. Finalmente, $\gcd(X-Y, n)$ é calculado, e se um fator não trivial for obtido, a fatoração estará concluída.&lt;/p>
&lt;hr>
&lt;h2 id="4-existe-algum-algoritmo-clássico-que-supere-o-gnfs">4. Existe algum algoritmo clássico que supere o GNFS?
&lt;/h2>&lt;p>Até o momento, não foi descoberto nenhum algoritmo clássico que seja capaz de atingir uma complexidade assintótica abaixo de $L_n[1/3, c]$ para a fatoração de números inteiros gerais. No entanto, existem algumas tentativas e algoritmos derivados voltados a romper esses limites teóricos e práticos.&lt;/p>
&lt;h3 id="41-crivo-de-múltiplos-campos-de-números-mnfs-multiple-number-field-sieve">4.1 Crivo de Múltiplos Campos de Números (MNFS: Multiple Number Field Sieve)
&lt;/h3>&lt;p>Como uma abordagem estendida do GNFS, existe o &lt;strong>Crivo de Múltiplos Campos de Números (MNFS)&lt;/strong> de D. Coppersmith. Enquanto o GNFS utiliza 2 polinômios (um lado racional e um algébrico), o MNFS utiliza múltiplos polinômios algébricos diferentes em conjunto com um único polinômio racional.&lt;/p>
$$ f_1(x), f_{2,1}(x), f_{2,2}(x), \dots, f_{2,V}(x) $$
&lt;p>Ao usar múltiplos corpos algébricos, a probabilidade de &amp;ldquo;ser suave em qualquer um dos corpos algébricos&amp;rdquo; em cada etapa da crivagem aumenta drasticamente. Com essa abordagem, Coppersmith conseguiu reduzir ligeiramente a constante $c$ da complexidade $L_n[1/3, c]$.
Especificamente, enquanto a constante no GNFS é $c = (64/9)^{1/3} \approx 1.923$, mostrou-se teoricamente que a complexidade pode ser reduzida até $c \approx 1.902$ ao otimizar o MNFS.
No entanto, na prática, a sobrecarga de gerenciar múltiplos corpos é grande, e não houve grandes avanços definitivos em módulos RSA em escalas de uso no mundo real.&lt;/p>
&lt;h3 id="42-algoritmos-de-classe-l_n14-são-possíveis">4.2 Algoritmos de classe $L_n[1/4]$ são possíveis?
&lt;/h3>&lt;p>O tema sobre &amp;ldquo;se um algoritmo com expoente $\alpha = 1/4$ existe&amp;rdquo;, quanto ao limite dos algoritmos clássicos de fatoração, tem sido debatido há muito tempo entre os matemáticos.
O GNFS atual e suas derivações estão fortemente atrelados ao modelo de &amp;ldquo;busca por suavidade&amp;rdquo; usando crivos, e é amplamente acreditado que $\alpha = 1/3$ é o limite desse paradigma. Com base na análise das probabilidades de distribuição de números inteiros suaves utilizando a função de Dickman, acredita-se que não é possível superar a barreira de $O(L_n[1/3])$ com a combinação dos métodos de construção de campos algébricos e de crivos atuais, não importa o quanto se otimize.&lt;/p>
&lt;p>Se um algoritmo $L_n[1/4]$ ou mesmo um algoritmo polinomial clássico existisse, dependeria de uma estrutura matemática inteiramente nova e inimaginável pela humanidade até então (como, por exemplo, a abordagem muito mais avançada de geometria algébrica, semelhante ao Algoritmo de Schoof para a criptografia de curvas elípticas), e não na abordagem de &amp;ldquo;base em suavidade&amp;rdquo; como no GNFS. No entanto, atualmente não há sinal disso.&lt;/p>
&lt;hr>
&lt;h2 id="5-o-grande-avanço-da-computação-quântica-algoritmo-de-shor">5. O Grande Avanço da Computação Quântica: Algoritmo de Shor
&lt;/h2>&lt;p>Enquanto os computadores clássicos enfrentam a barreira de $L_n[1/3]$, o &lt;strong>Algoritmo de Shor (Shor&amp;rsquo;s Algorithm)&lt;/strong>, introduzido por Peter Shor em 1994, destruiu esta parede mudando fundamentalmente o modelo de computação em si.&lt;/p>
&lt;h3 id="51-o-impacto-do-tempo-polinomial-quântico">5.1 O impacto do tempo polinomial quântico
&lt;/h3>&lt;p>O Algoritmo de Shor reduz o problema da fatoração a um &amp;ldquo;Problema de Busca de Ordem (Order Finding Problem)&amp;rdquo;. Dado um inteiro $a$, é o problema de encontrar o período (ordem) $r$ da função $f(x) = a^x \pmod n$.
Um computador clássico leva um tempo exponencial para encontrar esse período, mas usando a &lt;strong>Estimação de Fase Quântica (QPE: Quantum Phase Estimation)&lt;/strong> e a &lt;strong>Transformada de Fourier Quântica (QFT: Quantum Fourier Transform)&lt;/strong> em um computador quântico, todas as superposições de estado (Superposition) podem ser avaliadas em paralelo, o que permite extrair o período $r$ com alta probabilidade.&lt;/p>
&lt;p>Em termos de complexidade computacional, o tempo de execução do Algoritmo de Shor é de &lt;strong>tempo polinomial quântico&lt;/strong>, especificamente o seguinte:
&lt;/p>
$$ O((\log n)^3) $$
&lt;p>
Tendo em vista as implementações de circuitos otimizadas nos últimos anos, afirma-se que o tempo pode ser reduzido até $O((\log n)^2 \log \log n)$.&lt;/p>
&lt;div class="mermaid">graph LR
A["Algoritmo clássico (GNFS)"] -->|Limite| B["Tempo subexponencial L_n[1/3]"]
C["Algoritmo quântico (Shor)"] -->|Avanço| D["Tempo polinomial O((log n)^3)"]
B --> E["Uso contínuo de criptografia RSA (aumento do tamanho da chave)"]
D --> F["Colapso completo da criptografia RSA"]&lt;/div>
&lt;h3 id="52-tempo-subexponencial-clássico-vs-tempo-polinomial-quântico">5.2 Tempo subexponencial clássico vs Tempo polinomial quântico
&lt;/h3>&lt;p>A diferença entre essas duas classes de complexidade tem um significado decisivo na segurança de criptografias no mundo real.&lt;/p>
&lt;p>Por exemplo, considere a fatoração do RSA-2048 (um número composto de 2048 bits).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GNFS (Clássico)&lt;/strong>: Substituindo $n \approx 2^{2048}$ em $L_n[1/3, 1.923]$, serão necessárias cerca de $2^{112}$ operações. Essa é uma quantidade de cálculos astronômica que demoraria mais que a idade do universo, mesmo se reuníssemos todos os recursos de computação do planeta.&lt;/li>
&lt;li>&lt;strong>Algoritmo de Shor (Quântico)&lt;/strong>: No algoritmo $O((\log n)^3)$, seriam necessárias apenas cerca de $2048^3 \approx 8.5 \times 10^9$ operações em portas lógicas. Isso significa que a computação poderia ser concluída de apenas algumas horas a alguns dias se houvesse o hardware adequado (um computador quântico universal capaz de corrigir erros com alguns milhões de qubits físicos).&lt;/li>
&lt;/ul>
&lt;p>A mudança de paradigma da complexidade subexponencial com &amp;ldquo;expoente $\alpha=1/3$&amp;rdquo; para &amp;ldquo;tempo polinomial&amp;rdquo; anula a estratégia tradicional de criptografia que consiste em garantir a segurança por meio do alongamento do comprimento da chave.&lt;/p>
&lt;hr>
&lt;h2 id="6-conclusão-perspectivas-para-a-próxima-geração">6. Conclusão: Perspectivas para a próxima geração
&lt;/h2>&lt;p>O consenso atual na comunidade científica em relação à pergunta &amp;ldquo;Existe algum algoritmo clássico que supere o GNFS?&amp;rdquo; é o seguinte:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Aprimoramentos práticos continuam, mas não há um grande salto assintótico&lt;/strong>: As tentativas de melhorar o fator $c$ do GNFS através do MNFS, da otimização na seleção de polinômios, da paralelização do Método de Block Wiedemann, etc., seguem ocorrendo. Contudo, considera-se extremamente improvável que seja descoberto um algoritmo clássico abaixo de $\alpha = 1/3$.&lt;/li>
&lt;li>&lt;strong>A segurança do RSA em computadores clássicos permanece forte&lt;/strong>: A complexidade computacional do GNFS continua enorme, e os RSA-2048 e RSA-4096 permanecerão protegidos contra ataques vindos de computadores clássicos durante as próximas décadas.&lt;/li>
&lt;li>&lt;strong>A verdadeira ameaça é o algoritmo quântico&lt;/strong>: O Algoritmo de Shor, baseado nos princípios da mecânica quântica, ultrapassou os limites da complexidade computacional. Como resultado, o mundo é obrigado a realizar a transição para a Criptografia Pós-Quântica (PQC). A fronteira da criptografia de hoje encontra-se em novos problemas matemáticos, como a criptografia baseada em reticulados e a criptografia baseada em hashes, as quais são consideradas difíceis de se decifrar até para computadores quânticos (ou seja, não possuem resolução no tempo polinomial).&lt;/li>
&lt;/ol>
&lt;p>O Crivo Geral dos Campos de Números (GNFS) é uma das maiores conquistas matemáticas alcançadas pela humanidade ao desafiar os limites do design de algoritmos e matemática clássica. Compreender a profunda estrutura matemática do GNFS não é apenas aprender sobre a história da criptanálise, é também uma jornada de exploração intelectual que nos permite tocar na beleza da teoria da complexidade computacional e da teoria algébrica dos números. Até ao dia em que os computadores quânticos se tornarem práticos, o GNFS deverá manter a sua coroa como o algoritmo de fatoração de inteiros mais poderoso.&lt;/p></description></item><item><title>【Ilustrado PQC】Comparação dos principais algoritmos de criptografia pós-quântica</title><link>http://kenji.blog/pt/p/post-quantum-cryptography-algorithms-comparison/</link><pubDate>Fri, 11 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/post-quantum-cryptography-algorithms-comparison/</guid><description>&lt;img src="http://kenji.blog/p/post-quantum-cryptography-algorithms-comparison/img/eyecatch.jpg" alt="Featured image of post 【Ilustrado PQC】Comparação dos principais algoritmos de criptografia pós-quântica" />&lt;h2 id="1-introdução-a-crise-da-criptografia-trazida-pelos-computadores-quânticos">1. Introdução: A &amp;ldquo;crise da criptografia&amp;rdquo; trazida pelos computadores quânticos
&lt;/h2>&lt;p>Na sociedade da internet moderna, a tecnologia de criptografia de chave pública é infraestrutura indispensável para proteger a confidencialidade das comunicações e a integridade dos dados. A criptografia RSA e a criptografia de curva elíptica (ECC), amplamente utilizadas hoje, dependem de barreiras matemáticas, respectivamente a &amp;ldquo;dificuldade de fatoração de números compostos gigantescos&amp;rdquo; e a &amp;ldquo;dificuldade do problema do logaritmo discreto em curvas elípticas&amp;rdquo;, para garantir a segurança. Em computadores clássicos (os computadores que usamos hoje, incluindo supercomputadores), está provado que resolver esses problemas matemáticos levaria mais tempo do que a idade do universo, o que tem sido a base de sua segurança.&lt;/p>
&lt;p>No entanto, essa premissa robusta está prestes a ser fundamentalmente derrubada pelo progresso na teoria e aplicação prática dos &lt;strong>computadores quânticos&lt;/strong>. O &amp;ldquo;&lt;strong>Algoritmo de Shor&lt;/strong>&amp;rdquo;, publicado em 1994 pelo criptógrafo Peter Shor, provou teoricamente que problemas de fatoração de primos e logaritmos discretos podem ser resolvidos em &amp;ldquo;tempo polinomial&amp;rdquo; executando-os em um computador quântico universal tolerante a falhas (CRQC: Cryptographically Relevant Quantum Computer) com desempenho suficiente. Isso significa que toda a criptografia de chave pública atualmente em uso será neutralizada.&lt;/p>
&lt;div class="mermaid">graph TD
A["Computador quântico de grande escala (CRQC)"] -->|Execução| B["Algoritmo de Shor"]
B -->|Decodificação em tempo polinomial| C["Problema de fatoração (RSA)"]
B -->|Decodificação em tempo polinomial| D["Problema de logaritmo discreto (ECC / ECDSA)"]
C --> E["Interceptação, alteração de dados e falsificação de comunicação criptografada"]
D --> E
F["Store Now, Decrypt Later (SNDL)"] --> E&lt;/div>
&lt;p>É muito perigoso pensar que &amp;ldquo;não há problema porque a conclusão em grande escala dos computadores quânticos ainda está a décadas de distância&amp;rdquo;. Isso ocorre porque o método de ataque chamado &lt;strong>Store Now, Decrypt Later (SNDL: Armazene agora, descriptografe depois)&lt;/strong> já se tornou uma ameaça real. Trata-se de um ataque em que nações maliciosas ou organizações de hackers armazenam grandes quantidades de dados de comunicação atualmente criptografados (como o tráfego TLS) e os descriptografam todos no momento em que computadores quânticos poderosos se tornarem disponíveis no futuro. Segredos de estado, informações de infraestrutura e dados médicos que devem ser protegidos a longo prazo já estão expostos a essa ameaça.&lt;/p>
&lt;p>Além disso, para criptografia de chave simétrica (como AES) e funções de hash (como SHA-256), existe o &lt;strong>Algoritmo de Grover&lt;/strong>, descoberto em 1996. Isso reduz a complexidade computacional dos ataques de força bruta (brute force) à sua raiz quadrada. Em outras palavras, o nível de segurança do AES-128 é efetivamente reduzido pela metade, para 2 à potência de 64, portanto, na era quântica, recomenda-se usar chaves mais longas e comprimentos de hash como AES-256 e SHA-384.&lt;/p>
&lt;p>A &lt;strong>Criptografia Pós-Quântica (PQC)&lt;/strong>, baseada em novos problemas matemáticos difíceis de decifrar, mesmo usando computadores quânticos, nasceu para combater essa crise criptográfica sem precedentes. Neste artigo, com base nos resultados do processo de padronização PQC liderado pelo Instituto Nacional de Padrões e Tecnologia dos EUA (NIST), explicaremos os principais algoritmos PQC em detalhes extremos, desde sua base matemática até seus mecanismos e comparação de arquitetura.&lt;/p>
&lt;hr>
&lt;h2 id="2-todo-o-escopo-e-história-do-projeto-de-padronização-pqc-do-nist">2. Todo o escopo e história do projeto de padronização PQC do NIST
&lt;/h2>&lt;p>A transição da tecnologia de criptografia leva anos ou até décadas, incluindo o redesenho de protocolos, atualizações de sistema, substituição de hardware, etc. Por esse motivo, criptógrafos de todo o mundo vêm avançando na pesquisa PQC desde cedo. O NIST dos EUA desempenhou um papel central nisso. O NIST abriu o processo de padronização PQC ao público em 2016 e aceitou propostas de algoritmos de criptografia completamente novos da comunidade criptográfica global.&lt;/p>
&lt;p>As duas categorias principais para padronização foram as seguintes:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Criptografia de chave pública / Mecanismo de encapsulamento de chaves (KEM: Key Encapsulation Mechanism)&lt;/strong>: Um mecanismo para compartilhar de forma segura uma chave simétrica para criptografar o caminho de comunicação, como em conexões TLS.&lt;/li>
&lt;li>&lt;strong>Assinaturas digitais (Digital Signatures)&lt;/strong>: Um mecanismo para provar que os dados não foram alterados e que não há falsificação pelo remetente (autenticidade) em atualizações de software e certificados digitais.&lt;/li>
&lt;/ol>
&lt;p>Após quase 6 anos de feroz avaliação, análise e competição criptoanalítica (Rodada 1 à Rodada 3), alguns algoritmos também foram submetidos a uma avaliação adicional na Rodada 4. Como resultado, em 2024, os seguintes algoritmos foram oficialmente emitidos como Padrões Federais de Processamento de Informação (FIPS) e foram estabelecidos como padrões globais futuros.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>FIPS 203 (ML-KEM)&lt;/strong>: KEM baseado em CRYSTALS-Kyber&lt;/li>
&lt;li>&lt;strong>FIPS 204 (ML-DSA)&lt;/strong>: Assinatura digital baseada em CRYSTALS-Dilithium&lt;/li>
&lt;li>&lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>: Assinatura baseada em hash sem estado baseada em SPHINCS+&lt;/li>
&lt;li>&lt;strong>(Planejado para formulação futura) FN-DSA&lt;/strong>: Assinatura digital baseada em FALCON&lt;/li>
&lt;/ul>
&lt;p>Cada um desses algoritmos selecionados se baseia em diferentes &amp;ldquo;problemas de dificuldade&amp;rdquo; matemáticos, garantindo diversidade (Crypto Agility) de modo que, mesmo se uma vulnerabilidade fatal for descoberta em um algoritmo no futuro, o sistema inteiro não entrará em colapso. No processo de padronização, a criptografia baseada em reticulados (Lattice-based cryptography) assumiu o papel principal principalmente do ponto de vista do desempenho, mas a criptografia baseada em hash e a criptografia baseada em código foram adotadas como backups fortes.&lt;/p>
&lt;hr>
&lt;h2 id="3-classificação-das-principais-abordagens-matemáticas-para-pqc">3. Classificação das principais abordagens matemáticas para PQC
&lt;/h2>&lt;p>Os algoritmos PQC são categorizados principalmente nas 5 áreas a seguir com base nos problemas matemáticos em que baseiam sua segurança. Neste artigo, nos aprofundaremos principalmente nas três primeiras.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Criptografia baseada em reticulados (Lattice-based Cryptography)&lt;/strong>:
Baseia-se no Problema do Vetor Mais Curto (SVP) e no Problema do Vetor Mais Próximo (CVP) em espaços de reticulados multidimensionais, e no problema LWE derivado deles. É o centro da padronização do NIST, incluindo Kyber, Dilithium e FALCON. Possui o melhor equilíbrio entre velocidade de processamento, tamanho da chave pública e tamanho do texto cifrado, sendo adequado para uso geral.&lt;/li>
&lt;li>&lt;strong>Criptografia baseada em hash (Hash-based Cryptography)&lt;/strong>:
Baseia sua segurança unicamente na &amp;ldquo;resistência à colisão&amp;rdquo; e &amp;ldquo;unidirecionalidade&amp;rdquo; das funções de hash criptográficas (como SHA-2 e SHAKE). É aplicável apenas a assinaturas digitais (SPHINCS+, etc.), mas tem a prova matemática mais forte de segurança e é caracterizada por uma resistência extremamente alta a ataques matemáticos desconhecidos.&lt;/li>
&lt;li>&lt;strong>Criptografia baseada em código (Code-based Cryptography)&lt;/strong>:
Baseado na teoria de códigos de correção de erros, depende da dificuldade do Problema de Decodificação de Síndrome (Syndrome Decoding Problem). O Classic McEliece, proposto na década de 1970, é representativo e, embora tenha uma longa história e segurança comprovada, o tamanho da chave pública é extremamente grande, chegando a megabytes.&lt;/li>
&lt;li>&lt;strong>Criptografia polinomial multivariada (Multivariate Polynomial Cryptography)&lt;/strong>:
Baseia-se na dificuldade de encontrar soluções para um sistema de equações quadráticas simultâneas multivariadas sobre um corpo finito (problema MQ). Foi proposto principalmente para assinaturas digitais (como Rainbow), mas durante a rodada final do NIST, descobriu-se um método de ataque poderoso que o decifrou em alguns dias em um único PC, levando muitos algoritmos a serem retirados da padronização.&lt;/li>
&lt;li>&lt;strong>Criptografia baseada em isogenia (Isogeny-based Cryptography)&lt;/strong>:
Baseado no problema de encontrar caminhos em grafos de isogenia (Isogeny) de curvas elípticas. Com um tamanho de chave muito pequeno, era esperado que fosse o sucessor legítimo da ECC, mas seu candidato final, &amp;ldquo;SIKE&amp;rdquo;, foi completamente decifrado em poucas horas num PC normal usando matemática clássica (como o ataque de Castryck-Decru) em 2022, resultando num final dramático que simboliza a dificuldade e o terror do design de PQC.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-o-abismo-da-criptografia-baseada-em-reticulados-a-base-matemática-do-problema-lwe-e-do-module-lwe">4. O abismo da criptografia baseada em reticulados: A base matemática do problema LWE e do Module-LWE
&lt;/h2>&lt;p>Atualmente considerada a mais promissora e o centro da padronização, a &lt;strong>criptografia baseada em reticulados&lt;/strong>. Na raiz de sua segurança está o &lt;strong>Problema LWE (Learning with Errors: Aprendizado com Erros)&lt;/strong>. Proposto por Oded Regev em 2005, essa conquista inovadora lhe rendeu o Prêmio Gödel. A compreensão moderna da PQC é impossível sem entender o problema LWE.&lt;/p>
&lt;h3 id="41-o-que-é-o-problema-lwe-learning-with-errors">4.1. O que é o problema LWE (Learning with Errors)?
&lt;/h3>&lt;p>Primeiro, vamos considerar um sistema simples de equações lineares. Suponha que, sob um certo módulo $q$ (módulo $q$), temos uma matriz aleatória conhecida $A$, um vetor secreto desconhecido $\vec{s}$, e seu produto $\vec{b}$ é dado.&lt;/p>
$$ \vec{b} = A\vec{s} \pmod q $$
&lt;p>Neste caso, é fácil encontrar o desconhecido $\vec{s}$ a partir das informações públicas $A$ e $\vec{b}$. Usando o clássico &amp;ldquo;método de eliminação de Gauss&amp;rdquo;, $\vec{s}$ pode ser facilmente calculado em tempo polinomial.&lt;/p>
&lt;p>No entanto, adicionar um &amp;ldquo;pequeno erro (ruído) intencional&amp;rdquo; a esta equação aumenta drasticamente a dificuldade do problema. Este é o &lt;strong>problema LWE&lt;/strong>.&lt;/p>
&lt;p>Preparamos um vetor secreto desconhecido $\vec{s} \in \mathbb{Z}_q^n$ e uma matriz escolhida aleatoriamente $A \in \mathbb{Z}_q^{m \times n}$. Além disso, preparamos um vetor de erro $\vec{e} \in \mathbb{Z}_q^m$, escolhido de acordo com uma distribuição normal ou binomial, cujos &amp;ldquo;valores dos elementos são suficientemente pequenos&amp;rdquo;, e calculamos $\vec{b}$ da seguinte forma:&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod q $$
&lt;p>O &lt;strong>Problema LWE de Busca (Search LWE)&lt;/strong> é o problema de &amp;ldquo;encontrar a informação secreta $\vec{s}$ a partir da informação pública $(A, \vec{b})$&amp;rdquo;. Devido à existência deste erro $\vec{e}$, se você tentar métodos algébricos como a eliminação de Gauss, o erro $\vec{e}$ será amplificado como uma bola de neve durante a adição e subtração das equações, tornando-se indistinguível de valores aleatórios e, em última análise, colapsando.&lt;/p>
&lt;p>A maravilha do problema LWE é que existe uma prova teórica forte (redução) de que, a menos que haja um algoritmo quântico que possa resolver os problemas de complexidade do pior caso (Worst-case hardness) no reticulado, como o GapSVP (Problema de Decisão do Vetor Mais Curto) ou SIVP (Problema de Vetores Independentes Mais Curtos), o problema LWE também não pode ser resolvido no caso médio (Average-case). Em outras palavras, mesmo chaves criptográficas geradas aleatoriamente têm garantia de forte segurança apoiada por limites teóricos.&lt;/p>
&lt;h3 id="42-aumento-drástico-na-eficiência-através-do-ring-lwe-e-module-lwe">4.2. Aumento drástico na eficiência através do Ring-LWE e Module-LWE
&lt;/h3>&lt;p>O problema LWE normal (Standard LWE) tem uma base de segurança muito clara, mas o tamanho da matriz $A$ se torna muito grande, resultando em chaves na ordem de megabytes, tornando-o impraticável. A abordagem proposta para resolver isso foi usar anéis polinomiais (Polynomial Rings) para introduzir estrutura algébrica.&lt;/p>
&lt;p>No &lt;strong>problema Ring-LWE&lt;/strong>, em vez de simples vetores e matrizes, usamos os elementos (polinômios) de um anel polinomial $R_q$. O anel polinomial ciclotômico a seguir é comumente usado nos padrões do NIST:&lt;/p>
$$ R_q = \mathbb{Z}_q[X]/(X^n + 1) $$
&lt;p>Aqui, $n$ é uma potência de 2 (por exemplo: 256) e $q$ é um número primo apropriado. Neste anel, calculamos $b = a \cdot s + e \pmod q$ usando elementos $a, s, e \in R_q$. Como um único polinômio $a$ tem $n$ coeficientes, os dados podem ser consideravelmente compactados, e usando a &lt;strong>NTT (Transformada Teórica dos Números: Number Theoretic Transform)&lt;/strong>, que é uma versão de corpo finito da Transformada Rápida de Fourier (FFT), a multiplicação de polinômios torna-se ultrarrápida com complexidade $O(n \log n)$.&lt;/p>
&lt;p>No entanto, o Ring-LWE tinha a preocupação de que &amp;ldquo;vulnerabilidades desconhecidas poderiam existir devido à estrutura algébrica especial do anel&amp;rdquo;. Além disso, para alterar o nível de segurança (por exemplo, equivalente a AES-128, 192, 256), o próprio grau do polinômio $n$ precisava ser alterado, e com isso, toda a implementação, como o algoritmo NTT, tinha que ser reescrita, apresentando um desafio de engenharia.&lt;/p>
&lt;p>Portanto, o &lt;strong>problema Module-LWE (M-LWE)&lt;/strong> foi adotado pelos algoritmos padronizados Kyber e Dilithium. Module-LWE é um compromisso, situando-se exatamente entre o Standard LWE, sem estrutura, e o Ring-LWE, excessivamente estruturado. Ele usa uma matriz $k \times k$ (módulo) cujos elementos são componentes do anel polinomial $R_q$.&lt;/p>
$$ \vec{b} = A\vec{s} + \vec{e} \pmod{R_q} \quad (A \in R_q^{k \times k}, \vec{s}, \vec{e} \in R_q^k) $$
&lt;p>A maior vantagem do Module-LWE é que, mantendo o grau do polinômio $n$ constante ($n=256$ no padrão NIST), o nível de segurança pode ser facilmente escalado simplesmente mudando a dimensão da matriz $k$.
Por exemplo, no caso do Kyber, a dimensão $k$ é ajustada da seguinte forma:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Kyber512 (Nível 1)&lt;/strong>: $k = 2$ (equivalente a AES-128)&lt;/li>
&lt;li>&lt;strong>Kyber768 (Nível 3)&lt;/strong>: $k = 3$ (equivalente a AES-192)&lt;/li>
&lt;li>&lt;strong>Kyber1024 (Nível 5)&lt;/strong>: $k = 4$ (equivalente a AES-256)&lt;/li>
&lt;/ul>
&lt;p>Isso tornou possível reutilizar 100% do código NTT subjacente e circuitos de hardware de operações polinomiais em todos os níveis de segurança, melhorando drasticamente a segurança e a eficiência da implementação.&lt;/p>
&lt;hr>
&lt;h2 id="5-crystals-kyber-ml-kem-o-mecanismo-de-encapsulamento-de-chaves-de-próxima-geração">5. CRYSTALS-Kyber (ML-KEM): O Mecanismo de Encapsulamento de Chaves de Próxima Geração
&lt;/h2>&lt;p>O CRYSTALS-Kyber, oficialmente padronizado como &lt;strong>FIPS 203 (ML-KEM)&lt;/strong>, é um mecanismo de encapsulamento de chaves (KEM) baseado no problema Module-LWE descrito acima. No futuro, se tornará o padrão global de fato para compartilhar chaves de sessão com segurança em TLS 1.3, SSH, etc.&lt;/p>
&lt;h3 id="51-arquitetura-do-kem-key-encapsulation-mechanism">5.1. Arquitetura do KEM (Key Encapsulation Mechanism)
&lt;/h3>&lt;p>Na era da PQC, a abordagem de encapsulamento de KEM torna-se padrão, em vez da abordagem direta como no RSA, onde &amp;ldquo;o cliente cria uma chave simétrica e a criptografa com a chave pública do servidor e a envia&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Client as "Cliente (Alice)"
participant Server as "Servidor (Bob)"
Note over Client: "ML-KEM KeyGen()"
Client->>Client: "Gera a chave secreta (sk) e a chave pública (pk)"
Client->>Server: "Envia a chave pública (pk)"
Note over Server: "ML-KEM Encaps()"
Server->>Server: "Gera uma chave simétrica aleatória (K)"
Server->>Server: "Encapsula K com pk para criar o texto cifrado (c)"
Server->>Client: "Envia o texto cifrado (c)"
Note over Client: "ML-KEM Decaps()"
Client->>Client: "Descriptografa o texto cifrado (c) usando a chave secreta (sk)"
Client->>Client: "Desencapsula para extrair a chave simétrica (K)"
Note over Client, Server: "Inicia a comunicação criptografada usando a chave simétrica compartilhada (K) via AES, etc."&lt;/div>
&lt;h3 id="52-o-mecanismo-algorítmico-interno-do-kyber-e-a-transformada-de-fujisaki-okamoto">5.2. O mecanismo algorítmico interno do Kyber e a Transformada de Fujisaki-Okamoto
&lt;/h3>&lt;p>O design do Kyber é extremamente refinado. Primeiro, constrói-se um esquema de criptografia de chave pública (Kyber.CPAPKE) seguro apenas contra CPA (Ataque de Texto Simples Escolhido). Em seguida, aplicando um método criptográfico muito poderoso chamado &lt;strong>Transformada de Fujisaki-Okamoto (Fujisaki-Okamoto Transform)&lt;/strong>, ele é atualizado para um KEM completo, seguro até mesmo contra CCA (Ataque de Texto Cifrado Escolhido Adaptativo).&lt;/p>
&lt;p>Os mecanismos principais de criptografia e descriptografia do CPAPKE são os seguintes:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Geração de Chave (Key Generation)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>A partir de um valor semente aleatório, gera uma matriz $A \in R_q^{k \times k}$ no domínio NTT. O módulo $q$ usado é $3329$.&lt;/li>
&lt;li>Um vetor secreto $\vec{s}$ e um vetor de erro $\vec{e}$ com coeficientes pequenos são amostrados de uma distribuição binomial centralizada (CBD).&lt;/li>
&lt;li>Calcula $\vec{t} = A\vec{s} + \vec{e}$. A chave pública é $(A, \vec{t})$ e a chave secreta é $\vec{s}$. (Na prática, $A$ é revelado como um valor de semente para economizar largura de banda).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Criptografia (Encryption)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Uma mensagem de 32 bytes a ser compartilhada (o material para a chave simétrica) $m$ é codificada em um polinômio.&lt;/li>
&lt;li>Um novo vetor aleatório $\vec{r}$ e pequenos erros $\vec{e_1}, e_2$ são gerados.&lt;/li>
&lt;li>$\vec{u} = A^T\vec{r} + \vec{e_1}$&lt;/li>
&lt;li>$v = \vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m$&lt;/li>
&lt;li>O texto cifrado é $(\vec{u}, v)$.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Descriptografia (Decryption)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>O receptor calcula $v - \vec{s}^T\vec{u}$.&lt;/li>
&lt;li>Expandindo esta fórmula, obtemos o seguinte:
$v - \vec{s}^T\vec{u} = (\vec{t}^T\vec{r} + e_2 + \lfloor q/2 \rceil \cdot m) - \vec{s}^T(A^T\vec{r} + \vec{e_1})$&lt;/li>
&lt;li>Substituindo $\vec{t} = A\vec{s} + \vec{e}$ aqui, o termo principal $\vec{s}^TA^T\vec{r}$ se cancela.&lt;/li>
&lt;li>O que resta é $\lfloor q/2 \rceil \cdot m + (\vec{e}^T\vec{r} + e_2 - \vec{s}^T\vec{e_1})$.&lt;/li>
&lt;li>O termo entre parênteses é &amp;ldquo;o produto ou soma de pequenos erros&amp;rdquo;, então permanece um valor pequeno (ruído) como um todo. Portanto, julgando pelos limites se cada coeficiente está perto de $0$ ou de $q/2$, os bits (0 ou 1) da mensagem original $m$ podem ser perfeitamente restaurados sem erros.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>A maior força do Kyber é sua impressionante &lt;strong>velocidade de processamento&lt;/strong> e &lt;strong>tamanho de chave moderado&lt;/strong>. Para o Kyber768, o tamanho da chave pública é de 1.184 bytes e o tamanho do texto cifrado é de 1.088 bytes. Embora sejam maiores em comparação com o RSA-3072 (tamanho da chave em torno de 384 bytes), eles podem caber dentro do MTU (Maximum Transmission Unit) das comunicações modernas da internet sem fragmentação de pacotes, tendo um efeito adverso quase nulo na latência da rede.&lt;/p>
&lt;hr>
&lt;h2 id="6-crystals-dilithium-ml-dsa-assinatura-digital-de-uso-geral-baseada-em-reticulado">6. CRYSTALS-Dilithium (ML-DSA): Assinatura digital de uso geral baseada em reticulado
&lt;/h2>&lt;p>Na padronização de assinaturas digitais, algoritmos com diferentes filosofias de design competiram mesmo na mesma abordagem de criptografia baseada em reticulado. Dentre eles, &lt;strong>CRYSTALS-Dilithium&lt;/strong> foi selecionado como &lt;strong>FIPS 204 (ML-DSA)&lt;/strong> para ser a assinatura digital de uso geral.&lt;/p>
&lt;h3 id="61-paradigma-fiat-shamir-com-abortos">6.1. Paradigma Fiat-Shamir com Abortos
&lt;/h3>&lt;p>Como o Kyber, Dilithium é um esquema de assinatura digital baseado no problema Module-LWE (e no problema Module-SIS). O design é baseado no paradigma extremamente importante chamado &amp;ldquo;&lt;strong>Fiat-Shamir with Aborts (Transformada de Fiat-Shamir com Interrupções)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>A transformada Fiat-Shamir em si é um método padrão para converter um protocolo de prova de conhecimento zero interativo em uma assinatura digital não interativa. O provador (assinante) gera um compromisso $y$, calcula $w = Ay$, passa-o por uma função de hash para obter um desafio aleatório $c$ e calcula a resposta $z = y + cs$.&lt;/p>
&lt;p>No entanto, quando isso é aplicado de forma simples à criptografia baseada em reticulado, a distribuição da resposta $z$ torna-se enviesada dependendo do valor da chave secreta $s$, levando a um problema fatal (vazamento matemático do tipo canal lateral) em que as informações da chave secreta $s$ vazam gradualmente para um invasor que observa um grande número de assinaturas.&lt;/p>
&lt;p>A equipe de design do Dilithium (Lyubashevsky et al.) introduziu um método chamado &amp;ldquo;&lt;strong>Rejection Sampling (Amostragem de Rejeição)&lt;/strong>&amp;rdquo;: se os coeficientes do resultado do cálculo da assinatura $z$ não se enquadrarem em um intervalo de limite de segurança predefinido, todo o processo de assinatura é abortado, e os cálculos são reiniciados desde o início usando um novo número aleatório $y$.&lt;/p>
&lt;p>Como resultado, a assinatura final $z$ tem uma distribuição perfeitamente uniforme, completamente independente da chave secreta, evitando totalmente qualquer vazamento matemático de informações.&lt;/p>
&lt;h3 id="62-vantagens-e-facilidade-de-implementação-do-dilithium">6.2. Vantagens e facilidade de implementação do Dilithium
&lt;/h3>&lt;p>Uma grande vantagem de design do Dilithium é que ele &lt;strong>não usa de forma alguma&lt;/strong> &amp;ldquo;amostragem de distribuição gaussiana&amp;rdquo; ou &amp;ldquo;operações de ponto flutuante&amp;rdquo; complexas no processo de geração de assinatura. Como pode ser implementado apenas com amostragem de distribuição uniforme, aritmética modular de inteiros simples, NTT e funções de hash (SHAKE), é fácil de implementar de forma segura e com tempo constante (Constant-time) em uma ampla variedade de ambientes, de microcontroladores embarcados a servidores em nuvem. Isso lhe dá uma forte resistência contra ataques físicos de canal lateral, como ataques de tempo.&lt;/p>
&lt;hr>
&lt;h2 id="7-falcon-fn-dsa-assinatura-de-reticulado-extremamente-compacta">7. FALCON (FN-DSA): Assinatura de reticulado extremamente compacta
&lt;/h2>&lt;p>O NIST selecionou &lt;strong>FALCON (Fast-Fourier Lattice-based Compact Signatures over NTRU)&lt;/strong>, outra assinatura baseada em reticulado com características diferentes do Dilithium, como um candidato de padronização (atualmente em elaboração como FN-DSA).&lt;/p>
&lt;h3 id="71-reticulado-ntru-e-amostragem-gaussiana">7.1. Reticulado NTRU e Amostragem Gaussiana
&lt;/h3>&lt;p>A maior característica do FALCON é que ele usa &lt;strong>reticulados NTRU (N-th degree Truncated polynomial Ring Units)&lt;/strong>, com uma longa história que remonta a 1996, em vez do problema LWE. Além disso, adota o paradigma &amp;ldquo;&lt;strong>Hash-and-Sign (Fazer hash e assinar)&lt;/strong>&amp;rdquo; baseado na estrutura GPV (Gentry-Peikert-Vaikuntanathan).&lt;/p>
&lt;p>No Hash-and-Sign, o valor do hash da mensagem é o ponto alvo no espaço, e o ponto no reticulado mais próximo desse ponto (a solução aproximada para o Problema do Vetor Mais Próximo) torna-se a assinatura. Isso requer a amostragem de pontos de acordo com uma distribuição gaussiana discreta, usando uma &amp;ldquo;base curta e de boa qualidade&amp;rdquo; que é a chave secreta.&lt;/p>
&lt;p>O FALCON acelerou drasticamente esse cálculo pesado usando uma técnica chamada &amp;ldquo;&lt;strong>Ortogonalização Rápida de Fourier (Fast Fourier Orthogonalization: FFO)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;h3 id="72-vantagens-e-desvantagens-do-falcon">7.2. Vantagens e Desvantagens do FALCON
&lt;/h3>&lt;p>A vantagem esmagadora do FALCON é que &lt;strong>o tamanho da assinatura e da chave pública são extremamente pequenos (compactos)&lt;/strong>. Enquanto o tamanho da assinatura do Dilithium3 é de cerca de 3.309 bytes, o tamanho da assinatura do FALCON-512 é de apenas cerca de 666 bytes. A chave pública também é bem pequena, 897 bytes, tornando-se uma salvação em ambientes com limitações severas de largura de banda, dispositivos IoT e determinados protocolos de rede.&lt;/p>
&lt;p>No entanto, há uma desvantagem significativa. Como a amostragem gaussiana discreta, que requer cálculos complexos de &lt;strong>ponto flutuante (64 bits IEEE 754)&lt;/strong>, é obrigatória na geração de assinaturas, é extremamente difícil conseguir uma implementação em tempo constante para evitar o vazamento de tempo, e o código se torna massivo. Devido a isso, o FALCON é posicionado como um algoritmo altamente especializado para aplicações específicas, ao invés de uso geral (como o Dilithium).&lt;/p>
&lt;div class="mermaid">graph LR
A["Requisitos de assinatura digital"] --> B{"Qual é a restrição prioritária?"}
B -->|"Simplicidade de implementação, uso geral, facilidade de tempo constante"| C["Dilithium (ML-DSA)"]
B -->|"Minimizar largura de banda, compactação do tamanho de dados"| D["FALCON (FN-DSA)"]
C --> E["Certificados TLS de uso geral, assinatura digital de software"]
D --> F["Protocolos com limitações rigorosas de tamanho de pacote, ambientes especiais"]&lt;/div>
&lt;hr>
&lt;h2 id="8-sphincs-slh-dsa-assinatura-baseada-em-hash-que-ostenta-a-maior-segurança">8. SPHINCS+ (SLH-DSA): Assinatura baseada em hash que ostenta a maior segurança
&lt;/h2>&lt;p>Em preparação para o pior cenário, onde a segurança da criptografia baseada em reticulados seja no futuro quebrada por avanços de matemáticos geniais, o NIST estabeleceu o &lt;strong>FIPS 205 (SLH-DSA)&lt;/strong>, ou seja, &lt;strong>SPHINCS+&lt;/strong>, como padrão, possuindo uma abordagem completamente diferente da criptografia de reticulado.&lt;/p>
&lt;p>O SPHINCS+ é classificado como uma &lt;strong>assinatura baseada em hash&lt;/strong>. O fundamento para sua segurança depende de um único ponto: &amp;ldquo;a função hash criptográfica usada (como SHA-2 ou SHAKE256) tem resistência a colisões e unidirecionalidade&amp;rdquo;. Como não depende de problemas matemáticos com uma estrutura algébrica específica, como LWE ou fatoração, ele possui uma segurança extremamente robusta (a segurança mais conservadora): não importa quão poderosos os algoritmos quânticos se tornem no futuro, isso pode ser contra-atacado simplesmente estendendo o comprimento da saída da função hash.&lt;/p>
&lt;h3 id="81-arquitetura-stateless-com-wots-e-fors">8.1. Arquitetura Stateless com WOTS+ e FORS
&lt;/h3>&lt;p>O histórico das assinaturas baseadas em hash é antigo, remontando à Assinatura Lamport e à Assinatura de Uso Único de Winternitz (WOTS) da década de 1970. Eram chaves descartáveis que &amp;ldquo;podiam ser usadas para assinar com segurança apenas uma vez&amp;rdquo;. Para permitir o uso múltiplo, algoritmos como XMSS (eXtended Merkle Signature Scheme) e LMS foram desenvolvidos, combinando a Árvore de Merkle para gerenciar um número infinito de chaves descartáveis com um único hash raiz.&lt;/p>
&lt;p>No entanto, XMSS e LMS tinham uma falha grave: eram &amp;ldquo;&lt;strong>Stateful (com retenção de estado)&lt;/strong>&amp;rdquo;. Exigia-se gravar o estado do índice de &amp;ldquo;qual chave descartável foi usada&amp;rdquo; na memória não-volátil rigorosamente a cada assinatura. Se, por exemplo, ao restaurar um snapshot de uma máquina virtual, o estado retrocedesse e a mesma chave fosse usada duas vezes, a chave secreta vazaria instantaneamente e o sistema entraria em colapso.&lt;/p>
&lt;p>O SPHINCS+ é uma assinatura baseada em hash &amp;ldquo;&lt;strong>Stateless (sem retenção de estado)&lt;/strong>&amp;rdquo; que resolve essa complexidade do gerenciamento de estado.
A tecnologia principal é a seguinte combinação:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>WOTS+ (Winternitz One-Time Signature Plus)&lt;/strong>: Uma assinatura básica de uso único.&lt;/li>
&lt;li>&lt;strong>FORS (Forest of Random Subsets)&lt;/strong>: Tecnologia de Assinatura de Poucas Vezes (Few-Time Signature). A segurança é mantida mesmo se a mesma chave for reutilizada algumas vezes.&lt;/li>
&lt;li>&lt;strong>Hyper-Tree (Estrutura de árvore gigante)&lt;/strong>: Uma estrutura massiva com Árvores de Merkle sobrepostas em múltiplas camadas.&lt;/li>
&lt;/ol>
&lt;p>Na execução da assinatura, em vez de gerenciar o estado, o SPHINCS+ seleciona aleatoriamente usando números pseudoaleatórios uma das enormes quantidades de chaves FORS na base da Hyper-Tree e assina com ela. Como o número de folhas da árvore é astronomicamente grande, a probabilidade de escolher a mesma chave duas vezes por acaso (colisão) é baixa o suficiente para ser ignorada, realizando assim a propriedade stateless.&lt;/p>
&lt;p>A única e maior fraqueza do SPHINCS+ é o &lt;strong>tamanho gigantesco de suas assinaturas&lt;/strong>. Dependendo dos parâmetros, o tamanho pode variar de 17 kilobytes a 49 kilobytes, e a velocidade de geração de assinatura é esmagadoramente mais lenta em comparação com a criptografia de reticulado. Assim, o SPHINCS+ se destina a usos onde as assinaturas não são muito frequentes e a segurança absoluta de longo prazo é fortemente exigida, como assinatura para atualizações de software ou certificados de Autoridade de Certificação (CA) Raiz, ao invés da navegação web do dia-a-dia.&lt;/p>
&lt;hr>
&lt;h2 id="9-criptografia-baseada-em-código-o-bom-e-velho-gigante-classic-mceliece">9. Criptografia baseada em código: O bom e velho gigante Classic McEliece
&lt;/h2>&lt;p>Uma abordagem importante que ainda está sendo avaliada como candidato final da Rodada 4 no processo de padronização do NIST é o &lt;strong>Classic McEliece&lt;/strong>, uma &lt;strong>criptografia baseada em código&lt;/strong>.&lt;/p>
&lt;p>Proposto em 1978 por Robert McEliece, este algoritmo, juntamente com o RSA, é um dos mais antigos na história da criptografia de chave pública. Utiliza &amp;ldquo;Códigos de Goppa&amp;rdquo;, um código geométrico algébrico. Baseia-se no &amp;ldquo;&lt;strong>Problema de Decodificação de Síndrome (Syndrome Decoding Problem)&lt;/strong>&amp;rdquo;, em que a mensagem é criptografada adicionando um erro intencional (vetor de ruído), e apenas aquele com a matriz de verificação de paridade do código de Goppa como chave secreta pode usar recursos poderosos de correção de erros para remover o ruído e recuperar a mensagem original.&lt;/p>
$$ \vec{c} = \vec{m} G + \vec{e} $$
&lt;p>
(Onde $G$ é a matriz geradora codificada (scrambled) atuando como chave pública, e $\vec{e}$ é o vetor de erro com peso $t$)&lt;/p>
&lt;p>O que é mais incrível no Classic McEliece é o seu retrospecto avassalador: &lt;strong>apesar de mais de 40 anos desde a sua proposta, e sujeito a intensas pesquisas de criptoanálise em todo o mundo, nenhuma vulnerabilidade fundamental foi descoberta&lt;/strong>. Ele tem a &amp;ldquo;segurança robusta mais bem comprovada pelo tempo&amp;rdquo; na PQC.&lt;/p>
&lt;p>Além disso, tem a vantagem de um tamanho de texto cifrado extremamente pequeno (apenas cerca de 100 a 200 bytes). No entanto, há a desvantagem fatal de que &lt;strong>o tamanho da chave pública chega à ordem de megabytes (MB)&lt;/strong>. Mesmo no nível de segurança mais baixo (equivalente ao AES-128), a chave pública é de cerca de 250 KB e excede 1 MB nos níveis mais altos.&lt;/p>
&lt;p>Portanto, não é aplicável em cenários onde a chave pública é transmitida pela rede em toda comunicação, como no handshake TLS. No entanto, em casos de uso especiais onde a chave pública pode ser pré-implantada no sistema (hardcoded), como na troca de chaves pré-compartilhadas em VPNs, chaves públicas no firmware ou comunicações por satélite, continua a ser investigada como uma escolha extremamente promissora devido à sua sólida segurança.&lt;/p>
&lt;hr>
&lt;h2 id="10-comparação-de-desempenho-de-cada-algoritmo-pqc-e-trade-offs">10. Comparação de desempenho de cada algoritmo PQC e trade-offs
&lt;/h2>&lt;p>Aqui está um resumo das características de desempenho nos níveis comuns de segurança (níveis 2 a 3 do NIST, equivalentes ao AES-128 a 192) para os principais algoritmos explicados até agora.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">Algoritmo (Nome padrão)&lt;/th>
&lt;th style="text-align:left">Categoria&lt;/th>
&lt;th style="text-align:left">Base Matemática&lt;/th>
&lt;th style="text-align:left">Tamanho da chave pública&lt;/th>
&lt;th style="text-align:left">Tamanho da chave secreta&lt;/th>
&lt;th style="text-align:left">Tamanho texto cifrado/assin.&lt;/th>
&lt;th style="text-align:left">Tendência da vel. de processamento&lt;/th>
&lt;th style="text-align:left">Principais características e usos&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Kyber768&lt;/strong>&lt;br>(ML-KEM)&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1.184 Bytes&lt;/td>
&lt;td style="text-align:left">2.400 Bytes&lt;/td>
&lt;td style="text-align:left">1.088 Bytes&lt;/td>
&lt;td style="text-align:left">Muito rápida&lt;/td>
&lt;td style="text-align:left">Melhor equilíbrio de tamanho e velocidade. Padrão genérico de KEM para TLS 1.3, etc.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Dilithium3&lt;/strong>&lt;br>(ML-DSA)&lt;/td>
&lt;td style="text-align:left">Assinatura&lt;/td>
&lt;td style="text-align:left">Module-LWE&lt;/td>
&lt;td style="text-align:left">1.952 Bytes&lt;/td>
&lt;td style="text-align:left">4.032 Bytes&lt;/td>
&lt;td style="text-align:left">3.309 Bytes&lt;/td>
&lt;td style="text-align:left">Geração e verificação rápidas&lt;/td>
&lt;td style="text-align:left">Implementação simples. Padrão genérico de assinatura digital.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>FALCON-512&lt;/strong>&lt;br>(FN-DSA)&lt;/td>
&lt;td style="text-align:left">Assinatura&lt;/td>
&lt;td style="text-align:left">Reticulado NTRU&lt;/td>
&lt;td style="text-align:left">897 Bytes&lt;/td>
&lt;td style="text-align:left">1.281 Bytes&lt;/td>
&lt;td style="text-align:left">666 Bytes&lt;/td>
&lt;td style="text-align:left">Geração de assin. um pouco lenta, verificação ultrarrápida&lt;/td>
&lt;td style="text-align:left">Tamanho de assinatura mínimo. Porém, exige ponto flutuante. Focado em sistemas embarcados/IoT.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>SPHINCS+&lt;/strong>&lt;br>(SLH-DSA)&lt;/td>
&lt;td style="text-align:left">Assinatura&lt;/td>
&lt;td style="text-align:left">Função Hash&lt;/td>
&lt;td style="text-align:left">32 Bytes&lt;/td>
&lt;td style="text-align:left">64 Bytes&lt;/td>
&lt;td style="text-align:left">Aprox. 17.000 Bytes&lt;/td>
&lt;td style="text-align:left">Geração muito lenta&lt;/td>
&lt;td style="text-align:left">Risco quase nulo de colapso matemático. Uso para alta segurança como certificados raiz.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Classic McEliece&lt;/strong>&lt;/td>
&lt;td style="text-align:left">KEM&lt;/td>
&lt;td style="text-align:left">Código Goppa&lt;/td>
&lt;td style="text-align:left">&lt;strong>Aprox. 1,04 MB&lt;/strong>&lt;/td>
&lt;td style="text-align:left">13.568 Bytes&lt;/td>
&lt;td style="text-align:left">&lt;strong>188 Bytes&lt;/strong>&lt;/td>
&lt;td style="text-align:left">Encapsulamento rápido&lt;/td>
&lt;td style="text-align:left">40 anos de histórico de segurança. Chave pública imensa. Para ambientes com hardcode.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="compreendendo-os-trade-offs">Compreendendo os trade-offs
&lt;/h3>&lt;p>No mundo PQC, não existe um único algoritmo mágico que seja &amp;ldquo;pequeno em tamanho, rápido em velocidade e com garantia matemática perfeita&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Padrões da Internet (Kyber / Dilithium)&lt;/strong>: Possuem o melhor equilíbrio de desempenho, e são os mais adequados para um substituto direto (drop-in replacement) dos atuais RSA/ECC.&lt;/li>
&lt;li>&lt;strong>Conservadorismo Final (SPHINCS+)&lt;/strong>: Selecionado quando você deseja uma garantia absoluta (seguro) contra avanços matemáticos futuros, mesmo com o sacrifício do tamanho dos dados e da velocidade de processamento.&lt;/li>
&lt;li>&lt;strong>Para ambientes especiais (FALCON / Classic McEliece)&lt;/strong>: Armas de especialização escolhidas com base nas restrições do ambiente, como quando a largura de banda de comunicação é extremamente restrita ou quando a pré-distribuição é possível.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-desafios-de-implementação-prática-e-a-solução-realística-da-criptografia-híbrida">11. Desafios de implementação prática e a solução realística da &amp;ldquo;Criptografia Híbrida&amp;rdquo;
&lt;/h2>&lt;p>Com a conclusão da padronização pelo NIST e a emissão oficial do FIPS, a transição PQC das infraestruturas de TI mundiais (&lt;strong>migração PQC&lt;/strong>) começou a sério. O navegador Chrome do Google, o iMessage da Apple (Protocolo PQ3), provedores de rede como Cloudflare, entre outros, já integraram o suporte PQC em seus protocolos e iniciaram operações reais.&lt;/p>
&lt;p>Porém, existe um risco muito elevado em realizar uma transição completa e imediata para novos algoritmos de criptografia. Se, por exemplo, um matemático genial descobrir uma falha fatal de ataque (uma vulnerabilidade matemática decifrável até mesmo em um computador clássico) na criptografia de reticulado como o Kyber nos próximos anos, todo o sistema que depende dele será exposto instantaneamente.&lt;/p>
&lt;p>Uma abordagem realística e recomendada para mitigar este risco de incerteza é a &amp;ldquo;&lt;strong>Criptografia Híbrida (Hybrid Cryptography)&lt;/strong>&amp;rdquo;.&lt;/p>
&lt;p>Na criptografia híbrida, você usa simultaneamente a criptografia clássica com longo histórico de confiabilidade (por exemplo: criptografia de curva elíptica como X25519) e o novo PQC (por exemplo: Kyber768) para realizar a troca de chaves. Os componentes de chaves comuns são gerados de forma independente por cada algoritmo e, finalmente, as duas partes são combinadas por meio de uma Função de Derivação de Chave (KDF) segura para gerar o segredo mestre final.&lt;/p>
&lt;div class="mermaid">graph TD
A["Cliente"] -->|① Envia chave pública X25519 + chave pública Kyber| B["Servidor"]
B -->|② Retorna chave compartilhada X25519 + texto cifrado encapsulado Kyber| A
A --> C{"Derivação do Segredo Mestre (KDF)"}
B --> C
C -->|Entrada: (chave comum X25519) || (chave comum Kyber)| D["Chave de comunicação segura (AES-256 / ChaCha20)"]
D -->|"Resistente às ameaças quânticas e às vulnerabilidades clássicas"| E["Comunicação segura por criptografia híbrida (TLS 1.3)"]&lt;/div>
&lt;p>Isso realiza uma postura de segurança robusta de dois níveis: &amp;ldquo;Mesmo que um computador quântico seja construído e a ECC seja quebrada, o Kyber protegerá a comunicação&amp;rdquo;, e inversamente, &amp;ldquo;Mesmo que uma falha matemática desconhecida seja descoberta no Kyber, a ECC protegerá a comunicação&amp;rdquo;. Como exemplo representativo, existe o rascunho &lt;strong>X25519MLKEM768 (antigo X25519Kyber768)&lt;/strong> sendo padronizado na IETF, e a comunicação entre os navegadores Web atuais e servidores de ponta já é realizada usando exatamente esse método híbrido.&lt;/p>
&lt;p>Além disso, na concepção do sistema, o conceito de &amp;ldquo;&lt;strong>Crypto Agility (Agilidade Criptográfica)&lt;/strong>&amp;rdquo; – a arquitetura que permite não depender excessivamente de um algoritmo de criptografia específico e de poder mudar rapidamente para outro algoritmo (por exemplo, de Kyber para McEliece, de Dilithium para SPHINCS+) se um algoritmo for quebrado – se tornará um requisito indispensável para o desenvolvimento de sistemas no futuro.&lt;/p>
&lt;hr>
&lt;h2 id="12-conclusão-uma-nova-fronteira-tecnológica-criptográfica">12. Conclusão: Uma Nova Fronteira Tecnológica Criptográfica
&lt;/h2>&lt;p>Ironia do destino, o computador quântico, uma tecnologia dos sonhos da humanidade, tornou-se a maior ameaça a romper as paredes defensivas matemáticas, a &amp;ldquo;fatoração&amp;rdquo; e o &amp;ldquo;problema do logaritmo discreto&amp;rdquo;, nas quais confiamos por muitos anos. No entanto, criptógrafos de todo o mundo, sem se renderem, abriram domínios matemáticos multidimensionais muito mais profundos e complexos baseados em teorias de reticulados, árvores de funções hash e códigos de correção de erros, construindo novas muralhas defensivas conhecidas como Criptografia Pós-Quântica (PQC).&lt;/p>
&lt;p>O término da padronização de FIPS 203 (ML-KEM), FIPS 204 (ML-DSA) e FIPS 205 (SLH-DSA) pelo NIST não é a linha de chegada. É apenas o primeiro passo na épica jornada de migração para PQC que durará décadas. Para engenheiros de software e arquitetos de sistemas, o grande desafio tecnológico será como adaptar de forma otimizada os protocolos de rede e os sistemas para o &amp;ldquo;aumento no tamanho da chave&amp;rdquo; e &amp;ldquo;mudanças nos custos de computação&amp;rdquo; que esses novos algoritmos trazem.&lt;/p>
&lt;p>O conflito entre os computadores quânticos e a criptografia é a área emocionante onde a exploração matemática e a evolução da tecnologia da humanidade se cruzam da forma mais intensa. Esperamos que através deste artigo, você tenha conseguido compreender profundamente as belas teorias matemáticas por trás da PQC e os mecanismos surpreendentes de cada algoritmo que moldará o futuro da cibersegurança.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Referências:&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;em>Programa de Padronização de Criptografia Pós-Quântica do NIST&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 203: Padrão para Mecanismo de Encapsulamento de Chaves Baseado em Módulo de Reticulado&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 204: Padrão para Assinaturas Digitais Baseado em Módulo de Reticulado&lt;/em>&lt;/li>
&lt;li>&lt;em>FIPS 205: Padrão para Assinaturas Digitais Stateless Baseadas em Hash&lt;/em>&lt;/li>
&lt;/ul></description></item></channel></rss>