f = 2^kbits*x + p0 f = f.monic() roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3,在实际使用脚本的时候可以自己手动改nbits等参数,理解了原理再看脚本就很清楚明了了 if roots: x0 = roots[0] p = gcd(2^kbits*x0 + p0, n) return ZZ(p)
def find_p(d0, kbits, e, n): X = var('X')
for k in xrange(1, e+1): results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits) for x in results: p0 = ZZ(x[0]) p = partial_p(p0, kbits, n) if p: return p
if __name__ == '__main__': n = e = d0 = kbits = # 未知的d的bits数目 p = find_p(d0, kbits, e, n) print("found p: %d" % p) q = n//p print(inverse_mod(e, (p-1)*(q-1)))
如果将1、2两步分开列式,则修改函数find_p如下
1 2 3 4 5 6 7 8 9 10 11 12 13
def find_p(d0, kbits, e, n): X = var('X') for k in range(1, e+1): results = solve_mod([e*d0*X - k*X*(n-X+1)== X], 2^kbits) for x in results: s = ZZ(x[0]) pvar = var('p') p_results = solve_mod([pvar*pvar-s*pvar+n==0],2^kbits) for p0 in p_results: p0 = ZZ(p0[0]) p = partial_p(p0, kbits, n) if p: return p
def find_q(d0, kbits, e, qr, p): X = var('X') for k in range(1, e + 1): temp = k*(p-1) results = solve_mod([e*d0*X+temp*qr-temp*X*(qr-X+1)==X], 2 ^ kbits) for x in results: q = ZZ(x[0]) if qr % q == 0: return q return None
if __name__ == '__main__': qr = 6857671284539062742975668483013695756136974308830302383869017675211748459038460434623218652374536550644287079851235538790745857383008797698872874798021995947967308637270510423795384863442755166813716746318469915880844736019524077541319597047087620854791342900521099848683663304636436936596021386279685708537 p = 2141698433991046082370939321691850154692026423424010392532982575546199921995522418737105878977898158159119041866620684371362271661642476751663585379591337 c = 4329606906986929520922207896899782825966852252045645553852666134465727605375552409314262439896695961792039946511877813768609658516837096110397826574615865145364406310497152725490038135469839136190625952342503082553246584871237205558902774064100332461452316195663446307120094941991930964324406679011451626126064494215289724959537793057773764253924636259378833228904446486925068109314698993641720938647836132806653451109926428309922461595730642461604303078237048 d0 = 0x8e6f66a517d9c8a610eb65dac5a613e72d47a29beaa5c77a9eb857e0db5d09eadf3a317776fdf27b0d85db0b6677afc8e0683d6dc2b4580281b6e99c3050f649213c37 e = 7 kbits = 540 q = find_q(d0, kbits, e, qr, p) print(q) # q = 2505948797318027758820680066583904581437202552654881626817593379353882875609223855015707273771918291251411562855290697544161987271016184806489110771554269