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