# 已知参数 p = 2157911408903816440001478305817039407175476474018384087827264804670444904936946922895956667319579115769204739052099777659 c = 1174991717228130578398439743141866600386053936270000296953662636741858928760200802613536886618630745247582903538089645287
defxor_word(a, b): return [x ^ y for x, y inzip(a, b)]
defshift_right(a, k): r = [0] * 32 for i inrange(32 - k): r[i] = a[i + k] return r
defshift_left(a, k): r = [0] * 32 for i inrange(k, 32): r[i] = a[i - k] return r
defand_mask(a, mask): r = [0] * 32 for i inrange(32): if (mask >> i) & 1: r[i] = a[i] return r
defconst_mul(bitcoeff, const): r = [0] * 32 for i inrange(32): if (const >> i) & 1: r[i] = bitcoeff return r
defor_disjoint(u, l): return [x ^ y for x, y inzip(u, l)]
deftemper_bits(x): y = x y = xor_word(y, shift_right(y, 11)) y = xor_word(y, and_mask(shift_left(y, 7), B)) y = xor_word(y, and_mask(shift_left(y, 15), C)) y = xor_word(y, shift_right(y, 18)) return y
deftwist_sym_inplace(mt): mt = mt[:]
for kk inrange(N - M): y = or_disjoint( and_mask(mt[kk], UPPER_MASK), and_mask(mt[kk + 1], LOWER_MASK), ) mt[kk] = xor_word( xor_word(mt[kk + M], shift_right(y, 1)), const_mul(y[0], MATRIX_A), )
for kk inrange(N - M, N - 1): y = or_disjoint( and_mask(mt[kk], UPPER_MASK), and_mask(mt[kk + 1], LOWER_MASK), ) mt[kk] = xor_word( xor_word(mt[kk + (M - N)], shift_right(y, 1)), const_mul(y[0], MATRIX_A), )
defadd_row_to_basis(row, basis): while row: p = row.bit_length() - 1 if p == 0: return (row & 1) == 0 if p in basis: row ^= basis[p] else: basis[p] = row returnTrue returnTrue
defbuild_basis(hint_bytes, start_idx=SKIP_OUTPUTS): # bit0 存 RHS;bit1.. 对应变量 mt = [[(1 << (1 + i * 32 + b)) for b inrange(32)] for i inrange(N)] idx = start_idx basis = {}
for byte in hint_bytes: if idx >= N: mt = twist_sym_inplace(mt) idx = 0
defsolve_from_basis(basis, nvars): pivots = sorted(basis.keys()) pivot_vars = set(p - 1for p in pivots) free_vars = [i for i inrange(nvars) if i notin pivot_vars]
sol = 0 for p in pivots: row = basis[p] var = p - 1 rhs = row & 1 row_vars = (row >> 1) & ~(1 << var) parity = (sol & row_vars).bit_count() & 1 if rhs ^ parity: sol |= 1 << var
return sol, free_vars
defstate_from_solution(sol_bits): mt = [] for i inrange(N): w = 0 base = i * 32 for b inrange(32): if (sol_bits >> (base + b)) & 1: w |= 1 << b mt.append(w & 0xFFFFFFFF) return mt
# ======================= # Instance from rsa_o!rca!.py # ======================= N = Integer(17853573899076341181096267567874616214556285809566419320975211748455658403574952424384450961122059841394637349769390646220566170958316752370568080811) ENC = Integer(14134528243637339528516880595615017358007046031917320457849840313575913728415212293709028402353118219198627787035921516021202481286846551245272653155) E = Integer(65537)
# ======================= # M' : a special divisor of primorial(39) used in ROCA-512 setting # (This M' is exactly product of many primes <= 167 whose 65537-order divides 1201200) # ======================= M_PRIME = Integer(0x1b3e6c9433a7735fa5fc479ffe4027e13bea) # = 2373273553037774377596381010280540868262890 MM = 5 TT = MM + 1
# ======================= # Howgrave-Graham Coppersmith (univariate, self-contained) # ======================= defcoppersmith_howgrave_univariate(pol, modulus, beta, mm, tt, XX): dd = pol.degree() nn = dd * mm + tt
ifnot (0 < beta <= 1): raise ValueError("beta must be in (0,1].") ifnot pol.is_monic(): raise ArithmeticError("Polynomial must be monic.")
polZ = pol.change_ring(ZZ) x = polZ.parent().gen()
gg = [] for ii inrange(mm): for jj inrange(dd): gg.append((x * XX) ** jj * modulus ** (mm - ii) * polZ(x * XX) ** ii) for ii inrange(tt): gg.append((x * XX) ** ii * polZ(x * XX) ** mm)
BB = Matrix(ZZ, nn) for ii inrange(nn): for jj inrange(ii + 1): BB[ii, jj] = gg[ii][jj]
BB = BB.LLL()
new_pol = 0 for ii inrange(nn): new_pol += x ** ii * BB[0, ii] // (XX ** ii)
roots = [] for r, mult in new_pol.roots(): if r in ZZ: r = ZZ(r) val = polZ(r) if gcd(modulus, val) >= modulus ** beta: roots.append(r) return roots
# ======================= # Try a candidate exponent a (mod ord) and recover p via Coppersmith # ======================= deftry_a(N, Mp, a, mm, xx_bound): # r = 65537^a mod Mp -> p ≡ r (mod Mp) r = Integer(pow(E, a, Mp))
# known = r * Mp^{-1} (mod N) known = Integer((r * inverse_mod(Mp, N)) % N)
# polynomial f(x) = x + known (mod N), small root x = k where p = k*Mp + r F = PolynomialRing(Zmod(N), names=('x',), implementation='NTL') x = F.gen() pol = x + known
beta = 0.10 roots = coppersmith_howgrave_univariate(pol, N, beta, mm, mm + 1, xx_bound)
for k in roots: k = Integer(k) if k < 0: k = -k p = Integer(k * Mp + r) if p > 1and N % p == 0: return p, Integer(N // p) returnNone
# ======================= # ROCA-style factorization for this challenge # ======================= deffactor_orca(N): Mp = M_PRIME g = Zmod(Mp)(E)
if in_notebook: print("[+] Detected notebook/ipykernel -> run single-process (no multiprocessing).") for i, a inenumerate(range(int(inf), int(sup))): if (i + 1) % 10000 == 0: print(f"[+] checked {i+1} / {int(sup-inf)} a-values ...") val = try_a(N, Mp, a, MM, XX) if val isnotNone: return val returnNone
# --- CLI: use sage parallel multiprocessing --- from sage.parallel.multiprocessing_sage import parallel_iter from multiprocessing import cpu_count
for start inrange(int(inf), int(sup), chunk_size): end = min(start + chunk_size, int(sup)) inputs = [((N, Mp, a, MM, XX), {}) for a inrange(start, end)]
for _, val in parallel_iter(workers, try_a, inputs): if val isnotNone: return val
# ======================= # decrypt # ======================= deflong_to_bytes(x): x = int(x) if x == 0: returnb"\x00" l = (x.bit_length() + 7) // 8 return x.to_bytes(l, "big")
defmain(): print("[+] Starting factorization...") fac = factor_orca(N) if fac isNone: raise RuntimeError("[-] Factorization failed (unexpected for this instance).")
p, q = fac print("[+] Found factors:") print("[+] p =", int(p)) print("[+] q =", int(q))
from Crypto.Util.number import long_to_bytes import sys
# ================= 题目给定的已知参数 ================= e = 3269834770218481694809 n = 116751448703484355366840201775025865284279195145208042014752560554254636974525900445094434252393126306176328832097159472476466590293588331993005014071275598655101202121619626318044504094075467859952644155183869979160232841481376700194232735947985899320628279507496457026945044297152394600116703106832211346061 U = 555611581159257311716055656452890010637201822068729404411499 V = 520010580954705400377356820181443490009781402173307624774437 c = 99187346948849420907019215990061100332115122516855278156650894560306436495360198420769656203171806023514280892533005165646154539175562103367269192004403942772970427349736360945900801496540291398189377832235682243639988397146507656194107585761666153861534184005851946717219982375709146955987443467659229839064
# ================= 1. 数据预处理与非首一多项式构造 ================= Q = 2^199 M = e * Q A_prime = e * U - 1 B_prime = e * V - 1
# 原始方程: C3*xy + C1*x + C2*y + C0 ≡ 0 (mod M) C3 = (n - 1) % M C1 = (-B_prime) % M C2 = (-A_prime) % M C0 = (-A_prime * B_prime) % M
# 使用 XGCD 将 C3 转换为真正的公约数 g,避免假性整除问题 g, u, v = xgcd(C3, M)
# 构建等价的新系数方程 F'(x,y) = g*xy + C1'*x + C2'*y + C0' ≡ 0 (mod M) C1_prime = (u * C1) % M C2_prime = (u * C2) % M C0_prime = (u * C0) % M
defget_poly(row): returnsum(ZZ(B_mat[row, j] / W[j]) * monomials[j] for j inrange(9))
polys = [get_poly(i) for i inrange(9)] k1_val = None
print("[+] Computing resultants to solve for x (k1)...") for i inrange(9): for j inrange(i + 1, 9): res = polys[i].resultant(polys[j], y) ifnot res.is_zero() andnot res.is_constant(): pol_x = res.univariate_polynomial() roots_x = pol_x.roots() for root, mult in roots_x: if root > 0and root.is_integer(): k1_val = ZZ(root) print(f"[+] Successfully found k1 = {k1_val}") break if k1_val: break if k1_val: break
ifnot k1_val: raise Exception("[-] ERROR: Mathematics failed to yield a root. Check matrix construction bounds.")