Answers:
因为整数模运算是ℤ->ℤ/nℤ的一个环同态(Wikipedia),
(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 mod 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位寄存器进行计算。
但是,RSA中的X和N值要大得多,太大而无法放入寄存器中。模数通常为1024-4096位长!因此,您可以让计算机以“长”方式进行乘法,就像我们手动进行乘法一样。计算机将只使用“单词” 0-2 16 -1或类似的字词,而不是使用数字0-9 。(仅使用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上将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
实际上,周围有一些乘法运算的更快算法(Wikipedia),例如Strassen的快速傅立叶方法,还有一些更简单的方法,它们进行额外的加法和减法,但乘法次数较少,因此总体上更快。诸如GMP之类的数字库能够根据数字的大小来选择不同的算法:对于最大的数字,傅里叶变换只是最快的,对于较小的数字,傅里叶变换则使用较简单的算法。
mod N
在中国余数定理的末尾您却错过了一个额外的东西。((16 mod 5)
不等于(4 mod 5) * (4 mod 5)
:前者是1,后者是16。)
mod
是多余的。
(X * Y) mod N = (X mod N) * (Y mod N) mod N
是对的,但这与中国剩余定理没有关系。
答案很简单,那就是他们做不到,不是靠自己。确实,如果采用x位机的概念,那么可以用有限数量的位数表示有限数量的数字,就像可以用2位数字表示的数量有限一样十进制系统。
话虽如此,大量计算机表示是密码学领域的重要组成部分。有许多种方法可以在计算机中表示非常大的数字,每种数字都与之不同。
这些方法中的每一种都有不同的优点和缺点,尽管我没有/不能在这里列出所有方法,但我将只介绍一种。
假设整数只能容纳0-99之间的值。一个人怎么能代表100?起初这似乎是不可能的,但这是因为我们只考虑了一个变量。如果我有所谓的整数units
和一个叫hundreds
,我可以很容易地代表100: hundreds = 1; units = 0;
。我可以轻松地代表更大的数字,例如9223 :hundreds = 92; units = 23
。
尽管这是一种简单的方法,但可以认为它效率很低。像大多数限制计算机功能的算法一样,这通常是功耗(代表大量数字)和效率(快速检索/存储)之间的一场拉锯战。就像我之前说的,有很多方法可以表示计算机中的大数。只要找到一种方法并尝试一下即可!
希望这能回答您的问题!
进一步阅读:该文章和这一个可以派上用场以获取更多信息。
用同样的方法。
我猜想您不会立即知道342 * 189是什么。但是您确实知道以下事实:
9 * 2 = 18
9 * 4 = 36
9 * 3 = 27
8 * 2 = 16
8 * 4 = 32
8 * 3 = 24
1 * 2 = 2
1 * 4 = 4
1 * 3 = 3
18 + 360 + 2700 + 160 + 3200 + 24000 + 200 + 4000 + 30000 = 64638
通过了解这些简单的事实,并学会了一种操作它们的技术,您可以进行原本无法做到的算术运算。
同样,一台不能同时处理超过64位数学运算的计算机可以轻松地将较大的问题分解成较小的部分,再将这些较小的部分分解,然后重新组合起来,以解决先前较大的问题。无法回答的问题。
就加法和减法而言,如果算术运算已溢出,则许多CPU都有一个“进位”设置。因此,如果结果需要存储8个字节,并且CPU是32位(相当于4个8位字节),则它可以执行两个加法运算,首先是“低位字”,然后是“高位字”进位位可以防止溢出。必须先清除进位。这是为什么更高位数的CPU可以提高性能的原因之一,因为不必这样做。
当然,这是基于我有限的8位CPU汇编程序经验。我不知道带有乘法和除法指令的现代CPU的进位位是如何工作的。非Intel RISC CPU的行为也可能有所不同。
我对浮点数学不是很了解,但是基本上字节代表固定数量的位,但没有特定的位。这就是为什么它被称为“浮动”点。因此,例如,数字34459234将消耗与3.4459234或3.4459234E + 20大致相同的内存空间(即3.4459234 x 10 ^ 20)。