for p, k in factors: mod = p**k mods.append(mod) # 构建子环及其多项式环 R = Zmod(mod) P.<x> = PolynomialRing(R) # 传入系数列表,生成多项式 f = P(coeffs_rev) # 调用求根函数。sage 返回的是元组(解,重数),取 r [0] 即可 roots = [r[0] for r in f.roots()] all_roots.append(roots)
final_roots = [] # product 函数用于求笛卡尔积,也即列表内所有参数的全部排列组合,组合的数目即 all_roots 内的列表数目 for rems in product(*all_roots): # 类型转换 rems_int = [Integer(r) for r in rems] # 用 crt 解最小的同余方程组 combined_root = crt(rems_int, mods) final_roots.append(combined_root) returnsorted(final_roots)
pbits = isqrt(n).nbits() # 检查是 p >> k 还是 p >> k << k if pbits != p_high.nbits(): p_high = p_high << k R.<x> = PolynomialRing(Zmod(n)) f = p_high + x roots = f.small_roots(X = 2^k, beta = 0.499)
for r in roots: # 提取模环元素要加 int()类型转换 p = p_high + int(r) if n % p == 0: q = n // p phi = (p - 1) * (q - 1) d = inverse_mod(e, phi) m = pow(c, d, n) print(long_to_bytes(m).decode())
n = e = c = p_low = k = # 低位保留了多少位信息,不用 p_low.nbits()的原因是避免丢失前导 0
R.<x> = PolynomialRing(Zmod(n)) f = 2^k * x + p_low f = f.monic() pbits = isqrt(n).nbits() roots = f.small_roots(X = 2^(pbits - k), beta = 0.499)
for r in roots: p = p_low + int(r) * 2^k if n % p == 0: q = n // p phi = (p - 1) * (q - 1) d = inverse_mod(e, phi) m = pow(c, d, n) print(long_to_bytes(m).decode())
n_low = n % (2^t) R.<x> = PolynomialRing(Zmod(2^t)) candidates = [] for k inrange(1, e): f = k*x^2 + (e*d_low - k*n_low - k - 1)*x + k*n_low # 这里虽然调用了普通的.roots(),但 sage 不能在复合数模环上求重数,需要显式把这个功能关闭 roots = f.roots(multiplicities=False) for r in roots: # 这里不再是元组了 p_low = int(r) candidates.append(p_low)
# 退化回 p 的低位泄露 R_prime.<x> = PolynomialRing(Zmod(n)) for p_low in candidates: f = 2^t * x + p_low f = f.monic() pbits = isqrt(n).nbits() roots = f.small_roots(X = 2^(pbits - t), beta = 0.499) for r in roots: p = p_low + int(r) * 2^t if n % p == 0: q = n // p phi = (p - 1) * (q - 1) d = inverse_mod(e, phi) m = pow(c, d, n) print(long_to_bytes(m).decode())
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
ifisinstance(f, Polynomial): x, = polygens(f.base_ring(), f.variable_name(), 1) f = f(x)
R = f.base_ring() N = R.cardinality()
f /= f.coefficients().pop(0) f = f.change_ring(ZZ)
G = Sequence([], f.parent()) for i inrange(m+1): base = N^(m-i) * f^i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = base * prod(map(power, f.variables(), shifts)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1/factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(None, B*monomials): H.append(h) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: roots = [] for root in I.variety(ring=ZZ): root = tuple(R(root[var]) for var in f.variables()) roots.append(root) return roots