forked from GiacomoPope/Castryck-Decru-SageMath
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelpers.py
75 lines (69 loc) · 2.04 KB
/
helpers.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
62
63
64
65
66
67
68
69
70
71
72
73
74
from sage.all import parallel, GF
def possibly_parallel(num_cores):
if num_cores == 1:
def _wrap(fun):
def _fun(args):
for a in args:
yield ((a,), None), fun(a)
return _fun
return _wrap
return parallel(num_cores)
def supersingular_gens(E):
"""
Compute generators of E, assuming E is supersingular
with smooth order (p+1)^2 with factors 2 and 3 only.
This is faster than the PARI method.
"""
# Find a random point of order (p+1) (probability 1/3)
p = E.base_ring().characteristic()
while True:
P = E.random_point()
if ((p+1)//2) * P != 0 and ((p+1)//3) * P != 0:
break
while True:
Q = E.random_point()
if ((p+1)//2) * Q != 0 and ((p+1)//3) * Q != 0:
# but is it linearly independent? (probability 1/3)
w = P.weil_pairing(Q, p+1)
if w**((p+1)/2) != 1 and w**((p+1)//3) != 1:
return P, Q
def fast_log3(x, base):
"""
Fast discrete log when elements are known to have order
dividing 3^k
"""
one = x.parent().one()
powers = [base]
b = base
log_order = None
for i in range(10_000):
b = b**3
if b.is_one():
log_order = i+1
break
powers.append(b)
if not b.is_one():
raise Exception("impossible")
digits = []
#assert x**(3**log_order) == 1
#assert base**(3**(log_order-1)) != 1
for i in range(log_order):
for d in range(3):
if (x * powers[i]**d)**(3**(log_order-i-1)) == 1:
digits.append((-d) % 3)
if d:
x /= powers[i]**(3-d)
break
if x == 1:
break
#assert x == 1
dlog = sum(d*3**i for i, d in enumerate(digits))
return dlog
def test_fast_log3():
K = GF(70 * 3**69 + 1)
g = K.multiplicative_generator()
g = g**70
for _ in range(1000):
r = K.random_element()**70
dl = fast_log3(r, g)
assert r == g**dl