Path: blob/main/direct-reimplementation/SIKE_challenge.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)910# Stop slow primality checks GF(p^k) construction11proof.arithmetic(False)1213# $IKEp217 parameters14a = 11015b = 6716p = 2^a*3^b - 117Fp2.<i> = GF(p^2, modulus=x^2+1)18assert i^2 == -11920R.<x> = PolynomialRing(Fp2)2122E_start = EllipticCurve(Fp2, [0,6,0,1,0])23# Speeds things up in Sage24E_start.set_order((p+1)^2)2526phi = EllipticCurveIsogeny(E_start, x)27E1728 = phi.codomain()28# Speeds things up in Sage29E1728.set_order((p+1)^2)3031for iota in E1728.automorphisms():32P = E1728.random_point()33if iota(iota(P)) == -P:34two_i = phi.post_compose(iota).post_compose(phi.dual())35break3637# $IKEp217 public parameters3839xQ2 = 86445170414599058485968715662346922796016566052081315743781191908 + i*4045278112745363234206223190163440799235027420621931179964233023040yQ2 = 65598021239445364766945421641383356785387864046503211101901536990 + i*418518804344282095061206766264246958383873009640823597269071475041Q2 = E_start(xQ2, yQ2)4243xP2 = 37927755131506746411537091732732279589710442710570639382902295344 + i*3701749525907447551685856803956351275290554868452895537506661697644yP2 = 47930070613074499206421889519713097155043539387599009924307417901 + i*717630269860368344248694873348419051324247005755356174108158209845P2 = E_start(xP2, yP2)4647# CONSISTENCY WITH R (NOT NEEDED BUT OK)48xR2 = 46724562430016373759602265681716628459894400021233033976074511127 + i*6286924719151616761903231142658386220127715353181757597867328065449assert (P2 - Q2)[0] == xR25051xQ3 = 4779313878520280849331087047226954849969368668204554267286624378152yQ3 = i*5923339225169722802511569533864008871424331184550463284642614732753Q3 = E_start(xQ3, yQ3)5455xP3 = 9253798132167735998428275268152632170984825716791458129518202948256yP3 = 6489070673268770364441873046641887381810095879335935430646248753357P3 = E_start(xP3, yP3)5859# CONSISTENCY WITH R (NOT NEEDED BUT OK)60# Typo in magma, should be P3 and Q361xR3 = 100985822528123790926639173045977043567721100360555352880158477546 + i*5365115130720847921600764900148092851465430682931220224499708880362assert (P3 - Q3)[0] == xR36364# ALICE'S PUBLIC KEY:65xPA = 78851325149093883127710876413676714831509071567295995722742563459 + i*2148124127702942204846572124026162029627696436741055793659729437566xQA = 109443172641179151776707590487317622581952970379528972130069645642 + i*386722195698191891564336544587523647476740815449204154997773057367xRA = 24146826348939386714009375843953121070061474437444339669850030464 + i*97940940305875900442864870454942772485510072809212638403107915166869A = (1 - xPA*xQA - xPA*xRA - xQA*xRA)^2/(4*xPA*xQA*xRA) - xPA - xQA - xRA7071yPA = sqrt(xPA^3 + A*xPA^2 + xPA)72yQA = sqrt(xQA^3 + A*xQA^2 + xQA)7374# SMALL ERROR IN SIDH-spec.pdf, CORRECTED HERE75if xRA + xQA + xPA + A != (yQA + yPA)^2 / (xQA - xPA)^2:76yQA = -yQA7778# let's check:79EA = EllipticCurve(Fp2, [0,A,0,1,0])80EA.set_order((p+1)^2)81PA = EA(xPA, yPA)82QA = EA(xQA, yQA)8384# BOB'S PUBLIC KEY:85xPB = 52037618715847826453371077000320105687598036562145407135988121710 + i*6294543628505586034615133765513165749104224353464487189480919674786xQB = 94057161062674597281795314311864564004565620907834550169224722966 + i*9142073149675965777912606385950868266337795590333429632163955124987xRB = 43790287819500432145214110821932450371863522319238208485657321972 + i*986946403762060667794821917257760910852590449353426657893893254468889B = (1 - xPB*xQB - xPB*xRB - xQB*xRB)^2/(4*xPB*xQB*xRB) - xPB - xQB - xRB9091yPB = sqrt(xPB^3 + B*xPB^2 + xPB)92yQB = sqrt(xQB^3 + B*xQB^2 + xQB)9394# SMALL ERROR IN SIDH-spec.pdf, CORRECTED HERE95if xRB + xQB + xPB + B != (yQB + yPB)^2 / (xQB - xPB)^2:96yQB = -yQB9798# let's check:99EB = EllipticCurve(Fp2, [0,B,0,1,0])100EB.set_order((p+1)^2)101PB = EB(xPB, yPB)102QB = EB(xQB, yQB)103104# ===================================105# ===== ATTACK ====================106# ===================================107tim = time.time()108109skB = [] # TERNARY DIGITS IN EXPANSION OF BOB'S SECRET KEY110111# gathering the alpha_i, u, v from table112113expdata = [[0, 0, 0] for _ in range(b-3)]114# for i in [1..b-3] do115for i in range(1,b-2):116# if IsOdd(b-i) then117if (b-i)%2 == 1:118index = (b - i + 1) // 2119exp = uvtable[index-1][1]120if exp <= a:121u = uvtable[index-1][2]122v = uvtable[index-1][3]123expdata[i-1] = [exp, u, v]124125# gather digits until beta_1126bet1 = 0127while expdata[bet1][0] == 0:128bet1 += 1129bet1 += 1130131ai = expdata[bet1-1][0]132u = expdata[bet1-1][1]133v = expdata[bet1-1][2]134135print(f"Determination of first {bet1} ternary digits. We are working with 2^{ai}-torsion.")136137bi = b - bet1138alp = a - ai139140# for j in CartesianPower([0,1,2], bet1) do141for j in product([0,1,2], repeat=int(bet1)):142print(f"Testing digits: {[j[k] for k in range(bet1)]}")143144# tauhatkernel = 3^bi*P3 + sum([3^(k-1)*j[k-1] for k in range(1,beta+1)])*3^bi*Q3145tauhatkernel = 3^bi*P3146for k in range(1, bet1+1):147tauhatkernel += (3^(k-1)*j[k-1])*3^bi*Q3148149tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)150151C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, bet1)152153P_c = u*P2 + v*two_i(P2)154for taut in tau_tilde:155P_c = taut(P_c)156Q_c = u*Q2 + v*two_i(Q2)157for taut in tau_tilde:158Q_c = taut(Q_c)159160# 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) then161if j == (2,)*bet1 or Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai):162print("Glue-and-split! These are most likely the secret digits.")163for k in j:164skB.append(k)165break166167print(skB)168169170# now compute longest prolongation of Bob's isogeny that may be needed171length = 1172max_length = 0173# for i in [bet1+1..b-3] do174for i in range(bet1 + 1, b - 2):175if expdata[i-1][0] != 0:176max_length = max(length, max_length)177length = 0178else:179length += 1180181while True:182K = 2^a*3^(b - max_length)*EB.random_point()183if K.order() == 3^max_length:184break185186while True:187alternativeK = 2^a*3^(b - max_length)*EB.random_point()188if K.weil_pairing(alternativeK, 3^max_length)^(3^(max_length - 1)) != 1:189break190191_, EBprolong = Pushing3Chain(EB, K, max_length)192193# gather next digit and change prolongation if needed194i = bet1 + 1195bi = b - i196197print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")198prolong = 1199print("Prolonging with 1 steps.")200endPB = EBprolong[0](PB)201endQB = EBprolong[0](QB)202endEB = EBprolong[0].codomain()203# Speeds things up in Sage204endEB.set_order((p+1)^2)205206positives = []207208for j in range(0,2+1):209print(f"Testing digit: {j}")210# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;211tauhatkernel = 3^bi*P3212for k in range(1, i):213tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3214tauhatkernel += 3^(i-1)*j*3^bi*Q3215216tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)217218C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)219P_c = u*P2 + v*two_i(P2)220for taut in tau_tilde:221P_c = taut(P_c)222Q_c = u*Q2 + v*two_i(Q2)223for taut in tau_tilde:224Q_c = taut(Q_c)225226if Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):227print("Glue-and-split!")228positives.append(j)229break230231if len(positives) == 1:232print(f"Most likely good prolongation and the secret digit is: {positives[0]}")233skB.append(positives[0])234next_i = i + 1235else:236print("All glue-and-splits, must be bad prolongation: changing it and redoing this digit.")237_, EBprolong = Pushing3Chain(EB, alternativeK, max_length)238next_i = i239prolong = 0240241242# now gather all remaining digits, except for last three (we close that gap by trial and error)243244# for i in [next_i..b-3] do245for i in range(next_i, b-2):246bi = b - i247if expdata[i-1][0] != 0:248ai = expdata[i-1][0]249alp = a - ai250u = expdata[i-1][1]251v = expdata[i-1][2]252prolong = 0253else:254prolong += 1255256print(f"Determination of the {i}th ternary digit. We are working with 2^{ai}-torsion.")257print(f"Prolonging with {prolong} steps. Current: {skB}")258endPB = PB259endQB = QB260endEB = EB261# for j in [1..prolong] do262for j in range(1,prolong+1):263endPB = EBprolong[j-1](endPB)264endQB = EBprolong[j-1](endQB)265if j == prolong:266endEB = EBprolong[j-1].codomain()267# Speeds things up in Sage268endEB.set_order((p+1)^2)269270271for j in range(0,3):272print(f"Testing digit: {j}")273# tauhatkernel := 3^bi*P3 + (&+[3^(k-1)*skB[k] : k in [1..i-1]] + 3^(i-1)*j)*3^bi*Q3;274tauhatkernel = 3^bi*P3275for k in range(1, i):276tauhatkernel += (3^(k-1)*skB[k-1])*3^bi*Q3277tauhatkernel += 3^(i-1)*j*3^bi*Q3278279tauhatkernel_distort =u*tauhatkernel + v*two_i(tauhatkernel)280281C, tau_tilde = Pushing3Chain(E_start, tauhatkernel_distort, i)282P_c = u*P2 + v*two_i(P2)283for taut in tau_tilde:284P_c = taut(P_c)285Q_c = u*Q2 + v*two_i(Q2)286for taut in tau_tilde:287Q_c = taut(Q_c)288if j == 2 or Does22ChainSplit(C, endEB, 2^alp*P_c, 2^alp*Q_c, 2^alp*endPB, 2^alp*endQB, ai):289print("Glue-and-split! This is most likely the secret digit.")290skB.append(j)291break292293key = sum([skB[i-1]*3^(i-1) for i in range(1,b-2)])294295# bridge last safety gap296tim2 = time.time()297298found = false299for i in range(3^5+1):300bobskey = key + i*3^(b-3)301bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)302if bobscurve.j_invariant() == EB.j_invariant():303found = true304break305306print(f"Bridging last gap took: {time.time() - tim2}")307308if found:309print(f"Bob's secret key revealed as: {bobskey}")310print(f"In ternary, this is: {Integer(bobskey).digits(base=3)}")311else:312print("Something went wrong.")313314print(f"Altogether this took {time.time() - tim} seconds.")315316317318319320321322323324325326