# Coming soon

## Implementation

from Crypto.Util.number import getPrime

def get_pq(SEED):
p = SEED
while True:
p = next_prime(p)
if p%3 == 2:
q = p^2 + p + 1
if is_prime(q):
return p,q

def get_embedding(prime, order):
k = 1
while True:
if (p^k-1) % order == 0:
return k
k += 1
if k > 10:
print("Something is broken")
exit()

# p picked, q = p^1 + p + 1
p,q = get_pq(1<<10)
print(f'p: {p}')
print(f'q: {q}')
print((p^6 - 1).factor())

F = GF(p)
E = EllipticCurve(F,[0,1])
order = E.order()
j_inv = E.j_invariant()
assert j_inv == 0
k = get_embedding(p, order)
assert k == 2

"""
Given p, q = p^1 + p + 1, we now need to do a base change from E/F_p to E' / F_p^2
If we get this right, the order
E'/F_p^2 == q
"""

Fy = GF(p^2)
Ee = E.change_ring(Fy)
prim = Fy.multiplicative_generator()

# for j_inv = 0, use sextic twists
i = 1
if j_inv == 0:
while i < 6:
E_twisted = Ee.sextic_twist(Fy(prim^i))
if E_twisted.order() == q:
break
i+=1

print(E_twisted)
print(f"Order of twisted curve: {E_twisted.order()}")

"""
With a supersingular curve of prime order, we can do the MOV attack from E / F_p^2 -> F_p^6
"""

Fy6 = GF(p^6)
E2 = E_twisted
max_val = E2.order()
E6 = E_twisted.change_ring(Fy6)

print(E6)

P = E2.gens()
xP = 123*P
Pe = E6(P)
xPe = E6(xP)

while True:
R = E6.random_point()
m = R.order()
d = gcd(m, P.order())
Q = (m//d)*R
if P.order()/Q.order() in ZZ and P.order() == Q.order():
break

n = P.order()
print('computing pairings')
alpha = Pe.weil_pairing(Q,n)
beta = xPe.weil_pairing(Q,n)

print('computing log')
dd = beta.log(alpha)
assert P*dd == xP
print(dd)