Path: blob/master/shared/small_roots/herrmann_may_multivariate.py
2589 views
import logging1from math import gcd23from sage.all import ZZ45from shared import small_roots678def _get_shifts(m, x, k, shift, j, sum, shifts):9if j == len(x):10shifts.append(shift)11else:12for ij in range(m + 1 - k - sum):13_get_shifts(m, x, k, shift * x[j] ** ij, j + 1, sum + ij, shifts)141516def modular_multivariate(f, N, m, t, X, roots_method="groebner"):17"""18Computes small modular roots of a multivariate polynomial.19More information: Herrmann M., May A., "Solving Linear Equations Modulo Divisors: On Factoring Given Any Bits" (Section 3 and 4)20:param f: the polynomial21:param N: the modulus22:param m: the the parameter m23:param t: the the parameter t24:param X: a list of approximate bounds on the roots for each variable25:param roots_method: the method to use to find roots (default: "groebner")26:return: a generator generating small roots (tuples) of the polynomial27"""28f = f.change_ring(ZZ)29pr = f.parent()30x = pr.gens()3132# Sage lm method depends on the term ordering33l = 134for monomial in f.monomials():35if monomial % l == 0:36l = monomial3738al = int(f.coefficient(l))39assert gcd(al, N) == 140f_ = (pow(al, -1, N) * f % N).change_ring(ZZ)4142logging.debug("Generating shifts...")4344shifts = []45for k in range(m + 1):46_get_shifts(m, x, k, f_ ** k * N ** max(t - k, 0), 1, 0, shifts)4748L, monomials = small_roots.create_lattice(pr, shifts, X)49L = small_roots.reduce_lattice(L)50polynomials = small_roots.reconstruct_polynomials(L, f, N, monomials, X)51for roots in small_roots.find_roots(pr, polynomials, method=roots_method):52yield tuple(roots[xi] for xi in x)535455