Path: blob/main/castryck_decru_shortcut.sage
323 views
# Python imports1import time2from itertools import product34# Local Imports5from helpers import possibly_parallel, supersingular_gens, fast_log36from richelot_aux import AuxiliaryIsogeny, Does22ChainSplit, Pushing3Chain7from uvtable import uvtable89# Load Sage Files10load('speedup.sage')1112# ===================================13# ===== ATTACK ====================14# ===================================151617def CastryckDecruAttack(E_start, P2, Q2, EB, PB, QB, two_i, num_cores=1):18tim = time.time()1920skB = [] # TERNARY DIGITS IN EXPANSION OF BOB'S SECRET KEY2122# gathering the alpha_i, u, v from table23expdata = [[0, 0, 0] for _ in range(b-3)]24for i in range(b%2, b-3, 2):25index = (b-i) // 226row = uvtable[index-1]27if row[1] <= a:28expdata[i] = row[1:4]2930# gather digits until beta_131bet1 = 032while not expdata[bet1][0]:33bet1 += 134bet1 += 13536ai,u,v = expdata[bet1-1]3738print(f"Determination of first {bet1} ternary digits. We are working with 2^{ai}-torsion.")3940bi = b - bet141alp = a - ai4243@possibly_parallel(num_cores)44def CheckGuess(first_digits):45print(f"Testing digits: {first_digits}")4647scalar = sum(3^k*d for k,d in enumerate(first_digits))48tauhatkernel = 3^bi * (P3 + scalar*Q3)4950tauhatkernel_distort = u*tauhatkernel + v*two_i(tauhatkernel)5152C, P_c, Q_c, chainC = AuxiliaryIsogeny(bet1, u, v, E_start, P2, Q2, tauhatkernel, two_i)53# We have a diagram54# C <- Eguess <- E_start55# | |56# v v57# CB-> EB58split = Does22ChainSplit(C, EB, 2^alp*P_c, 2^alp*Q_c, 2^alp*PB, 2^alp*QB, ai)59if split:60Eguess, _ = Pushing3Chain(E_start, tauhatkernel, bet1)6162chain, (E1, E2) = split63# Compute the 3^b torsion in C64P3c = chainC(P3)65Q3c = chainC(Q3)66# Map it through the (2,2)-isogeny chain67if E2.j_invariant() == Eguess.j_invariant():68CB, index = E1, 069else:70CB, index = E2, 171def apply_chain(c, X):72X = (X, None) # map point to C x {O_EB}73for f in c:74X = f(X)75return X[index]76print("Computing image of 3-adic torsion in split factor CB")77P3c_CB = apply_chain(chain, P3c)78Q3c_CB = apply_chain(chain, Q3c)7980Z3 = Zmod(3^b)81# Determine kernel of the 3^b isogeny.82# The projection to CB must have 3-adic rank 1.83# To compute the kernel we choose a symplectic basis of the84# 3-torsion at the destination, and compute Weil pairings.85CB.set_order((p+1)^2, num_checks=1) # keep sanity check86P_CB, Q_CB = supersingular_gens(CB)87P3_CB = ((p+1) / 3^b) * P_CB88Q3_CB = ((p+1) / 3^b) * Q_CB89w = P3_CB.weil_pairing(Q3_CB, 3^b)90# Compute kernel91for G in (P3_CB, Q3_CB):92xP = fast_log3(P3c_CB.weil_pairing(G, 3^b), w)93xQ = fast_log3(Q3c_CB.weil_pairing(G, 3^b), w)94if xQ % 3 != 0:95sk = int(-Z3(xP) / Z3(xQ))96return sk9798return True99100guesses = [ZZ(i).digits(3, padto=bet1) for i in range(3^bet1)]101102for result in CheckGuess(guesses):103((first_digits,), _), sk = result104if sk is not None:105print("Glue-and-split! These are most likely the secret digits.")106bobskey = sk107break108109# Sanity check110bobscurve, _ = Pushing3Chain(E_start, P3 + bobskey*Q3, b)111found = bobscurve.j_invariant() == EB.j_invariant()112113if found:114print(f"Bob's secret key revealed as: {bobskey}")115print(f"In ternary, this is: {Integer(bobskey).digits(base=3)}")116print(f"Altogether this took {time.time() - tim} seconds.")117return bobskey118else:119print("Something went wrong.")120print(f"Altogether this took {time.time() - tim} seconds.")121return None122123124