def recover_p(p0, n): PR = PolynomialRing(Zmod(n), 'x') x = PR.gen() nbits = 1024 p0bits = p0.bit_length() f = 2^(p0bits - 2) * x + p0 f = f.monic() roots = f.small_roots(X=2^(nbits // 2 - p0bits + 2), beta=0.49) if roots: x0 = roots[0] p = gcd(2^(p0bits - 2) * int(x0) + p0, n) print(f"Found p = {p}") return ZZ(p) return None def find_p0(d0, e, n, bits): modulus = 1 << bits P.<x> = PolynomialRing(Zmod(modulus), 'x') for k in range(1, e + 1): # 构造多项式 k*X^2 + (e*d0 - (1+k*(n+1)))*X + k*n f = k * x^2 + (e * d0 - (1 + k * (n + 1))) * x + k * n roots = f.roots(multiplicities=False) for root in roots: p0 = ZZ(root) p = recover_p(p0, n) if p and p != 1: return p return None
from Crypto.Util.number import * n=127060392619341060272126983366487069092712215979664340339428955285201267724168574813227106020122399594060458777939446978632526348867806863618885370221957087197582864380885199290793062293120324984868138488667017882272415668310242448870352699380394381756621677031459335310964085476227148301120850021800822495119 e=65537 ct=18305235107479382231970252522433686185039231184629854177334609960907102735540326234277108553640185845164498239822263821349544015918443334769445559622730315115384134147808359107914969010678607157349844717217781801237935737980608575612421610972048739840839726108493286994232100086338529591086935374295281642738 gift=8312456126096895497368692810699639462746223116345115761188530231045483000989605820 gift=gift<<750 r=bytes_to_long(b'n1junior2025') PR.<x>=PolynomialRing(RealField(1000)) for k in range(2000,5000): f=(2025*x+r^2)*x^2-gift*x-k*(x-1)*(n-x) root=f.roots(multiplicities=False) for xx in root: p0=int(xx) P.<y>=PolynomialRing(Zmod(n)) g=p0+y res=g.small_roots(X=2^226,beta=0.499,epsilon=0.04) for y0 in res: p=int(y0)+p0 if 0<p<n and n%p==0: q=n//p d=inverse_mod(e,(p-1)*(q-1)) print(long_to_bytes(pow(ct,d,n)))
def small_roots(f, bounds, m=1, d=None): if not d: d = f.degree() R = f.base_ring() N = R.cardinality() #f /= f.coefficients().pop(0) f = f.change_ring(ZZ) G = Sequence([], f.parent()) for i in range(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) B, monomials = G.coefficients_monomials() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor in enumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor in enumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h in filter(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 return []
这里的bound是指多元多项式各个未知量的上限
dp高位泄露
1 2 3 4 5 6 7 8 9 10 11 12
PR.<x,y> = PolynomialRing(Zmod(n)) f = e * (dp_high + x) + (y - 1) res = small_roots(f,(2^bits,2^bits),m=1,d=3) for root in res: dp_low = root[0] dp = dp_high + dp_low tmp = pow(2,e*dp,n) - 2 p = GCD(tmp,n) q = n // p d = inverse(e,(p-1)*(q-1)) m = pow(c,d,n) print(long_to_bytes(int(m)))