Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/attacks/acd/mp.py
2589 views
1
import logging
2
import os
3
import sys
4
from itertools import product
5
from math import gcd
6
7
from sage.all import ZZ
8
9
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__)))))
10
if sys.path[1] != path:
11
sys.path.insert(1, path)
12
13
from shared import small_roots
14
15
16
def attack(N, a, rho, t=1, k=1, roots_method="groebner"):
17
"""
18
Solves the ACD problem using the multivariate polynomial approach.
19
More information: Galbraith D. S. et al., "Algorithms for the Approximate Common Divisor Problem" (Section 5)
20
:param N: N = p * q0
21
:param a: the a samples, with ai = p * qi + ri
22
:param rho: the bit length of the r values
23
:param t: the parameter t (default: 1)
24
:param k: the parameter k (default: 1)
25
:param roots_method: the method to use to find roots (default: "groebner")
26
:return: the secret integer p and a list containing the r values, or None if p could not be found
27
"""
28
assert len(a) > 0, "At least one a value is required."
29
assert t >= k, "t must be greater than or equal to k."
30
31
R = 2 ** rho
32
33
pr = ZZ[tuple(f"x{i}" for i in range(len(a)))]
34
x = pr.gens()
35
X = [R] * len(x)
36
37
logging.debug("Generating shifts...")
38
39
shifts = []
40
for i in product(*[range(t + 1) for _ in x]):
41
if sum(i) <= t:
42
l = max(k - sum(i), 0)
43
fi = N ** l
44
for m in range(len(i)):
45
fi *= (x[m] - a[m]) ** i[m]
46
47
shifts.append(fi)
48
49
B, monomials = small_roots.create_lattice(pr, shifts, X)
50
B = small_roots.reduce_lattice(B)
51
polynomials = small_roots.reconstruct_polynomials(B, None, N ** k, monomials, X)
52
for roots in small_roots.find_roots(pr, polynomials, method=roots_method):
53
r = [roots[xi] for xi in x]
54
if all(-R < ri < R for ri in r):
55
return int(gcd(N, a[0] - r[0])), r
56
57