计算pow(a,b)mod n

时间:2011-12-13 21:08:08

标签: c++ c algorithm

我想计算一个 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;
}

14 个答案:

答案 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;
}

您可以在文献中找到此算法和相关讨论。

的244
  

Schneier,Bruce(1996)。应用密码学:C,第二版(第2版)中的协议,算法和源代码。威利。 ISBN 978-0-471-11709-4。


请注意,此简化版本中的乘法result * basebase * 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 / 2a * 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)%na^(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

  1. OP代码的一个关键问题是a * a。当int足够大时,这是a溢出(未定义的行为)。 res的类型与a * a的乘法无关。

    解决方案是确保:

    • 乘法用2x宽数学或
    • 完成
    • 模数 nn*n <= type_MAX + 1
  2. 没有理由返回比 modulus 的类型更宽的类型,因为结果总是由该类型表示。

    // unsigned long int decrypt2(int a,int b,int n)
    int decrypt2(int a,int b,int n)
    
  3. 使用 unsigned 数学肯定更适合OP的RSA目标。

  4. // (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)

对于RSA,

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 inversea可以具有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解密中,你应该只使用整数。