Baby-step giant-step
称之为大步小步算法,一种解决离散对数问题的方法,其主要思路是中间相遇攻击。
我们可以把这个 x
转化为x = i*m+j
, 而这个m的值就是⌈√n⌉, 并且i
和j
的值要在m
的范围内,所以m的值决定着该算法计算出结果所需要的时间。
所以该式可变为:
接下来就可以枚举j
,计算g^j
的结果并存储下来,接着枚举i
计算y*g^(-m*j)
的值,找到g^j
和y*g^(-m*j)
相等的时候,这时的i
和j
就是我们要找的值。之后带入x = i*m + j
,这时i*m+j
的值就是x
的值。
例:
已知:g = 17 p = 509 y = g^x%p = 438 计算x的值
对于这个式子我们就可以先枚举j
先算出结果并存入列表中。
j | g^j % p |
---|---|
1 | 17 |
13 | 238 |
25 | 278 |
44 | 356 |
59 | 438 |
然后我们在对i
进行枚举
i | yg^(-m*i) % p |
---|---|
1 | 199 |
2 | 238 |
25 | 185 |
44 | 368 |
59 | 445 |
这里可以找到i=2, j=13
时,他们求出来得值是一样的,所以可以算出 x=i*m+13, m在这里是23
, 所以可以算出m
的值为59
算法代码:
from gmpy2 import *
g = 17
p = 509
y = 438
m = iroot(p, 2)[0] + 1
def BSGS(g, y, p):
m = iroot(p, 2)[0] + 1
s = {pow(g, j, p): j for j in range(m)}
gs = pow(g, -m, p)
for i in range(m):
if y in s:
return m*i + s[y]
y = y * gs % p
return None
print(BSGS(g, y, p))
再举个用在CTF中的例子:
from libnum import *
from gmpy2 import *
flag = "flag{big_and_small}"
a = s2n(flag)
print(a)
m = a >> 16 << 16
p = generate_prime(1024)
g = 5
y = pow(g,a,p)
print(f"m = {m}")
print("g =", g)
print("p =", p)
print("y =", y)
#m = 2284117282071477104642039231536944446836572160
#g = 5
#p = 117061102100923822494374971271356428838245797897131713833497324490347029897509453234867144323074426358251468387009784964409490629474760505325012358657612358218630936761844853452752207513376553400570437173183245325363865380385444332069521612219917516076129636378470207520184345636826950827640031147884327602403
#y = 36330338308028857799449375552374448525921689801126735837219113818543840068942804412602004817464522788143367479566994608891201675854663902669408381421532026724950780811697860458785100785315287105361742435587380380417609918284799177467034247188834721615753928207192485082356827804549590792117891230279436213258
这道题也要用到BSGS(大步小步算法)。已知m
的值是a
向右向左移位16
位得到的数,要求的数是m
缺少的16位数, 所以可以把目标设为只求缺少的数,这样我们要求的数字最大就是(2^16)
,而不是去整体计算a
这个大值。
接下来可以写出算法代码:
from libnum import *
from gmpy2 import *
m = 2284117282071477104642039231536944446836572160
g = 5
p = 104902226273988324576427043280139630983677434981789024088951356016939994526304119354435543071985576434554541580765980475339863817923069063092822047759376193281443519615446894334112711636144801809678018855363243259870518701678872861580764859373668820885488992214504069164524801155987240703746883303678741931657
y = 52132387535704137390458836331516728932227502073670482441552732370459557430160087735998314933737812855984248770511516860301143061293647971484306910330283327130899876785232553721318312581135200914802966676159312701878015611579070659605675344114334474279389271370807188711609485615280774712598619602033548583710
def BSGS(g, y, p, bound):
x = iroot(bound, 2)[0] + 1
s = {pow(g, j, p): j for j in range(x)}
sg = pow(g, -m, p)
for i in range(m):
if y in s:
return i*x + s[y]
y = y * sg % p
return None
a = BSGS(g, y*invert(pow(g,m,p), p)%p, p, 2**32) + m
print(n2s(int(a)))
#b'flag{big_and_small}'
在这个代码中。
y*invert(pow(g, m, p), p) % p
:表示的是
这样我们就只需要求a_low
的值即可。