Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/shared/small_roots/herrmann_may_multivariate.py
2589 views
1
import logging
2
from math import gcd
3
4
from sage.all import ZZ
5
6
from shared import small_roots
7
8
9
def _get_shifts(m, x, k, shift, j, sum, shifts):
10
if j == len(x):
11
shifts.append(shift)
12
else:
13
for ij in range(m + 1 - k - sum):
14
_get_shifts(m, x, k, shift * x[j] ** ij, j + 1, sum + ij, shifts)
15
16
17
def modular_multivariate(f, N, m, t, X, roots_method="groebner"):
18
"""
19
Computes small modular roots of a multivariate polynomial.
20
More information: Herrmann M., May A., "Solving Linear Equations Modulo Divisors: On Factoring Given Any Bits" (Section 3 and 4)
21
:param f: the polynomial
22
:param N: the modulus
23
:param m: the the parameter m
24
:param t: the the parameter t
25
:param X: a list of approximate bounds on the roots for each variable
26
:param roots_method: the method to use to find roots (default: "groebner")
27
:return: a generator generating small roots (tuples) of the polynomial
28
"""
29
f = f.change_ring(ZZ)
30
pr = f.parent()
31
x = pr.gens()
32
33
# Sage lm method depends on the term ordering
34
l = 1
35
for monomial in f.monomials():
36
if monomial % l == 0:
37
l = monomial
38
39
al = int(f.coefficient(l))
40
assert gcd(al, N) == 1
41
f_ = (pow(al, -1, N) * f % N).change_ring(ZZ)
42
43
logging.debug("Generating shifts...")
44
45
shifts = []
46
for k in range(m + 1):
47
_get_shifts(m, x, k, f_ ** k * N ** max(t - k, 0), 1, 0, shifts)
48
49
L, monomials = small_roots.create_lattice(pr, shifts, X)
50
L = small_roots.reduce_lattice(L)
51
polynomials = small_roots.reconstruct_polynomials(L, f, N, monomials, X)
52
for roots in small_roots.find_roots(pr, polynomials, method=roots_method):
53
yield tuple(roots[xi] for xi in x)
54
55