Debido a que la operación de módulo entero es un homomorfismo de anillo ( Wikipedia ) de ℤ -> ℤ / nℤ,
(X * Y) mod N = (X mod N) * (Y mod N) mod N
Puede verificar esto usted mismo con un poco de álgebra simple. (Tenga en cuenta que la final mod
en el lado derecho aparece debido a la definición de multiplicación en un anillo modular).
Las computadoras usan este truco para calcular exponenciales en anillos modulares sin tener que calcular una gran cantidad de dígitos.
/ 1 I = 0,
El |
(X ^ I) mod N = <(X * (X ^ (I-1) mod N)) mod NI impar,
El |
\ (X ^ (I / 2) mod N) ^ 2 mod NI incluso & I / = 0.
En forma algorítmica,
-- compute X^I mod N
function expmod(X, I, N)
if I is zero
return 1
elif I is odd
return (expmod(X, I-1, N) * X) mod N
else
Y <- expmod(X, I/2, N)
return (Y*Y) mod N
end if
end function
Puede usar esto para calcular (855^2753) mod 3233
con solo registros de 16 bits, si lo desea.
Sin embargo, los valores de X y N en RSA son mucho más grandes, demasiado grandes para caber en un registro. ¡Un módulo suele tener una longitud de 1024-4096 bits! Entonces, puede hacer que una computadora haga la multiplicación de la manera "larga", de la misma manera que hacemos la multiplicación a mano. Solo que en lugar de usar dígitos 0-9, la computadora usará "palabras" 0-2 16 -1 o algo así. (El uso de solo 16 bits significa que podemos multiplicar dos números de 16 bits y obtener el resultado completo de 32 bits sin recurrir al lenguaje ensamblador. En lenguaje ensamblador, generalmente es muy fácil obtener el resultado completo de 64 bits, o para una computadora de 64 bits , el resultado completo de 128 bits).
-- Multiply two bigints by each other
function mul(uint16 X[N], uint16 Y[N]):
Z <- new array uint16[N*2]
for I in 1..N
-- C is the "carry"
C <- 0
-- Add Y[1..N] * X[I] to Z
for J in 1..N
T <- X[I] * Y[J] + C + Z[I + J - 1]
Z[I + J - 1] <- T & 0xffff
C <- T >> 16
end
-- Keep adding the "carry"
for J in (I+N)..(N*2)
T <- C + Z[J]
Z[J] <- T & 0xffff
C <- T >> 16
end
end
return Z
end
-- footnote: I wrote this off the top of my head
-- so, who knows what kind of errors it might have
Esto multiplicará X por Y en una cantidad de tiempo aproximadamente igual al número de palabras en X multiplicado por el número de palabras en Y. Esto se llama tiempo O (N 2 ). Si observa el algoritmo anterior y lo separa, es la misma "multiplicación larga" que enseñan en la escuela. No tiene tablas de tiempos memorizadas con 10 dígitos, pero aún puede multiplicar 1,926,348 x 8,192,004 si se sienta y trabaja.
Multiplicación larga:
1,234
x 5,678
---------
9,872
86,38
740,4
6,170
---------
7,006,652
En realidad, existen algunos algoritmos más rápidos para la multiplicación ( Wikipedia ), como el método de Fourier rápido de Strassen, y algunos métodos más simples que suman y restan extra pero menos multiplicación, y así terminan más rápido en general. Las bibliotecas numéricas como GMP son capaces de seleccionar diferentes algoritmos en función de qué tan grandes son los números: la transformación de Fourier es solo la más rápida para los números más grandes, los números más pequeños usan algoritmos más simples.