Path: blob/main/direct-reimplementation/SIKEp434.sage
323 views
import time1from itertools import product23load('richelot_aux.sage')4load('uvtable.sage')5load('speedup.sage')67# Remove annoying messages about slow Gröbner8set_verbose(-1)910SIKE_parameters = {11"SIKEp434" : (216, 137),12"SIKEp503" : (250, 159),13"SIKEp610" : (305, 192),14"SIKEp751" : (372, 239)15}1617# Change me to attack different parameter sets18NIST_submission = "SIKEp434"19a, b = SIKE_parameters[NIST_submission]2021print(f"Running the attack against {NIST_submission} parameters, which has a prime: 2^{a}*3^{b} - 1")2223p = 2^a*3^b - 124Fp2.<i> = GF(p^2, modulus=x^2+1)25assert i^2 == -12627R.<x> = PolynomialRing(Fp2)2829E_start = EllipticCurve(Fp2, [0,6,0,1,0])30# Speeds things up in Sage31E_start.set_order((p+1)^2)3233phi = EllipticCurveIsogeny(E_start, x)34E1728 = phi.codomain()35# Speeds things up in Sage36E1728.set_order((p+1)^2)3738for iota in E1728.automorphisms():39P = E1728.random_point()40if iota(iota(P)) == -P:41two_i = -phi.dual()*iota*phi42break4344infty = E_start(0)4546def get_l_torsion_basis(E, l):47n = (p+1) // l48return (n*G for G in E.gens())4950P2, Q2 = get_l_torsion_basis(E_start, 2^a)51P3, Q3 = get_l_torsion_basis(E_start, 3^b)5253# Make sure Torsion points are54# generated correctly55assert 2^(a-1)*P2 != infty56assert 3^(b-1)*P3 != infty57assert P2.weil_pairing(Q2, 2^a)^(2^(a-1)) != 158assert P3.weil_pairing(Q3, 3^b)^(3^(b-1)) != 15960# generate challenge key61Bobskey = randint(0,3^b)6263EB, chain = Pushing3Chain(E_start, P3 + Bobskey*Q3, b)64# Speeds things up in Sage65EB.set_order((p+1)^2)66PB = P267for c in chain:68PB = c(PB)69QB = Q270for c in chain:71QB = c(QB)7273print(f"If all goes well then the following digits should be found: {Integer(Bobskey).digits(base=3)}")7475# ===================================76# ===== ATTACK ====================77# ===================================78tim = time.time()7980skB = [] # TERNARY DIGITS IN EXPANSION OF BOB'S SECRET KEY8182# gathering the alpha_i, u, v from table8384expdata = [[0, 0, 0] for _ in range(b-3)]85# for i in [1..b-3] do86for i in range(1,b-2):87# if IsOdd(b-i) then88if (b-i)%2 == 1:89index = (b - i + 1) // 290exp = uvtable[index-1][1]91if exp <= a:92u = uvtable[index-1][2]93v = uvtable[index-1][3]94expdata[i-1] = [exp, u, v]9596# gather digits until beta_197bet1 = 098while expdata[bet1][0] == 0:99bet1 += 1100bet1 += 1101102ai = expdata[bet1-1][0]103u = expdata[bet1-1][1]104v = expdata[bet1-1][2]105106print(f"Determination of first {bet1} ternary digits. We are working with 2^{ai}-torsion.")107108bi = b - bet1109alp = a - ai110111# for j in CartesianPower([0,1,2], bet1) do112for j in product([0,1,2], repeat=int(bet1)):113print(f"Testing digits: {[j[k] for k in range(bet1)]}")114115# tauhatkernel = 3^bi*P3 + sum([3^(k-1)*j[k-1] for k in range(1,beta+1)])*3^bi*Q3116tauhatkernel = 3^bi*P3117for k in range(1, bet1+1):118tauhatkernel += (3^(k-1)*j[k-1])*3^bi*Q3119120tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)121122C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, bet1)123124P_c = u*P2 + v*two_i(P2)125for taut in tau_tilde:126P_c = taut(P_c)127Q_c = u*Q2 + v*two_i(Q2)128for taut in tau_tilde:129Q_c = taut(Q_c)130131# 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) then132if j == (2,)*bet1 or Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai):133print("Glue-and-split! These are most likely the secret digits.")134for k in j:135skB.append(k)136break137138print(skB)139140141# now compute longest prolongation of Bob's isogeny that may be needed142length = 1143max_length = 0144# for i in [bet1+1..b-3] do145for i in range(bet1 + 1, b - 2):146if expdata[i-1][0] != 0:147max_length = max(length, max_length)148length = 0149else:150length += 1151152while True:153K = 2^a*3^(b - max_length)*EB.random_point()154if K.order() == 3^max_length:155break156157while True:158alternativeK = 2^a*3^(b - max_length)*EB.random_point()159if K.weil_pairing(alternativeK, 3^max_length)^(3^(max_length - 1)) != 1:160break161162_, EBprolong = Pushing3Chain(EB, K, max_length)163164# gather next digit and change prolongation if needed165i = bet1 + 1166bi = b - i167168print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")169prolong = 1170print("Prolonging with 1 steps.")171endPB = EBprolong[0](PB)172endQB = EBprolong[0](QB)173endEB = EBprolong[0].codomain()174# Speeds things up in Sage175endEB.set_order((p+1)^2)176177positives = []178179for j in range(0,2+1):180print(f"Testing digit: {j}")181# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;182tauhatkernel = 3^bi*P3183for k in range(1, i):184tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3185tauhatkernel += 3^(i-1)*j*3^bi*Q3186187tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)188189C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)190P_c = u*P2 + v*two_i(P2)191for taut in tau_tilde:192P_c = taut(P_c)193Q_c = u*Q2 + v*two_i(Q2)194for taut in tau_tilde:195Q_c = taut(Q_c)196197if Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):198print("Glue-and-split!")199positives.append(j)200break201202if len(positives) == 1:203print(f"Most likely good prolongation and the secret digit is: {positives[0]}")204skB.append(positives[0])205next_i = i + 1206else:207print("All glue-and-splits, must be bad prolongation: changing it and redoing this digit.")208_, EBprolong = Pushing3Chain(EB, alternativeK, max_length)209next_i = i210prolong = 0211212213# now gather all remaining digits, except for last three (we close that gap by trial and error)214215# for i in [next_i..b-3] do216for i in range(next_i, b-2):217bi = b - i218if expdata[i-1][0] != 0:219ai = expdata[i-1][0]220alp = a - ai221u = expdata[i-1][1]222v = expdata[i-1][2]223prolong = 0224else:225prolong += 1226227print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")228print(f"Prolonging with {prolong} steps.")229endPB = PB230endQB = QB231endEB = EB232# for j in [1..prolong] do233for j in range(1,prolong+1):234endPB = EBprolong[j-1](endPB)235endQB = EBprolong[j-1](endQB)236if j == prolong:237endEB = EBprolong[j-1].codomain()238# Speeds things up in Sage239endEB.set_order((p+1)^2)240241242for j in range(0,3):243print(f"Testing digit: {j}")244# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;245tauhatkernel = 3^bi*P3246for k in range(1, i):247tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3248tauhatkernel += 3^(i-1)*j*3^bi*Q3249250tauhatkernel_distort =u*tauhatkernel + v*two_i(tauhatkernel)251252C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)253P_c = u*P2 + v*two_i(P2)254for taut in tau_tilde:255P_c = taut(P_c)256Q_c = u*Q2 + v*two_i(Q2)257for taut in tau_tilde:258Q_c = taut(Q_c)259if j == 2 or Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):260print("Glue-and-split! This is most likely the secret digit.")261skB.append(j)262break263264key = sum([skB[i-1]*3^(i-1) for i in range(1,b-2)])265266# bridge last safety gap267tim2 = time.time()268269found = false270for i in range(3^5+1):271bobskey = key + i*3^(b-3)272bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)273if bobscurve.j_invariant() == EB.j_invariant():274found = true275break276277print(f"Bridging last gap took: {time.time() - tim2}")278279if found:280print(f"Bob's secret key revealed as: {bobskey}")281print(f"In ternary, this is: {Integer(bobskey).digits(base=3)}")282else:283print("Something went wrong.")284285print(f"Altogether this took {time.time() - tim} seconds.")286287288289290291292293294295