Pohlig-Hellman算法求解离散对数问题
离散对数(DLP)问题:
a
x
≡
b
(
m
o
d
p
)
a^{x} \equiv b \pmod{p}
ax≡b(modp)
p
p
p是大素数。
前面已经介绍了求解离散对数问题的小步大步算法(BSGS)(时间复杂度是 O ( p ) O(\sqrt{p}) O(p)),这里介绍另外一种求解光滑阶循环群上的离散对数的方法——Pohlig-Hellman方法。事实上,Pohlig-Hellman算法的复杂度在一般情况下比BSGS算法高!但是在特殊情况下(循环群的阶是光滑数,即可以因子分解成较小的数的乘积),使用Pohlig-Hellman能取得好的效果。而且有些时候,尽管BSGS能够将复杂度降至 p \sqrt{p} p,但是这个数依然很大,所以不能用。这时我们可以考虑Pohlig-hellman方法能不能起作用。
算法思想
考虑上述DLP问题。因为
p
p
p是大素数,模
p
p
p的循环群的阶是
p
−
1
p-1
p−1。假设模
p
p
p的最小的本原元是
g
g
g(本原元是可以求的),那么有
a
≡
g
a
′
(
m
o
d
p
)
b
≡
g
b
′
(
m
o
d
p
)
a\equiv g^{a'}\pmod{p}\\ b\equiv g^{b'}\pmod{p}
a≡ga′(modp)b≡gb′(modp)
进一步有
a
x
≡
b
(
m
o
d
p
)
⟺
g
a
′
x
≡
g
b
′
(
m
o
d
p
)
a^{x} \equiv b\pmod{p} \iff g^{a'x}\equiv g^{b'} \pmod{p}\\
ax≡b(modp)⟺ga′x≡gb′(modp)
有
a
′
x
≡
b
′
(
m
o
d
p
−
1
)
a'x \equiv b' \pmod{p-1}
a′x≡b′(modp−1)
如果我们求出了满足上式的
a
′
a'
a′和
b
′
b'
b′,通过扩展的gcd方法可以求一次同余方程的解得到
x
x
x。
问题归结成如何求
a
′
a'
a′和
b
′
b'
b′。即原本的一个离散对数问题,现在变成两个离散对数问题:
a
≡
g
a
′
(
m
o
d
p
)
b
≡
g
b
′
(
m
o
d
p
)
a\equiv g^{a'}\pmod{p}\\ b\equiv g^{b'}\pmod{p}
a≡ga′(modp)b≡gb′(modp)
如何求解 a ′ a' a′和 b ′ b' b′
以求 a ′ a' a′为例,解DLP问题: g x ≡ a ( m o d p ) g^{x}\equiv a \pmod{p} gx≡a(modp)
将 p − 1 p-1 p−1进行标准的素因子分解,即 p − 1 = ∏ i = 1 m p i k i = p 1 k 1 p 2 k 2 p 3 k 3 ⋯ p m k m p-1=\prod \limits_{i=1}^{m}p_{i}^{k_{i}}=p_{1}^{k_{1}}p_{2}^{k_{2}}p_{3}^{k_{3}}\cdots p_{m}^{k_{m}} p−1=i=1∏mpiki=p1k1p2k2p3k3⋯pmkm
对每个素因子 p i p_{i} pi,将 x x x表示成 p i p_{i} pi进制,有 x = a 0 + a 1 p i + a 2 p i 2 + a 3 p i 3 + ⋯ + a k i − 1 p i k i − 1 ( m o d p i k i ) x=a_{0}+a_{1}p_{i}+a_{2}p_{i}^{2}+a_{3}p_{i}^{3}+\cdots+a_{k_{i}-1}p_{i}^{k_{i}-1} \pmod{p_{i}^{k_{i}}} x=a0+a1pi+a2pi2+a3pi3+⋯+aki−1piki−1(modpiki),这样的 p i p_{i} pi进制表示,系数 a i a_{i} ai自然是小于 p i p_{i} pi
令 r = 1 r=1 r=1,有
( g x ) p − 1 p i r ≡ a p − 1 p i r ( m o d p ) \left( g^{x} \right)^{\frac{p-1}{p_{i}^{r}}}\equiv a ^{\frac{p-1}{p_{i}^{r}}} \pmod{p} (gx)pirp−1≡apirp−1(modp)
展开 x x x有
( g a 0 + a 1 p i + a 2 p i 2 + a 3 p i 3 + ⋯ + a k i − 1 p i k i − 1 ) p − 1 p i r ≡ a p − 1 p i r ( m o d p ) g a 0 ∗ p − 1 p i × g a 1 ( p − 1 ) × g a 2 ( p − 1 ) p i × ⋯ × g a k i − 1 ( p − 1 ) p i k i − 2 ≡ a p − 1 p i ( m o d p ) \left( g^{a_{0}+a_{1}p_{i}+a_{2}p_{i}^{2}+a_{3}p_{i}^{3}+\cdots+a_{k_{i}-1}p_{i}^{k_{i}-1} } \right)^{\frac{p-1}{p_{i}^{r}}}\equiv a ^{\frac{p-1}{p_{i}^{r}}} \pmod{p}\\ g^{a_{0}* \frac{p-1}{p_{i}}}\times g^{a_{1}(p-1)} \times g^{a_{2}(p-1)p_{i}}\times \cdots \times g^{a_{k_{i}-1}(p-1)p_{i}^{k_{i}-2}}\equiv a ^{\frac{p-1}{p_{i}}} \pmod{p} (ga0+a1pi+a2pi2+a3pi3+⋯+aki−1piki−1)pirp−1≡apirp−1(modp)ga0∗pip−1×ga1(p−1)×ga2(p−1)pi×⋯×gaki−1(p−1)piki−2≡apip−1(modp)
注意从第二项开始,每一项指数都包含 p − 1 p-1 p−1(由费马小定理知 g p − 1 ≡ 1 ( m o d p ) g^{p-1} \equiv 1\pmod{p} gp−1≡1(modp)),所以式子变成
g a 0 ∗ p − 1 p i ≡ a p − 1 p i ( m o d p ) g^{a_{0}* \frac{p-1}{p_{i}}} \equiv a ^{\frac{p-1}{p_{i}}} \pmod{p} \\ ga0∗pip−1≡apip−1(modp)
这个式子中只有 a 0 a_{0} a0是未知的,因为 a 0 ∈ [ 0 , p i − 1 ] a_{0} \in \left[ 0,p_{i}-1 \right] a0∈[0,pi−1],所以可以穷举得到 a 0 a_{0} a0的值。再令 r = 2 、 3 、 4 、 ⋯ 、 k i r=2、3、4、\cdots 、k_{i} r=2、3、4、⋯、ki ,重复步骤3,依次穷举求出 a 1 , a 2 , ⋯ , a k i − 1 a_{1},a_{2},\cdots ,a_{k_{i}-1} a1,a2,⋯,aki−1,整个的时间复杂度是 O ( p i k i ) O(p_{i}k_{i}) O(piki)。那么可以的到
x = a 0 + a 1 p i + a 2 p i 2 + a 3 p i 3 + ⋯ + a k i − 1 p i k i − 1 ( m o d p i k i ) x=a_{0}+a_{1}p_{i}+a_{2}p_{i}^{2}+a_{3}p_{i}^{3}+\cdots+a_{k_{i}-1}p_{i}^{k_{i}-1} \pmod{p_{i}^{k_{i}}} x=a0+a1pi+a2pi2+a3pi3+⋯+aki−1piki−1(modpiki)重复上述过程,得到 m m m个关于 x x x的式子,利用中国剩余定理(CRT),可以计算出 x x x的值。
利用这个方法求出 a ′ a' a′和 b ′ b' b′后,就可以得到原DLP问题的解。
举例
关于举例和代码可以看这个博客离散对数问题——pohlig-hellman算法讲解(有例子)。
Q&A
- 但是看完这个算法的流程之后,我就产生一个问题:为什么要先把 a x ≡ b ( m o d p ) a^{x}\equiv b\pmod{p} ax≡b(modp)转化成
a
≡
g
a
′
(
m
o
d
p
)
b
≡
g
b
′
(
m
o
d
p
)
a\equiv g^{a'}\pmod{p}\\ b\equiv g^{b'}\pmod{p}
a≡ga′(modp)b≡gb′(modp)
计算出
a
′
a'
a′和
b
′
b'
b′之后再得到
x
x
x?直接利用后面的方法求出
x
x
x不行吗?
答:Pohlig-Hellman算法最重要的点是利用了原根的性质,它只能解决 a ≡ g x ( m o d p ) a\equiv g^{x}\pmod{p} a≡gx(modp)( g g g是原根)的问题,对于 g g g不是原根的情况,需要利用原根将原方程转化成两个关于原根的离散对数问题。为什么呢?
可以看算法中,在利用
p
i
p_{i}
pi进制表示之后,得到了
g
a
0
∗
p
−
1
p
i
≡
a
p
−
1
p
i
(
m
o
d
p
)
g^{a_{0}* \frac{p-1}{p_{i}}} \equiv a ^{\frac{p-1}{p_{i}}} \pmod{p}
ga0∗pip−1≡apip−1(modp)
这个式子,然后穷举得到
a
0
a_{0}
a0的值。如果
g
g
g不是原根,则有
g
g
g的阶不会是
p
−
1
p-1
p−1,可能有
g
p
−
1
p
i
≡
1
(
m
o
d
p
)
g^{\frac{p-1}{p_{i}}} \equiv 1 \pmod{p}
gpip−1≡1(modp),这样无论
a
0
a_{0}
a0取何值,式子始终成立,无法求出
a
0
a_{0}
a0,算法就失效了。
- 注意Pohlig-hellman只能用于求解光滑阶群,也就是 p − 1 p-1 p−1可以分解成小的素因子乘积。否则,穷举 a i a_{i} ai的时间复杂度依旧很高。另外可以考虑在穷举 a i a_{i} ai时利用小步大步算法,进一步优化算法复杂度。