C++ 使用加法链计算(a^x)模n。C++;

C++ 使用加法链计算(a^x)模n。C++;,c++,math,cryptography,modular-arithmetic,C++,Math,Cryptography,Modular Arithmetic,我读过密码学,在Bruice Schneier的《应用密码学》(Applied cryptography)一书中,我发现上述算法能够以较低的计算成本计算(x^y)mod n。它基本上使用一种称为加法链的算法来减少计算中的乘法量。我能够在纸上和笔上使用这个过程,但是尽管一遍又一遍地阅读上面的代码,我仍然无法理解它是如何工作的。因此,请给我指出正确的方向(某种文章链接),我可以在这里分析上述算法,或者如果你能在这里给出解释,这将非常有帮助 附言:本书中没有对代码进行解释。指数y被写成二的幂和,即二进

我读过密码学,在Bruice Schneier的《应用密码学》(Applied cryptography)一书中,我发现上述算法能够以较低的计算成本计算
(x^y)mod n
。它基本上使用一种称为加法链的算法来减少计算中的乘法量。我能够在纸上和笔上使用这个过程,但是尽管一遍又一遍地阅读上面的代码,我仍然无法理解它是如何工作的。因此,请给我指出正确的方向(某种文章链接),我可以在这里分析上述算法,或者如果你能在这里给出解释,这将非常有帮助


附言:本书中没有对代码进行解释。

指数
y
被写成二的幂和,即二进制

考虑一个实际的例子:
(x**11)%M
。从数学上讲

unsigned long qe2(unsigned long x, unsigned long y , unsigned long n)
{
    unsigned long s,t,u;

    s=1; t=x; u=y;

    while(u)
    {
        if(u&1)
            s = (s*t)%n;
        u>>=1;
        t= ( t*t)%n;
    }
    return s;
}
这很有用,因为一个简单的循环就足以计算两次幂的幂。例如,如果要计算
x**(2**i)

请注意,测试
(i&index)
是一个二进制AND运算,如果结果为非零,则为真;如果结果为零,则为假。因为
i
是二的幂,所以在二进制中它有一个
1
,所有其他二进制数字为零,因此它基本上测试用二进制编写的指数在该位置是否有一个
1

OP的代码更简单,因为它不使用单独的变量
i
因子
,而是将
指数
向右移动(删除最右边的二进制数字),并使用
本身。就是

unsigned long power(unsigned long basis,
                    unsigned long exponent)
{
    unsigned long result = 1u;
    unsigned long factor = basis;
    unsigned long i;

    for (i = 1u; i < exponent; i = i * 2u) {
        /* i is some power of two,
           and factor = basis**i.
        */

        /* If i is in the sum (of powers of two) for exponent,
           we include the corresponding power of basis
           in the product. */
        if (i & exponent)
            result = result * factor;

        /* Update factor for the next i. */
        factor = factor * factor;
    }

    return result;
}
模运算是最后的折痕,但它也很琐碎。如果计算某个正整数的乘积,则可以对每个项和每个临时结果应用模运算符,而不会影响结果:

unsigned long power(unsigned long basis,
                    unsigned long exponent)
{
    unsigned long result = 1u;

    while (exponent > 0u) {
        if (exponent & 1u)
            result = result * basis;
        basis = basis * basis;
        exponent = exponent >> 1;
    }

    return result;
}
这显然很有用,因为您可以计算任意数量项的乘积,所有项都小于
m
,所有中间项都小于
m*m


这种求幂运算的时间复杂度是O(logn),其中N是指数。

了解其工作原理的最佳方法可能是使用调试器逐行遍历代码。然后观察变量值在每一步是如何变化的。“加法链”是用来描述这类算法的通用术语。但是,这是一个简化的特殊情况,通常称为,并且您可以找到许多使用该搜索词的文档。由于Stack Overflow对您隐藏了密切的原因:“要求我们推荐或查找书籍、工具、软件库、教程或其他非现场资源的问题与Stack Overflow无关,因为它们往往会吸引固执己见的答案和垃圾邮件。相反,请描述问题以及迄今为止为解决问题所做的工作。”这帮助了我,谢谢,但是我认为代码中有一个错误:在函数power()的第二个示例中,结果最初是零(我认为应该是1)。。它一直保持为零直到结束,因此函数将始终返回零。@RatulThakur:当然,两个
power()
函数都应该以
result=1u
开头。固定的。抢手货非常感谢。
unsigned long power(unsigned long basis,
                    unsigned long exponent)
{
    unsigned long result = 1u;
    unsigned long factor = basis;
    unsigned long i;

    for (i = 1u; i < exponent; i = i * 2u) {
        /* i is some power of two,
           and factor = basis**i.
        */

        /* If i is in the sum (of powers of two) for exponent,
           we include the corresponding power of basis
           in the product. */
        if (i & exponent)
            result = result * factor;

        /* Update factor for the next i. */
        factor = factor * factor;
    }

    return result;
}
unsigned long power(unsigned long basis,
                    unsigned long exponent)
{
    unsigned long result = 1u;

    while (exponent > 0u) {
        if (exponent & 1u)
            result = result * basis;
        basis = basis * basis;
        exponent = exponent >> 1;
    }

    return result;
}
(a * b * c * d * ... * z) % m
= ( (a % m) * (b % m) * (c % m) * ... * (z % m) ) % m
= ( ... (((((a % m) * (b % m)) % m) * (c % m)) % m) * ... * (z % m)) % m