Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/shared/matrices.py
2587 views
1
import logging
2
3
from sage.all import GF
4
from sage.all import identity_matrix
5
from sage.matrix.matrix2 import _jordan_form_vector_in_difference
6
7
8
def find_eigenvalues(A):
9
"""
10
Computes the eigenvalues and P matrices for a specific matrix A.
11
:param A: the matrix A.
12
:return: a generator generating tuples of
13
K: the extension field of the eigenvalue,
14
k: the degree of the factor of the charpoly associated with the eigenvalue,
15
e: the multiplicity of the factor of the charpoly associated with the eigenvalue,
16
l: the eigenvalue,
17
P: the transformation matrix P (only the first e columns are filled)
18
"""
19
factors = {}
20
for g, e in A.charpoly().factor():
21
k = g.degree()
22
if k not in factors or e > factors[k][0]:
23
factors[k] = (e, g)
24
25
p = A.base_ring().order()
26
for k, (e, g) in factors.items():
27
logging.debug(f"Found factor {g} with degree {k} and multiplicity {e}")
28
K = GF(p ** k, "x", modulus=g, impl="modn" if k == 1 else "pari")
29
l = K.gen()
30
# Assuming there is only 1 Jordan block for this eigenvalue.
31
Vlarge = ((A - l) ** e).right_kernel().basis()
32
Vsmall = ((A - l) ** (e - 1)).right_kernel().basis()
33
v = _jordan_form_vector_in_difference(Vlarge, Vsmall)
34
P = identity_matrix(K, A.nrows())
35
for i in reversed(range(e)):
36
P.set_row(i, v)
37
v = (A - l) * v
38
39
P = P.transpose()
40
yield K, k, e, l, P
41
42
43
def dlog(A, B):
44
"""
45
Computes l such that A^l = B.
46
:param A: the matrix A
47
:param B: the matrix B
48
:return: a generator generating values for l and m, where A^l = B mod m.
49
"""
50
assert A.is_square() and B.is_square() and A.nrows() == B.nrows()
51
52
p = A.base_ring().order()
53
for K, k, e, l, P in find_eigenvalues(A):
54
B_ = P ** -1 * B * P
55
logging.debug(f"Computing dlog in {K}...")
56
yield int(B_[0, 0].log(l)), int(p ** k - 1)
57
if e >= 2:
58
B1 = B_[e - 1, e - 1]
59
B2 = B_[e - 2, e - 1]
60
yield int((l * B2) / B1), int(p ** k)
61
62
63
def dlog_equation(A, x, y):
64
"""
65
Computes l such that A^l * x = y, in GF(p).
66
:param A: the matrix A
67
:param x: the vector x
68
:param y: the vector y
69
:return: l, or None if l could not be found
70
"""
71
assert A.is_square()
72
73
# TODO: extend to GF(p^k) if necessary?
74
J, P = A.jordan_form(transformation=True)
75
x = P ** -1 * x
76
y = P ** -1 * y
77
r = 0
78
for s1, s2 in zip(*J.subdivisions()):
79
S = J.subdivision(s1, s2)
80
assert S.is_square()
81
82
n = S.nrows()
83
r += n
84
if n >= 2:
85
x1 = x[r - 1]
86
x2 = x[r]
87
y1 = y[r - 1]
88
y2 = y[r]
89
l = S[n - 1, n - 1] * (y1 - x1 * y2 / x2) / y2
90
return int(l)
91
92
return None
93
94