Оскільки операція з цілим модулем - це кільцевий гомоморфізм ( Вікіпедія ) від ℤ -> ℤ / nℤ,
(X * Y) mod N = (X mod N) * (Y mod N) mod N
Ви можете перевірити це самостійно за допомогою трохи простої алгебри. (Зверніть увагу, що фінал mod
праворуч з'являється завдяки визначенню множення в модульному кільці.)
Комп'ютери використовують цей трюк для обчислення експонентів у модульних кільцях без необхідності обчислення великої кількості цифр.
/ 1 I = 0,
|
(X ^ I) mod N = <(X * (X ^ (I-1) mod N)) mod NI непарне,
|
\ (X ^ (I / 2) mod N) ^ 2 мод NI навіть & I / = 0.
В алгоритмічній формі
-- 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
Ви можете використовувати це для обчислення (855^2753) mod 3233
лише 16-бітових регістрів, якщо вам це подобається.
Однак значення X і N в RSA набагато більші, занадто великі, щоб вписатись у регістр. Модуль, як правило, становить 1024-4096 біт! Таким чином, ви можете мати комп'ютер, який виконує множення "довгим шляхом", так само, як ми робимо множення вручну. Тільки замість цифр 0-9 комп'ютер використовуватиме "слова" 0-2 16 -1 або щось подібне. (Використовуючи лише 16 біт, це означає, що ми можемо помножити два 16-бітові числа та отримати повний 32-бітний результат, не вдаючись до мови складання. У мові складання зазвичай дуже просто отримати повний 64-бітний результат або для 64-розрядного комп'ютера , повний 128-розрядний результат.)
-- 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
Це помножить X на Y на кількість часу, що приблизно дорівнює кількості слів у X, помноженій на кількість слів у Y. Це називається часом O (N 2 ). Якщо ви подивитеся на алгоритм вище та розімніть його, це те саме «довге множення», яке вони навчають у школі. У вас немає разів запам’ятовувати таблиці на 10 цифр, але ви все одно можете перемножувати 1,926,348 x 8,192,004, якщо сісти і опрацювати.
Довге множення:
1,234
x 5,678
---------
9,872
86,38
740,4
6,170
---------
7,006,652
Насправді існує кілька швидших алгоритмів для множення ( Вікіпедія ), наприклад, швидкий метод Фур'є Страссена та деякі більш прості методи, які роблять додаткове додавання і віднімання, але менше множення, і так в кінцевому підсумку швидше. Числові бібліотеки, такі як GMP, здатні вибирати різні алгоритми залежно від того, наскільки великі числа: перетворення Фур'є є лише найшвидшим для найбільших чисел, менші числа використовують більш прості алгоритми.