Pohlig-Hellman
Pohlig-Hellman
一种解决离散对数问题的方法,针对循环群的阶光滑的情况
这里我们考虑模p的乘法群下Pohlig-Hellman的应用
对于同余方程ax=b(mod p),其中p-1光滑
设p-1=\(p_1^{α_1}p_2^{α_2}...p_n^{α_n}\)
对于pi
设x=\(\sum_{j=0}^{α_i-1}a_jp_i^j(mod p_i^{α_i})\)
由同余方程ax=b(mod p)=>\(a^{\frac{p-1}{p_i^s}*x}=b^{\frac{p-1}{p_i^s}}(mod p)\)
记A=\(a^{\frac{p-1}{p_i^s}}\),B=\(b^{\frac{p-1}{p_i^s}}\)
=>Ax=B(mod p)
∵\(A^{p_i^s}=1(mod p)\)=>\(A^{\sum_{j=0}^{s-1}a_jp_i^j}=B(mod p)\)(※)
对(※)我们从s=1开始计算直到αi,可知每次在复杂度为O(p)下枚举aj的取值即可
最后可得\(x(mod p_i^{α_i})\)的值(i=0,1,...,n)
中国剩余定理即可求得x(mod p-1)
代码实现
def Polig_Hellman(g,y,p):
factors, exponents = zip(*factor(p-1))
temp=[]
for i in range(len(factors)):
q=factors[i]
a=[]
for j in range(1,exponents[i]+1):
gg=pow(g,((p-1)//q^j),p)
yy=pow(y,((p-1)//q^j),p)
for k in range(q):
s=0
for t in range(len(a)):
s+=a[t]*q^t
s+=k*q^(len(a))
if pow(gg,s,p)==yy:
a.append(k)
break
x_q=0
for j in range(len(a)):
x_q+=a[j]*q^j
temp.append(x_q)
f=[]
for i in range(len(factors)):
f.append(factors[i]^exponents[i])
return crt(temp,f)
p=176473303538524259200554324953336384726672109110665668162293282699973540848874702767584458062843333942678732811932897476909679289489853667242704250498709920215500564359945126566451281262283662096646326724094693217360879121741192532765498098061185923631716696944607478088126741032221004102364580340388512170139
G=GF(p)
g=3
y=pow(3,1561654659848997911129,p)
print(discrete_log(G(y),G(g)))
x=Polig_Hellman(g,y,p)
print(pow(g,x,p)-y)
这里有个神奇的事情就是我自己写的p-h算出来的x和我初设的不同,实际上满足的是在g模p的阶下同余,sage自带的discrete_log是会自动约化到小于阶的情况
summary
总的来说,p-h算法在解决光滑阶循环群的dlp问题是一个十分有力的工具,所反映的思想也很值得学习,上述代码在计算O(p)时可以采用bsgs进一步降低复杂度