#生成64位的素数p作为模数,int为32位,超过int要在数字后加L p=random_prime(2L**64) #定义有限域GF(p) G=GF(p) #找一个模p的原根 gp ('znprimroot('+str(p)+')') #输出Mod(rt,p),则x是模p的原根 g=G(rt) #生成私钥 x=G(ZZ.random_element(p-1)) #公钥y=g^x mod p,由于已经定义在GF(p)上,因此g**x就是g^x mod p y=g**x
from operator import inv, mul, neg, add Z = Integers()
if operation in multiplication_names: identity = b.parent()(1) inverse = inv op = mul iford==None: ord = b.multiplicative_order() elif operation in addition_names: identity = b.parent()(0) inverse = neg op = add iford==None: ord = b.order() else: iford==Noneor identity==Noneor inverse==Noneor op==None: print(ord, identity, inverse, op)
iford < 100: c = identity for i inrange(ord): if c == a: # is b^i return Z(i) c = op(c,b)
m = ord.isqrt()+1# we need sqrt(ord) rounded up table = dict() # will hold pairs (b^j,j) for j in range(m) g = identity # will run through b**j for j inrange(m): if a==g: return Z(j) table[g] = j g = op(g,b)
g = inverse(g) # this is now b**(-m) h = op(a,g) # will run through a*g**i = a*b**(-i*m) for i inrange(1,m): j = table.get(h) ifnot j==None: # then a*b**(-i*m) == b**j return Z(i*m + j) if i < m-1: h = op(h,g)
defd_log(q): print("dlogging: ", q) dlogs = [] for f in factors: t = order//f qt = G_mul(q,t) gent = G_mul(gen, t) dlog = old_discrete_log(qt, gent, ord=f, operation='NONE', op=G_add, identity=zero, inverse=inverse) dlogs.append(dlog) ifNonein dlogs: raise ValueError("oh no") l = CRT_list(dlogs, factors) return l
gen = (,) c = (,) k = d_log(c) print(k)
大步小步算法(BSGS)
大步小步算法常用于求解用于解决解高次同余方程的问题,问题形式如:有同余方程$a^x \equiv b \pmod p$,$p$ 为质数,求最小非负整数解 $x$ 使得原方程成立。这类问题也称为离散对数问题。该算法的复杂度可以达到$O(\sqrt{p}\log{n})$甚至更低。
defbabystep_giantstep(g, y, p): m = int((p-1)**0.5 + 0.5) # Baby step table = {} gr = 1# g^r for r inrange(m): table[gr] = r gr = (gr * g) % p # Giant step gm = pow(g, -m, p) # gm = g^{-m} ygqm = y # ygqm = y * g^{-qm} for q inrange(m): if ygqm in table: # 右辺と左辺が一致するとき return q * m + table[ygqm] ygqm = (ygqm * gm) % p returnNone
g = y = p = x = babystep_giantstep(g, y, p) print(x) print(pow(g, x, p) == y)
defpollard_rho(g, y, p): q = (p-1) // 2 defnew_xab(x, a, b, g, y, p, q): subset = x % 3 if subset == 0: return ((x*x) % p, (a*2) % q, (b*2) % q) if subset == 1: return ((x*g) % p, (a+1) % q, b ) if subset == 2: return ((x*y) % p, a , (b+1) % q) x, a, b = 1, 0, 0 X, A, B = x, a, b for i inrange(1, p): x, a, b = new_xab(x, a, b, g, y, p, q) X, A, B = new_xab(X, A, B, g, y, p, q) X, A, B = new_xab(X, A, B, g, y, p, q) if x == X: break res = ((a - A) * pow(B - b, -1, q)) % q ifpow(g, res, p) == y: return res ifpow(g, res + q, p) == y: return res + q returnNone
g = y = p = x = pollard_rho(g, y, p) print(x) print(pow(g, x, p) == y)
# Baby-step Giant-step法 defbabystep_giantstep(g, y, p, q=None): if q isNone: q = p - 1 m = int(q**0.5 + 0.5) # Baby step table = {} gr = 1# g^r for r inrange(m): table[gr] = r gr = (gr * g) % p # Giant step try: gm = pow(g, -m, p) # gm = g^{-m} except: returnNone ygqm = y # ygqm = y * g^{-qm} for q inrange(m): if ygqm in table: return q * m + table[ygqm] ygqm = (ygqm * gm) % p returnNone
# Pohlig–Hellman法 defpohlig_hellman_DLP(g, y, p): crt_moduli = [] crt_remain = [] for q, _ in factor(p-1): x = babystep_giantstep(pow(g,(p-1)//q,p), pow(y,(p-1)//q,p), p, q) if (x isNone) or (x <= 1): continue crt_moduli.append(q) crt_remain.append(x) x = crt(crt_remain, crt_moduli) return x
g = y = p = x = pohlig_hellman_DLP(g, y, p) print(x) print(pow(g, x, p) == y)
deffind_congruences(B, g, p, congruences=[]): unique = lambda l: list(set(l)) bases = [] max_equations = prime_pi(B) whileTrue: k = randint(2, p-1) ok, factors = is_Bsmooth(B, pow(g,k,p)) if ok: congruences.append((factors, k)) iflen(congruences) >= max_equations: break bases = unique([base for c in [c[0].keys() for c in congruences] for base in c]) return bases, congruences
defto_matrices(R, bases, congruences): M = [[c[0][base] if base in c[0] else0 \ for base in bases] for c in congruences] b = [c[1] for c in congruences] return Matrix(R, M), vector(R, b)
defindex_calculus(g, y, p, B=None): R = IntegerModRing(p-1) if B isNone: B = ceil(exp(0.5*sqrt(2*log(p)*log(log(p))))) bases = [] congruences = [] for i inrange(100): bases, congruences = find_congruences(B, g, p, congruences) M, b = to_matrices(R, bases, congruences) try: exponents = M.solve_right(b) break except ValueError: # matrix equation has no solutions continue else: returnNone # ag^y mod p whileTrue: k = randint(2, p-1) ok, factors = is_Bsmooth(B, (y * pow(g,k,p)) % p) if ok andset(factors.keys()).issubset(bases): print('found k = {}'.format(k)) break print('bases:', bases) print('q:', factors.keys()) dlogs = {b: exp for (b,exp) inzip(bases, exponents)} x = (sum(dlogs[q] * e for q, e in factors.items()) - k) % (p-1) ifpow(g, x, p) == y: return x returnNone
g = y = p = x = index_calculus(g, y, p) print(x) print(pow(g, x, p) == y)
#Sage defbrute_dlp(gi, ci, n, lim): bi = gi for i inrange(1, lim+1): if bi == ci: return i bi = (bi * gi) % n print("[-] NOT in the range") print("[-] Something's Wrong, you gotta check the range", lim)
defpohlig_hellman(g, c, s, n, factors): res = [] modulus = [] for q, e in factors: assertpow(g, s//(q**e), n) != 1 gi = pow(g, s//(q**e), n) ci = pow(c, s//(q**e), n) dlogi = brute_dlp(gi, ci, n, q**e) print("[+] dlog modulo {0} == {1}".format(q**e, dlogi)) res.append(dlogi) modulus.append(q**e) print("\n[*] res = ", res) print("[*] modulus = ", modulus) dlog = CRT(res, modulus) print("\n[+] dlog modulo {0} == {1}".format(prod(modulus), dlog)) return dlog
p = P = PolynomialRing(Zmod(p), name='x') x = P.gen() n = g = nfactors = n.factor() s = 1 for i in nfactors: s *= p**(i[0].degree()) - 1
print(s) print(factor(s)) qe = dlog = pohlig_hellman(g, c, s, n, qe)
flag = bytes.fromhex(hex(dlog)[2:]) print("\n[*] flag = ", flag.decode())