Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jack4818
GitHub Repository: jack4818/Castryck-Decru-SageMath
Path: blob/main/direct-reimplementation/SIKEp434.sage
323 views
1
import time
2
from itertools import product
3
4
load('richelot_aux.sage')
5
load('uvtable.sage')
6
load('speedup.sage')
7
8
# Remove annoying messages about slow Gröbner
9
set_verbose(-1)
10
11
SIKE_parameters = {
12
"SIKEp434" : (216, 137),
13
"SIKEp503" : (250, 159),
14
"SIKEp610" : (305, 192),
15
"SIKEp751" : (372, 239)
16
}
17
18
# Change me to attack different parameter sets
19
NIST_submission = "SIKEp434"
20
a, b = SIKE_parameters[NIST_submission]
21
22
print(f"Running the attack against {NIST_submission} parameters, which has a prime: 2^{a}*3^{b} - 1")
23
24
p = 2^a*3^b - 1
25
Fp2.<i> = GF(p^2, modulus=x^2+1)
26
assert i^2 == -1
27
28
R.<x> = PolynomialRing(Fp2)
29
30
E_start = EllipticCurve(Fp2, [0,6,0,1,0])
31
# Speeds things up in Sage
32
E_start.set_order((p+1)^2)
33
34
phi = EllipticCurveIsogeny(E_start, x)
35
E1728 = phi.codomain()
36
# Speeds things up in Sage
37
E1728.set_order((p+1)^2)
38
39
for iota in E1728.automorphisms():
40
P = E1728.random_point()
41
if iota(iota(P)) == -P:
42
two_i = -phi.dual()*iota*phi
43
break
44
45
infty = E_start(0)
46
47
def get_l_torsion_basis(E, l):
48
n = (p+1) // l
49
return (n*G for G in E.gens())
50
51
P2, Q2 = get_l_torsion_basis(E_start, 2^a)
52
P3, Q3 = get_l_torsion_basis(E_start, 3^b)
53
54
# Make sure Torsion points are
55
# generated correctly
56
assert 2^(a-1)*P2 != infty
57
assert 3^(b-1)*P3 != infty
58
assert P2.weil_pairing(Q2, 2^a)^(2^(a-1)) != 1
59
assert P3.weil_pairing(Q3, 3^b)^(3^(b-1)) != 1
60
61
# generate challenge key
62
Bobskey = randint(0,3^b)
63
64
EB, chain = Pushing3Chain(E_start, P3 + Bobskey*Q3, b)
65
# Speeds things up in Sage
66
EB.set_order((p+1)^2)
67
PB = P2
68
for c in chain:
69
PB = c(PB)
70
QB = Q2
71
for c in chain:
72
QB = c(QB)
73
74
print(f"If all goes well then the following digits should be found: {Integer(Bobskey).digits(base=3)}")
75
76
# ===================================
77
# ===== ATTACK ====================
78
# ===================================
79
tim = time.time()
80
81
skB = [] # TERNARY DIGITS IN EXPANSION OF BOB'S SECRET KEY
82
83
# gathering the alpha_i, u, v from table
84
85
expdata = [[0, 0, 0] for _ in range(b-3)]
86
# for i in [1..b-3] do
87
for i in range(1,b-2):
88
# if IsOdd(b-i) then
89
if (b-i)%2 == 1:
90
index = (b - i + 1) // 2
91
exp = uvtable[index-1][1]
92
if exp <= a:
93
u = uvtable[index-1][2]
94
v = uvtable[index-1][3]
95
expdata[i-1] = [exp, u, v]
96
97
# gather digits until beta_1
98
bet1 = 0
99
while expdata[bet1][0] == 0:
100
bet1 += 1
101
bet1 += 1
102
103
ai = expdata[bet1-1][0]
104
u = expdata[bet1-1][1]
105
v = expdata[bet1-1][2]
106
107
print(f"Determination of first {bet1} ternary digits. We are working with 2^{ai}-torsion.")
108
109
bi = b - bet1
110
alp = a - ai
111
112
# for j in CartesianPower([0,1,2], bet1) do
113
for j in product([0,1,2], repeat=int(bet1)):
114
print(f"Testing digits: {[j[k] for k in range(bet1)]}")
115
116
# tauhatkernel = 3^bi*P3 + sum([3^(k-1)*j[k-1] for k in range(1,beta+1)])*3^bi*Q3
117
tauhatkernel = 3^bi*P3
118
for k in range(1, bet1+1):
119
tauhatkernel += (3^(k-1)*j[k-1])*3^bi*Q3
120
121
tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)
122
123
C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, bet1)
124
125
P_c = u*P2 + v*two_i(P2)
126
for taut in tau_tilde:
127
P_c = taut(P_c)
128
Q_c = u*Q2 + v*two_i(Q2)
129
for taut in tau_tilde:
130
Q_c = taut(Q_c)
131
132
# if j eq <2 : k in [1..bet1]> or Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai) then
133
if j == (2,)*bet1 or Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai):
134
print("Glue-and-split! These are most likely the secret digits.")
135
for k in j:
136
skB.append(k)
137
break
138
139
print(skB)
140
141
142
# now compute longest prolongation of Bob's isogeny that may be needed
143
length = 1
144
max_length = 0
145
# for i in [bet1+1..b-3] do
146
for i in range(bet1 + 1, b - 2):
147
if expdata[i-1][0] != 0:
148
max_length = max(length, max_length)
149
length = 0
150
else:
151
length += 1
152
153
while True:
154
K = 2^a*3^(b - max_length)*EB.random_point()
155
if K.order() == 3^max_length:
156
break
157
158
while True:
159
alternativeK = 2^a*3^(b - max_length)*EB.random_point()
160
if K.weil_pairing(alternativeK, 3^max_length)^(3^(max_length - 1)) != 1:
161
break
162
163
_, EBprolong = Pushing3Chain(EB, K, max_length)
164
165
# gather next digit and change prolongation if needed
166
i = bet1 + 1
167
bi = b - i
168
169
print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")
170
prolong = 1
171
print("Prolonging with 1 steps.")
172
endPB = EBprolong[0](PB)
173
endQB = EBprolong[0](QB)
174
endEB = EBprolong[0].codomain()
175
# Speeds things up in Sage
176
endEB.set_order((p+1)^2)
177
178
positives = []
179
180
for j in range(0,2+1):
181
print(f"Testing digit: {j}")
182
# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;
183
tauhatkernel = 3^bi*P3
184
for k in range(1, i):
185
tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3
186
tauhatkernel += 3^(i-1)*j*3^bi*Q3
187
188
tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)
189
190
C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)
191
P_c = u*P2 + v*two_i(P2)
192
for taut in tau_tilde:
193
P_c = taut(P_c)
194
Q_c = u*Q2 + v*two_i(Q2)
195
for taut in tau_tilde:
196
Q_c = taut(Q_c)
197
198
if Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):
199
print("Glue-and-split!")
200
positives.append(j)
201
break
202
203
if len(positives) == 1:
204
print(f"Most likely good prolongation and the secret digit is: {positives[0]}")
205
skB.append(positives[0])
206
next_i = i + 1
207
else:
208
print("All glue-and-splits, must be bad prolongation: changing it and redoing this digit.")
209
_, EBprolong = Pushing3Chain(EB, alternativeK, max_length)
210
next_i = i
211
prolong = 0
212
213
214
# now gather all remaining digits, except for last three (we close that gap by trial and error)
215
216
# for i in [next_i..b-3] do
217
for i in range(next_i, b-2):
218
bi = b - i
219
if expdata[i-1][0] != 0:
220
ai = expdata[i-1][0]
221
alp = a - ai
222
u = expdata[i-1][1]
223
v = expdata[i-1][2]
224
prolong = 0
225
else:
226
prolong += 1
227
228
print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")
229
print(f"Prolonging with {prolong} steps.")
230
endPB = PB
231
endQB = QB
232
endEB = EB
233
# for j in [1..prolong] do
234
for j in range(1,prolong+1):
235
endPB = EBprolong[j-1](endPB)
236
endQB = EBprolong[j-1](endQB)
237
if j == prolong:
238
endEB = EBprolong[j-1].codomain()
239
# Speeds things up in Sage
240
endEB.set_order((p+1)^2)
241
242
243
for j in range(0,3):
244
print(f"Testing digit: {j}")
245
# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;
246
tauhatkernel = 3^bi*P3
247
for k in range(1, i):
248
tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3
249
tauhatkernel += 3^(i-1)*j*3^bi*Q3
250
251
tauhatkernel_distort =u*tauhatkernel + v*two_i(tauhatkernel)
252
253
C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)
254
P_c = u*P2 + v*two_i(P2)
255
for taut in tau_tilde:
256
P_c = taut(P_c)
257
Q_c = u*Q2 + v*two_i(Q2)
258
for taut in tau_tilde:
259
Q_c = taut(Q_c)
260
if j == 2 or Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):
261
print("Glue-and-split! This is most likely the secret digit.")
262
skB.append(j)
263
break
264
265
key = sum([skB[i-1]*3^(i-1) for i in range(1,b-2)])
266
267
# bridge last safety gap
268
tim2 = time.time()
269
270
found = false
271
for i in range(3^5+1):
272
bobskey = key + i*3^(b-3)
273
bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)
274
if bobscurve.j_invariant() == EB.j_invariant():
275
found = true
276
break
277
278
print(f"Bridging last gap took: {time.time() - tim2}")
279
280
if found:
281
print(f"Bob's secret key revealed as: {bobskey}")
282
print(f"In ternary, this is: {Integer(bobskey).digits(base=3)}")
283
else:
284
print("Something went wrong.")
285
286
print(f"Altogether this took {time.time() - tim} seconds.")
287
288
289
290
291
292
293
294
295