给出任意整数p
,g
和r
并赋予y
使得y = gx mod p
,其中x
是未知整数,如何解决C
在C = gr• (gx)-1 mod p
的地方?
我的数学在下面,但是当我在验证程序功能中输入数学运算时,它说答案不正确。
y•u = 1 mod p y•u = 1 + mp uy - mp = 1
其中u
是y
的倒数,而m
是自然数的集合(因为mod的倒数要求这样做)
答案 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]