from Crypto.Util.number import*
c = 63488316931652165283768913693816254792896563414188573961010693330775143775030913217280890394659049814570506800869658798199766919279796699387348933980902437475407321186495972207055265266498997713893677789253948774459839170286422387924339017064620132596766605191433871936998603329570606903349148944177923042129
e = 65537
n = 96718802331928486399440471324839538140537235267473988763367174256395151407905179947160991624325793272001609865770400579479699246848732420404657206862379932460142346799183080432865152364837341193526953437531245191267443260742413602677075914430257485504145532873739572516607058139153045169040886155418058016911
x = 463242922872367824870065968430782963359186990291269168445088582686817098312265100478236517597115371129636612590922320350
p = [0]
q = [0]
maskx = 1
maskn = 2
for i in range(400):
xbit = (x & maskx)>>i
nbit = n % maskn
tmpp = []
tmpq = []
for j in range(len(p)):
for pbar in range(2):
for qbar in range(2):
if pbar^qbar ==xbit:
temp2 = n % maskn
temp1 = (pbar * maskn //2 + p[j]) * (qbar * maskn//2 + q[j]) % maskn
if temp1 == temp2:
tmpp.append( pbar * maskn // 2 + p[j])
tmpq.append( qbar * maskn // 2 + q[j])
maskx *= 2
maskn *= 2
p = tmpp
q = tmpq
print(i,len(p))
这次来研究一下大佬的dfs代码。代码如上,可以自己先调试分析下。
题目的条件是已知p和q低400个二进制位的异或结果。这个条件其实不够强,简单来想的话,400个位异或结果知道了,每个位都有两种可能,400个位就有2**400种可能,遍历是不可能的。但是结合 n=p*q ,设计算法其实可以较快得到精准的p和q的低400位。
下面来分析下算法:
该算法的基本思路是逐位根据条件得到可能的(p,q)对,每次更新p和q的表,更新的依据有两个:
step1:
if pbar^qbar ==xbit
表示这个位符合题目给的异或结果
step2:
temp2 = n % maskn
temp1 = (pbar * maskn //2 + p[j]) * (qbar * maskn//2 + q[j]) % maskn
if temp1 == temp2:
这一段先是构造在现有可能的 p 和 q 的前 j 位的前面接上通过第一层筛选的pbar和qbar,来测试这些位相乘得到的结果是不是与n相符,进而得到 j+1 位的情况下的可能的(p,q)对
重复step1,2 400次即可获得可能的(p,q) 的低400位的情况。
然后利用sage逐个带入求根(能求出来的那个就是本来的q,p):
N = n
pbits = 512
for i in range(len(p)):
pbar = p[i]
kbits = 514 - len(bin(pbar))
R.<x> = Zmod(n)[]
f = (pbar + x * 2 ** (512-kbits)).monic()
rot = f.small_roots(X = 2^kbits,beta = 0.4)
if rot:
print(pbar + rot[0] * 2 ** (512-kbits))
得到p,q题就完事了。