<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cryptography on kenji.blog</title><link>http://kenji.blog/es/tags/cryptography/</link><description>Recent content in Cryptography on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 21:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/tags/cryptography/index.xml" rel="self" type="application/rss+xml"/><item><title>Intuición matemática de la criptografía basada en retículos (Lattice-based cryptography)</title><link>http://kenji.blog/es/p/lattice-based-cryptography-math-intuition/</link><pubDate>Fri, 11 Sep 2026 21:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Intuición matemática de la criptografía basada en retículos (Lattice-based cryptography)" />&lt;h1 id="1-introducción-el-amanecer-de-la-criptografía-poscuántica-pqc-y-el-auge-de-la-criptografía-basada-en-retículos">1. Introducción: El amanecer de la criptografía poscuántica (PQC) y el auge de la criptografía basada en retículos
&lt;/h1>&lt;p>La infraestructura digital de la sociedad moderna se basa en tecnologías de criptografía de clave pública, como el cifrado RSA y la criptografía de curva elíptica (ECC). Estos métodos basan su seguridad en la dificultad matemática de problemas como la &amp;ldquo;factorización de enteros&amp;rdquo; o el &amp;ldquo;logaritmo discreto&amp;rdquo;, los cuales se cree que no pueden resolverse eficientemente (requieren tiempo exponencial) con computadoras clásicas convencionales.&lt;/p>
&lt;p>Sin embargo, el &amp;ldquo;Algoritmo de Shor&amp;rdquo;, publicado por Peter Shor en 1994, sacudió el mundo de la criptografía. Este algoritmo demostró matemáticamente que una vez que se construyan computadoras cuánticas a gran escala, estas podrán resolver los problemas de factorización de enteros y de logaritmo discreto en tiempo polinomial. Esto significa que la criptografía de clave pública ampliamente utilizada en la actualidad se volverá completamente descifrable en el futuro.&lt;/p>
&lt;p>Para contrarrestar esta &amp;ldquo;Amenaza Cuántica (Quantum Threat)&amp;rdquo;, se hizo imperativo investigar nuevos métodos de cifrado que sean difíciles de descifrar incluso utilizando computadoras cuánticas. Este es el campo conocido como &amp;ldquo;Criptografía Poscuántica (Post-Quantum Cryptography: PQC)&amp;rdquo; o &amp;ldquo;Criptografía resistente a la computación cuántica&amp;rdquo;.&lt;/p>
&lt;p>Existen varios candidatos prometedores para la PQC, como la criptografía basada en hashes, la criptografía basada en códigos, la criptografía multivariable y la criptografía basada en isogenias. Sin embargo, el método que actualmente atrae más la atención y que está en el centro del proceso de estandarización de PQC por parte del NIST (Instituto Nacional de Estándares y Tecnología de EE. UU.) es la &amp;ldquo;Criptografía basada en retículos (Lattice-based cryptography)&amp;rdquo;. En comparación con otros métodos, la criptografía de retículos ofrece velocidades de cifrado y descifrado muy rápidas, y cuenta con una característica destacada: una prueba de seguridad extremadamente sólida en la teoría criptográfica basada en la reducción de la &amp;ldquo;complejidad en el peor de los casos (Worst-case complexity)&amp;rdquo; a la &amp;ldquo;complejidad en el caso promedio (Average-case complexity)&amp;rdquo;.&lt;/p>
&lt;p>En este artículo, partiremos de la definición matemática de &amp;ldquo;Retículo (Lattice)&amp;rdquo;, que es la base de esta criptografía, y explicaremos profundamente mediante fórmulas, intuición geométrica y ejemplos numéricos específicos los problemas difíciles sobre retículos como SVP (Problema del vector más corto) y CVP (Problema del vector más cercano), y el corazón de la criptografía de retículos moderna, el &amp;ldquo;Problema LWE (Learning With Errors)&amp;rdquo;.&lt;/p>
&lt;h1 id="2-definición-matemática-e-intuición-geométrica-de-un-retículo-lattice">2. Definición matemática e intuición geométrica de un Retículo (Lattice)
&lt;/h1>&lt;h2 id="21-espacio-vectorial-y-retículos">2.1 Espacio vectorial y retículos
&lt;/h2>&lt;p>En matemáticas, un &amp;ldquo;Retículo (Lattice)&amp;rdquo; es un conjunto discreto de puntos dispuestos regularmente en un espacio vectorial real de $n$ dimensiones $\mathbb{R}^n$. Es similar al espacio vectorial (Vector Space) que se estudia en álgebra lineal, pero existe una diferencia crucial. Mientras que un espacio vectorial es un espacio continuo representado por combinaciones lineales de vectores base con &amp;ldquo;coeficientes reales&amp;rdquo;, un retículo es un espacio discreto representado por combinaciones lineales de vectores base con &amp;ldquo;coeficientes enteros&amp;rdquo;.&lt;/p>
&lt;p>Demos una definición matemática rigurosa. Consideremos $n$ vectores linealmente independientes $\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n$ (donde $n \le m$) en un espacio vectorial real de $m$ dimensiones $\mathbb{R}^m$. Sea $B = [\mathbf{b}_1, \mathbf{b}_2, \dots, \mathbf{b}_n] \in \mathbb{R}^{m \times n}$ una matriz que tiene estos vectores como columnas. Llamamos a esta $B$ la &amp;ldquo;Base (Basis)&amp;rdquo; del retículo.&lt;/p>
&lt;p>El retículo $\mathcal{L}(B)$ generado por esta base $B$ se define de la siguiente manera:&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>Lo importante aquí es que los coeficientes $x_i$ están limitados a números enteros $\mathbb{Z}$, en lugar de números reales $\mathbb{R}$. Como resultado, en lugar de puntos continuos que existen en un número infinito en el espacio, se forma un &amp;ldquo;conjunto discreto de puntos&amp;rdquo; similar a las intersecciones espaciadas uniformemente en una cuadrícula.&lt;/p>
&lt;h2 id="22-imagen-geométrica">2.2 Imagen geométrica
&lt;/h2>&lt;p>Consideremos un ejemplo en el plano bidimensional $\mathbb{R}^2$. Si elegimos los vectores base $\mathbf{b}_1 = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ y $\mathbf{b}_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$, el retículo generado por ellos será el conjunto de todas las coordenadas enteras $(x, y) \in \mathbb{Z}^2$ en el plano cartesiano. Este es el &amp;ldquo;retículo cuadrado&amp;rdquo; más simple.&lt;/p>
&lt;p>Sin embargo, los retículos no siempre son ortogonales. Por ejemplo, considerando una base como $\mathbf{b}_1 = \begin{pmatrix} 2 \\ 1 \end{pmatrix}$ y $\mathbf{b}_2 = \begin{pmatrix} 1 \\ 3 \end{pmatrix}$, los puntos generados se parecerán a las intersecciones de una malla sesgada diagonalmente.&lt;/p>
&lt;h2 id="23-no-unicidad-de-la-base-y-transformación-unimodular">2.3 No unicidad de la base y transformación unimodular
&lt;/h2>&lt;p>Existe una propiedad importante relacionada con la base de la seguridad de la criptografía de retículos: &amp;ldquo;existen infinitas bases que generan el mismo retículo&amp;rdquo;.&lt;/p>
&lt;p>Por ejemplo, el retículo $\mathbb{Z}^2$ generado por la base $\mathbf{b}_1 = (1, 0)^T, \mathbf{b}_2 = (0, 1)^T$ mencionada anteriormente es exactamente el mismo retículo $\mathbb{Z}^2$ que el generado por la base $\mathbf{b}'_1 = (1, 1)^T, \mathbf{b}'_2 = (2, 3)^T$.&lt;/p>
&lt;p>La condición necesaria y suficiente para que una base $B$ y otra base $B'$ generen el mismo retículo es que exista una matriz con componentes enteros $U \in \mathbb{Z}^{n \times n}$ cuyo determinante sea $\det(U) = \pm 1$, tal que:
&lt;/p>
$$ B' = B U $$
&lt;p>
A una matriz $U$ de este tipo se le llama &amp;ldquo;Matriz unimodular (Unimodular matrix)&amp;rdquo;.&lt;/p>
&lt;p>La idea básica en la aplicación a la criptografía es utilizar una &amp;ldquo;buena base&amp;rdquo; (una base casi ortogonal formada por vectores cortos) como clave privada, y una &amp;ldquo;mala base&amp;rdquo; (una base con vectores extremadamente oblicuos entre sí y muy largos) como clave pública. Calcular una buena base a partir de una mala base se vuelve muy difícil a medida que aumentan las dimensiones. Esta es la intuición básica de la criptografía basada en retículos.&lt;/p>
&lt;h1 id="3-problemas-computacionalmente-difíciles-en-retículos">3. Problemas computacionalmente difíciles en retículos
&lt;/h1>&lt;p>La seguridad de la criptografía basada en retículos depende de la dificultad de resolver problemas matemáticos específicos en los retículos. Aquí presentaremos dos de los problemas más fundamentales y conocidos.&lt;/p>
&lt;h2 id="31-problema-del-vector-más-corto-shortest-vector-problem-svp">3.1 Problema del vector más corto (Shortest Vector Problem: SVP)
&lt;/h2>&lt;p>SVP es el problema más clásico y famoso de la teoría de retículos.&lt;/p>
&lt;p>&lt;strong>Definición (SVP):&lt;/strong>
Dada una base de retículo arbitraria $B$, encontrar el vector $\mathbf{v}$ distinto de cero que pertenece al retículo $\mathcal{L}(B)$ y tiene la norma euclidiana (longitud) mínima.&lt;/p>
&lt;p>Expresado en fórmula matemática, es el problema de encontrar $\mathbf{v}$ tal que $\min_{\mathbf{v} \in \mathcal{L}(B) \setminus \{\mathbf{0}\}} \| \mathbf{v} \|$. A esta longitud mínima se le denota como $\lambda_1(\mathcal{L})$ y se le llama &amp;ldquo;Primer mínimo sucesivo (First successive minimum) del retículo&amp;rdquo;.&lt;/p>
&lt;p>En dimensiones bajas como 2 o 3, podemos encontrar el vector más corto visualmente dibujando un gráfico, o podemos resolverlo eficientemente usando algoritmos como el algoritmo de reducción de bases de Gauss. Sin embargo, cuando la dimensión $n$ alcanza valores altos como cientos o miles, se sabe que resolver estrictamente SVP es NP-difícil.&lt;/p>
&lt;p>En criptografía real, no se busca el vector más corto estricto, sino que se utiliza un SVP aproximado ($\gamma$-SVP) para encontrar un &amp;ldquo;vector aproximadamente corto&amp;rdquo;. Si el factor de aproximación $\gamma$ es de tamaño polinomial, este problema se sigue considerando extremadamente difícil.&lt;/p>
&lt;h2 id="32-problema-del-vector-más-cercano-closest-vector-problem-cvp">3.2 Problema del vector más cercano (Closest Vector Problem: CVP)
&lt;/h2>&lt;p>CVP es también un problema de extrema importancia en la criptografía basada en retículos.&lt;/p>
&lt;p>&lt;strong>Definición (CVP):&lt;/strong>
Dada una base de retículo arbitraria $B$ y un vector objetivo arbitrario $\mathbf{t} \in \mathbb{R}^m$ en el espacio (que no necesariamente es un punto del retículo), encontrar el punto del retículo $\mathbf{v} \in \mathcal{L}(B)$ más cercano a $\mathbf{t}$.&lt;/p>
&lt;p>Expresado matemáticamente, es el problema de buscar un punto de retículo $\mathbf{v}$ tal que $\min_{\mathbf{v} \in \mathcal{L}(B)} \| \mathbf{v} - \mathbf{t} \|$.&lt;/p>
&lt;p>Al igual que SVP, CVP también es NP-difícil en altas dimensiones. Desde la perspectiva de la aplicación criptográfica, el problema LWE que discutiremos más adelante está estrechamente relacionado con una variante especial de este CVP (Decodificación de distancia acotada o Bounded Distance Decoding: BDD).&lt;/p>
&lt;h2 id="33-por-qué-es-insoluble-en-altas-dimensiones-los-límites-de-lll-y-bkz">3.3 ¿Por qué es insoluble en altas dimensiones? (Los límites de LLL y BKZ)
&lt;/h2>&lt;p>Un algoritmo famoso para resolver problemas de retículos de altas dimensiones es el algoritmo LLL (Lenstra-Lenstra-Lovász algorithm). El algoritmo LLL se ejecuta en tiempo polinomial y puede reducir en cierta medida la base del retículo a una &amp;ldquo;buena base&amp;rdquo;. Sin embargo, el vector más corto que el algoritmo LLL puede encontrar tiene un factor de aproximación exponencial ($2^{\mathcal{O}(n)}$) en relación con la longitud del vector más corto verdadero, por lo que no es suficiente para romper la seguridad criptográfica.&lt;/p>
&lt;p>Si se utiliza un algoritmo de reducción de bases más potente como el algoritmo BKZ (Block Korkine-Zolotarev), que es una mejora de LLL, se pueden encontrar vectores más cortos, pero su complejidad computacional aumenta exponencialmente con respecto al tamaño del bloque. En la criptografía de retículos, los parámetros seguros (como el tamaño de la dimensión $n$) se determinan estimando el tiempo de ejecución de este algoritmo BKZ. Con los parámetros estándar actuales de PQC, se eligen dimensiones $n$ de 500 a 1000 o más, y se considera que descifrarlos tomaría más tiempo que la edad del universo, incluso utilizando supercomputadoras o futuras computadoras cuánticas.&lt;/p>
&lt;h1 id="4-formulación-matemática-del-problema-lwe-learning-with-errors">4. Formulación matemática del problema LWE (Learning With Errors)
&lt;/h1>&lt;p>La mayor parte de la criptografía de retículos moderna se basa en el &amp;ldquo;Problema LWE (Learning With Errors)&amp;rdquo; propuesto por Oded Regev en 2005. La belleza del problema LWE radica en la simplicidad de su formulación y en el hecho de que cuenta con una poderosa prueba matemática de &amp;ldquo;reducción de la complejidad en el peor caso a la complejidad en el caso promedio&amp;rdquo;.&lt;/p>
&lt;h2 id="41-sistema-de-ecuaciones-lineales-sin-ruido">4.1 Sistema de ecuaciones lineales sin ruido
&lt;/h2>&lt;p>Para entender el problema LWE, primero consideremos un simple sistema de ecuaciones lineales sin ruido.
Supongamos que hay un vector secreto desconocido $\mathbf{s} \in \mathbb{Z}_q^n$ (donde cada componente es un número entero de $0$ a $q-1$). Aquí $q$ es un número primo.&lt;/p>
&lt;p>Elegimos vectores de coeficientes aleatorios $\mathbf{a}_1, \mathbf{a}_2, \dots \in \mathbb{Z}_q^n$ y calculamos su producto interno con el vector 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>Si se nos da un número suficiente (al menos $n$) de pares $(\mathbf{a}_i, b_i)$, podemos recuperar fácilmente el vector secreto $\mathbf{s}$ usando la &amp;ldquo;Eliminación de Gauss (Gaussian elimination)&amp;rdquo; de álgebra lineal. Este es un problema que puede resolverse fácilmente en tiempo polinomial.&lt;/p>
&lt;h2 id="42-definición-del-problema-lwe-agregando-ruido">4.2 Definición del problema LWE: Agregando ruido
&lt;/h2>&lt;p>Entonces, ¿qué sucedería si añadimos un ligero &amp;ldquo;ruido (error)&amp;rdquo; a este problema?
Esta es la esencia del problema LWE.&lt;/p>
&lt;p>Para el vector secreto desconocido $\mathbf{s} \in \mathbb{Z}_q^n$, añadimos un pequeño error $e_i \in \mathbb{Z}_q$ al resultado de cada ecuación.
$b_i = \langle \mathbf{a}_i, \mathbf{s} \rangle + e_i \pmod q$&lt;/p>
&lt;p>Aquí, $e_i$ es un pequeño valor entero con media 0 y una desviación estándar relativamente pequeña (por ejemplo, elegido de una distribución gaussiana discreta, similar a una distribución normal).
La información proporcionada es una lista de pares de un vector aleatorio $\mathbf{a}_i$ y $b_i$ calculado añadiendo un error.
$( \mathbf{a}_1, b_1 ), ( \mathbf{a}_2, b_2 ), \dots, ( \mathbf{a}_m, b_m )$&lt;/p>
&lt;p>Representar esto en forma matricial lo hace muy claro.
Usando una matriz aleatoria $A \in \mathbb{Z}_q^{m \times n}$, un vector secreto $\mathbf{s} \in \mathbb{Z}_q^n$ y un vector de error $\mathbf{e} \in \mathbb{Z}_q^m$:
&lt;/p>
$$ \mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q $$
&lt;p>
Solo se nos proporciona $A$ y $\mathbf{b}$. Encontrar $\mathbf{s}$ a partir de aquí es el &amp;ldquo;Problema de búsqueda LWE (Search LWE problem)&amp;rdquo;.&lt;/p>
&lt;p>Debido a que el error $e_i$ está presente, intentar usar la eliminación de Gauss amplificaría el error de forma exponencial durante el proceso de sumar y restar ecuaciones, haciendo imposible llegar a la respuesta correcta. A primera vista, parece un simple sistema de ecuaciones lineales, pero al agregar este pequeño ruido, la dificultad del problema se eleva al nivel de NP-difícil.&lt;/p>
&lt;h2 id="43-problema-lwe-de-decisión-decision-lwe">4.3 Problema LWE de decisión (Decision LWE)
&lt;/h2>&lt;p>En las pruebas de la teoría criptográfica, la variante frecuentemente utilizada es el &amp;ldquo;Problema LWE de decisión (Decision LWE problem)&amp;rdquo;, que es una variante del problema de búsqueda LWE.&lt;/p>
&lt;p>El problema LWE de decisión es el problema de determinar de cuál de las siguientes dos distribuciones proviene una lista de muestras dada:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Distribución LWE&lt;/strong>: $(A, \mathbf{b} = A\mathbf{s} + \mathbf{e} \pmod q)$ calculada intencionadamente.&lt;/li>
&lt;li>&lt;strong>Distribución aleatoria uniforme&lt;/strong>: $(A, \mathbf{u})$ formada por una matriz $A$ y un vector $\mathbf{u}$ elegidos de forma completamente aleatoria.&lt;/li>
&lt;/ol>
&lt;p>Sorprendentemente, si se eligen adecuadamente los parámetros del problema LWE, los pares obtenidos de la distribución LWE se vuelven &amp;ldquo;computacionalmente indistinguibles (Computationally Indistinguishable)&amp;rdquo; de los pares de datos completamente aleatorios. Esta propiedad es la base que permite a la criptografía basada en LWE generar &amp;ldquo;textos cifrados indistinguibles de números aleatorios&amp;rdquo;.&lt;/p>
&lt;h2 id="44-reducción-de-la-complejidad-en-el-peor-caso-a-la-del-caso-promedio-teorema-de-regev">4.4 Reducción de la complejidad en el peor caso a la del caso promedio (Teorema de Regev)
&lt;/h2>&lt;p>El mayor logro de Oded Regev fue vincular matemáticamente la dificultad de este problema LWE con la dificultad de los problemas de retículos mencionados anteriormente (SVP y CVP).&lt;/p>
&lt;p>Utilizó la reducción cuántica (Quantum reduction) para demostrar que &amp;ldquo;si existe un algoritmo de tiempo polinomial capaz de resolver el problema LWE en el caso promedio (para $A$ y $\mathbf{e}$ elegidos al azar), entonces existe un algoritmo cuántico de tiempo polinomial capaz de resolver el Gap-SVP en el peor caso (el caso más difícil) para cualquier retículo&amp;rdquo;. (Posteriormente, Peikert y otros también demostraron una reducción clásica).&lt;/p>
&lt;p>Esta es una propiedad soñada en la teoría criptográfica. Esto se debe a que disipa la preocupación de que &amp;ldquo;la criptografía podría romperse si por casualidad elegimos una clave débil (una parte del caso promedio)&amp;rdquo; y ofrece una fuerte garantía de que &amp;ldquo;si se puede resolver el LWE promedio, entonces se pueden resolver todos los problemas difíciles del retículo (por lo tanto, el LWE es absolutamente difícil)&amp;rdquo;.&lt;/p>
&lt;div class="mermaid">graph TD
A["Problemas de retículos en el peor caso (Gap-SVP, SIVP)"] -->|Reducción Cuántica/Clásica| B["Problema LWE en el caso promedio"]
B -->|Construcción Criptográfica| C["Criptosistemas basados en 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-construcción-de-un-sistema-de-criptografía-de-clave-pública-utilizando-lwe-criptografía-de-regev">5. Construcción de un sistema de criptografía de clave pública utilizando LWE (Criptografía de Regev)
&lt;/h1>&lt;p>Habiendo entendido la dificultad del problema LWE, veamos cómo funciona el cifrado y descifrado usándolo en el sistema de criptografía de clave pública básico propuesto por Oded Regev. Aquí explicaremos el mecanismo más básico para cifrar un mensaje de 1 bit $M \in \{0, 1\}$.&lt;/p>
&lt;h2 id="51-generación-de-claves-key-generation">5.1 Generación de claves (Key Generation)
&lt;/h2>&lt;ol>
&lt;li>Como parámetros del sistema, se determinan el módulo primo $q$, la dimensión $n$ y el número de ecuaciones $m$ ($m > n \log q$).&lt;/li>
&lt;li>Se elige al azar el vector secreto $\mathbf{s} \in \mathbb{Z}_q^n$ como clave privada.&lt;/li>
&lt;li>Se genera una matriz aleatoria $A \in \mathbb{Z}_q^{m \times n}$.&lt;/li>
&lt;li>Se selecciona un pequeño vector de error $\mathbf{e} \in \mathbb{Z}_q^m$ a partir de una distribución de errores como la distribución gaussiana discreta.&lt;/li>
&lt;li>Se calcula el vector $\mathbf{b} = A \mathbf{s} + \mathbf{e} \pmod q$.&lt;/li>
&lt;li>La clave pública (Public Key) será $(A, \mathbf{b})$.&lt;/li>
&lt;li>La clave secreta o privada (Secret Key) será $\mathbf{s}$.&lt;/li>
&lt;/ol>
&lt;p>La clave pública es precisamente una &amp;ldquo;instancia del problema LWE&amp;rdquo;. Dado que derivar la clave secreta $\mathbf{s}$ a partir de la clave pública $(A, \mathbf{b})$ equivale a resolver el problema de búsqueda LWE, la seguridad está garantizada.&lt;/p>
&lt;h2 id="52-cifrado-encryption">5.2 Cifrado (Encryption)
&lt;/h2>&lt;p>Alice cifra un mensaje de 1 bit $M \in \{0, 1\}$ utilizando la clave pública de Bob $(A, \mathbf{b})$.&lt;/p>
&lt;ol>
&lt;li>Elige un vector binario aleatorio (con componentes 0 o 1) $\mathbf{r} \in \{0, 1\}^m$.&lt;/li>
&lt;li>Como primera parte del texto cifrado, calcula el vector $\mathbf{u} = A^T \mathbf{r} \pmod q$. ($A^T$ es la matriz transpuesta de $A$. Es decir, suma las filas de $A$ donde el componente de $\mathbf{r}$ es 1).&lt;/li>
&lt;li>Como segunda parte del texto cifrado, calcula el escalar $v = \mathbf{b}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor \pmod q$.
(Si el mensaje $M$ es 0, no suma nada; si es $1$, suma exactamente la mitad del valor de $q$, $\lfloor \frac{q}{2} \rfloor$).&lt;/li>
&lt;li>El texto cifrado (Ciphertext) será $(\mathbf{u}, v)$.&lt;/li>
&lt;/ol>
&lt;p>La implicación intuitiva del cifrado es tomar la &amp;ldquo;suma de un subconjunto aleatorio&amp;rdquo; de la matriz de la clave pública $A$ y del vector $\mathbf{b}$. Debido a la dificultad del problema LWE de decisión, este texto cifrado $(\mathbf{u}, v)$ parece indistinguible de un vector completamente aleatorio y de un número aleatorio uniforme (Seguridad semántica: Semantic Security).&lt;/p>
&lt;div class="mermaid">flowchart LR
M["Mensaje M en {0,1}"] --> Enc
PK["Clave Pública (A, b)"] --> Enc
r["Vector binario aleatorio r"] --> Enc
subgraph Enc ["Proceso de Cifrado"]
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-descifrado-decryption">5.3 Descifrado (Decryption)
&lt;/h2>&lt;p>Bob descifra el texto cifrado $(\mathbf{u}, v)$ usando su clave secreta $\mathbf{s}$.&lt;/p>
&lt;ol>
&lt;li>Calcula el siguiente valor: $D = v - \mathbf{s}^T \mathbf{u} \pmod q$&lt;/li>
&lt;li>Si el resultado calculado está cerca de $0$, la salida es $M=0$; si está cerca de $\lfloor \frac{q}{2} \rfloor$, la salida es $M=1$.&lt;/li>
&lt;/ol>
&lt;p>Desarrollemos matemáticamente por qué se puede descifrar con esto.
Recuerde 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>Aquí, $\mathbf{s}^T A^T \mathbf{r}$ se cancela claramente y desaparece de la ecuación.
Lo que queda es $\mathbf{e}^T \mathbf{r} + M \cdot \lfloor \frac{q}{2} \rfloor$.&lt;/p>
&lt;p>$\mathbf{e}$ es un vector de ruido con componentes muy pequeños, y $\mathbf{r}$ es un vector binario con componentes de 0 o 1. Por lo tanto, su producto interno $\mathbf{e}^T \mathbf{r}$ también permanece como un valor relativamente pequeño (si los parámetros se eligen adecuadamente).&lt;/p>
&lt;ul>
&lt;li>Si $M=0$, el resultado es $\mathbf{e}^T \mathbf{r}$, que será un valor pequeño cerca de $0$.&lt;/li>
&lt;li>Si $M=1$, el resultado es $\mathbf{e}^T \mathbf{r} + \lfloor \frac{q}{2} \rfloor$, que se situará alrededor de la mitad del valor de $q$, $\lfloor \frac{q}{2} \rfloor$.&lt;/li>
&lt;/ul>
&lt;p>Si los parámetros están diseñados para que el valor absoluto del error $\mathbf{e}^T \mathbf{r}$ sea menor a $\frac{q}{4}$, Bob puede determinar (descifrar) con precisión el mensaje $M$ simplemente verificando si el resultado del cálculo está más cerca de $0$ o de $\lfloor \frac{q}{2} \rfloor$. Este es el hermoso mecanismo por el cual funciona la criptografía basada en LWE.&lt;/p>
&lt;div class="mermaid">flowchart LR
CT["Texto Cifrado (u, v)"] --> Dec
SK["Clave Secreta s"] --> Dec
subgraph Dec ["Proceso de Descifrado"]
direction TB
calc["Calcular D = v - s^T * u mod q"]
check["Comprobar si D está más cerca de 0 o q/2"]
end
calc --> check
Dec --> M_out["Mensaje Recuperado M"]&lt;/div>
&lt;h1 id="6-ejemplo-ilustrativo-de-criptografía-lwe-usando-valores-numéricos-específicos">6. Ejemplo ilustrativo de criptografía LWE usando valores numéricos específicos
&lt;/h1>&lt;p>Es posible que resulte difícil comprender solo con una lista de fórmulas matemáticas, así que intentemos establecer parámetros numéricos muy pequeños y seguir los cálculos desde el cifrado hasta el descifrado.
(* En un sistema de criptografía real, se utilizan valores para $n$ mayores de 500 y para $q$ valores de miles o más para garantizar la seguridad).&lt;/p>
&lt;p>&lt;strong>[Configuración de parámetros]&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Módulo $q = 17$ (Un número primo. Por tanto, los valores están en el rango de $0$ a $16$).&lt;/li>
&lt;li>Dimensión $n = 2$&lt;/li>
&lt;li>Número de ecuaciones $m = 4$&lt;/li>
&lt;li>Supondremos que se cifrará el mensaje $M = 1$.&lt;/li>
&lt;li>Cantidad de desplazamiento del mensaje: $\lfloor \frac{q}{2} \rfloor = \lfloor \frac{17}{2} \rfloor = 8$&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>[1. Fase de generación de claves]&lt;/strong>
Bob elige su clave secreta $\mathbf{s}$, la matriz $A$ y el vector de error $\mathbf{e}$ al azar.
&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>Luego calcula la clave 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 esto módulo 17 (como $66 = 17 \times 3 + 15$ etc.):
&lt;/p>
$$ A \mathbf{s} \pmod{17} = \begin{pmatrix} 15 \\ 1 \\ 11 \\ 16 \end{pmatrix} $$
&lt;p>
Sumando el vector de error $\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>La clave pública es $A$ y $\mathbf{b} = (16, 0, 11, 1)^T$.&lt;/p>
&lt;p>&lt;strong>[2. Fase de cifrado]&lt;/strong>
Alice cifra el mensaje $M = 1$.
Elige un vector aleatorio $\mathbf{r}$. Aquí usaremos $\mathbf{r} = (1, 0, 1, 0)^T$.&lt;/p>
&lt;p>Calcula $\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>Calcula $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>
Suma el valor correspondiente al mensaje $M=1$, $\lfloor 17/2 \rfloor = 8$:
&lt;/p>
$$ v = \mathbf{b}^T \mathbf{r} + M \cdot 8 = 10 + 1 \times 8 = 18 \equiv 1 \pmod{17} $$
&lt;p>Alice envía el texto cifrado $(\mathbf{u}, v) = \left( \begin{pmatrix} 16 \\ 3 \end{pmatrix}, 1 \right)$ a Bob.&lt;/p>
&lt;p>&lt;strong>[3. Fase de descifrado]&lt;/strong>
Bob, al recibir el texto cifrado, lo descifra usando su clave secreta $\mathbf{s} = (3, 4)^T$.
Fórmula de descifrado: 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>Aquí, en el mundo del módulo 17, $-8$ es igual a $9$ ($-8 + 17 = 9$).
Determina si el valor obtenido $D = 9$ está más cerca de $0$ o de $8$ ($\lfloor 17/2 \rfloor$).
Dado que $9$ está claramente más cerca de $8$ que de $0$, ¡Bob logra restaurar correctamente $M = 1$!&lt;/p>
&lt;p>¿Por qué resultó 9? Recordemos la prueba anterior.
La parte de error es $\mathbf{e}^T \mathbf{r} = (1, -1, 0, 2) (1, 0, 1, 0)^T = 1 \times 1 + 0 \times 1 = 1$.
Por lo tanto, el resultado del cálculo es $\mathbf{e}^T \mathbf{r} + M \cdot 8 = 1 + 8 = 9$, confirmando que se ha calculado el valor tal como en la teoría.&lt;/p>
&lt;h1 id="7-evolución-hacia-la-aplicación-práctica-ring-lwe-y-module-lwe">7. Evolución hacia la aplicación práctica: Ring-LWE y Module-LWE
&lt;/h1>&lt;p>El problema LWE estándar (Standard LWE) explicado hasta ahora tiene pruebas de seguridad muy sólidas, pero en la práctica tiene defectos fatales. Estos son el &amp;ldquo;tamaño gigante de las claves&amp;rdquo; y el &amp;ldquo;alto costo computacional&amp;rdquo;.&lt;/p>
&lt;p>En Standard LWE, la clave pública incluye una matriz gigante $A \in \mathbb{Z}_q^{m \times n}$. Cuando el parámetro $n$ alcanza cifras entre cientos y miles, el tamaño de esta matriz llega a varios megabytes, lo que la hace demasiado pesada para enviar y recibir cada vez a través de protocolos de comunicación en internet (como TLS). Además, la multiplicación de matrices y vectores requiere una complejidad computacional de $\mathcal{O}(n^2)$.&lt;/p>
&lt;p>Para resolver estos problemas se introdujeron el &amp;ldquo;Ring-LWE (RLWE)&amp;rdquo; y el &amp;ldquo;Module-LWE (MLWE)&amp;rdquo;, que incorporan estructuras algebraicas llamadas anillos de polinomios (Polynomial rings) en los retículos.&lt;/p>
&lt;h2 id="71-intuición-de-ring-lwe">7.1 Intuición de Ring-LWE
&lt;/h2>&lt;p>En Ring-LWE, los vectores y matrices se sustituyen por elementos (polinomios) de un anillo de polinomios $\mathcal{R}_q = \mathbb{Z}_q[X]/(X^n + 1)$. (Donde $n$ se elige como una potencia de 2).&lt;/p>
&lt;p>Mientras que la clave pública en Standard LWE era una matriz $A$, en Ring-LWE se utiliza un solo polinomio $a(x)$. La clave secreta $s(x)$ y el error $e(x)$ también se convierten en polinomios.
La ecuación queda de la siguiente manera:
&lt;/p>
$$ b(x) = a(x) \cdot s(x) + e(x) \pmod q $$
&lt;p>Al tratarse de multiplicación de polinomios, utilizando la &amp;ldquo;Transformada Teórica de Números (Number Theoretic Transform: NTT)&amp;rdquo;, que es similar a la Transformada Rápida de Fourier (FFT), la complejidad computacional se puede reducir drásticamente a $\mathcal{O}(n \log n)$. Además, debido a que el tamaño de la clave pública se reduce de una matriz a un solo polinomio, el tamaño de los datos se reduce a $\mathcal{O}(n)$. Esto proporciona una ventaja abrumadora en términos de ancho de banda de comunicación.&lt;/p>
&lt;p>Matemáticamente, Ring-LWE se reduce a problemas en retículos con una simetría especial conocidos como &amp;ldquo;Retículos Ideales (Ideal Lattices)&amp;rdquo; en lugar de retículos generales.&lt;/p>
&lt;h2 id="72-module-lwe-y-estandarización-del-nist-kyber--ml-kem">7.2 Module-LWE y Estandarización del NIST (Kyber / ML-KEM)
&lt;/h2>&lt;p>Aunque Ring-LWE es eficiente, había una ligera preocupación de que la estructura algebraica especial del retículo ideal pudiera ser la base para futuros ataques. Por lo tanto, el &amp;ldquo;Module-LWE (MLWE)&amp;rdquo; tomó &amp;ldquo;lo mejor de ambos mundos&amp;rdquo;: la seguridad conservadora de Standard LWE y la eficiencia de Ring-LWE.&lt;/p>
&lt;p>En Module-LWE, consideramos matrices y vectores pequeños cuyos elementos son polinomios. Es decir, manejamos módulos sobre anillos.
Actualmente, &amp;ldquo;CRYSTALS-Kyber&amp;rdquo; (Nombre estandarizado: ML-KEM), que ha sido seleccionado por el NIST como estándar para el algoritmo de intercambio de claves PQC (KEM), está construido precisamente en base a la dificultad de este problema Module-LWE.&lt;/p>
&lt;h1 id="8-por-qué-es-seguro-contra-las-computadoras-cuánticas">8. ¿Por qué es seguro contra las computadoras cuánticas?
&lt;/h1>&lt;p>Finalmente, tocaremos el núcleo de la pregunta: &amp;ldquo;¿Por qué se cree que la criptografía basada en retículos no se puede descifrar ni siquiera usando computadoras cuánticas?&amp;rdquo;&lt;/p>
&lt;p>El algoritmo de Shor, que hace que las computadoras cuánticas rompan RSA y ECC, es esencialmente un algoritmo para resolver el &amp;ldquo;Problema del Subgrupo Oculto (Hidden Subgroup Problem: HSP)&amp;rdquo;. La estructura matemática (grupos abelianos finitos) detrás de RSA y ECC tiene periodicidad, y al usar una operación cuántica específica llamada Transformada Cuántica de Fourier (QFT), este período (el subgrupo oculto) se puede extraer de una vez.&lt;/p>
&lt;p>Sin embargo, los problemas de retículos son fundamentalmente diferentes. Aunque los retículos también tienen periodicidad, lo que se busca en SVP y CVP son propiedades geométricas no lineales, como la &amp;ldquo;distancia más corta&amp;rdquo; o la &amp;ldquo;eliminación del ruido&amp;rdquo;. Incluso aplicando directamente la &amp;ldquo;Transformada Cuántica de Fourier sobre un grupo abeliano&amp;rdquo; como en el algoritmo de Shor, no se puede extraer eficientemente información útil que resuelva el problema del retículo. Hasta la fecha, no se han descubierto algoritmos cuánticos capaces de resolver SVP o LWE en tiempo polinomial, y se cree ampliamente que, a pesar del poder de cálculo paralelo de las computadoras cuánticas, el único método efectivo es una búsqueda casi exhaustiva (aproximadamente una aceleración de la raíz cuadrada mediante el algoritmo de Grover).&lt;/p>
&lt;h1 id="9-conclusión">9. Conclusión
&lt;/h1>&lt;p>En este artículo, explicamos detalladamente la intuición matemática de la criptografía de retículos, comenzando con la definición geométrica de los retículos, seguido de la formulación del problema LWE, hasta la construcción de la criptografía de clave pública.&lt;/p>
&lt;ol>
&lt;li>Un &lt;strong>Retículo (Lattice)&lt;/strong> es un espacio discreto representado por combinaciones lineales con coeficientes enteros de vectores base, y en altas dimensiones resulta difícil encontrar una &amp;ldquo;buena base&amp;rdquo; casi ortogonal (SVP).&lt;/li>
&lt;li>El &lt;strong>Problema LWE (Learning With Errors)&lt;/strong> es un problema de resolver sistemas de ecuaciones lineales con ruido, y dado que esto está ligado a la dificultad del problema del retículo en el peor de los casos, proporciona una base sólida para la seguridad.&lt;/li>
&lt;li>Utilizando el problema LWE, el cifrado y descifrado (&lt;strong>Criptografía de Regev&lt;/strong>) se logran mediante un ingenioso mecanismo que intencionalmente añade y elimina el ruido.&lt;/li>
&lt;li>En los protocolos reales, se emplean &lt;strong>Ring-LWE&lt;/strong> o &lt;strong>Module-LWE&lt;/strong> usando anillos de polinomios para aumentar la eficiencia de comunicación y la velocidad de cálculo, sirviendo como la base del estándar &lt;strong>ML-KEM&lt;/strong> del NIST.&lt;/li>
&lt;/ol>
&lt;p>Con el cambio de paradigma computacional sin precedentes que representan las computadoras cuánticas acercándose, es muy fascinante que la &amp;ldquo;criptografía de retículos&amp;rdquo;, nacida del abismo del álgebra lineal clásica y la teoría de números, se convierta en la base de la seguridad del internet del futuro. Las matemáticas subyacentes a la criptografía de retículos no son excesivamente complejas, y con conocimientos básicos de álgebra lineal y probabilidades, es perfectamente posible comprender su hermosa estructura. Esperamos que este artículo sirva de ayuda para comprender la criptografía de retículos, el núcleo de la PQC.&lt;/p></description></item><item><title>La Hipótesis de Riemann y la Distribución de los Números Primos: Su Profunda Relación con la Criptografía Moderna</title><link>http://kenji.blog/es/p/riemann-hypothesis-prime-distribution-cryptography/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 La Hipótesis de Riemann y la Distribución de los Números Primos: Su Profunda Relación con la Criptografía Moderna" />&lt;h1 id="1-introducción-el-misterio-cósmico-de-los-números-primos-y-la-hipótesis-de-riemann">1. Introducción: El misterio cósmico de los números primos y la Hipótesis de Riemann
&lt;/h1>&lt;p>Los &amp;ldquo;números primos&amp;rdquo; (Prime Numbers) son números naturales divisibles únicamente por 1 y por sí mismos, y también se les llama los &amp;ldquo;átomos&amp;rdquo; del mundo de las matemáticas. Esta secuencia que continúa con 2, 3, 5, 7, 11, 13&amp;hellip; parece a primera vista aparecer de manera caótica y aleatoria. Desde que el matemático de la antigua Grecia, Euclides, demostró que &amp;ldquo;los números primos son infinitos&amp;rdquo;, innumerables matemáticos han intentado desentrañar la regularidad oculta en esta disposición de números primos.&lt;/p>
&lt;p>Quien más se acercó a este misterio de los números primos fue el matemático alemán Bernhard Riemann, quien en 1859 propuso la &lt;strong>&amp;ldquo;Hipótesis de Riemann&amp;rdquo; (Riemann Hypothesis)&lt;/strong>. La Hipótesis de Riemann es uno de los problemas más importantes y no resueltos de las matemáticas modernas, y tiene una recompensa de 1 millón de dólares al ser uno de los Problemas del Milenio establecidos por el Instituto Clay de Matemáticas.&lt;/p>
&lt;p>A primera vista, un problema tan difícil de matemáticas puras relacionado con la distribución de los números primos puede parecer ajeno a nuestra vida diaria. Sin embargo, la seguridad de Internet que sustenta la infraestructura de la sociedad moderna, en particular &lt;strong>las tecnologías criptográficas modernas como la criptografía RSA y la criptografía de curva elíptica (ECC)&lt;/strong>, dependen profundamente de las propiedades de los números primos gigantes.&lt;/p>
&lt;p>En este artículo, emprenderemos un viaje matemático desde la distribución de los números primos, pasando por el Teorema de los Números Primos, la función zeta de Riemann, hasta llegar al núcleo de la Hipótesis de Riemann. Profundizaremos en detalle sobre cómo se relaciona con la criptografía moderna y qué sucedería en el mundo si se demostrara la Hipótesis de Riemann.&lt;/p>
&lt;hr>
&lt;h1 id="2-el-teorema-de-los-números-primos-y-la-distribución-de-los-números-primos-el-descubrimiento-de-gauss">2. El Teorema de los Números Primos y la distribución de los números primos: El descubrimiento de Gauss
&lt;/h1>&lt;p>Para comprender cómo se distribuyen los números primos, los matemáticos consideraron la &lt;strong>función contadora de números primos (Prime-counting function)&lt;/strong> $\pi(x)$, que representa &amp;ldquo;cuántos números primos existen menores o iguales a un cierto número $x$&amp;rdquo;.&lt;/p>
&lt;p>Por ejemplo:&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>El matemático prodigio de 15 años Carl Friedrich Gauss calculó tablas masivas de números primos y descubrió que la frecuencia de aparición de los números primos disminuye en proporción inversa al logaritmo natural $\ln x$. En otras palabras, conjeturó que la probabilidad de encontrar un número primo cerca de un cierto número $x$ es aproximadamente $\frac{1}{\ln x}$.&lt;/p>
&lt;p>La expresión de esto utilizando integrales es la &lt;strong>integral logarítmica (Logarithmic integral)&lt;/strong> $\text{Li}(x)$.&lt;/p>
$$ \text{Li}(x) = \int_{2}^{x} \frac{dt}{\ln t} $$
&lt;p>La conjetura de Gauss fue demostrada de forma independiente en 1896 por Jacques Hadamard y Charles-Jean de La Vallée Poussin, y se estableció como el &lt;strong>Teorema de los Números Primos (Prime Number Theorem, PNT)&lt;/strong>.&lt;/p>
$$ \lim_{x \to \infty} \frac{\pi(x)}{\text{Li}(x)} = 1 $$
&lt;p>O se expresa de manera aproximada de la siguiente forma:&lt;/p>
$$ \pi(x) \sim \frac{x}{\ln x} $$
&lt;p>Gracias a este teorema, sabemos que, a nivel macroscópico, los números primos tienen una distribución muy suave y predecible. Sin embargo, a nivel microscópico, siempre existe un &amp;ldquo;error&amp;rdquo; o &amp;ldquo;fluctuación&amp;rdquo; entre $\pi(x)$ y $\text{Li}(x)$. La verdadera naturaleza de esta fluctuación es exactamente el mayor misterio que la Hipótesis de Riemann intenta desentrañar.&lt;/p>
&lt;hr>
&lt;h1 id="3-la-función-zeta-de-riemann-y-el-producto-de-euler">3. La función zeta de Riemann y el producto de Euler
&lt;/h1>&lt;p>El arma más poderosa para analizar la distribución de los números primos es la &lt;strong>función zeta de Riemann (Riemann Zeta Function)&lt;/strong>. Originalmente fue una serie infinita definida por Leonhard Euler para números reales $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>Uno de los mayores logros de Euler fue demostrar que esta serie infinita podía expresarse como un producto infinito sobre todos los números primos $p$. Este es el &lt;strong>producto 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>Una comprensión intuitiva de la demostración es que si expandimos cada término del lado derecho como una serie geométrica y los multiplicamos, gracias al teorema fundamental de la aritmética (todo número natural se puede expresar de forma única como el producto de números primos), se reconstruye completamente la suma de los recíprocos de los números naturales en el lado izquierdo.&lt;/p>
&lt;p>&lt;strong>Esta única fórmula se convirtió en el puente que conecta el análisis matemático (series infinitas y funciones continuas) y la teoría de números (números primos y números discretos).&lt;/strong> Estudiar la función zeta es sinónimo de estudiar la distribución de los números primos.&lt;/p>
&lt;hr>
&lt;h1 id="4-continuación-analítica-y-la-extensión-al-plano-complejo">4. Continuación analítica y la extensión al plano complejo
&lt;/h1>&lt;p>La genialidad de Riemann radica en haber extendido la variable $s$ de $\zeta(s)$, que Euler había considerado únicamente para números reales, a &lt;strong>números complejos $s = \sigma + it$ ($\sigma$ es la parte real, $t$ es la parte imaginaria)&lt;/strong>.&lt;/p>
&lt;p>La serie infinita original converge solo para $\sigma > 1$, pero Riemann utilizó una técnica llamada &amp;ldquo;continuación analítica&amp;rdquo; (Analytic Continuation) para extender la definición de manera que $\zeta(s)$ tenga sentido en todo el plano complejo, excluyendo el polo en $s = 1$.&lt;/p>
&lt;p>Además, dedujo una hermosa ecuación funcional (Functional equation) que satisface la función zeta.&lt;/p>
$$ \zeta(s) = 2^s \pi^{s-1} \sin\left(\frac{\pi s}{2}\right) \Gamma(1-s) \zeta(1-s) $$
&lt;p>Donde $\Gamma(x)$ es la función gamma. A través de esta ecuación, podemos conocer las propiedades del semiplano izquierdo a partir de las propiedades del semiplano derecho.&lt;/p>
&lt;h3 id="ceros-de-la-función-zeta-zeros-of-the-zeta-function">Ceros de la Función Zeta (Zeros of the Zeta Function)
&lt;/h3>&lt;p>Los números complejos $s$ para los cuales el valor de la función zeta se vuelve 0 se denominan &amp;ldquo;ceros&amp;rdquo;.
A partir de la ecuación funcional, cuando $s$ es un número par negativo ($-2, -4, -6, \dots$), dado que $\sin(\pi s / 2)$ se vuelve 0, se tiene $\zeta(s) = 0$. Estos se conocen como &lt;strong>ceros triviales (Trivial zeros)&lt;/strong>.&lt;/p>
&lt;p>Sin embargo, lo que es importante para la distribución de los números primos son los otros ceros, es decir, los &lt;strong>ceros no triviales (Non-trivial zeros)&lt;/strong> que existen en la &amp;ldquo;banda crítica&amp;rdquo; (Critical strip) donde $0 \le \sigma \le 1$.&lt;/p>
&lt;hr>
&lt;h1 id="5-el-núcleo-de-la-hipótesis-de-riemann-y-la-fórmula-explícita">5. El núcleo de la Hipótesis de Riemann y la fórmula explícita
&lt;/h1>&lt;p>Riemann calculó unos pocos ceros y formuló una conjetura sorprendente. Esta es la &lt;strong>Hipótesis de Riemann&lt;/strong>.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Hipótesis de Riemann (Riemann Hypothesis)&lt;/strong>
Todos los ceros no triviales de la función zeta de Riemann $\zeta(s)$ se encuentran en la línea recta donde la parte real es igual a $1/2$ ($\text{Re}(s) = 1/2$).&lt;/p>
&lt;/blockquote>
&lt;p>A esta recta donde la parte real es 1/2 se le llama la &amp;ldquo;línea crítica&amp;rdquo; (Critical line).&lt;/p>
&lt;div class="mermaid">graph TD
A["Función zeta de Riemann ζ(s)"] --> B["Extensión al plano complejo mediante continuación analítica"]
B --> C["Ceros triviales (s = -2, -4, -6 ...)"]
B --> D["Ceros no triviales (0 &lt;= Re(s) &lt;= 1)"]
D --> E["Hipótesis de Riemann"]
E --> F["Todos los ceros no triviales están en Re(s) = 1/2"]
F --> G["Hacia la demostración del límite del término de error de la distribución de primos"]&lt;/div>
&lt;p>¿Por qué es tan importante la Hipótesis de Riemann? Porque los ceros de la función zeta determinan &lt;strong>completamente&lt;/strong> la distribución de los números primos.&lt;/p>
&lt;p>Riemann y el posterior matemático von Mangoldt derivaron una &amp;ldquo;fórmula explícita&amp;rdquo; (Explicit formula) que describe con precisión la distribución de los números primos. Utilizando la función de Chebyshev $\psi(x)$, se expresa de la siguiente manera:&lt;/p>
$$ \psi(x) = x - \sum_{\rho} \frac{x^\rho}{\rho} - \ln(2\pi) - \frac{1}{2}\ln(1 - x^{-2}) $$
&lt;p>Aquí, $\rho$ es la suma sobre todos los ceros no triviales de la función zeta.
El término principal es $x$ (que corresponde al Teorema de los Números Primos), y al sumar y restar los términos ondulatorios que dependen de los ceros $\rho$, se restaura la distribución precisa en forma de escalera de los números primos. Se puede decir que los ceros no triviales representan la &amp;ldquo;frecuencia (onda)&amp;rdquo; de la distribución de los números primos.&lt;/p>
&lt;p>Si la Hipótesis de Riemann es correcta y la parte real de todos los ceros no triviales $\rho$ es exactamente $1/2$, entonces el término de error del Teorema de los Números Primos se mantendrá dentro del rango mínimo teóricamente concebible.&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>En otras palabras, &lt;strong>si la Hipótesis de Riemann es verdadera, se demuestra que los números primos están distribuidos de la manera más &amp;ldquo;regular y hermosa&amp;rdquo; que podamos imaginar&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="6-la-relación-inseparable-entre-la-criptografía-moderna-y-los-números-primos">6. La relación inseparable entre la criptografía moderna y los números primos
&lt;/h1>&lt;p>Hasta aquí hemos estado en el profundo mundo de las matemáticas puras, pero las propiedades de estos números primos sostienen desde sus cimientos a la sociedad digital moderna. El principal representante de esto es la criptografía de clave pública, liderada por la &lt;strong>criptografía RSA&lt;/strong>.&lt;/p>
&lt;p>La seguridad de todas las comunicaciones, como los pagos con tarjeta de crédito en Internet, la transmisión de contraseñas y las firmas digitales de blockchain, depende de los &amp;ldquo;números primos&amp;rdquo;.&lt;/p>
&lt;h3 id="funcionamiento-de-la-criptografía-rsa">Funcionamiento de la criptografía RSA
&lt;/h3>&lt;p>La seguridad de la criptografía RSA se basa en el hecho matemático de que &amp;ldquo;la factorización en números primos de números compuestos de muchos dígitos es extremadamente difícil&amp;rdquo; (el problema de la factorización de enteros).&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Generación de claves&lt;/strong>:
Se eligen aleatoriamente dos números primos gigantes, $p$ y $q$ (por ejemplo, de 2048 bits cada uno).
Se multiplican para calcular $N = p \times q$. Este $N$ se convierte en parte de la clave pública.
Utilizando la función indicatriz de Euler $\phi(N) = (p-1)(q-1)$, se genera la clave privada $d$.&lt;/p>
$$ e \times d \equiv 1 \pmod{\phi(N)} $$
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Cifrado y descifrado&lt;/strong>:
El texto plano $M$ se transforma en el texto cifrado $C$ utilizando la clave pública $e, N$.
&lt;/p>
$$ C \equiv M^e \pmod{N} $$
&lt;p>
Solo quien posee la clave privada $d$ puede descifrarlo.
&lt;/p>
$$ M \equiv C^d \pmod{N} $$
&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph LR
A["Texto plano (Plaintext)"] --> B["Cifrado con clave pública (e, N)"]
B --> C["Texto cifrado (Ciphertext)"]
C --> D["Descifrado con clave privada (d)"]
D --> E["Texto plano original"]
F["Atacante (Attacker)"] -- "Intenta la factorización prima de N" --> C
F -.-> G["Si p y q son desconocidos, d es incalculable"]&lt;/div>
&lt;p>Para romper la criptografía RSA, es necesario encontrar los números primos originales $p$ y $q$ a partir del enorme $N$ (factorización prima). Incluso utilizando los algoritmos convencionales actuales (como la criba general del cuerpo de números: GNFS, por sus siglas en inglés), factorizar un número de cientos de dígitos tomaría un tiempo que supera con creces la edad del universo, incluso utilizando supercomputadoras.&lt;/p>
&lt;hr>
&lt;h1 id="7-el-impacto-de-la-hipótesis-de-riemann-en-la-criptografía">7. El impacto de la Hipótesis de Riemann en la criptografía
&lt;/h1>&lt;p>Entonces, ¿cómo se cruzan la &amp;ldquo;Hipótesis de Riemann&amp;rdquo;, que se encuentra en la cima de las matemáticas puras, y la &amp;ldquo;criptografía&amp;rdquo;?&lt;/p>
&lt;h3 id="71-algoritmos-de-generación-de-números-primos-test-de-primalidad-y-la-hipótesis-generalizada-de-riemann-grh">7.1. Algoritmos de generación de números primos (test de primalidad) y la Hipótesis Generalizada de Riemann (GRH)
&lt;/h3>&lt;p>Para operar la criptografía RSA, primero es necesario generar los primos gigantes $p$ y $q$. Sin embargo, no es fácil determinar de manera segura y rápida si &amp;ldquo;un número es primo o no&amp;rdquo;.&lt;/p>
&lt;p>Actualmente, lo que se utiliza de forma práctica es un algoritmo probabilístico llamado el &lt;strong>test de primalidad de Miller-Rabin (Miller-Rabin primality test)&lt;/strong>. Este algoritmo es rápido, pero conlleva el riesgo de identificar incorrectamente un número compuesto como primo con una probabilidad extremadamente baja (un &amp;ldquo;pseudoprimo&amp;rdquo;).&lt;/p>
&lt;p>Sin embargo, si asumimos como cierta la &lt;strong>&amp;ldquo;Hipótesis Generalizada de Riemann&amp;rdquo; (Generalized Riemann Hypothesis, GRH)&lt;/strong>, que extiende la Hipótesis de Riemann a las funciones L de Dirichlet, la historia cambia drásticamente.
Si la GRH es verdadera, se garantiza matemáticamente un límite superior en el número de pruebas en el test de Miller-Rabin, elevándolo de un algoritmo probabilístico a un &lt;strong>&amp;ldquo;algoritmo determinista de tiempo polinómico&amp;rdquo;&lt;/strong> (este era un hecho crucial conocido incluso antes de que se descubriera el test de primalidad AKS).&lt;/p>
&lt;p>En otras palabras, la Hipótesis de Riemann (y sus generalizaciones) desempeña el papel de otorgar una garantía directa a la creación de los cimientos de la criptografía: &amp;ldquo;si es posible generar números primos gigantes a gran velocidad y con absoluta confianza&amp;rdquo;.&lt;/p>
&lt;h3 id="72-relación-con-los-algoritmos-de-factorización">7.2. Relación con los algoritmos de factorización
&lt;/h3>&lt;p>A la hora de evaluar la complejidad computacional de los algoritmos de quienes intentan descifrar la criptografía (como la criba general del cuerpo de números), también es indispensable el conocimiento sobre la distribución de los números primos. Muchos algoritmos de factorización dependen de la distribución de &amp;ldquo;números lisos&amp;rdquo; (Smooth numbers: números que solo tienen factores primos pequeños).&lt;/p>
&lt;p>Para evaluar rigurosamente con qué frecuencia aparecen los números lisos, se requiere una profunda comprensión de la distribución de los números primos, y es aquí donde también se emplean técnicas de teoría analítica de números que están directamente vinculadas a la función zeta y a la Hipótesis de Riemann. Si se demuestra la Hipótesis de Riemann y se determina completamente el error en la distribución de los números primos, también será posible identificar de manera más precisa los límites de rendimiento de los algoritmos de factorización en números primos.&lt;/p>
&lt;hr>
&lt;h1 id="8-si-se-demuestra-la-hipótesis-de-riemann-se-romperá-la-criptografía">8. Si se demuestra la Hipótesis de Riemann, ¿se romperá la criptografía?
&lt;/h1>&lt;p>A veces se cuenta como una leyenda urbana que &amp;ldquo;si se resuelve la Hipótesis de Riemann, la criptografía RSA colapsará en un instante&amp;rdquo;, pero &lt;strong>esto es matemáticamente inexacto&lt;/strong>.&lt;/p>
&lt;p>La demostración de la Hipótesis de Riemann en sí misma no produciría inmediatamente un algoritmo mágico que acelere drásticamente la factorización de números primos. Esto se debe a que la Hipótesis de Riemann es simplemente un teorema sobre la &amp;ldquo;regularidad de la distribución macroscópica&amp;rdquo; de los números primos, y no nos indica directamente qué números primos dividen a un número particular $N$ (propiedad local).&lt;/p>
&lt;p>Sin embargo, el impacto no es nulo.
Existe una probabilidad extremadamente alta de que, en el proceso de demostrar la Hipótesis de Riemann, se descubran &lt;strong>&amp;ldquo;nuevas herramientas matemáticas&amp;rdquo; y &amp;ldquo;métodos analíticos desconocidos&amp;rdquo;&lt;/strong>. Si observamos la historia, cuando se demostró el Último Teorema de Fermat o la Conjetura de Poincaré, las nuevas teorías desarrolladas en el proceso hicieron avanzar enormemente a todas las matemáticas.&lt;/p>
&lt;p>Si se establecen métodos desconocidos de geometría algebraica o geometría no conmutativa que puedan manipular por completo las propiedades de los ceros de la función zeta de Riemann, no se puede descartar la posibilidad de que conduzcan al descubrimiento de algoritmos de factorización innovadores (por ejemplo, algoritmos clásicos que reduzcan la complejidad computacional a tiempo polinómico). En ese sentido, los criptógrafos nunca pueden quitarle los ojos de encima al progreso de la Hipótesis de Riemann.&lt;/p>
&lt;h3 id="las-computadoras-cuánticas-y-el-algoritmo-de-shor">Las computadoras cuánticas y el algoritmo de Shor
&lt;/h3>&lt;p>Una amenaza más directa y realista para la criptografía no es la demostración de la Hipótesis de Riemann, sino &lt;strong>las computadoras cuánticas&lt;/strong>. El &amp;ldquo;algoritmo de Shor&amp;rdquo;, publicado por Peter Shor en 1994, demostró que si existiera una computadora cuántica con suficiente capacidad, la factorización en números primos podría resolverse en tiempo polinómico. Con esto, la criptografía RSA y la criptografía de curva elíptica quedarían fundamentalmente rotas.&lt;/p>
&lt;p>Actualmente, en todo el mundo se está promoviendo la transición hacia la &amp;ldquo;criptografía post-cuántica (Post-Quantum Cryptography, PQC)&amp;rdquo; (como la criptografía basada en retículos), que no puede ser descifrada ni siquiera por computadoras cuánticas. La tecnología criptográfica que depende de los números primos puede, en cierto sentido, estar llegando al final de su edad de oro, pero el valor matemático de los números primos en sí mismos nunca se perderá.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusión-la-intersección-entre-la-abstracción-matemática-y-la-sociedad-real">9. Conclusión: La intersección entre la abstracción matemática y la sociedad real
&lt;/h1>&lt;div class="mermaid">graph TD
A["Búsqueda en las matemáticas puras"] --> B["Resolución de la Hipótesis de Riemann"]
B --> C["Comprensión completa de la distribución de números primos"]
C --> D["Desarrollo espectacular de la teoría de números y geometría algebraica"]
D -.-> E["Posibilidad de nuevos algoritmos de factorización prima"]
E -.-> F["Actualización de la evaluación de seguridad de la criptografía"]
A --> G["Matemáticas aplicadas e informática"]
G --> H["Mejora en la eficiencia del test de primalidad y generación criptográfica"]
H --> F&lt;/div>
&lt;p>La incansable búsqueda sobre los números primos que continúa desde la antigua Grecia fue sublimada en una hermosa sinfonía sobre el plano complejo (los ceros de la función zeta) por un genio llamado Riemann. Y sorprendentemente, ese cristal de matemáticas puras y puristas se está aplicando, siglos después, como el escudo más fuerte para garantizar la seguridad de la sociedad de Internet.&lt;/p>
&lt;p>La Hipótesis de Riemann es una entidad que simboliza simultáneamente la &amp;ldquo;belleza abstracta&amp;rdquo; que poseen las matemáticas y su &amp;ldquo;asombrosa aplicabilidad al mundo físico y a la sociedad real&amp;rdquo;.&lt;/p>
&lt;p>Cuando esta gigantesca montaña matemática, a cuya cima aún nadie ha llegado, sea conquistada algún día, comprenderemos por completo la verdad cósmica de los números primos, y al mismo tiempo obtendremos una nueva perspectiva sobre los cimientos de la sociedad de la información. Aprender sobre criptografía es, de hecho, un viaje que recorre la historia de la sabiduría de la humanidad.&lt;/p></description></item><item><title>Historia de la criptografía: del cifrado César a la criptografía poscuántica (PQC)</title><link>http://kenji.blog/es/p/history-of-cryptography-caesar-to-pqc/</link><pubDate>Fri, 11 Sep 2026 15:00:00 +0900</pubDate><guid>http://kenji.blog/es/p/history-of-cryptography-caesar-to-pqc/</guid><description>&lt;img src="http://kenji.blog/p/history-of-cryptography-caesar-to-pqc/img/eyecatch.jpg" alt="Featured image of post Historia de la criptografía: del cifrado César a la criptografía poscuántica (PQC)" />&lt;h1 id="1-introducción-qué-es-la-criptografía">1. Introducción: ¿Qué es la criptografía?
&lt;/h1>&lt;p>La criptografía (Cryptography) es la tecnología utilizada para mantener el secreto de la información y ha evolucionado junto con la historia de la humanidad. Desde la transmisión de órdenes secretas en las guerras antiguas hasta la protección de la información de tarjetas de crédito en el internet moderno, el propósito de la criptografía ha sido constante. Es &amp;ldquo;garantizar que solo el destinatario previsto pueda entender la información y que no pueda ser descifrada por terceros&amp;rdquo;.&lt;/p>
&lt;p>En la seguridad de la información moderna, la criptografía no se limita simplemente al &amp;ldquo;secreto de la información (Confidencialidad: Confidentiality)&amp;rdquo;, sino que desempeña roles cruciales como la &amp;ldquo;Integridad (Integrity)&amp;rdquo;, la &amp;ldquo;Autenticación (Authentication)&amp;rdquo; y el &amp;ldquo;No repudio (Non-repudiation)&amp;rdquo; de los datos.&lt;/p>
&lt;p>En este artículo, desentrañaremos en detalle la historia de la evolución de la criptografía desde una perspectiva técnica y matemática, comenzando desde los simples cifrados de sustitución de la antigüedad, pasando por los cifrados mecánicos, la criptografía moderna de clave simétrica y pública, hasta llegar a la era de la &amp;ldquo;criptografía poscuántica (PQC)&amp;rdquo;, que llegará con la implementación práctica de las computadoras cuánticas.&lt;/p>
&lt;hr>
&lt;h1 id="2-la-era-de-la-criptografía-clásica-sustitución-y-transposición-de-caracteres">2. La era de la criptografía clásica: sustitución y transposición de caracteres
&lt;/h1>&lt;p>Los orígenes de la criptografía se remontan a antes de Cristo. Los primeros cifrados consistían principalmente en dos enfoques: &amp;ldquo;transposición (reordenamiento)&amp;rdquo; y &amp;ldquo;sustitución (reemplazo)&amp;rdquo;.&lt;/p>
&lt;h2 id="cifrado-escítala-cifrado-de-transposición">Cifrado Escítala (Cifrado de transposición)
&lt;/h2>&lt;p>La &amp;ldquo;Escítala (Scytale)&amp;rdquo;, utilizada en la antigua Esparta de Grecia en el siglo V a.C., es uno de los dispositivos criptográficos más antiguos. Se enrollaba una tira de pergamino larga y estrecha alrededor de un bastón de madera de un grosor específico, y el mensaje se escribía transversalmente en él. Al desenrollar el pergamino, las letras aparecían en un orden sin sentido, pero el destinatario, al tener un bastón del mismo grosor y volver a enrollar el pergamino, podía leer el mensaje original.&lt;/p>
&lt;h2 id="cifrado-césar-cifrado-de-sustitución-monoalfabética">Cifrado César (Cifrado de sustitución monoalfabética)
&lt;/h2>&lt;p>Se dice que en el siglo I a.C., el héroe de la antigua Roma, Julio César, utilizó el &amp;ldquo;cifrado César&amp;rdquo;. Este es un cifrado de sustitución monoalfabética (Monoalphabetic substitution) que desplaza el alfabeto un número fijo de posiciones (generalmente 3 letras).&lt;/p>
&lt;p>Matemáticamente, tratando las letras como valores numéricos del $0$ al $25$ y dejando que el número de desplazamientos sea $K$, la conversión de texto plano $P$ a texto cifrado $C$ se expresa mediante la siguiente congruencia:&lt;/p>
$$C \equiv P + K \pmod{26}$$
&lt;p>El descifrado realiza la operación inversa:&lt;/p>
$$P \equiv C - K \pmod{26}$$
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ejemplo simple de implementación del cifrado César en Python&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;encrypt&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">mode&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;decrypt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">shift&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">shift&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">char&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">text&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isalpha&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">char&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isupper&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cálculo del desplazamiento&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="nb">chr&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nb">ord&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">char&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">base&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">shift&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">26&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">char&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ejemplo de ejecución&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">plaintext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;HELLO WORLD&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">caesar_cipher&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">plaintext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;encrypt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># KHOOR ZRUOG&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="análisis-de-frecuencias-y-el-cifrado-vigenère">Análisis de frecuencias y el cifrado Vigenère
&lt;/h2>&lt;p>Los cifrados de sustitución monoalfabética se volvieron fáciles de descifrar mediante el &amp;ldquo;análisis de frecuencias (Frequency Analysis)&amp;rdquo;, ideado por el erudito árabe Al-Kindi en el siglo IX. Aprovecha las propiedades estadísticas del idioma, como la alta frecuencia de aparición de las letras &amp;ldquo;E&amp;rdquo; y &amp;ldquo;T&amp;rdquo; en inglés.&lt;/p>
&lt;p>Para contrarrestar esto, en el siglo XVI se ideó el &amp;ldquo;cifrado Vigenère (Vigenère cipher)&amp;rdquo;. Este es un cifrado de sustitución polialfabética (Polyalphabetic substitution) que utiliza múltiples desplazamientos (claves) cambiando periódicamente, y fue llamado &amp;ldquo;El cifrado indescifrable (Le Chiffre Indéchiffrable)&amp;rdquo; durante unos 300 años.&lt;/p>
&lt;p>Matemáticamente, se cifra utilizando la $i$-ésima letra del texto plano $P_i$ y la $i$-ésima letra de la clave repetida $K_i$ de la siguiente manera:&lt;/p>
$$C_i \equiv P_i + K_i \pmod{26}$$
&lt;p>Sin embargo, este cifrado también fue descifrado en el siglo XIX, cuando Charles Babbage y Friedrich Kasiski descubrieron el &amp;ldquo;examen Kasiski (Kasiski examination)&amp;rdquo;, que deduce la longitud de la clave a partir de patrones repetidos en el texto cifrado.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Clasificación de la criptografía clásica"
A["Criptografía clásica"] --> B["Cifrado de transposición"]
A --> C["Cifrado de sustitución"]
B --> D["Cifrado Escítala"]
C --> E["Sustitución monoalfabética"]
C --> F["Sustitución polialfabética"]
E --> G["Cifrado César"]
F --> H["Cifrado Vigenère"]
end&lt;/div>
&lt;hr>
&lt;h1 id="3-criptografía-mecánica-y-guerras-mundiales-enigma-y-su-descifrado">3. Criptografía mecánica y guerras mundiales: Enigma y su descifrado
&lt;/h1>&lt;p>En el siglo XX, a medida que los medios de comunicación pasaron de las cartas al telégrafo y la radio, se requería mayor velocidad y complejidad en el cifrado. Fue aquí donde apareció la &amp;ldquo;criptografía mecánica&amp;rdquo;, que combinaba rotores (discos giratorios).&lt;/p>
&lt;h2 id="la-amenaza-de-enigma">La amenaza de Enigma
&lt;/h2>&lt;p>Durante la Segunda Guerra Mundial, la Alemania nazi utilizó &amp;ldquo;Enigma&amp;rdquo;, la máquina de cifrado más famosa en la historia de la criptografía. Enigma constaba de múltiples rotores (generalmente de 3 a 4), un panel de conexiones (Steckerbrett) que intercambiaba el cableado de las letras, y un reflector (rotor de inversión).&lt;/p>
&lt;p>Dado que los rotores giraban cada vez que se escribía una letra en el teclado, incluso si se escribía la misma letra consecutivamente, se emitían diferentes letras cifradas (el pináculo de la criptografía polialfabética). Su espacio de claves (combinaciones de configuraciones) era de aproximadamente $1.58 \times 10^{19}$ (unos 15,8 trillones), y se consideraba imposible de descifrar por fuerza bruta con la tecnología de la época.&lt;/p>
&lt;h2 id="alan-turing-y-la-bombe">Alan Turing y la &amp;ldquo;Bombe&amp;rdquo;
&lt;/h2>&lt;p>El equipo de descifrado británico de Bletchley Park, basándose en los logros iniciales de matemáticos polacos como Marian Rejewski, desafió a la inexpugnable Enigma.&lt;/p>
&lt;p>En particular, Alan Turing (Alan Turing) utilizó conjeturas de texto plano que correspondían a partes del texto cifrado (Crib) para desarrollar la &amp;ldquo;Bombe (Bombe)&amp;rdquo;, una máquina de descifrado electromecánica. La Bombe detectaba rápidamente contradicciones lógicas, descartando rápidamente configuraciones imposibles de los rotores y teniendo éxito en descifrar Enigma. Se dice que este logro adelantó la victoria de los Aliados en varios años.&lt;/p>
&lt;hr>
&lt;h1 id="4-el-amanecer-de-la-criptografía-moderna-criptografía-de-clave-simétrica-des-y-aes">4. El amanecer de la criptografía moderna: criptografía de clave simétrica (DES y AES)
&lt;/h1>&lt;p>Después de la guerra, con la llegada de las computadoras, la criptografía experimentó un cambio de paradigma drástico, pasando de la manipulación de &amp;ldquo;caracteres&amp;rdquo; a la manipulación de &amp;ldquo;bits (0 y 1)&amp;rdquo;.&lt;/p>
&lt;h2 id="claude-shannon-y-la-teoría-de-la-información">Claude Shannon y la teoría de la información
&lt;/h2>&lt;p>En 1949, Claude Shannon publicó el artículo &amp;ldquo;Teoría de la comunicación de los sistemas secretos&amp;rdquo;, sentando las bases matemáticas de la criptografía moderna. Propuso la &amp;ldquo;confusión (Confusion)&amp;rdquo; y la &amp;ldquo;difusión (Diffusion)&amp;rdquo; como principios para un diseño criptográfico seguro.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Confusión (Confusion)&lt;/strong>: Hacer que la relación entre la clave y el texto cifrado sea lo más compleja posible. (Logrado mediante sustitución/cajas S)&lt;/li>
&lt;li>&lt;strong>Difusión (Diffusion)&lt;/strong>: Hacer que un cambio de 1 bit en el texto plano afecte a muchos bits en el texto cifrado. (Logrado mediante transposición/permutación)&lt;/li>
&lt;/ul>
&lt;h2 id="des-data-encryption-standard">DES (Data Encryption Standard)
&lt;/h2>&lt;p>En 1977, el Instituto Nacional de Estándares y Tecnología de EE. UU. (NIST, entonces NBS) estableció &amp;ldquo;DES&amp;rdquo;, basado en un diseño de IBM, como estándar criptográfico.
DES adoptó una arquitectura llamada &amp;ldquo;Red de Feistel (Feistel Network)&amp;rdquo; y tenía un tamaño de bloque de 64 bits y una longitud de clave de 56 bits. Tenía la ventaja de implementación de que los algoritmos de cifrado y descifrado tenían estructuras casi idénticas.&lt;/p>
&lt;p>Sin embargo, a medida que aumentaba el poder de cálculo de las computadoras, se hizo evidente que una longitud de clave de 56 bits (aproximadamente $7.2 \times 10^{16}$ combinaciones) era insuficiente. En 1998, la Electronic Frontier Foundation (EFF) desarrolló una máquina dedicada llamada &amp;ldquo;Deep Crack&amp;rdquo; y demostró que podía descifrar DES en unos pocos días.&lt;/p>
&lt;h2 id="aes-advanced-encryption-standard">AES (Advanced Encryption Standard)
&lt;/h2>&lt;p>Como nuevo estándar para reemplazar a DES, en 2001 se estableció &amp;ldquo;AES&amp;rdquo;. Se adoptó el algoritmo &amp;ldquo;Rijndael&amp;rdquo;, creado por criptógrafos belgas y elegido a través de un concurso público.&lt;/p>
&lt;p>AES adoptó la &amp;ldquo;Red de Sustitución-Permutación (SPN: Substitution-Permutation Network)&amp;rdquo; en lugar de la red de Feistel y utiliza operaciones matemáticas sobre el cuerpo de Galois (cuerpo finito) $GF(2^8)$. La longitud de la clave se puede elegir entre 128, 192 y 256 bits, y todavía se utiliza ampliamente en todo el mundo como la criptografía de clave simétrica estándar.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Procesamiento de 1 ronda de AES (Estructura SPN)"
A["Estado de entrada (128-bit)"] --> B("SubBytes (Sustitución de bytes / S-Box)")
B --> C("ShiftRows (Desplazamiento de filas)")
C --> D("MixColumns (Mezcla de columnas / Multiplicación sobre GF(2^8))")
D --> E("AddRoundKey (XOR con clave de ronda)")
E --> F["A la siguiente ronda"]
end&lt;/div>
&lt;hr>
&lt;h1 id="5-la-revolución-de-la-criptografía-de-clave-pública-de-diffie-hellman-a-rsa">5. La revolución de la criptografía de clave pública: de Diffie-Hellman a RSA
&lt;/h1>&lt;p>La criptografía de clave simétrica tenía una debilidad fatal. Ese era el &amp;ldquo;Problema de distribución de claves (Key Distribution Problem)&amp;rdquo;. Este es el problema de cómo compartir de forma segura una &amp;ldquo;clave común&amp;rdquo; con una parte lejana antes de iniciar una comunicación cifrada. La &amp;ldquo;criptografía de clave pública&amp;rdquo;, nacida en la década de 1970, resolvió este problema.&lt;/p>
&lt;h2 id="intercambio-de-claves-diffie-hellman">Intercambio de claves Diffie-Hellman
&lt;/h2>&lt;p>En 1976, Whitfield Diffie y Martin Hellman publicaron el artículo pionero &amp;ldquo;New Directions in Cryptography&amp;rdquo;. Propusieron un método para compartir claves de forma segura incluso en un canal de comunicación interceptado, explotando la dificultad matemática del &amp;ldquo;Problema del logaritmo discreto (Discrete Logarithm Problem)&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>Se publican un número primo grande $p$ y un generador $g$.&lt;/li>
&lt;li>Alice elige un valor secreto $a$ y envía $A = g^a \pmod{p}$ a Bob.&lt;/li>
&lt;li>Bob elige un valor secreto $b$ y envía $B = g^b \pmod{p}$ a Alice.&lt;/li>
&lt;li>Alice calcula $K = B^a \pmod{p}$ y Bob calcula $K = A^b \pmod{p}$.&lt;/li>
&lt;li>Por las leyes de los exponentes, $K = (g^b)^a = (g^a)^b = g^{ab} \pmod{p}$, y comparten con éxito la misma clave $K$.&lt;/li>
&lt;/ol>
&lt;h2 id="criptografía-rsa">Criptografía RSA
&lt;/h2>&lt;p>Al año siguiente, en 1977, Ron Rivest, Adi Shamir y Leonard Adleman idearon la &amp;ldquo;Criptografía RSA&amp;rdquo;. Se basa en la propiedad de que &amp;ldquo;la factorización de números primos de números compuestos enormes es difícil&amp;rdquo;.&lt;/p>
&lt;p>&lt;strong>Mecanismo matemático de RSA:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>Se eligen dos números primos enormes $p$ y $q$, y se calcula $n = p \times q$.&lt;/li>
&lt;li>Se calcula la función totiente de Euler $\phi(n) = (p-1)(q-1)$.&lt;/li>
&lt;li>Se elige un entero $e$ (clave pública) que sea coprimo con $\phi(n)$.&lt;/li>
&lt;li>Se calcula un entero $d$ (clave privada) de modo que $e \times d \equiv 1 \pmod{\phi(n)}$.&lt;/li>
&lt;/ol>
&lt;p>Cifrado: Para un texto plano $M$, $C \equiv M^e \pmod{n}$
Descifrado: Para un texto cifrado $C$, $M \equiv C^d \pmod{n}$&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Código Python que muestra el concepto de la criptografía RSA (no para uso práctico)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cálculo del inverso modular mediante el algoritmo de Euclides extendido&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">g&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">rsa_example&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Ejemplo utilizando números primos pequeños&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">p&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">61&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">53&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">phi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">17&lt;/span> &lt;span class="c1"># Valor coprimo con phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ext_euclid&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">phi&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">phi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Clave pública: (e=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, n=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">)&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Clave privada: (d=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, n=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">)&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Cifrado y descifrado de mensajes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">65&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ciphertext&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">decrypted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">pow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Texto plano: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; Texto cifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">ciphertext&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; Descifrado: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">decrypted&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">rsa_example&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h1 id="6-el-auge-de-la-criptografía-de-curva-elíptica-ecc">6. El auge de la criptografía de curva elíptica (ECC)
&lt;/h1>&lt;p>Aunque la criptografía RSA es poderosa, a medida que el rendimiento de las computadoras ha mejorado, se ha vuelto necesario utilizar longitudes de clave más largas (actualmente 2048 o 3072 bits) para mantener la seguridad, lo que aumenta los costos de cálculo.&lt;/p>
&lt;p>Por lo tanto, en 1985 se propuso la &amp;ldquo;Criptografía de curva elíptica (Elliptic Curve Cryptography: ECC)&amp;rdquo;. Esto utiliza la suma de puntos en curvas elípticas (generalmente en la forma $y^2 = x^3 + ax + b$) sobre cuerpos finitos.&lt;/p>
&lt;p>Se sabe que el problema del logaritmo discreto de curva elíptica (ECDLP) es aún más difícil de resolver que el problema de factorización de enteros, y &lt;strong>la misma seguridad que RSA de 3072 bits se puede lograr con ECC utilizando una longitud de clave de solo 256 bits&lt;/strong>. Esto ha permitido una comunicación cifrada rápida y segura (como ECDSA y ECDH) incluso en entornos con recursos informáticos limitados, como teléfonos inteligentes y dispositivos IoT.&lt;/p>
&lt;hr>
&lt;h1 id="7-la-amenaza-de-las-computadoras-cuánticas-y-la-criptografía-poscuántica-pqc">7. La amenaza de las computadoras cuánticas y la criptografía poscuántica (PQC)
&lt;/h1>&lt;p>Aunque la tecnología criptográfica parecía sólida como una roca, el &amp;ldquo;algoritmo de Shor&amp;rdquo; publicado por Peter Shor en 1994 causó un gran impacto.&lt;/p>
&lt;p>Las computadoras cuánticas utilizan las propiedades de la mecánica cuántica como la &amp;ldquo;superposición&amp;rdquo; y el &amp;ldquo;entrelazamiento cuántico&amp;rdquo; para realizar cálculos. Se demostró matemáticamente que ejecutar el algoritmo de Shor en una computadora cuántica suficientemente potente puede resolver el problema de factorización de enteros y el problema del logaritmo discreto en &amp;ldquo;tiempo polinomial&amp;rdquo;. En otras palabras, el día en que se perfeccionen las computadoras cuánticas prácticas (Q-Day), las criptografías de clave pública que se utilizan actualmente, como RSA y ECC, se romperán instantáneamente.&lt;/p>
&lt;h2 id="la-llegada-de-pqc-post-quantum-cryptography">La llegada de PQC (Post-Quantum Cryptography)
&lt;/h2>&lt;p>En preparación para esta amenaza sin precedentes, se está acelerando la investigación sobre la &amp;ldquo;criptografía poscuántica (PQC: Post-Quantum Cryptography)&amp;rdquo;, basada en nuevos problemas matemáticos que son difíciles de resolver incluso para las computadoras cuánticas. El NIST (Instituto Nacional de Estándares y Tecnología de EE. UU.) ha estado avanzando en el proceso de estandarización de PQC durante muchos años, y los siguientes enfoques matemáticos se consideran los más prometedores:&lt;/p>
&lt;h3 id="1-criptografía-basada-en-retículos-lattice-based-cryptography">1. Criptografía basada en retículos (Lattice-based Cryptography)
&lt;/h3>&lt;p>Actualmente es el enfoque más prometedor y también se adopta en los algoritmos de estandarización del NIST (ML-KEM / Kyber, ML-DSA / Dilithium). Se basa en la dificultad de problemas como encontrar puntos específicos en un &amp;ldquo;retículo (Lattice)&amp;rdquo; de un espacio multidimensional (Problema del vector más corto: SVP, etc.) o el problema LWE (Learning With Errors: Aprendizaje con errores).&lt;/p>
&lt;p>El concepto del problema LWE aprovecha la propiedad de que si se añade intencionalmente un &amp;ldquo;pequeño ruido (error)&amp;rdquo; a un sistema de ecuaciones lineales, de repente se vuelve difícil encontrar la solución.
Sistema de ecuaciones: $\mathbf{A}\mathbf{s} + \mathbf{e} \equiv \mathbf{b} \pmod{q}$
($\mathbf{A}$ y $\mathbf{b}$ son públicos, $\mathbf{s}$ es la clave privada, $\mathbf{e}$ es el pequeño ruido)&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pseudocódigo conceptual del problema LWE (con fines de aprendizaje)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span> &lt;span class="c1"># Dimensión&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">q&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3329&lt;/span> &lt;span class="c1"># Módulo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">512&lt;/span> &lt;span class="c1"># Número de ecuaciones&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"># Clave secreta s y pequeño error e&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Matriz pública A y vector público b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">A&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">A&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">s&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">q&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Se considera extremadamente difícil restaurar s a partir de A y b incluso usando una computadora cuántica&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-criptografía-basada-en-hash-hash-based-cryptography">2. Criptografía basada en hash (Hash-based Cryptography)
&lt;/h3>&lt;p>Es un esquema de firma digital que basa su seguridad únicamente en la resistencia a colisiones de las funciones hash. Dado que no tiene una estructura matemática, es resistente a los ataques cuánticos, pero los tamaños de firma tienden a ser grandes (como SPHINCS+).&lt;/p>
&lt;h3 id="3-criptografía-basada-en-códigos-code-based-cryptography">3. Criptografía basada en códigos (Code-based Cryptography)
&lt;/h3>&lt;p>Es un esquema criptográfico basado en la teoría de códigos de corrección de errores. El cifrado McEliece propuesto en 1978 es famoso, tiene una larga historia y una seguridad bien establecida, pero tiene el problema de que el tamaño de la clave pública es muy grande (a veces alcanza varios megabytes).&lt;/p>
&lt;div class="mermaid">timeline
title "Historia de la evolución de la criptografía y las computadoras"
"Antigüedad a Edad Media" : "Cifrado César" : "Cifrado Vigenère" : "Nacimiento del análisis de frecuencias"
"Años 1930 a 1940" : "Operación y descifrado de Enigma" : "Desarrollo de la máquina de Turing y la Bombe"
"Años 1970" : "Estandarización de DES (1977)" : "Intercambio de claves Diffie-Hellman (1976)" : "Nacimiento de la criptografía RSA (1977)"
"Años 1980 a 1990" : "Propuesta de la criptografía de curva elíptica (ECC)" : "Publicación del algoritmo de Shor (1994)"
"Años 2000" : "Estandarización de AES (2001)"
"Años 2010 al presente" : "Aceleración de la investigación en computadoras cuánticas" : "Inicio del proyecto de estandarización de PQC por el NIST"
"Futuro cercano (Q-Day)" : "¿Realización de computadoras cuánticas a gran escala?" : "Transición completa a PQC (ML-KEM/ML-DSA)"&lt;/div>
&lt;hr>
&lt;h1 id="8-conclusión-la-batalla-interminable-del-escudo-y-la-espada">8. Conclusión: La batalla interminable del escudo y la espada
&lt;/h1>&lt;p>La historia de la criptografía es la historia de una batalla interminable entre la invención de nuevos métodos de cifrado (escudos) y nuevas técnicas de descifrado (espadas) para romperlos.&lt;/p>
&lt;p>El cifrado César fue derrotado por el análisis de frecuencias, y la invencible Enigma fue derrotada por el genio de Turing y el poder de las máquinas. Y ahora, las poderosas criptografías como RSA y ECC, que sustentan la sociedad de Internet moderna, también están amenazadas por una nueva &amp;ldquo;espada&amp;rdquo;, las computadoras cuánticas.&lt;/p>
&lt;p>Sin embargo, la humanidad ya está mirando hacia el futuro y preparando un nuevo &amp;ldquo;escudo&amp;rdquo;, la criptografía poscuántica (PQC). Actualmente, prepararse para la transición de la criptografía de clave pública existente a PQC (garantizar la agilidad criptográfica: Crypto Agility) es una tarea urgente para la infraestructura de TI en todo el mundo.&lt;/p>
&lt;p>La tecnología criptográfica no es solo un complejo rompecabezas matemático, sino el baluarte más fuerte para proteger nuestra privacidad, propiedad y la infraestructura social misma.&lt;/p></description></item><item><title>Fundamentos matemáticos de la criptografía de curva elíptica (ECC) e implementación en C++</title><link>http://kenji.blog/es/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/es/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post Fundamentos matemáticos de la criptografía de curva elíptica (ECC) e implementación en C++" />&lt;h1 id="fundamentos-matemáticos-de-la-criptografía-de-curva-elíptica-ecc-e-implementación-en-c">Fundamentos matemáticos de la criptografía de curva elíptica (ECC) e implementación en C++
&lt;/h1>&lt;p>En la tecnología criptográfica moderna, la &lt;strong>criptografía de curva elíptica (Elliptic Curve Cryptography: ECC)&lt;/strong> juega un papel extremadamente importante. Desde nuestras comunicaciones diarias en Internet (HTTPS/TLS), los enclaves seguros de los teléfonos inteligentes, la autenticación de servidores mediante SSH, la autenticación sin contraseña como FIDO, e incluso en criptomonedas como Bitcoin y Ethereum, no es una exageración decir que la base de confianza de la sociedad digital moderna está respaldada por ECC.&lt;/p>
&lt;p>En este artículo, explicaremos exhaustivamente con un volumen abrumador cómo funciona esta criptografía de curva elíptica, partiendo de la hermosa pero compleja teoría matemática detrás de ella (geometría algebraica sobre campos finitos), los métodos de implementación prácticos usando C++, y además, técnicas de codificación seguras para prevenir ataques de canal lateral (ataques de tiempo).&lt;/p>
&lt;hr>
&lt;h2 id="1-por-qué-la-criptografía-de-curva-elíptica-comparación-con-rsa">1. ¿Por qué la criptografía de curva elíptica? (Comparación con RSA)
&lt;/h2>&lt;p>Cuando se hablaba de criptografía de clave pública, durante mucho tiempo el sinónimo era &lt;strong>RSA&lt;/strong>. RSA basa su seguridad en la &amp;ldquo;dificultad de factorizar números compuestos enormes&amp;rdquo;. Sin embargo, con el aumento de la capacidad computacional de los ordenadores, para mantener la seguridad ha surgido la necesidad de alargar continuamente el tamaño de la clave RSA (el número de bits del módulo). Hoy en día, se recomienda una longitud de clave de al menos 2048 bits, o 3072 y 4096 bits para mayor seguridad.&lt;/p>
&lt;p>Por otro lado, la criptografía de curva elíptica (ECC) fundamenta su seguridad en una dificultad matemática diferente: el &lt;strong>&amp;ldquo;problema del logaritmo discreto en curvas elípticas (ECDLP)&amp;rdquo;&lt;/strong>. Hasta la fecha, no se ha descubierto ningún algoritmo eficiente (como algoritmos de tiempo subexponencial) para resolver el ECDLP, e incluso los métodos de ataque más eficientes conocidos requieren un tiempo exponencial.&lt;/p>
&lt;p>Debido a esta propiedad, ECC tiene la ventaja decisiva de &lt;strong>poder lograr el mismo nivel de seguridad que RSA con una longitud de clave mucho más corta&lt;/strong>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Nivel de seguridad (bits)&lt;/th>
&lt;th style="text-align:center">Longitud de clave RSA (bits)&lt;/th>
&lt;th style="text-align:center">Longitud de clave ECC (bits)&lt;/th>
&lt;th style="text-align:center">Proporción de longitud de clave&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Como muestra la tabla anterior, para obtener una seguridad de 128 bits (el estándar actual), RSA requiere una clave de 3072 bits, pero con ECC solo se necesitan 256 bits. Esto permite una reducción en la cantidad de cálculos, un menor uso de memoria y un ahorro de ancho de banda en la red, presumiendo de una ventaja abrumadora, especialmente en entornos con recursos limitados como dispositivos IoT y tarjetas inteligentes.&lt;/p>
&lt;hr>
&lt;h2 id="2-preparación-matemática-teoría-de-grupos-y-el-mundo-de-los-campos-finitos">2. Preparación matemática: Teoría de grupos y el mundo de los campos finitos
&lt;/h2>&lt;p>Para comprender verdaderamente la criptografía de curva elíptica, es necesario dominar los conceptos básicos del álgebra abstracta (teoría de grupos y teoría de campos). Aquí resumiremos de manera concisa los conocimientos previos para construir ECC.&lt;/p>
&lt;h3 id="21-grupo-group-y-grupo-abeliano">2.1. Grupo (Group) y grupo abeliano
&lt;/h3>&lt;p>Un &lt;strong>grupo (Group)&lt;/strong> es un conjunto $G$ junto con una operación binaria (aquí la asumiremos como adición $+$) en ese conjunto, denotado como $(G, +)$, que satisface los siguientes 4 axiomas:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Clausura (Closure)&lt;/strong>: Para cualesquiera $a, b \in G$, se cumple que $a + b \in G$.&lt;/li>
&lt;li>&lt;strong>Asociatividad (Associativity)&lt;/strong>: Para cualesquiera $a, b, c \in G$, se cumple que $(a + b) + c = a + (b + c)$.&lt;/li>
&lt;li>&lt;strong>Existencia del elemento neutro (Identity element)&lt;/strong>: Existe un elemento $e \in G$ tal que para cualquier $a \in G$, $a + e = e + a = a$. En el caso de un grupo aditivo, este elemento neutro generalmente se denota como $0$ o $\mathcal{O}$.&lt;/li>
&lt;li>&lt;strong>Existencia del elemento inverso (Inverse element)&lt;/strong>: Para cualquier $a \in G$, existe un elemento $b \in G$ tal que $a + b = b + a = e$. Este $b$ se denota como $-a$.&lt;/li>
&lt;/ol>
&lt;p>Además, si el resultado no cambia al invertir el orden de la operación, es decir, si satisface la siguiente condición, el grupo se denomina &lt;strong>grupo abeliano (grupo conmutativo)&lt;/strong>.&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>Conmutatividad (Commutativity)&lt;/strong>: Para cualesquiera $a, b \in G$, se cumple que $a + b = b + a$.&lt;/li>
&lt;/ol>
&lt;p>El conjunto de puntos en una curva elíptica, al definir una regla de adición específica, forma este &lt;strong>grupo abeliano&lt;/strong>.&lt;/p>
&lt;h3 id="22-campo-finito-finite-field">2.2. Campo finito (Finite Field)
&lt;/h3>&lt;p>En la teoría criptográfica, no se utilizan campos con un número infinito de elementos continuos como los números reales o complejos, sino un &lt;strong>campo finito (Finite Field)&lt;/strong> o campo de Galois (Galois Field), donde el número de elementos es finito.&lt;/p>
&lt;p>El campo finito más básico es el &lt;strong>campo primo $\mathbb{F}_p$&lt;/strong> utilizando un número primo $p$. Esto es el conjunto de enteros $\{0, 1, 2, \dots, p-1\}$ en el que se definen las cuatro operaciones aritméticas (suma, resta, multiplicación, división) módulo $p$ (el resto de dividir por $p$).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Suma&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Resta&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>Multiplicación&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>División&lt;/strong>: $a \times b^{-1} \pmod p$ (donde $b^{-1}$ es el inverso multiplicativo de $b$ módulo $p$)&lt;/li>
&lt;/ul>
&lt;p>El cálculo del &lt;strong>inverso multiplicativo modular (Modular Multiplicative Inverse)&lt;/strong> es extremadamente importante en las implementaciones criptográficas. Para encontrar $b^{-1}$ que satisfaga $b \times b^{-1} \equiv 1 \pmod p$, se utilizan principalmente los dos siguientes algoritmos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Algoritmo de Euclides extendido (Extended Euclidean Algorithm)&lt;/strong>: Es rápido, pero dependiendo de la implementación, el tiempo de procesamiento puede depender de los valores de entrada, por lo que existe el riesgo de ataques de tiempo.&lt;/li>
&lt;li>&lt;strong>Pequeño teorema de Fermat (Fermat&amp;rsquo;s Little Theorem)&lt;/strong>: Cuando $p$ es primo y $b \neq 0$, se cumple que $b^{p-1} \equiv 1 \pmod p$. Dividiendo ambos lados por $b$, obtenemos $b^{p-2} \equiv b^{-1} \pmod p$. En otras palabras, calculando la potencia $p-2$ de $b$, se obtiene el inverso. Dado que las operaciones de exponenciación son fáciles de implementar en tiempo constante, esta es la preferida en implementaciones criptográficas.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-ecuación-de-la-curva-elíptica-y-geometría">3. Ecuación de la curva elíptica y geometría
&lt;/h2>&lt;h3 id="31-forma-normal-de-weierstrass">3.1. Forma normal de Weierstrass
&lt;/h3>&lt;p>Una &lt;strong>curva elíptica (Elliptic Curve)&lt;/strong> es una curva plana generalmente definida por la siguiente ecuación, llamada &lt;strong>forma normal de Weierstrass (Weierstrass normal form)&lt;/strong>.&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>Aquí, $a$ y $b$ son constantes, y como condición para que la curva no tenga puntos singulares (auto-intersecciones o cúspides), es decir, para que sea una curva suave, se requiere que el siguiente &lt;strong>discriminante (Discriminant) $\Delta$&lt;/strong> no sea cero.&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>Dado que una curva con puntos singulares compromete la seguridad criptográfica, siempre se eligen coeficientes $a, b$ que satisfagan esta condición.&lt;/p>
&lt;h3 id="32-punto-en-el-infinito-point-at-infinity">3.2. Punto en el infinito (Point at Infinity)
&lt;/h3>&lt;p>Para convertir matemáticamente la curva elíptica en un grupo completo, además de los puntos en el plano, introducimos un punto virtual llamado &lt;strong>&amp;ldquo;punto en el infinito (Point at Infinity)&amp;rdquo;&lt;/strong>. Lo denotamos como $\mathcal{O}$.&lt;/p>
&lt;p>El punto en el infinito $\mathcal{O}$ se define como el punto donde todas las líneas verticales se cruzan en el infinito infinito. En la teoría de grupos, este punto en el infinito $\mathcal{O}$ funciona como el &lt;strong>elemento neutro en la adición&lt;/strong> (cero).&lt;/p>
&lt;p>Es decir, para cualquier punto $P$ en la curva, se cumple lo siguiente:
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>Además, el inverso $-P$ del punto $P = (x, y)$ se define como el punto simétrico con respecto al eje x, $(x, -y)$. Por lo tanto:
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;hr>
&lt;h2 id="4-operaciones-de-grupo-en-la-curva-elíptica-suma-de-puntos-y-duplicación">4. Operaciones de grupo en la curva elíptica (Suma de puntos y duplicación)
&lt;/h2>&lt;p>El núcleo de la criptografía de curva elíptica es la operación de &lt;strong>&amp;ldquo;suma (Addition)&amp;rdquo;&lt;/strong> entre puntos de la curva. Esta difiere de la suma habitual de números enteros y se define basándose en operaciones geométricas.&lt;/p>
&lt;h3 id="41-suma-geométrica-tangent-and-chord-method">4.1. Suma geométrica (Tangent and Chord Method)
&lt;/h3>&lt;p>El procedimiento para sumar dos puntos diferentes $P$ y $Q$ en la curva para obtener un nuevo punto $R$ ($R = P + Q$) es el siguiente:&lt;/p>
&lt;ol>
&lt;li>Se traza una línea recta (cuerda) que pasa por los puntos $P$ y $Q$.&lt;/li>
&lt;li>Esta línea recta siempre interceptará la curva elíptica en un tercer punto (a este lo llamaremos $-R$). (*Según un teorema de la geometría algebraica)&lt;/li>
&lt;li>El punto obtenido al reflejar el punto de intersección $-R$ simétricamente sobre el eje x (invirtiendo el signo de la coordenada y) será el punto $R$ buscado.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["Trazar una línea que conecte P(x1, y1) y Q(x2, y2)"] --> Step2["Encontrar el tercer punto de intersección -R con la curva"]
Step2 --> Step3["Reflejar -R sobre el eje x para obtener R(x3, y3)"]
Step3 -.-> Result["Esto es R = P + Q"]&lt;/div>
&lt;h3 id="42-duplicación-de-puntos-point-doubling">4.2. Duplicación de puntos (Point Doubling)
&lt;/h3>&lt;p>Al sumar el mismo punto $P$ a sí mismo ($P + P = 2P$), no se puede trazar una línea que pase por dos puntos. En este caso, se traza la &lt;strong>línea tangente (Tangent) a la curva en el punto $P$&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>Se traza la línea tangente a la curva en el punto $P$.&lt;/li>
&lt;li>Esta línea tangente interceptará la curva en un segundo punto $-R$.&lt;/li>
&lt;li>El punto reflejado simétricamente sobre el eje x será el punto buscado $R = 2P$.&lt;/li>
&lt;/ol>
&lt;h3 id="43-fórmulas-de-cálculo-algebraico">4.3. Fórmulas de cálculo algebraico
&lt;/h3>&lt;p>Las operaciones geométricas se traducen a fórmulas algebraicas para que puedan ser calculadas por un ordenador.
Todas las operaciones se realizan &lt;strong>sobre el campo finito $\mathbb{F}_p$ (módulo $p$)&lt;/strong>.&lt;/p>
&lt;p>Sean el punto $P = (x_1, y_1)$ y el punto $Q = (x_2, y_2)$.
Además, el punto resultante del cálculo será $R = P + Q = (x_3, y_3)$.&lt;/p>
&lt;p>Sea $\lambda$ (lambda) la pendiente de la recta.&lt;/p>
&lt;p>&lt;strong>[Caso 1: Cuando $P \neq Q$ (Suma de puntos)]&lt;/strong>
La pendiente $\lambda$ es la tasa de cambio entre los dos puntos.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>Usando este $\lambda$, $x_3, y_3$ se calculan de la siguiente manera:
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>[Caso 2: Cuando $P = Q$ (Duplicación de puntos)]&lt;/strong>
La pendiente $\lambda$ es la pendiente de la recta tangente obtenida por diferenciación. (Se deriva implícitamente $y^2 = x^3 + ax + b$)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
Por lo tanto,
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>Las fórmulas para $x_3, y_3$ tienen la misma forma que en la suma, pero como $x_2 = x_1$, se convierten en:
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
Estas fórmulas incluyen &lt;strong>divisiones (cálculo del inverso modular)&lt;/strong>, como $(x_2 - x_1)^{-1}$ y $(2y_1)^{-1}$. Dado que el cálculo del inverso modular tiene un costo computacional muy alto, en las implementaciones reales generalmente se utilizan sistemas de coordenadas proyectivas que retrasan la división, como las &lt;strong>&amp;ldquo;Coordenadas Jacobianas (Jacobian Coordinates)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-multiplicación-escalar-y-el-problema-del-logaritmo-discreto-en-curvas-elípticas-ecdlp">5. Multiplicación escalar y el problema del logaritmo discreto en curvas elípticas (ECDLP)
&lt;/h2>&lt;p>En la criptografía de curva elíptica, la operación con mayor costo computacional y que forma el núcleo de la seguridad es la &lt;strong>multiplicación escalar (Scalar Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="51-qué-es-la-multiplicación-escalar">5.1. ¿Qué es la multiplicación escalar?
&lt;/h3>&lt;p>La operación de sumar un punto $P$ un número $k$ de veces se llama multiplicación escalar y se denota como $kP$.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{ veces}} $$
&lt;p>Aquí, $k$ es un número entero muy grande (por ejemplo, un entero de 256 bits).&lt;/p>
&lt;h3 id="52-problema-del-logaritmo-discreto-en-curvas-elípticas-ecdlp">5.2. Problema del logaritmo discreto en curvas elípticas (ECDLP)
&lt;/h3>&lt;p>La seguridad de la criptografía de curva elíptica depende de la dificultad del siguiente problema.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Problema del logaritmo discreto en curvas elípticas (Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
Dado un punto conocido $P$ (punto base) y el punto resultante $Q$, encontrar el escalar $k$ que satisfaga $Q = kP$.&lt;/p>
&lt;/blockquote>
&lt;p>Calcular $Q$ a partir de $k$ y $P$ (dirección directa) es fácil (tiempo polinomial) utilizando el algoritmo descrito a continuación, pero calcular $k$ inversamente a partir de $P$ y $Q$ (dirección inversa) no tiene una solución eficiente aparte de una búsqueda exhaustiva (fuerza bruta), lo que lo hace virtualmente imposible (función unidireccional).
En los protocolos criptográficos, &lt;strong>$k$ corresponde a la &amp;ldquo;clave privada&amp;rdquo; y $Q$ a la &amp;ldquo;clave pública&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="53-algoritmo-double-and-add-doble-y-suma">5.3. Algoritmo Double-and-Add (Doble y Suma)
&lt;/h3>&lt;p>Cuando $k$ es un número enorme (por ejemplo: $2^{256}$), sumar ingenuamente $P$ un total de $k$ veces no terminaría ni siquiera si se agotara la vida del universo. Por lo tanto, para realizar la multiplicación escalar a alta velocidad, se utiliza el &lt;strong>método Double-and-Add (método binario)&lt;/strong>.&lt;/p>
&lt;p>Esta es la versión de curva elíptica del método de &amp;ldquo;cuadratura repetida&amp;rdquo; para calcular potencias de enteros de manera rápida. Expresa el escalar $k$ en formato binario y lo procesa secuencialmente desde el bit más significativo.&lt;/p>
&lt;ol>
&lt;li>Inicializar el punto $R$ que mantiene el resultado con $\mathcal{O}$.&lt;/li>
&lt;li>Repetir lo siguiente desde el bit más significativo de $k$ hasta el menos significativo:
&lt;ul>
&lt;li>Duplicar $R$ (Point Doubling: $R = 2R$)&lt;/li>
&lt;li>Si el bit actual es &lt;code>1&lt;/code>, sumar $P$ a $R$ (Point Addition: $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Gracias a este algoritmo, la complejidad computacional se reduce drásticamente de $O(k)$ a $O(\log_2 k)$, permitiendo cálculos en un tiempo realista (cuestión de milisegundos).&lt;/p>
&lt;hr>
&lt;h2 id="6-intercambio-de-claves-de-curva-elíptica-diffie-hellman-ecdh">6. Intercambio de claves de curva elíptica Diffie-Hellman (ECDH)
&lt;/h2>&lt;p>Aquí explicaremos el funcionamiento del &lt;strong>protocolo de intercambio de claves ECDH (Elliptic Curve Diffie-Hellman)&lt;/strong>, que es el ejemplo de aplicación más representativo de ECC. ECDH es un mecanismo que permite a Alice y Bob generar y compartir de forma segura una clave secreta compartida (clave de sesión) sobre un canal de comunicación que podría ser espiado (es el núcleo del apretón de manos TLS).&lt;/p>
&lt;p>&lt;strong>[Parámetros preestablecidos (Parámetros de dominio)]&lt;/strong>
Ambas partes comparten de antemano la curva elíptica $E$ a utilizar, el número primo $p$ y el punto base $G$. (Por ejemplo, NIST P-256 o secp256k1)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice"
participant Bob as "Bob"
Note over Alice,Bob: "Parámetros públicos: Curva E, Punto base G, Primo p"
Alice->>Alice: "Generar clave privada d_A (entero aleatorio)"
Alice->>Alice: "Calcular clave pública Q_A = d_A * G"
Bob->>Bob: "Generar clave privada d_B (entero aleatorio)"
Bob->>Bob: "Calcular clave pública Q_B = d_B * G"
Alice->>Bob: "Enviar clave pública Q_A (texto plano)"
Bob->>Alice: "Enviar clave pública Q_B (texto plano)"
Alice->>Alice: "Calcular secreto compartido S = d_A * Q_B"
Bob->>Bob: "Calcular secreto compartido S = d_B * Q_A"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "¡Los resultados de cálculo S de ambos coinciden perfectamente!"&lt;/div>
&lt;p>Un atacante (Eve) que intercepte la comunicación puede obtener $G$, $Q_A$ y $Q_B$ que fluyen por la red, pero debido a la dificultad del ECDLP, no puede deducir la clave privada $d_A$ de Alice a partir de $Q_A = d_A \cdot G$. Además, multiplicar $Q_A$ y $Q_B$ no produce la clave compartida $S$, por lo que el espía no puede calcular $S$.&lt;/p>
&lt;hr>
&lt;h2 id="7-dificultades-en-la-implementación-ataques-de-canal-lateral-y-contramedidas">7. Dificultades en la implementación: Ataques de canal lateral y contramedidas
&lt;/h2>&lt;p>Incluso si un algoritmo criptográfico es teóricamente perfecto, pueden surgir vulnerabilidades en el proceso de implementarlo como programa. Esto se conoce como &lt;strong>&amp;ldquo;ataque de canal lateral (Side-Channel Attack)&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;h3 id="71-ataque-de-tiempo-timing-attack">7.1. Ataque de tiempo (Timing Attack)
&lt;/h3>&lt;p>Revisemos el algoritmo Double-and-Add mencionado anteriormente.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pseudocódigo vulnerable de Double-and-Add
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Siempre se ejecuta
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// ¡Solo se ejecuta cuando el bit es 1!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Esta implementación tiene una falla fatal. Dado que la suma de puntos (Point Addition) se ejecuta cuando el bit es &lt;code>1&lt;/code>, el &lt;strong>tiempo de cálculo será ligeramente mayor&lt;/strong> que cuando el bit es &lt;code>0&lt;/code>. Además, el comportamiento de predicción de bifurcaciones del procesador y la memoria caché también cambiará.
Si un atacante observa estadísticamente esta diminuta diferencia en el tiempo de cálculo (o el consumo de energía) miles de veces, &lt;strong>podría recuperar completamente la secuencia de bits de la clave privada $k$ bit por bit&lt;/strong>. Este es el ataque de tiempo.&lt;/p>
&lt;h3 id="72-implementación-de-tiempo-constante-constant-time-escalera-de-montgomery-montgomery-ladder">7.2. Implementación de tiempo constante (Constant-Time): Escalera de Montgomery (Montgomery Ladder)
&lt;/h3>&lt;p>Para prevenir los ataques de tiempo, es necesario adoptar un algoritmo en el que &lt;strong>la secuencia de instrucciones ejecutadas y el tiempo de cálculo sean siempre constantes (Constant-Time), independientemente del valor de los bits de la clave privada&lt;/strong>.&lt;/p>
&lt;p>El ejemplo representativo de esto es la &lt;strong>Escalera de Montgomery (Montgomery Ladder)&lt;/strong>.&lt;/p>
&lt;div class="mermaid">graph TD
Start["Inicialización: R0 = O, R1 = P"] --> LoopStart["Para cada bit i (desde el más significativo)"]
LoopStart --> Cond{"¿Cuál es el valor de k_i?"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["Siguiente bit"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"Todos los bits completados"| End["Fin: R0 es el resultado (kP)"]&lt;/div>
&lt;p>Lo hermoso de la Escalera de Montgomery es que, sin importar si el bit es &lt;code>0&lt;/code> o &lt;code>1&lt;/code>, &lt;strong>&amp;ldquo;siempre se ejecuta una suma de puntos (Point Addition) y una duplicación de puntos (Point Doubling)&amp;rdquo;&lt;/strong>. Esto elimina por completo la dependencia de los datos en el tiempo de cálculo.&lt;/p>
&lt;p>Sin embargo, si la bifurcación misma (&lt;code>if (k_i == 0)&lt;/code>) sigue existiendo, aún persiste el riesgo de que el tiempo de ejecución varíe debido a las optimizaciones del compilador o la predicción de saltos de la CPU. Por lo tanto, en una implementación real de Constant-Time, las bifurcaciones condicionales (instrucciones &lt;code>if&lt;/code>) se eliminan y se utiliza un &lt;strong>intercambio condicional (Conditional Swap) empleando operaciones a nivel de bits&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="8-implementación-de-criptografía-de-curva-elíptica-en-c">8. Implementación de criptografía de curva elíptica en C++
&lt;/h2>&lt;p>A partir de aquí, plasmaremos la teoría en código C++. Las bibliotecas criptográficas prácticas (como OpenSSL o libsodium) utilizan optimizaciones avanzadas en ensamblador o el sistema de coordenadas jacobianas, pero aquí, para profundizar en la comprensión matemática, mostraremos la estructura de una &lt;strong>implementación Constant-Time fácil de entender usando coordenadas afines&lt;/strong>.&lt;/p>
&lt;p>Asumiremos el uso de &lt;code>boost::multiprecision::cpp_int&lt;/code> para las operaciones con enteros gigantes.&lt;/p>
&lt;h3 id="81-aritmética-modular-y-el-inverso">8.1. Aritmética modular y el inverso
&lt;/h3>&lt;p>Primero, definiremos funciones de ayuda para operaciones en campos finitos. Implementaremos el cálculo del inverso modular utilizando el pequeño teorema de Fermat.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Ejemplo usando el número primo p y parámetros de secp256k1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Operación modular que devuelve un residuo positivo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Exponenciación modular (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Inverso modular usando el pequeño teorema de Fermat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Asumiendo que m es primo: n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-representación-de-puntos-y-operaciones-de-grupo-suma-y-duplicación">8.2. Representación de puntos y operaciones de grupo (Suma y Duplicación)
&lt;/h3>&lt;p>Implementamos la estructura &lt;code>Point&lt;/code> que maneja el punto en el infinito con una bandera, y las fórmulas de suma.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Crear el punto en el infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Crear un punto normal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Suma de puntos en la curva elíptica (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = punto en el infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (Caso P = Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (Caso P != Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-implementación-de-intercambio-condicional-en-tiempo-constante-constant-time-conditional-swap">8.3. Implementación de intercambio condicional en tiempo constante (Constant-Time Conditional Swap)
&lt;/h3>&lt;p>Al intercambiar el contenido de variables basado en el valor de un bit de la clave privada, realizamos el intercambio únicamente mediante operaciones a nivel de bits (máscaras) sin utilizar sentencias &lt;code>if&lt;/code>. Esto asegura que la ruta de ejecución sea completamente constante.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
En implementaciones reales, las clases de enteros de precisión múltiple con asignación dinámica como &lt;code>cpp_int&lt;/code> no son adecuadas para procesamientos de tiempo constante, ya que se filtra información de temporización mediante la asignación de memoria o variaciones en el tamaño de los arreglos. Las bibliotecas prácticas los representan con una longitud fija (por ejemplo, arreglos de 4 elementos uint64_t) e implementan el enmascaramiento a nivel de bits. El siguiente es un ejemplo conceptual.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Constant-Time Swap conceptual (asumiendo enteros de longitud fija)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Si el bit es 1, intercambia P1 y P2; si es 0, no los intercambia
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit es 0 o 1. La máscara es todo 1s (0xFF..) si bit=1, y todo 0s si es 0.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (Aquí asumimos que cada palabra de la clase BigInt de longitud fija es w para la explicación)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // Procesar de igual manera la coordenada y, así como la bandera isInfinity
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// * Un intercambio perfecto de tiempo constante en boost::multiprecision es difícil,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// pero aquí lo limitaremos a simularlo mediante ramificación para comprender la lógica.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-multiplicación-escalar-mediante-la-escalera-de-montgomery">8.4. Multiplicación escalar mediante la Escalera de Montgomery
&lt;/h3>&lt;p>Combinamos &lt;code>pointAdd&lt;/code> y &lt;code>cswap&lt;/code> previamente descritos para implementar una multiplicación escalar segura.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Multiplicación escalar k * P (Método de Escalera de Montgomery)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Punto en el infinito
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtener la longitud de bits de k (256 bits para secp256k1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtener el valor del i-ésimo bit (0 o 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si bit == 1, intercambiar R0 y R1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Siempre se ejecuta la misma operación (Point Addition y Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Si bit == 1, volver a intercambiar para restaurar el estado original
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Con esta lógica de implementación, sin importar si cada bit del escalar $k$ es &lt;code>0&lt;/code> o &lt;code>1&lt;/code>, las operaciones ejecutadas dentro de la iteración de cada bucle (&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>) seguirán un flujo exactamente igual, previniendo fuertemente la fuga de información confidencial a través de variaciones en la temporización o los patrones de acceso a la caché.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusión">9. Conclusión
&lt;/h2>&lt;p>A primera vista, la criptografía de curva elíptica (ECC) puede parecer un misterio y hacernos preguntar, &amp;ldquo;¿Cómo pueden las operaciones geométricas como trazar una línea recta y reflejar intersecciones convertirse en criptografía?&amp;rdquo;. Sin embargo, al mapearlo al mundo discreto de los campos finitos, es el producto de una fusión milagrosa entre las matemáticas y la criptografía que nos permite construir espléndidas funciones unidireccionales (problema del logaritmo discreto).&lt;/p>
&lt;p>En este artículo explicamos los siguientes puntos clave:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Ventaja sobre RSA&lt;/strong>: Ofrece una seguridad robusta con longitudes de clave muy cortas, ideal para la era actual móvil e IoT.&lt;/li>
&lt;li>&lt;strong>Fundamentos de teoría de grupos y campos finitos&lt;/strong>: La estructura matemática que sirve como base para ECC.&lt;/li>
&lt;li>&lt;strong>Fórmulas de suma y duplicación&lt;/strong>: Métodos de implementación de operaciones de grupo algebraicas usando la ecuación de Weierstrass.&lt;/li>
&lt;li>&lt;strong>La amenaza de los ataques de canal lateral&lt;/strong>: Cómo las bifurcaciones condicionales que dependen de los bits de la clave privada crean vulnerabilidades fatales.&lt;/li>
&lt;li>&lt;strong>Implementación de tiempo constante (Constant-Time)&lt;/strong>: Técnicas de codificación en C++ usando la Escalera de Montgomery y el Intercambio Condicional para igualar el comportamiento a nivel de hardware y prevenir ataques.&lt;/li>
&lt;/ol>
&lt;p>Crear por tu cuenta una biblioteca criptográfica para entornos de producción generalmente no se recomienda (&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;) debido a los riesgos de seguridad extremadamente altos. Sin embargo, comprender profundamente los algoritmos subyacentes y el contexto matemático puede ser una herramienta invaluable y poderosa para los ingenieros que diseñan y operan sistemas más seguros y eficientes.&lt;/p>
&lt;p>En el próximo artículo, nos gustaría profundizar más en el mecanismo de &lt;strong>ECDSA (Elliptic Curve Digital Signature Algorithm)&lt;/strong>, un algoritmo de firma digital que utiliza esta curva elíptica, y en las &lt;strong>firmas de Schnorr&lt;/strong> adoptadas en Bitcoin.&lt;/p></description></item></channel></rss>