<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Math on kenji.blog</title><link>http://kenji.blog/pt/tags/math/</link><description>Recent content in Math 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/tags/math/index.xml" rel="self" type="application/rss+xml"/><item><title>【Para Iniciantes】Desvendando a Estrutura Matemática do Modelo Transformer</title><link>http://kenji.blog/pt/p/transformer-mathematical-structure/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/transformer-mathematical-structure/</guid><description>&lt;img src="http://kenji.blog/p/transformer-mathematical-structure/img/eyecatch.jpg" alt="Featured image of post 【Para Iniciantes】Desvendando a Estrutura Matemática do Modelo Transformer" />&lt;h1 id="introdução-por-que-aprender-a-matemática-do-transformer">Introdução: Por que aprender a matemática do Transformer?
&lt;/h1>&lt;p>Não é exagero dizer que a arquitetura &amp;ldquo;Transformer&amp;rdquo; reescreveu a história do Processamento de Linguagem Natural (NLP) e da IA moderna como um todo. Proposto pela primeira vez no artigo &amp;ldquo;Attention Is All You Need&amp;rdquo;, publicado por pesquisadores do Google em 2017, este modelo atua como o coração dos Grandes Modelos de Linguagem (LLMs) que dominam o mundo hoje, como a série GPT da OpenAI (a tecnologia base do ChatGPT), o BERT do Google e o Claude da Anthropic.&lt;/p>
&lt;p>No entanto, embora vejamos frequentemente explicações qualitativas sobre o funcionamento do Transformer, como &amp;ldquo;usar Attention (mecanismo de atenção) para entender o contexto&amp;rdquo;, a realidade é que existem surpreendentemente poucas explicações aprofundadas para iniciantes sobre a &lt;strong>estrutura matemática&lt;/strong> por trás disso. Para realmente entender como a IA processa &amp;ldquo;palavras&amp;rdquo; como &amp;ldquo;fórmulas matemáticas&amp;rdquo; e gera textos incrivelmente naturais, é essencial desvendar seus mecanismos matemáticos.&lt;/p>
&lt;p>Neste artigo, direcionado a pessoas com conhecimento básico em matemática e programação (que compreendem conceitos de matrizes e derivadas em nível de ensino médio), explicaremos de forma completa e acessível as estruturas matemáticas que formam o núcleo do Transformer: o mecanismo de &amp;ldquo;Self-Attention&amp;rdquo;, o modelo &amp;ldquo;Query, Key, Value (Q/K/V)&amp;rdquo;, a &amp;ldquo;Normalização com a função Softmax&amp;rdquo; e o &amp;ldquo;Positional Encoding&amp;rdquo;.&lt;/p>
&lt;p>Você pode se sentir sobrecarregado pela sucessão de fórmulas, mas cada cálculo tem um &amp;ldquo;significado&amp;rdquo; claro. Quando terminar de ler este artigo, você deverá compreender que o Transformer não é apenas uma caixa preta mágica, mas uma cristalização de matemática e estatística meticulosamente projetada.&lt;/p>
&lt;hr>
&lt;h1 id="1-limitações-dos-métodos-tradicionais-e-a-inovação-do-transformer">1. Limitações dos métodos tradicionais e a inovação do Transformer
&lt;/h1>&lt;p>Antes do surgimento do Transformer, a corrente principal do processamento de linguagem natural eram as Redes Neurais Recorrentes (RNN) e sua derivação, o LSTM (Long Short-Term Memory). As RNNs são projetadas para processar dados de séries temporais, lendo o texto sequencialmente, palavra por palavra, a partir do início.&lt;/p>
&lt;p>No entanto, as RNNs tinham duas fraquezas fatais:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Dificuldade em aprender dependências de longo prazo&lt;/strong>: À medida que a frase se torna mais longa, as informações das palavras inseridas no início desaparecem quando chegam ao fim (problema do desaparecimento do gradiente).&lt;/li>
&lt;li>&lt;strong>Impossibilidade de computação paralela&lt;/strong>: Como as palavras devem ser processadas sequencialmente, a computação paralela em larga escala usando GPUs é difícil, e o treinamento exige uma quantidade enorme de tempo.&lt;/li>
&lt;/ol>
&lt;p>O Transformer causou uma mudança de paradigma ao abandonar completamente a estrutura da RNN e usar apenas a &amp;ldquo;Attention&amp;rdquo; para capturar o contexto. Isso tornou possível processar sequências de qualquer tamanho sem perda de informação e, ao mesmo tempo, paralelizar os cálculos para maximizar o desempenho das GPUs.&lt;/p>
&lt;hr>
&lt;h1 id="2-arquitetura-geral-do-transformer">2. Arquitetura geral do Transformer
&lt;/h1>&lt;p>Primeiro, vamos dar uma visão geral da arquitetura do Transformer. O Transformer é amplamente dividido em dois blocos: &amp;ldquo;Encoder&amp;rdquo; (Codificador) e &amp;ldquo;Decoder&amp;rdquo; (Decodificador). Tomando uma tarefa de tradução como exemplo, o Encoder converte o idioma de entrada (ex.: inglês) em uma representação vetorial matemática, e o Decoder usa essa representação vetorial para gerar o idioma de saída (ex.: japonês).&lt;/p>
&lt;p>O diagrama abaixo é uma versão simplificada da estrutura interna do bloco Encoder.&lt;/p>
&lt;div class="mermaid">graph TD
A["Tokens de Entrada"] --> B["Input Embedding"]
B --> C["Positional Encoding"]
C --> D["Multi-Head Self-Attention"]
D --> E["Add &amp; Layer Normalization"]
E --> F["Feed Forward Network"]
F --> G["Add &amp; Layer Normalization"]
G --> H["Saída para a Próxima Camada"]
C -.->|"Conexão Residual"| E
E -.->|"Conexão Residual"| G&lt;/div>
&lt;p>A partir daqui, vamos analisar passo a passo as operações matemáticas que ocorrem em cada componente.&lt;/p>
&lt;hr>
&lt;h1 id="3-vetorização-de-palavras-e-positional-encoding-codificação-posicional">3. Vetorização de palavras e Positional Encoding (Codificação Posicional)
&lt;/h1>&lt;p>Os computadores não podem entender o texto como ele é. O texto de entrada é primeiro dividido em unidades chamadas &amp;ldquo;Tokens&amp;rdquo;, e cada um é convertido em um vetor de comprimento fixo. Este é o &lt;strong>Input Embedding&lt;/strong>.&lt;/p>
&lt;h2 id="31-a-matemática-do-input-embedding">3.1 A matemática do Input Embedding
&lt;/h2>&lt;p>Seja $V$ o tamanho do vocabulário e $d_{model}$ a dimensão do vetor de embedding (no artigo original, $d_{model} = 512$). Cada palavra $w_i$ é convertida em um vetor $x_i \in \mathbb{R}^{d_{model}}$ usando a matriz de embedding $W_E \in \mathbb{R}^{V \times d_{model}}$.&lt;/p>
$$ x_i = W_E \cdot \text{one\_hot}(w_i) $$
&lt;p>Desta forma, o texto inteiro é representado como uma matriz $X \in \mathbb{R}^{N \times d_{model}}$ (onde $N$ é o comprimento da frase).&lt;/p>
&lt;h2 id="32-a-necessidade-e-as-fórmulas-do-positional-encoding">3.2 A necessidade e as fórmulas do Positional Encoding
&lt;/h2>&lt;p>O Transformer não processa palavras sequencialmente como uma RNN, mas processa todas as palavras simultaneamente em paralelo. Esta é uma grande vantagem em termos de velocidade de cálculo, mas ao mesmo tempo causa o problema de &lt;strong>perda da informação crucial sobre a &amp;ldquo;ordem das palavras&amp;rdquo;&lt;/strong>. Por exemplo, &amp;ldquo;o cachorro morde o homem&amp;rdquo; e &amp;ldquo;o homem morde o cachorro&amp;rdquo; têm o mesmo conjunto de palavras de entrada, mas os significados são completamente diferentes.&lt;/p>
&lt;p>O que foi idealizado para fornecer essa informação sobre a ordem das palavras ao modelo é o &lt;strong>Positional Encoding&lt;/strong>.
O Positional Encoding $PE$ para a $i$-ésima dimensão de uma palavra na posição $pos$ é calculado usando as seguintes funções trigonométricas:&lt;/p>
$$ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
$$ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
&lt;p>Aqui, $pos$ é a posição da palavra ($0, 1, 2, \dots, N-1$) e $i$ é o índice da dimensão do vetor ($0, 1, \dots, d_{model}/2 - 1$).&lt;/p>
&lt;h3 id="por-que-usar-seno-e-cosseno">Por que usar seno e cosseno?
&lt;/h3>&lt;p>À primeira vista, parecem fórmulas muito complexas e estranhas, mas há uma razão matemática profunda para isso. Ao usar funções trigonométricas, o modelo pode aprender facilmente &lt;strong>não apenas a &amp;ldquo;posição absoluta&amp;rdquo;, mas também a diferença na &amp;ldquo;posição relativa&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Lembre-se do teorema de adição para funções trigonométricas aprendido na matemática do ensino médio:
&lt;/p>
$$ \sin(\alpha + \beta) = \sin\alpha \cos\beta + \cos\alpha \sin\beta $$
$$ \cos(\alpha + \beta) = \cos\alpha \cos\beta - \sin\alpha \sin\beta $$
&lt;p>O Positional Encoding de uma posição $pos + k$ deslocada por um offset $k$ a partir de uma certa posição $pos$ pode ser expresso como uma combinação linear do Positional Encoding da posição $pos$. Em outras palavras, pode ser escrito da seguinte forma usando uma matriz $M_k$:&lt;/p>
$$ PE_{pos+k} = M_k \cdot PE_{pos} $$
&lt;p>Com isso, o mecanismo de Attention pode reconhecer facilmente a distância relativa, ou seja, &amp;ldquo;o quão distantes&amp;rdquo; as palavras estão umas das outras, através do cálculo do produto escalar. Além disso, ao combinar múltiplas ondas de seno e cosseno com comprimentos de onda diferentes, há a vantagem de poder gerar vetores de posição únicos, não importa quão longa seja a frase.&lt;/p>
&lt;p>A matriz de entrada final $X_{input}$ é a soma dos vetores de embedding das palavras e deste Positional Encoding.&lt;/p>
$$ X_{input} = X + PE $$
&lt;hr>
&lt;h1 id="4-a-profunda-matemática-do-self-attention-mecanismo-de-auto-atenção">4. A profunda matemática do Self-Attention (Mecanismo de Auto-Atenção)
&lt;/h1>&lt;p>Agora vamos entrar no componente mais importante do Transformer: o &lt;strong>Self-Attention&lt;/strong>. O objetivo do Self-Attention é &amp;ldquo;calcular o grau de relacionamento entre todas as palavras na frase e atualizar o vetor de cada palavra para uma representação mais rica que leve em conta o contexto&amp;rdquo;.&lt;/p>
&lt;p>Aqui, usamos a analogia de um &amp;ldquo;sistema de busca&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Query (Q)&lt;/strong>: Consulta (termo de busca). &amp;ldquo;Qual informação estou procurando agora?&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>Key (K)&lt;/strong>: Chave (título). &amp;ldquo;Quais informações eu tenho?&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>Value (V)&lt;/strong>: Valor (entidade). &amp;ldquo;Qual informação eu realmente forneço?&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;h2 id="41-geração-das-matrizes-q-k-v">4.1 Geração das matrizes $Q, K, V$
&lt;/h2>&lt;p>Para a matriz de entrada $X \in \mathbb{R}^{N \times d_{model}}$ (ignoraremos o tamanho do batch aqui por simplicidade), calculamos as consultas $Q$, chaves $K$ e valores $V$ multiplicando pelas matrizes de pesos treináveis $W^Q, W^K, W^V \in \mathbb{R}^{d_{model} \times d_k}$. (Geralmente $d_k = d_v = d_{model} / h$)&lt;/p>
$$ Q = X W^Q $$
$$ K = X W^K $$
$$ V = X W^V $$
&lt;p>Aqui, $Q, K, V$ são todas matrizes em $\mathbb{R}^{N \times d_k}$.&lt;/p>
&lt;h2 id="42-cálculo-do-attention-score-produto-escalar">4.2 Cálculo do Attention Score (Produto Escalar)
&lt;/h2>&lt;p>Para medir o quão relacionada está a Query de cada palavra com as Keys de todas as outras palavras, calculamos o &lt;strong>produto escalar&lt;/strong> dos vetores. Escrito como uma operação de matriz, fica da seguinte forma:&lt;/p>
$$ \text{Scores} = Q K^T $$
&lt;p>Cada elemento $s_{ij}$ da matriz $\text{Scores} \in \mathbb{R}^{N \times N}$ obtida por este cálculo representa o produto escalar da Query da $i$-ésima palavra e a Key da $j$-ésima palavra, ou seja, a &amp;ldquo;força da relação&amp;rdquo;.&lt;/p>
&lt;h2 id="43-dimensionamento-scale">4.3 Dimensionamento (Scale)
&lt;/h2>&lt;p>Existe um problema com o cálculo da pontuação por produto escalar. Quando a dimensão do vetor $d_k$ aumenta, o valor do produto escalar pode se tornar extremamente grande ou pequeno.&lt;/p>
&lt;p>Vamos provar isso matematicamente.
Suponha que cada elemento de uma consulta $q \sim \mathcal{N}(0, 1)$ e cada elemento de uma chave $k \sim \mathcal{N}(0, 1)$ sigam distribuições normais padrão independentes.
Calculamos a média e a variância do produto escalar $q \cdot k = \sum_{i=1}^{d_k} q_i k_i$.
Média: Como $\mathbb{E}[q_i k_i] = \mathbb{E}[q_i] \mathbb{E}[k_i] = 0 \times 0 = 0$, a média da soma também é $0$.
Variância: Devido à independência, a variância de $q_i k_i$ é $\text{Var}(q_i k_i) = \mathbb{E}[(q_i k_i)^2] - (\mathbb{E}[q_i k_i])^2 = 1 \times 1 - 0 = 1$.
Portanto, a variância de todo o produto escalar será igual à dimensão $d_k$.&lt;/p>
$$ \text{Var}(q \cdot k) = d_k $$
&lt;p>Se a variância se tornar grande, na função Softmax aplicada posteriormente, o gradiente para valores além do valor máximo se tornará extremamente pequeno (ocorrendo o &amp;ldquo;desaparecimento do gradiente&amp;rdquo;), e o aprendizado não progredirá.
Para evitar isso, dividimos as pontuações por $\sqrt{d_k}$ (escalonamento) para manter a variância sempre em $1$.&lt;/p>
$$ \text{Scaled Scores} = \frac{Q K^T}{\sqrt{d_k}} $$
&lt;h2 id="44-transformação-em-probabilidades-com-a-função-softmax">4.4 Transformação em probabilidades com a função Softmax
&lt;/h2>&lt;p>Aplicamos a &lt;strong>função Softmax&lt;/strong> a cada linha para converter as pontuações obtidas em uma distribuição de probabilidade (pesos) cuja soma seja $1$.&lt;/p>
$$ a_{ij} = \text{softmax}(s_i)_j = \frac{\exp(s_{ij} / \sqrt{d_k})}{\sum_{m=1}^N \exp(s_{im} / \sqrt{d_k})} $$
&lt;p>A matriz $A \in \mathbb{R}^{N \times N}$ é chamada de matriz de Attention Weight (Pesos de Atenção). Observando cada linha $i$ desta matriz, vemos expressa em valores de 0 a 1 &amp;ldquo;quanta atenção (Attention) deve ser dada a qualquer outra palavra $j$ a fim de compreender a palavra $i$&amp;rdquo;.&lt;/p>
&lt;h2 id="45-soma-ponderada-dos-values">4.5 Soma ponderada dos Values
&lt;/h2>&lt;p>Finalmente, usando a matriz de Attention Weight $A$ obtida, calculamos a soma ponderada da matriz Value $V$.&lt;/p>
$$ \text{Output} = A V = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>A matriz $Z \in \mathbb{R}^{N \times d_v}$ gerada por esta operação é um conjunto de &amp;ldquo;representações vetoriais de palavras atualizadas considerando o contexto&amp;rdquo;.
Esta é toda a estrutura do &lt;strong>Scaled Dot-Product Attention&lt;/strong> definida no artigo.&lt;/p>
&lt;hr>
&lt;h1 id="5-multi-head-attention-atenção-multi-cabeças">5. Multi-Head Attention (Atenção Multi-Cabeças)
&lt;/h1>&lt;p>Com apenas um cálculo de Attention (single head), o contexto pode ser capturado sob apenas uma perspectiva (por exemplo, &amp;ldquo;relação gramatical&amp;rdquo;). Portanto, para capturar simultaneamente as diversas relações semânticas e sintáticas da linguagem (como &amp;ldquo;sujeito e predicado&amp;rdquo;, &amp;ldquo;pronome e seu referente&amp;rdquo;, etc.), o &lt;strong>Multi-Head Attention&lt;/strong> foi introduzido.&lt;/p>
&lt;p>O processo de geração de $Q, K, V$ e o cálculo de Attention vistos anteriormente são realizados em paralelo $h$ vezes (o número de cabeças. No artigo original, $h=8$).&lt;/p>
$$ \text{head}_i = \text{Attention}(X W_i^Q, X W_i^K, X W_i^V) $$
&lt;p>Aqui, $W_i^Q, W_i^K, W_i^V \in \mathbb{R}^{d_{model} \times d_k}$ são matrizes de pesos treináveis dedicadas à $i$-ésima cabeça.&lt;/p>
&lt;p>Os resultados produzidos por cada cabeça, $\text{head}_i \in \mathbb{R}^{N \times d_v}$, são concatenados (Concatenate) horizontalmente.&lt;/p>
$$ \text{Concat}(\text{head}_1, \dots, \text{head}_h) \in \mathbb{R}^{N \times (h \cdot d_v)} $$
&lt;p>Normalmente, isso é configurado de modo que $h \cdot d_v = d_{model}$, para que a dimensão após a concatenação volte a ser $d_{model}$, assim como na entrada. Por fim, multiplicamos esta matriz por uma matriz de pesos $W^O \in \mathbb{R}^{d_{model} \times d_{model}}$ para obter a saída final.&lt;/p>
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O $$
&lt;div class="mermaid">graph TD
X["Entrada X"] --> Q1["Q1"]
X --> K1["K1"]
X --> V1["V1"]
Q1 &amp; K1 &amp; V1 --> H1["Cabeça 1"]
X --> Q2["Q2"]
X --> K2["K2"]
X --> V2["V2"]
Q2 &amp; K2 &amp; V2 --> H2["Cabeça 2"]
X --> QN["..."]
X --> KN["..."]
X --> VN["..."]
QN &amp; KN &amp; VN --> HN["Cabeça h"]
H1 &amp; H2 &amp; HN --> C["Concatenar"]
C --> WO["Multiplicar por WO"]
WO --> OUT["Saída Multi-Head"]&lt;/div>
&lt;hr>
&lt;h1 id="6-feed-forward-neural-network-ffn">6. Feed-Forward Neural Network (FFN)
&lt;/h1>&lt;p>A saída do Multi-Head Attention é então inserida em uma &lt;strong>Position-wise Feed-Forward Network (FFN)&lt;/strong>.
Esta é uma rede neural de duas camadas totalmente conectada aplicada &amp;ldquo;independentemente a cada posição (palavra)&amp;rdquo; da sequência.&lt;/p>
&lt;p>Expresso em uma fórmula matemática, isso se parece com o seguinte:&lt;/p>
$$ \text{FFN}(x) = \max(0, x W_1 + b_1) W_2 + b_2 $$
&lt;p>Aqui, $\max(0, z)$ representa a função de ativação ReLU (Rectified Linear Unit) (em modelos recentes, GELU ou SwiGLU são frequentemente utilizados).&lt;/p>
&lt;p>O papel dessa rede é extremamente importante. O mecanismo de Attention aprende &amp;ldquo;as relações entre as palavras (relações espaciais e sequenciais)&amp;rdquo;, enquanto a FFN é responsável pela &amp;ldquo;transformação não-linear de características de cada vetor de palavra em si&amp;rdquo;.
Normalmente, a dimensão é primeiro bastante expandida pelos pesos da primeira camada $W_1$ (por exemplo, multiplicada por 4, de $d_{model}=512$ para $d_{ff}=2048$), e depois de realizar cálculos complexos no espaço de características, ela retorna à dimensão original através dos pesos da segunda camada $W_2$. Com essa &amp;ldquo;expansão e contração de dimensões&amp;rdquo;, a expressividade do modelo aumenta drasticamente.&lt;/p>
&lt;hr>
&lt;h1 id="7-conexão-residual-residual-connection-e-layer-normalization-normalização-de-camada">7. Conexão Residual (Residual Connection) e Layer Normalization (Normalização de Camada)
&lt;/h1>&lt;p>No deep learning, à medida que a rede se torna mais profunda, pode ocorrer o problema do desaparecimento ou da explosão dos gradientes durante o treinamento, o que impede a aprendizagem adequada. Para evitar isso, uma &lt;strong>Conexão Residual (Residual Connection)&lt;/strong> e uma &lt;strong>Layer Normalization (Normalização de Camada)&lt;/strong> são colocadas em torno de cada subcamada (Attention e FFN) do Transformer.&lt;/p>
&lt;p>Matematicamente, a saída de uma subcamada é processada da seguinte forma:&lt;/p>
$$ \text{Output} = \text{LayerNorm}(x + \text{Sublayer}(x)) $$
&lt;h2 id="71-conexão-residual-x--textsublayerx">7.1 Conexão Residual ($x + \text{Sublayer}(x)$)
&lt;/h2>&lt;p>A entrada $x$ é adicionada diretamente à saída da subcamada. Com isso, os gradientes durante a retropropagação passam por um atalho (shortcut) e são transmitidos diretamente para as camadas mais superficiais, permitindo que o treinamento seja estabilizado mesmo com um aumento na profundidade das camadas.&lt;/p>
&lt;h2 id="72-a-matemática-da-layer-normalization">7.2 A matemática da Layer Normalization
&lt;/h2>&lt;p>Layer Normalization é uma técnica para normalizar os dados, calculando a média e a variância ao longo da dimensão das características. Para uma entrada com um tamanho de batch $B$, comprimento da sequência $N$ e dimensão $d_{model}$, a normalização é feita de forma independente para cada vetor de palavra $x \in \mathbb{R}^{d_{model}}$.&lt;/p>
&lt;p>Calculamos a média $\mu$ e a variância $\sigma^2$:
&lt;/p>
$$ \mu = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} x_i $$
$$ \sigma^2 = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} (x_i - \mu)^2 $$
&lt;p>E então obtemos a saída normalizada $\hat{x}$:
&lt;/p>
$$ \text{LN}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta $$
&lt;p>
(Onde $\epsilon$ é uma pequena constante para evitar a divisão por zero. $\gamma$ e $\beta$ são parâmetros treináveis de escala e deslocamento)&lt;/p>
&lt;p>A razão pela qual se adotou a Layer Normalization em vez da Batch Normalization (normalização ao longo da dimensão do batch) é que estatísticas entre os batches tendem a ficar instáveis ao lidar com dados sequenciais de comprimentos variados, como textos. Graças à Layer Normalization, o Transformer pode alcançar um aprendizado estável, independentemente do tamanho do batch.&lt;/p>
&lt;hr>
&lt;h1 id="8-estrutura-específica-do-decoder-masked-attention-e-cross-attention">8. Estrutura específica do Decoder: Masked Attention e Cross-Attention
&lt;/h1>&lt;p>A estrutura explicada até agora diz respeito ao codificador (encoder). O bloco decodificador (decoder), que gera o texto, possui uma estrutura ligeiramente diferente.&lt;/p>
&lt;h2 id="81-masked-multi-head-attention">8.1 Masked Multi-Head Attention
&lt;/h2>&lt;p>A função do decodificador é &amp;ldquo;prever a próxima palavra com base nas palavras passadas&amp;rdquo;. Consequentemente, olhar para &amp;ldquo;palavras futuras&amp;rdquo; durante o treinamento seria trapaça. A operação matemática para evitar isso é o &lt;strong>Masking (Mascaramento)&lt;/strong>.&lt;/p>
&lt;p>À matriz de pontuações $Q K^T$, adicionamos uma matriz de máscara $M$ que define a parte triangular superior (correspondente às informações futuras) com valores extremamente pequenos, próximos de $-\infty$.&lt;/p>
$$ M_{ij} = \begin{cases} 0 &amp; (i \le j) \\ -\infty &amp; (i > j) \end{cases} $$
$$ \text{Masked Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T + M}{\sqrt{d_k}}\right) V $$
&lt;p>Quando a função Softmax é calculada, como $\exp(-\infty) = 0$, os pesos de atenção (Attention Weights) para as palavras futuras tornam-se completamente $0$. Dessa forma, é possível realizar uma geração autorregressiva que preserva a causalidade (Causality).&lt;/p>
&lt;h2 id="82-encoder-decoder-cross-attention">8.2 Encoder-Decoder Cross-Attention
&lt;/h2>&lt;p>A segunda subcamada no decodificador é a &lt;strong>Cross-Attention&lt;/strong>, que faz referência à saída do codificador.
Aqui, a Query $Q$ é gerada pela camada de decodificação anterior, mas as chaves $K$ e os valores $V$ são gerados a partir da saída da camada final do codificador.&lt;/p>
$$ Q_{decoder} = X_{dec} W^Q $$
$$ K_{encoder} = X_{enc} W^K $$
$$ V_{encoder} = X_{enc} W^V $$
&lt;p>Este cálculo permite que o modelo aprenda, por exemplo em tarefas de tradução, &amp;ldquo;a qual parte da frase no idioma estrangeiro original a palavra sendo traduzida agora está fortemente associada&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h1 id="9-complexidade-computacional-e-a-matemática-das-otimizações-modernas">9. Complexidade computacional e a matemática das otimizações modernas
&lt;/h1>&lt;p>O Transformer é um modelo excelente, mas as &amp;ldquo;fraquezas&amp;rdquo; inerentes à sua estrutura matemática também existem.
Considere a complexidade computacional do Self-Attention. O cálculo da matriz de pontuação $Q K^T$ envolve multiplicar uma matriz de tamanho $(N \times d_k)$ por uma de tamanho $(d_k \times N)$, então sua complexidade computacional é &lt;strong>$O(N^2 \cdot d_{model})$&lt;/strong>.&lt;/p>
&lt;p>Em outras palavras, &lt;strong>a quantidade de cálculo e o uso de memória crescem quadraticamente em relação ao comprimento da sequência $N$&lt;/strong>.
Quando as frases são curtas, isso não é um problema, mas se você tentar alimentar um LLM com um contexto vasto como o conteúdo de um livro inteiro, $N$ atinge dezenas a centenas de milhares, e o cálculo tradicional da Attention esgotará imediatamente a memória da GPU.&lt;/p>
&lt;p>Para quebrar essa maldição do $O(N^2)$, várias otimizações têm sido propostas nos últimos anos com base em abordagens matemáticas e de hardware.
Um exemplo representativo é o &lt;strong>FlashAttention&lt;/strong>. FlashAttention é um algoritmo que minimiza a transferência de dados (acesso à memória) entre a hierarquia de memória da GPU (SRAM e HBM) ao realizar cálculos de Attention particionados em blocos (Tiling). Embora matematicamente produza exatamente os mesmos resultados que a Attention padrão (Exact Attention), otimizações no nível do hardware proporcionaram acelerações drásticas e reduções de memória, tornando viáveis modelos de contexto longo como o GPT-4.&lt;/p>
&lt;p>Existem também muitas pesquisas ativas focadas em Sparse Attention e Linear Attention, que buscam aproximar a complexidade computacional em $O(N \log N)$ e $O(N)$.&lt;/p>
&lt;hr>
&lt;h1 id="10-exemplo-de-implementação-pseudocódigo-no-estilo-pytorch">10. Exemplo de implementação (Pseudocódigo no estilo PyTorch)
&lt;/h1>&lt;p>Quando traduzimos a estrutura matemática descrita até agora para um código de programação real (Python / PyTorch), percebemos que ela pode ser escrita de forma surpreendentemente simples. O código a seguir mostra o pseudocódigo para a parte central do Self-Attention.&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;/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">torch&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">torch.nn.functional&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">F&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">math&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">scaled_dot_product_attention&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">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Formato de q, k, v: [batch_size, num_heads, seq_length, d_k]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d_k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Cálculo da pontuação pelo produto escalar: Q * K^T&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Transpondo as últimas duas dimensões para calcular o produto de matrizes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&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">k&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">transpose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Dimensionamento (Scaling)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d_k&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. Mascaramento (para o caso de Masked Attention)&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">mask&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">masked_fill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mask&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mf">1e9&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"># 4. Transformação em probabilidades pelo Softmax&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attention_weights&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">F&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">softmax&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scores&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dim&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"># 5. Multiplicação pela matriz Value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">attention_weights&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&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">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attention_weights&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Podemos ver intuitivamente que a fórmula matemática $Q K^T / \sqrt{d_k}$ é implementada como &lt;code>torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)&lt;/code>. É um aspecto muito fascinante do deep learning como a teoria matemática ganha vida em apenas algumas linhas de código com o poder de bibliotecas avançadas de otimização.&lt;/p>
&lt;hr>
&lt;h1 id="conclusão-a-forma-da-inteligência-vista-através-da-matemática">Conclusão: A forma da &amp;ldquo;inteligência&amp;rdquo; vista através da matemática
&lt;/h1>&lt;p>Neste artigo, desvendamos a profunda estrutura matemática que reside dentro do modelo Transformer.&lt;/p>
&lt;p>O Embedding, que mapeia palavras em um espaço vetorial multidimensional, o Positional Encoding, que expressa a informação posicional ao combinar ondas trigonométricas, e o mecanismo de Self-Attention, que é o cálculo de produto escalar de matrizes nascido de uma analogia de recuperação de informação. Cada um desses componentes nada mais é do que o empilhamento de conceitos matemáticos básicos, como álgebra linear, cálculo diferencial, probabilidade e estatística.&lt;/p>
&lt;p>No entanto, quando essas simples operações de matrizes são acumuladas em várias camadas e, através de bilhões a centenas de bilhões de parâmetros, padrões são extraídos de bancos de dados massivos, surge uma &amp;ldquo;forma de inteligência&amp;rdquo; capaz de compreender nossas &amp;ldquo;palavras&amp;rdquo;, fazer raciocínios lógicos e, ocasionalmente, conceber ideias criativas.&lt;/p>
&lt;p>Como o título provocativo &amp;ldquo;Attention Is All You Need&amp;rdquo; sugere, a beleza dessa arquitetura - que descarta o processamento recursivo complexo e o processamento convolucional para se especializar totalmente no cálculo puro de &amp;ldquo;atenção (grau de relevância)&amp;rdquo; - encontra-se justamente na sua simplicidade matemática.&lt;/p>
&lt;p>Pode ser que no futuro surjam novas arquiteturas que superem o Transformer (como a Mamba, que é um State Space Model), mas o framework matemático de &amp;ldquo;compreensão de contexto através da Attention&amp;rdquo;, pavimentado pelo Transformer, certamente ficará gravado na história da IA para sempre.&lt;/p>
&lt;p>Se você tiver a oportunidade de usar LLMs como ChatGPT e Claude no futuro, tente imaginar os trilhões de multiplicações de matrizes $Q K^T$ sendo calculadas nos bastidores a cada segundo, bem como as probabilidades sendo geradas pela função Softmax. Sua resolução tecnológica aumentará, e você sem dúvida achará o mundo da IA ainda mais interessante.&lt;/p>
&lt;h3 id="referências">Referências
&lt;/h3>&lt;ul>
&lt;li>Vaswani, A., et al. (2017). &amp;ldquo;Attention Is All You Need.&amp;rdquo; &lt;em>Advances in Neural Information Processing Systems&lt;/em>.&lt;/li>
&lt;li>Alammar, J. (2018). &amp;ldquo;The Illustrated Transformer.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>Este artigo foi escrito como um guia para aqueles que desejam aprender os fundamentos matemáticos do processamento de linguagem natural e da IA. Sinta-se à vontade para deixar suas dúvidas ou comentários na seção de discussão abaixo!&lt;/em>&lt;/p></description></item><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>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>【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></channel></rss>