push
This commit is contained in:
commit
8ae65c6f2b
1 changed files with 168 additions and 0 deletions
168
file.sage
Normal file
168
file.sage
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
def torsion_basis(E, l, e, p):
|
||||||
|
n = E.order()
|
||||||
|
cofactor = n // l^e
|
||||||
|
while True:
|
||||||
|
P = cofactor * E.random_point()
|
||||||
|
if P * l^(e-1) != E(0):
|
||||||
|
break
|
||||||
|
while True:
|
||||||
|
Q = cofactor * E.random_point()
|
||||||
|
if Q * l^(e-1) != E(0):
|
||||||
|
eP = P.weil_pairing(Q, l^e)
|
||||||
|
if eP^(l^(e-1)) != eP.parent()(1):
|
||||||
|
break
|
||||||
|
return P, Q
|
||||||
|
def velu_isogeny(E, K):
|
||||||
|
phi = E.isogeny(K)
|
||||||
|
return phi, phi.codomain()
|
||||||
|
|
||||||
|
def find_curve_with_l_torsion(p, l):
|
||||||
|
Fp = GF(p)
|
||||||
|
for _ in range(2000):
|
||||||
|
a, b = Fp.random_element(), Fp.random_element()
|
||||||
|
if 4*a^3 + 27*b^2 == 0:
|
||||||
|
continue
|
||||||
|
E = EllipticCurve(Fp, [a, b])
|
||||||
|
if E.order() % l == 0:
|
||||||
|
return E
|
||||||
|
raise ValueError(f"I cant find a curve over GF({p}) with {l}-torsion")
|
||||||
|
|
||||||
|
def random_l_isogeny(E, l):
|
||||||
|
n = E.order()
|
||||||
|
if n % l != 0:
|
||||||
|
raise ValueError(f"l={l} does not divide #E = {n}")
|
||||||
|
cofactor = n // l
|
||||||
|
for _ in range(500):
|
||||||
|
P = E.random_point()
|
||||||
|
K = cofactor * P
|
||||||
|
if K != E(0) and K.order() == l:
|
||||||
|
return velu_isogeny(E, K)
|
||||||
|
raise ValueError("no kernel point found after too many tries")
|
||||||
|
|
||||||
|
|
||||||
|
def csidh_params():
|
||||||
|
small_primes = [3, 5, 7, 11, 13, 17, 19]
|
||||||
|
product = 4 * prod(small_primes)
|
||||||
|
for k in range(1, 10000):
|
||||||
|
p = product * k - 1
|
||||||
|
if p > 0 and is_prime(p) and p % 4 == 3:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("Could not find CSIDH prime")
|
||||||
|
print(f" [csidh_params] p = {p} (p mod 4 = {p % 4})")
|
||||||
|
Fp = GF(p)
|
||||||
|
E0 = EllipticCurve(Fp, [1, 0])
|
||||||
|
assert E0.is_supersingular(), "E0 must be supersingular"
|
||||||
|
return p, small_primes, E0
|
||||||
|
|
||||||
|
def _csidh_step(E_cur, l, sign, p):
|
||||||
|
Fp = GF(p)
|
||||||
|
n = E_cur.order()
|
||||||
|
if n % l != 0:
|
||||||
|
E_try = E_cur.quadratic_twist()
|
||||||
|
if E_try.order() % l == 0:
|
||||||
|
E_cur = E_try
|
||||||
|
n = E_cur.order()
|
||||||
|
else:
|
||||||
|
raise ValueError(f"neither E nor its twist has {l}-torsion (n={n}, are you fr now?)")
|
||||||
|
cofactor = n // l
|
||||||
|
for _ in range(1000):
|
||||||
|
R = E_cur.random_point()
|
||||||
|
K = cofactor * R
|
||||||
|
if K != E_cur(0) and K.order() == l:
|
||||||
|
phi = E_cur.isogeny(K)
|
||||||
|
return phi.codomain()
|
||||||
|
raise ValueError(f"no {l}-torsion kernel point found")
|
||||||
|
|
||||||
|
def csidh_action(E, exp_vec, primes, p):
|
||||||
|
E_cur = E
|
||||||
|
for l, e in zip(primes, exp_vec):
|
||||||
|
if e == 0:
|
||||||
|
continue
|
||||||
|
sign = 1 if e > 0 else -1
|
||||||
|
for _ in range(abs(e)):
|
||||||
|
E_cur = _csidh_step(E_cur, l, sign, p)
|
||||||
|
return E_cur
|
||||||
|
|
||||||
|
def make_sidh_prime(eA, eB):
|
||||||
|
for f in range(1, 100000):
|
||||||
|
p = 2^eA * 3^eB * f - 1
|
||||||
|
if p > 0 and is_prime(p):
|
||||||
|
return p, f
|
||||||
|
raise ValueError("I cant find a SIDH prime!!!!!!!!!!")
|
||||||
|
|
||||||
|
def sidh_setup(p, eA, eB):
|
||||||
|
R.<x> = GF(p)[]
|
||||||
|
Fp2.<i> = GF(p^2, modulus=x^2+1)
|
||||||
|
E0 = EllipticCurve(Fp2, [1, 0])
|
||||||
|
PA, QA = torsion_basis(E0, 2, eA, p)
|
||||||
|
PB, QB = torsion_basis(E0, 3, eB, p)
|
||||||
|
return E0, PA, QA, PB, QB
|
||||||
|
|
||||||
|
def sidh_keygen_A(E0, PA, QA, PB, QB, eA):
|
||||||
|
while True:
|
||||||
|
mA, nA = randint(0, 2^eA-1), randint(0, 2^eA-1)
|
||||||
|
if (mA, nA) != (0, 0):
|
||||||
|
break
|
||||||
|
KA = mA*PA + nA*QA
|
||||||
|
phi_A = E0.isogeny(KA, algorithm='factored')
|
||||||
|
EA = phi_A.codomain()
|
||||||
|
return (mA, nA), EA, phi_A(PB), phi_A(QB)
|
||||||
|
|
||||||
|
def sidh_keygen_B(E0, PA, QA, PB, QB, eB):
|
||||||
|
while True:
|
||||||
|
mB, nB = randint(0, 3^eB-1), randint(0, 3^eB-1)
|
||||||
|
if (mB, nB) != (0, 0):
|
||||||
|
break
|
||||||
|
KB = mB*PB + nB*QB
|
||||||
|
phi_B = E0.isogeny(KB, algorithm='factored')
|
||||||
|
EB = phi_B.codomain()
|
||||||
|
return (mB, nB), EB, phi_B(PA), phi_B(QA)
|
||||||
|
|
||||||
|
def sidh_shared_A(mA, nA, EB, phi_PA, phi_QA):
|
||||||
|
KA = mA*phi_PA + nA*phi_QA
|
||||||
|
return EB.isogeny(KA, algorithm='factored').codomain().j_invariant()
|
||||||
|
|
||||||
|
def sidh_shared_B(mB, nB, EA, phi_PB, phi_QB):
|
||||||
|
KB = mB*phi_PB + nB*phi_QB
|
||||||
|
return EA.isogeny(KB, algorithm='factored').codomain().j_invariant()
|
||||||
|
def isogeny_graph_neighbors(E, l):
|
||||||
|
poly = E.division_polynomial(l)
|
||||||
|
neighbors = []
|
||||||
|
seen_j = set()
|
||||||
|
for fac, _ in poly.factor():
|
||||||
|
if fac.degree() != 1:
|
||||||
|
continue
|
||||||
|
x0 = -fac[0] / fac[1]
|
||||||
|
try:
|
||||||
|
pts = E.lift_x(x0, all=True)
|
||||||
|
for P in pts:
|
||||||
|
if P != E(0) and (l * P) == E(0):
|
||||||
|
phi = E.isogeny(P)
|
||||||
|
F = phi.codomain()
|
||||||
|
j = F.j_invariant()
|
||||||
|
if j not in seen_j:
|
||||||
|
seen_j.add(j)
|
||||||
|
neighbors.append(F)
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return neighbors
|
||||||
|
|
||||||
|
def bfs_isogeny_path(E_start, j_end, l, max_depth=8):
|
||||||
|
from collections import deque
|
||||||
|
queue = deque([(E_start, [E_start.j_invariant()])])
|
||||||
|
visited = {E_start.j_invariant()}
|
||||||
|
while queue:
|
||||||
|
E, path = queue.popleft()
|
||||||
|
if E.j_invariant() == j_end:
|
||||||
|
return path
|
||||||
|
if len(path) > max_depth:
|
||||||
|
continue
|
||||||
|
for F in isogeny_graph_neighbors(E, l):
|
||||||
|
j = F.j_invariant()
|
||||||
|
if j not in visited:
|
||||||
|
visited.add(j)
|
||||||
|
queue.append((F, path + [j]))
|
||||||
|
return None
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue