我想计算一个 b mod n用于RSA解密。我的代码(如下)返回错误的答案。这有什么问题?
unsigned long int decrypt2(int a,int b,int n)
{
unsigned long int res = 1;
for (int i = 0; i < (b / 2); i++)
{
res *= ((a * a) % n);
res %= n;
}
if (b % n == 1)
res *=a;
res %=n;
return res;
}
答案 0 :(得分:44)
您可以尝试使用此C ++代码。我用它有32位和64位整数。我确定我从SO那里得到了这个。
template <typename T>
T modpow(T base, T exp, T modulus) {
base %= modulus;
T result = 1;
while (exp > 0) {
if (exp & 1) result = (result * base) % modulus;
base = (base * base) % modulus;
exp >>= 1;
}
return result;
}
您可以在文献中找到此算法和相关讨论。
的244Schneier,Bruce(1996)。应用密码学:C,第二版(第2版)中的协议,算法和源代码。威利。 ISBN 978-0-471-11709-4。
请注意,此简化版本中的乘法result * base
和base * base
会出现溢出。如果模数大于T
宽度的一半(即大于最大T
值的平方根),那么应该使用合适的模乘法算法 - 参见 Ways to do modulo multiplication with primitive types
答案 1 :(得分:16)
为了计算用于RSA解密的pow(a,b) % n
,我遇到的最佳算法是 Primality Testing 1),如下所示:< / p>
int modulo(int a, int b, int n){
long long x=1, y=a;
while (b > 0) {
if (b%2 == 1) {
x = (x*y) % n; // multiplying with base
}
y = (y*y) % n; // squaring the base
b /= 2;
}
return x % n;
}
有关详细信息,请参阅以下参考资料。
1) Primality Testing : Non-deterministic Algorithms – topcoder
答案 2 :(得分:10)
通常它是这样的:
while (b)
{
if (b % 2) { res = (res * a) % n; }
a = (a * a) % n;
b /= 2;
}
return res;
答案 3 :(得分:6)
我看到的唯一实际逻辑错误是这一行:
if (b % n == 1)
应该是这样的:
if (b % 2 == 1)
但是您的整体设计存在问题:您的函数执行O(b)乘法和模数运算,但使用b / 2
和a * a
意味着您的目标是执行O(log b)运算(通常是模幂运算的完成方式)。
答案 4 :(得分:3)
执行原始电源操作非常昂贵,因此您可以应用以下逻辑来简化解密。
来自here,
现在说我们要加密消息m = 7,
c = m ^ e mod n = 7 ^ 3 mod 33 = 343 mod 33 = 13.
因此密文c = 13.为了检查解密,我们计算了m'= c ^ d mod n = 13 ^ 7 mod 33 = 7.
注意 我们不必计算功率7的全部值13 这里。我们可以利用这样的事实:a a = bc mod n =(b mod n)。(c mod n)mod n
所以我们可以将一个潜在的大数字分解成它 组件并结合更简单,更小的计算结果 计算最终价值。计算m'的一种方法如下: - 注意任何数字都可以 表示为2的幂之和。所以首先计算值为13 ^ 2, 13 ^ 4,13 ^ 8,...通过反复平方连续值模数33. 13 ^ 2 =169≡4,13^ 4 = 4.4 = 16,13 ^ 8 = 16.16 =256≡25。
然后,由于7 = 4 + 2 + 1,我们得到m'= 13 ^ 7 = 13 ^( 4 + 2 + 1)= 13 ^ 4.13 ^ 2.13 ^ 1
≡16x 4 x 13 = 832 ≡7mod 33
答案 5 :(得分:1)
您是否尝试计算(a^b)%n
或a^(b%n)
?
如果您想要第一个,那么只有当 b 为偶数时,您的代码才有效,因为 b / 2 。 “if b%n==1
”不正确,因为您在此处不关心b%n
,而是关注b%2
。
如果你想要第二个,那么循环是错误的,因为你循环 b / 2 次而不是(b%n)/ 2 次。 / p>
无论哪种方式,您的功能都不必要地复杂。为什么要循环直到 b / 2 并尝试每次乘以2 a?为什么不循环直到 b 并且每次都在一个多个循环中。这将消除许多不必要的复杂性,从而消除潜在的错误。您是否认为通过将循环次数减半来使程序更快?坦率地说,这是一个糟糕的编程实践:微优化。它并没有多大帮助:你仍然乘以相同的次数,你所做的就是减少测试循环的次数。如果b通常较小(如一个或两个数字),那就不值得了。如果b很大 - 如果它可能是数百万 - 那么这是不够的,你需要一个更激进的优化。
另外,为什么%n
每次都在循环中?为什么不在最后做一次呢?
答案 6 :(得分:1)
计算pow(a,b)mod n
OP代码的一个关键问题是a * a
。当int
足够大时,这是a
溢出(未定义的行为)。 res
的类型与a * a
的乘法无关。
解决方案是确保:
n
,n*n <= type_MAX + 1
没有理由返回比 modulus 的类型更宽的类型,因为结果总是由该类型表示。
// unsigned long int decrypt2(int a,int b,int n)
int decrypt2(int a,int b,int n)
使用 unsigned 数学肯定更适合OP的RSA目标。
// (a^b)%n
// n != 0
// Test if unsigned long long at least 2x values bits as unsigned
#if ULLONG_MAX/UINT_MAX - 1 > UINT_MAX
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
unsigned long long result = 1u % n; // Insure result < n, even when n==1
while (b > 0) {
if (b & 1) result = (result * a) % n;
a = (1ULL * a * a) %n;
b >>= 1;
}
return (unsigned) result;
}
#else
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
// Detect if UINT_MAX + 1 < n*n
if (UINT_MAX/n < n-1) {
return TBD_code_with_wider_math(a,b,n);
}
a %= n;
unsigned result = 1u % n;
while (b > 0) {
if (b & 1) result = (result * a) % n;
a = (a * a) % n;
b >>= 1;
}
return result;
}
#endif
答案 7 :(得分:0)
int
通常是不够的(除非你正在处理小的简化例子)
你需要一个数据类型,可以存储最多2个 256 (对于256位RSA密钥)或2个 512 对于512位密钥等的整数
答案 8 :(得分:0)
此(加密)更多的是算法设计问题,而不是编程问题。重要的缺失部分是对现代代数的熟悉。我建议您在群体理论和数论中寻求巨大的优化。
如果n
是质数,则pow(a,n-1)%n==1
(假设无穷数字整数)。因此,基本上,您需要计算pow(a,b%(n-1))%n
;根据群论,您可以找到e
,使得每隔一个数字就等于e
乘幂n
的幂。因此,范围[1..n-1]
可以表示为e
的幂的排列。给定用于为e
找到n
并以a
为底e
的对数的算法,可以显着简化计算。密码学需要一定的数学背景知识;我宁愿没有足够的背景知识离开这一领域。
答案 9 :(得分:0)
对于我在php中的代码 a ^ k mod n :
function pmod(a, k, n)
{
if (n==1) return 0;
power = 1;
for(i=1; i<=k; $i++)
{
power = (power*a) % n;
}
return power;
}
答案 10 :(得分:0)
这是另一种方式。请记住,当我们在mod modulo multiplicative inverse
下找到a
的{{1}}时。
然后
a 和 m 必须彼此
m
。
我们可以使用coprime
来计算gcd extended
。
当modulo multiplicative inverse
和a
可以具有10个以上的时,用于计算 a b mod m 5 位数,然后很难计算结果。
下面的代码将完成计算部分:
b
该代码之所以有效,是因为 a b mod m 可以写为(a mod m ) b mod m-1 mod m 。
希望它对 {:)
有帮助答案 11 :(得分:-1)
使用快速取幂可能.....给出与上面的模板相同的o(log n)
int power(int base, int exp,int mod)
{
if(exp == 0)
return 1;
int p=power(base, exp/2,mod);
p=(p*p)% mod;
return (exp%2 == 0)?p:(base * p)%mod;
}
答案 12 :(得分:-2)
#include <cmath>
...
static_cast<int>(std::pow(a,b))%n
但我最好的选择是你溢出int(IE:这个数字是两个大的int)的功率我有同样的问题创建完全相同的功能。
答案 13 :(得分:-2)
我正在使用此功能:
int CalculateMod(int base, int exp ,int mod){
int result;
result = (int) pow(base,exp);
result = result % mod;
return result;
}
我解析变量结果因为pow给你一个double,而对于使用mod你需要两个int类型的变量,无论如何,在RSA解密中,你应该只使用整数。