Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/shared/complex_multiplication.py
2587 views
1
import logging
2
3
from sage.all import EllipticCurve
4
from sage.all import GF
5
from sage.all import hilbert_class_polynomial
6
from sage.all import is_prime_power
7
8
9
def elementary_symmetric_function(x, k):
10
assert k > 0
11
12
if k > len(x):
13
return 0
14
15
e = [0] * k
16
for i, xi in enumerate(x):
17
ej = e[0]
18
e[0] += xi
19
ej_1 = ej
20
for j in range(1, min(k, i + 1)):
21
ej = e[j]
22
e[j] += xi * ej_1
23
ej_1 = ej
24
25
return e[k - 1]
26
27
28
def hilbert_class_polynomial_roots(D, gf):
29
"""
30
Computes the roots of H_D(X) mod q given D and GF(q).
31
TODO: implement "Accelerating the CM method" by Sutherland.
32
:param D: the CM discriminant (negative)
33
:param gf: the finite field GF(q)
34
:return: a generator generating the roots (values j)
35
"""
36
assert D < 0 and (D % 4 == 0 or D % 4 == 1), "D must be negative and a discriminant"
37
H = hilbert_class_polynomial(D)
38
pr = gf["x"]
39
for j in pr(H).roots(multiplicities=False):
40
yield j
41
42
43
def generate_curve(gf, k, c=None):
44
"""
45
Generates an Elliptic Curve given GF(q), k, and parameter c
46
:param gf: the finite field GF(q)
47
:param k: j / (j - 1728)
48
:param c: an optional parameter c which is used to generate random a and b values (default: random element in Zmod(q))
49
:return:
50
"""
51
c_ = c if c is not None else 0
52
while c_ == 0:
53
c_ = gf.random_element()
54
55
a = 3 * k * c_ ** 2
56
b = 2 * k * c_ ** 3
57
return EllipticCurve(gf, [a, b])
58
59
60
def solve_cm(D, q, c=None):
61
"""
62
Solves a Complex Multiplication equation for a given discriminant D, prime q, and parameter c.
63
:param D: the CM discriminant (negative)
64
:param q: the prime q
65
:param c: an optional parameter c which is used to generate random a and b values (default: random element in Zmod(q))
66
:return: a generator generating elliptic curves in Zmod(q) with random a and b values
67
"""
68
assert is_prime_power(q)
69
70
logging.debug(f"Solving CM equation for {q = } using {D = } and {c = }")
71
gf = GF(q)
72
if gf.characteristic() == 2 or gf.characteristic() == 3:
73
return
74
75
ks = []
76
for j in hilbert_class_polynomial_roots(D, gf):
77
if j != 0 and j != gf(1728):
78
k = j / (1728 - j)
79
yield generate_curve(gf, k, c)
80
ks.append(k)
81
82
while len(ks) > 0:
83
for k in ks:
84
yield generate_curve(gf, k, c)
85
86