Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jack4818
GitHub Repository: jack4818/Castryck-Decru-SageMath
Path: blob/main/castryck_decru_shortcut.sage
323 views
1
# Python imports
2
import time
3
from itertools import product
4
5
# Local Imports
6
from helpers import possibly_parallel, supersingular_gens, fast_log3
7
from richelot_aux import AuxiliaryIsogeny, Does22ChainSplit, Pushing3Chain
8
from uvtable import uvtable
9
10
# Load Sage Files
11
load('speedup.sage')
12
13
# ===================================
14
# ===== ATTACK ====================
15
# ===================================
16
17
18
def CastryckDecruAttack(E_start, P2, Q2, EB, PB, QB, two_i, num_cores=1):
19
tim = time.time()
20
21
skB = [] # TERNARY DIGITS IN EXPANSION OF BOB'S SECRET KEY
22
23
# gathering the alpha_i, u, v from table
24
expdata = [[0, 0, 0] for _ in range(b-3)]
25
for i in range(b%2, b-3, 2):
26
index = (b-i) // 2
27
row = uvtable[index-1]
28
if row[1] <= a:
29
expdata[i] = row[1:4]
30
31
# gather digits until beta_1
32
bet1 = 0
33
while not expdata[bet1][0]:
34
bet1 += 1
35
bet1 += 1
36
37
ai,u,v = expdata[bet1-1]
38
39
print(f"Determination of first {bet1} ternary digits. We are working with 2^{ai}-torsion.")
40
41
bi = b - bet1
42
alp = a - ai
43
44
@possibly_parallel(num_cores)
45
def CheckGuess(first_digits):
46
print(f"Testing digits: {first_digits}")
47
48
scalar = sum(3^k*d for k,d in enumerate(first_digits))
49
tauhatkernel = 3^bi * (P3 + scalar*Q3)
50
51
tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)
52
53
C, P_c, Q_c, chainC = AuxiliaryIsogeny(bet1, u, v, E_start, P2, Q2, tauhatkernel, two_i)
54
# We have a diagram
55
# C <- Eguess <- E_start
56
# | |
57
# v v
58
# CB-> EB
59
split = Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai)
60
if split:
61
Eguess, _ = Pushing3Chain(E_start, tauhatkernel, bet1)
62
63
chain, (E1, E2) = split
64
# Compute the 3^b torsion in C
65
P3c = chainC(P3)
66
Q3c = chainC(Q3)
67
# Map it through the (2,2)-isogeny chain
68
if E2.j_invariant() == Eguess.j_invariant():
69
CB, index = E1, 0
70
else:
71
CB, index = E2, 1
72
def apply_chain(c, X):
73
X = (X, None) # map point to C x {O_EB}
74
for f in c:
75
X = f(X)
76
return X[index]
77
print("Computing image of 3-adic torsion in split factor CB")
78
P3c_CB = apply_chain(chain, P3c)
79
Q3c_CB = apply_chain(chain, Q3c)
80
81
Z3 = Zmod(3^b)
82
# Determine kernel of the 3^b isogeny.
83
# The projection to CB must have 3-adic rank 1.
84
# To compute the kernel we choose a symplectic basis of the
85
# 3-torsion at the destination, and compute Weil pairings.
86
CB.set_order((p+1)^2, num_checks=1) # keep sanity check
87
P_CB, Q_CB = supersingular_gens(CB)
88
P3_CB = ((p+1) / 3^b) * P_CB
89
Q3_CB = ((p+1) / 3^b) * Q_CB
90
w = P3_CB.weil_pairing(Q3_CB, 3^b)
91
# Compute kernel
92
for G in (P3_CB, Q3_CB):
93
xP = fast_log3(P3c_CB.weil_pairing(G, 3^b), w)
94
xQ = fast_log3(Q3c_CB.weil_pairing(G, 3^b), w)
95
if xQ % 3 != 0:
96
sk = int(-Z3(xP) / Z3(xQ))
97
return sk
98
99
return True
100
101
guesses = [ZZ(i).digits(3, padto=bet1) for i in range(3^bet1)]
102
103
for result in CheckGuess(guesses):
104
((first_digits,), _), sk = result
105
if sk is not None:
106
print("Glue-and-split! These are most likely the secret digits.")
107
bobskey = sk
108
break
109
110
# Sanity check
111
bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)
112
found = bobscurve.j_invariant() == EB.j_invariant()
113
114
if found:
115
print(f"Bob's secret key revealed as: {bobskey}")
116
print(f"In ternary, this is: {Integer(bobskey).digits(base=3)}")
117
print(f"Altogether this took {time.time() - tim} seconds.")
118
return bobskey
119
else:
120
print("Something went wrong.")
121
print(f"Altogether this took {time.time() - tim} seconds.")
122
return None
123
124