-
Notifications
You must be signed in to change notification settings - Fork 125
/
smart_attack.py
61 lines (50 loc) · 2.06 KB
/
smart_attack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import logging
from sage.all import EllipticCurve
from sage.all import Qq
from sage.all import ZZ
# Convert a field element to a p-adic number.
def _gf_to_qq(n, qq, x):
return ZZ(x) if n == 1 else qq(list(map(int, tuple(x))))
# Lift a point to the p-adic numbers.
def _lift(E, p, Px, Py):
for P in E.lift_x(Px, all=True):
if (P.xy()[1] % p) == Py:
return P
def attack(G, P):
"""
Solves the discrete logarithm problem using Smart's attack.
More information: Smart N. P., "The Discrete Logarithm Problem on Elliptic Curves of Trace One"
More information: Hofman S. J., "The Discrete Logarithm Problem on Anomalous Elliptic Curves" (Section 6)
:param G: the base point
:param P: the point multiplication result
:return: l such that l * G == P
"""
E = G.curve()
assert E.trace_of_frobenius() == 1, f"Curve should have trace of Frobenius = 1."
F = E.base_ring()
p = F.characteristic()
q = F.order()
n = F.degree()
qq = Qq(q, names="g")
# Section 6.1: case where n == 1
logging.info(f"Computing l % {p}...")
E = EllipticCurve(qq, [_gf_to_qq(n, qq, a) + q * ZZ.random_element(1, q) for a in E.a_invariants()])
Gx, Gy = _gf_to_qq(n, qq, G.xy()[0]), _gf_to_qq(n, qq, G.xy()[1])
Gx, Gy = (q * _lift(E, p, Gx, Gy)).xy()
Px, Py = _gf_to_qq(n, qq, P.xy()[0]), _gf_to_qq(n, qq, P.xy()[1])
Px, Py = (q * _lift(E, p, Px, Py)).xy()
l = ZZ(((Px / Py) / (Gx / Gy)) % p)
if n > 1:
# Section 6.2: case where n > 1
G0 = p ** (n - 1) * G
G0x, G0y = _gf_to_qq(n, qq, G0.xy()[0]), _gf_to_qq(n, qq, G0.xy()[1])
G0x, G0y = (q * _lift(E, p, G0x, G0y)).xy()
for i in range(1, n):
logging.info(f"Computing l % {p ** (i + 1)}...")
Pi = p ** (n - i - 1) * (P - l * G)
if Pi.is_zero():
continue
Pix, Piy = _gf_to_qq(n, qq, Pi.xy()[0]), _gf_to_qq(n, qq, Pi.xy()[1])
Pix, Piy = (q * _lift(E, p, Pix, Piy)).xy()
l += p ** i * ZZ(((Pix / Piy) / (G0x / G0y)) % p)
return int(l)