Path: blob/master/shared/small_roots/jochemsz_may_integer.py
2589 views
import logging1from abc import ABCMeta2from abc import abstractmethod3from math import gcd45from sage.all import ZZ67from shared import small_roots8910class Strategy(metaclass=ABCMeta):11@abstractmethod12def generate_S_M(self, f, m):13"""14Generates the S and M sets.15:param f: the polynomial16:param m: the amount of normal shifts to use17:return: a tuple containing the S and M sets18"""19pass202122class BasicStrategy(Strategy):23def generate_S_M(self, f, m):24S = set((f ** (m - 1)).monomials())25M = set((f ** m).monomials())26return S, M272829class ExtendedStrategy(Strategy):30def __init__(self, t):31self.t = t3233def generate_S_M(self, f, m):34x = f.parent().gens()35assert len(x) == len(self.t)3637S = set()38for monomial in (f ** (m - 1)).monomials():39for xi, ti in zip(x, self.t):40for j in range(ti + 1):41S.add(monomial * xi ** j)4243M = set()44for monomial in S:45M.update((monomial * f).monomials())4647return S, M484950class Ernst1Strategy(Strategy):51def __init__(self, t):52self.t = t5354def generate_S_M(self, f, m):55x1, x2, x3 = f.parent().gens()5657S = set()58for i1 in range(m):59for i2 in range(m - i1):60for i3 in range(i2 + self.t + 1):61S.add(x1 ** i1 * x2 ** i2 * x3 ** i3)6263M = set()64for i1 in range(m + 1):65for i2 in range(m - i1 + 1):66for i3 in range(i2 + self.t + 1):67M.add(x1 ** i1 * x2 ** i2 * x3 ** i3)6869return S, M707172class Ernst2Strategy(Strategy):73def __init__(self, t):74self.t = t7576def generate_S_M(self, f, m):77x1, x2, x3 = f.parent().gens()7879S = set()80for i1 in range(m):81for i2 in range(m - i1 + self.t):82for i3 in range(m - i1):83S.add(x1 ** i1 * x2 ** i2 * x3 ** i3)8485M = set()86for i1 in range(m + 1):87for i2 in range(m - i1 + self.t + 1):88for i3 in range(m - i1 + 1):89M.add(x1 ** i1 * x2 ** i2 * x3 ** i3)9091return S, M929394def integer_multivariate(f, m, W, X, strategy, roots_method="resultants"):95"""96Computes small integer roots of a multivariate polynomial.97More information: Jochemsz E., May A., "A Strategy for Finding Roots of Multivariate Polynomials with New Applications in Attacking RSA Variants" (Section 2.2)98:param f: the polynomial99:param m: the parameter m100:param W: the parameter W101:param X: a list of approximate bounds on the roots for each variable102:param strategy: the strategy to use (Appendix B)103:param roots_method: the method to use to find roots (default: "resultants")104:return: a generator generating small roots (tuples) of the polynomial105"""106pr = f.parent()107x = pr.gens()108assert len(x) > 1109110S, M = strategy.generate_S_M(f, m)111l = [0] * len(x)112for monomial in S:113for j, xj in enumerate(x):114l[j] = max(l[j], monomial.degree(xj))115116a0 = int(f.constant_coefficient())117assert a0 != 0118while gcd(a0, W) != 1:119W += 1120121R = W122for j, Xj in enumerate(X):123while gcd(a0, Xj) != 1:124Xj += 1125126R *= Xj ** l[j]127X[j] = Xj128129assert gcd(a0, R) == 1130f_ = (pow(a0, -1, R) * f % R).change_ring(ZZ)131132logging.debug("Generating shifts...")133134shifts = []135monomials = set()136for monomial in S:137g = monomial * f_138for xj, Xj, lj in zip(x, X, l):139g *= Xj ** (lj - monomial.degree(xj))140141shifts.append(g)142monomials.add(monomial)143144for monomial in M:145if monomial not in S:146shifts.append(monomial * R)147monomials.add(monomial)148149L, monomials = small_roots.create_lattice(pr, shifts, X)150L = small_roots.reduce_lattice(L)151polynomials = small_roots.reconstruct_polynomials(L, f, R, monomials, X)152for roots in small_roots.find_roots(pr, [f] + polynomials, method=roots_method):153yield tuple(roots[xi] for xi in x)154155156