Path: blob/master/shared/small_roots/jochemsz_may_modular.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_M(self, f, l, m):13"""14Generates the M dict.15:param f: the polynomial16:param l: the leading monomial17:param m: the amount of normal shifts to use18:return: the M dict19"""20pass212223class BasicStrategy(Strategy):24def generate_M(self, f, l, m):25M = {}26fm_monomials = (f ** m).monomials()27for k in range(m + 1):28M[k] = set()29fmk_monomials = (f ** (m - k)).monomials()30for monomial in fm_monomials:31if monomial // (l ** k) in fmk_monomials:32M[k].add(monomial)3334M[m + 1] = []35return M363738class ExtendedStrategy(Strategy):39def __init__(self, t):40self.t = t4142def generate_M(self, f, l, m):43x = f.parent().gens()44assert len(x) == len(self.t)4546M = {}47fm_monomials = (f ** m).monomials()48for k in range(m + 1):49M[k] = set()50fmk_monomials = (f ** (m - k)).monomials()51for monomial in fm_monomials:52if monomial // (l ** k) in fmk_monomials:53for xi, ti in zip(x, self.t):54for j in range(ti + 1):55M[k].add(monomial * xi ** j)5657M[m + 1] = []58return M596061class BonehDurfeeStrategy(Strategy):62def __init__(self, t):63self.t = t6465def generate_M(self, f, l, m):66x1, x2 = f.parent().gens()6768M = {}69for k in range(m + 1):70M[k] = set()71for i1 in range(k, m + 1):72for i2 in range(k, i1 + self.t + 1):73M[k].add(x1 ** i1 * x2 ** i2)7475M[m + 1] = []76return M777879class BlomerMayStrategy(Strategy):80def __init__(self, t):81self.t = t8283def generate_M(self, f, l, m):84x1, x2, x3 = f.parent().gens()8586M = {}87for k in range(m + 1):88M[k] = set()89for i1 in range(k, m + 1):90for i2 in range(m - i1 + 1):91for i3 in range(i2 + self.t - 1):92M[k].add(x1 ** i1 * x2 ** i2 * x3 ** i3)9394M[m + 1] = []95return M969798def modular_multivariate(f, N, m, X, strategy, roots_method="groebner"):99"""100Computes small integer roots of a multivariate polynomial.101More information: Jochemsz E., May A., "A Strategy for Finding Roots of Multivariate Polynomials with New Applications in Attacking RSA Variants" (Section 2.1)102:param f: the polynomial103:param N: the modulus104:param m: the parameter m105:param X: a list of approximate bounds on the roots for each variable106:param strategy: the strategy to use (Appendix A)107:param roots_method: the method to use to find roots (default: "groebner")108:return: a generator generating small roots (tuples) of the polynomial109"""110f = f.change_ring(ZZ)111pr = f.parent()112x = pr.gens()113assert len(x) > 1114115# Sage lm method depends on the term ordering116l = 1117for monomial in f.monomials():118if monomial % l == 0:119l = monomial120121al = int(f.coefficient(l))122assert gcd(al, N) == 1123f_ = (pow(al, -1, N) * f % N).change_ring(ZZ)124125logging.debug("Generating shifts...")126127M = strategy.generate_M(f, l, m)128shifts = []129monomials = set()130for k in range(m + 1):131for monomial in M[k]:132if monomial not in M[k + 1]:133shifts.append(monomial // (l ** k) * f_ ** k * N ** (m - k))134monomials.add(monomial)135136L, monomials = small_roots.create_lattice(pr, shifts, X)137L = small_roots.reduce_lattice(L)138polynomials = small_roots.reconstruct_polynomials(L, f, N ** m, monomials, X)139for roots in small_roots.find_roots(pr, polynomials, method=roots_method):140yield tuple(roots[xi] for xi in x)141142143