0x00 前言
之前学习了ECDSA 和 ECDH 算法。不难发现椭圆曲线的离散对数难题对该密码的安全性有着多么重要的作用。之前谈及,椭圆曲线的离散对数难题非常难,尽管如此,也应该有些方法可以解开这个问题。就好像对于模运算的密码系统,比如RSA而言,可以用yafu工具来强解,也可以上某网站查表,也包括一些共模攻击,小指数攻击等方法。
参考的网站
相关代码
0x01 BSGS 小步大步法
方法的英文名是Baby-step, giant-step,这个算法基于一个非常简单的道理
$$Q = xP = (am +b)P \Longrightarrow Q -amP = bP$$
1.1 算法简介
BSGS方法的步骤就是中间相遇。算是一种比较机智的暴力搜索法。该算法的工作步骤如下。
对于知道公钥和域参数六元组的情况下计算 $m = \sqrt{n}$
对于 $b={0..m}$,计算$bP$并打表
对于 $a={0..m}$
计算 $Q - amP$
寻找与 上式子结果相同的 $bP$
如果找到,那么$k=b + am$
那么所谓的baby其实就是b。而gaint 就是 am。参考某作者的一张图片,可以很清晰的阐明这个思路。
之所以取 $m = \sqrt{n}$ 是因为这样可以取遍所有 n的情况对于 $a = 0 ; Q = (0m + b)P$ 这样就去遍历了所有 $Q = (1..m)P$ 的情况
对于 $a = 1 ; Q = (m + b)P$ 这样就去遍历了所有 $Q = m + (1..m)P$ 的情况
...
对于 $a = m-1 ; Q = (m-1 + b)P$ 这样就去遍历了所有 $Q = (m)m + (1..m)P$ 的情况
之后来看下其复杂度,如果认为查表的速度为O(1),那么该算法的时间复杂度和空间复杂度是$O(\sqrt{n})$
实际上这还是一个非常大的数字。
对于prime256v1而言,$\sqrt{n}$大概为$3.402823669209385 \times 10^{38}$。即使是哈希表的每个节点占1B,那也必然是Memory Error。
1.2 算法实践
之后可以简单实践以下这个算法def BSGS(E, p, q):
# B
step = 0
hash_table = {}
m = math.floor(math.sqrt(E.GF))
for i in range(m):
tmp = E.get_scalar_multiplication(i, p)
hash_table[tmp] = i
hash_list = hash_table.keys()
# G
for a in range(m):
amP = E.get_scalar_multiplication(-a * m, p)
Q_amP = E.get_three_pionts(amP, q)
if Q_amP in hash_list:
return hash_table[Q_amP] + a * m, step
else:
step += 1
return 0, 0
对于这样的测试样例,很快就可以算出来了。(我算了102步)E = EllipticCurve(a=1, b=-1, p=10177, GF=10331)
p = (0x1, 0x1)
q = (0x1a28, 0x8fb)
k = 325
k0, step = BSGS(E, p, q)
0x02 Pollard rho 算法
刚才谈及,小步大步算法的空间复杂度太高,对于大参数曲线无法使用。因此得想些别的办法。pallard rho算法就是解决了这样的问题,时间复杂度与BSGS一样(但是理论上BSGS更快),空间复杂度只有$O(1)$
其核心思想是找到满足 $aP+bQ=AP+BQ$的参数$a,b,A,B$
对于 $Q