模块化逆计算

时间:2019-10-30 03:02:49

标签: algorithm math

给出任意整数pgr并赋予y使得y = gx mod p,其中x是未知整数,如何解决CC = gr• (gx)-1 mod p的地方?

我的数学在下面,但是当我在验证程序功能中输入数学运算时,它说答案不正确。

    y•u = 1 mod p

    y•u = 1 + mp
    uy - mp = 1

其中uy的倒数,而m是自然数的集合(因为mod的倒数要求这样做)

1 个答案:

答案 0 :(得分:0)

如果我看对了,您正在寻找逆模。数学是这样的:

ab = a^b % p
ab + c*p = a^b
log(ab+c*p)/log(a) = b
(ab+c*p)^(1/b) = a

其中c是整数c={ 0,1,2,3,4... },可在常规算术和模块化算术之间转换。因此,您要计算b。问题是,如果log(ab+c*p)/log(a)不比c大,则p的增长会随着a的增长而非常缓慢。因此,在这种情况下,更快地使用b的所有组合,直到在C ++中找到类似这样的拟合为止:

//---------------------------------------------------------------------------
ALU32 alu;
DWORD modmul(DWORD a,DWORD b,DWORD p)   //  ans = a*b % p
    {
    DWORD ch,cl,c,d;
    alu.mul(ch,cl,a,b);
    alu.div(c,d,ch,cl,p);
    return d;
    }
//---------------------------------------------------------------------------
DWORD modinv(DWORD a,DWORD p)   //  a * ans % p = 1
    {
    DWORD b,c,db,dc,i=0;
    db=p/a;
    dc=db*a;
    for (b=1,c=a;b<p;i++)
        {
        if (c==1) return b;
        b+=db; c+=dc;
        while (c<p){ b++; c+=a; }
        c-=p;
        }
    return 0;
    }
//---------------------------------------------------------------------------

DWORD modpow(DWORD a,DWORD b,DWORD p)   //  ans = a^b % p
    {   // b is not mod(p) !
    DWORD i,d=1;
    for (a%=p,i=0;i<32;i++,b<<=1)
        {
        d=modmul(d,d,p);
        if (DWORD(b&0x80000000)) d=modmul(d,a,p);
        }
    return d;
    }
//---------------------------------------------------------------------------
DWORD imodpow(DWORD ab,DWORD a,DWORD p) // ab = a^ans % p
    { // ans is not mod(p) !
    DWORD b,AB;
    for (AB=1,b=0;;)
        {
        if (AB==ab) return b;
        b++; if (!b) return  0;
        AB=modmul(AB,a,p);
        }
    }
//---------------------------------------------------------------------------

这是SLOOOOW,这就是为什么用于加密的原因... 另外,请注意,有多个有效的解决方案,发现的第一个可能不是您要寻找的解决方案,因此您需要添加其他条件...

ALU32.h可以在这里Cant make value propagate through carry

中找到

并且模块化算术基于此:Modular arithmetics and NTT (finite field DFT) optimizations

这里有一个比较样本(忽略VCL和tbeg / tend / tstr函数):

DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;
tbeg(); ab=modpow(a,b,p); tend();   mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,b ,p,ab)+tstr(1));
tbeg(); bb=imodpow(ab,a,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,bb,p,ab)+tstr(1));

并输出:

87654321^12345678 mod 3221225473 = 3038293251 [   0.002 ms]
87654321^12345678 mod 3221225473 = 3038293251 [ 421.910 ms]

PS。

如果p很特殊,例如质数,两个质数的合成,甚至是单位的第n个根,那么可能会采用一些更高级的方法,但是它位于离我很远的星系中专业知识。

[edit1]

从您新发布的question中可以明显看出,您确实只是想要modular inverse,而与imodpow无关。所以你想要的是这个

a*b % p = 1

b未知的地方,因此只需按递增方式尝试所有b,其中a*b % p只是被p截断为零,如果结果为1,则您找到了答案。我使用modinv函数更新了上面的代码,并进行了一些优化。但是,我认为使用GCD或其他方法可以更快地实现这一目标。

这里有另一个测试样本:

DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;

        ab=modmul(a,b,p);
tbeg(); bb=modinv(b,p);     tend(); mm_log->Lines->Add(AnsiString().sprintf("       1/%8u mod %u = %u ",b,p,bb)+tstr(1));
tbeg(); a =modmul(b,bb,p);  tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",b,bb,p,a)+tstr(1));
tbeg(); a =modmul(ab,bb,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",ab,bb,p,a)+tstr(1));

并输出:

       1/12345678 mod 3221225473 = 165081805  [   4.999 ms]
12345678*165081805 mod 3221225473 = 1         [   0.000 ms]
652073126*165081805 mod 3221225473 = 87654321 [   0.000 ms]