2020-09-26 13:37:50 -07:00
|
|
|
|
#!/usr/bin/env sage
|
2019-09-10 08:24:08 -07:00
|
|
|
|
# -*- coding: utf-8 -*-
|
2020-09-26 13:37:50 -07:00
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
import sys
|
|
|
|
|
from multiprocessing import Pool, cpu_count
|
|
|
|
|
from traceback import print_exc
|
|
|
|
|
from itertools import combinations
|
2020-11-19 11:54:53 -08:00
|
|
|
|
from string import maketrans
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2020-04-25 09:38:14 -07:00
|
|
|
|
if sys.version_info[0] == 2: range = xrange
|
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
# Let Ep/Fp : y^2 = x^3 + bp
|
|
|
|
|
# Let Eq/Fq : y^2 = x^3 + bq
|
|
|
|
|
|
|
|
|
|
# p and q should each be ~ L bits.
|
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
DEFAULT_TWOADICITY = 32
|
2019-09-10 08:24:08 -07:00
|
|
|
|
DEFAULT_STRETCH = 0
|
|
|
|
|
|
2019-09-15 09:00:21 -07:00
|
|
|
|
COEFFICIENT_RANGE = (5,)
|
2020-09-26 13:32:27 -07:00
|
|
|
|
#COEFFICIENT_RANGE = range(1, 100)
|
2019-09-15 09:00:21 -07:00
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
GCD_PRIMES = (5, 7, 11, 13, 17)
|
2019-09-15 09:00:21 -07:00
|
|
|
|
|
2020-11-19 11:54:53 -08:00
|
|
|
|
# Set to a prime, or 0 to disable searching for isogenies.
|
|
|
|
|
ISOGENY_DEGREE_MAX = 3
|
|
|
|
|
#ISOGENY_DEGREE_MAX = 37
|
2020-09-26 13:43:31 -07:00
|
|
|
|
|
|
|
|
|
DEFAULT_TWIST_SECURITY = 120
|
2019-09-17 03:25:41 -07:00
|
|
|
|
REQUIRE_PRIMITIVE = True
|
2020-09-27 13:18:47 -07:00
|
|
|
|
REQUIRE_HALFZERO = True # nearpowerof2 strategy only
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# <https://cryptojedi.org/papers/pfcpo.pdf> section 2:
|
2019-09-17 10:31:34 -07:00
|
|
|
|
# [...] the order of a curve satisfying the norm equation 3V^2 = 4p - T^2 has one
|
|
|
|
|
# of the six forms {p+1 +/- T, p+1 +/- (T +/- 3V)/2} [IEEE Std 1363-2000, section
|
2019-09-10 08:24:08 -07:00
|
|
|
|
# A.14.2.3, item 6].
|
|
|
|
|
#
|
2019-09-17 10:31:34 -07:00
|
|
|
|
# We choose 4p = 3V^2 + T^2, where (V-1)/2 and (T-1)/2 are both multiples of 2^twoadicity.
|
2019-09-10 08:24:08 -07:00
|
|
|
|
#
|
2019-09-17 10:31:34 -07:00
|
|
|
|
# Then 4p = (3(V-1)^2 + 6(V-1) + 3) + ((T-1)^2 + 2(T-1) + 1)
|
|
|
|
|
# = 3(V-1)^2 + 6(V-1) + (T-1)^2 + 2(T-1) + 4
|
|
|
|
|
# p = 3((V-1)/2)^2 + 3(V-1)/2 + ((T-1)/2)^2 + (T-1)/2 + 1
|
2019-09-10 08:24:08 -07:00
|
|
|
|
#
|
2019-09-17 03:25:41 -07:00
|
|
|
|
# So p-1 will be a multiple of 2^twoadicity, and so will q-1 for q in
|
2019-09-17 10:31:34 -07:00
|
|
|
|
# { p + 1 - T, p + 1 + (T-3V)/2 }.
|
2019-09-10 08:24:08 -07:00
|
|
|
|
#
|
2019-09-17 03:25:41 -07:00
|
|
|
|
# We'd also like both p and q to be 1 (mod 6), so that we have efficient endomorphisms
|
|
|
|
|
# on both curves.
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
|
|
|
|
def low_hamming_order(L, twoadicity, wid, processes):
|
|
|
|
|
Vlen = (L-1)//2 + 1
|
|
|
|
|
Vbase = 1 << Vlen
|
2019-09-17 10:31:34 -07:00
|
|
|
|
Tlen = (L-1)//4
|
|
|
|
|
Tbase = 1 << Tlen
|
2019-09-10 08:24:08 -07:00
|
|
|
|
trailing_zeros = twoadicity+1
|
2020-04-25 09:38:14 -07:00
|
|
|
|
for w in range(wid, Tlen-trailing_zeros, processes):
|
|
|
|
|
for Vc in combinations(range(trailing_zeros, Vlen), w):
|
2019-09-10 08:24:08 -07:00
|
|
|
|
V = Vbase + sum([1 << i for i in Vc]) + 1
|
|
|
|
|
assert(((V-1)/2) % (1<<twoadicity) == 0)
|
2020-04-25 09:38:14 -07:00
|
|
|
|
for Tw in range(1, w+1):
|
2020-09-27 13:18:47 -07:00
|
|
|
|
for Tc in combinations(range(trailing_zeros, Tlen), Tw):
|
2019-09-17 10:31:34 -07:00
|
|
|
|
T = Tbase + sum([1 << i for i in Tc]) + 1
|
|
|
|
|
assert(((T-1)/2) % (1<<twoadicity) == 0)
|
|
|
|
|
if T % 6 != 1:
|
2019-09-10 08:24:08 -07:00
|
|
|
|
continue
|
2019-09-17 10:31:34 -07:00
|
|
|
|
p4 = 3*V^2 + T^2
|
2019-09-10 08:24:08 -07:00
|
|
|
|
assert(p4 % 4 == 0)
|
|
|
|
|
p = p4//4
|
|
|
|
|
assert(p % (1<<twoadicity) == 1)
|
2019-09-15 08:59:45 -07:00
|
|
|
|
if p % 6 == 1 and is_pseudoprime(p):
|
2019-09-17 10:31:34 -07:00
|
|
|
|
yield (p, T, V)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
def near_powerof2_order(L, twoadicity, wid, processes):
|
|
|
|
|
trailing_zeros = twoadicity+1
|
2019-09-15 08:59:45 -07:00
|
|
|
|
Vbase = isqrt((1<<(L+1))//3) >> trailing_zeros
|
2019-09-17 03:25:41 -07:00
|
|
|
|
for Voffset in symmetric_range(100000, base=wid, step=processes):
|
2019-09-10 08:24:08 -07:00
|
|
|
|
V = ((Vbase + Voffset) << trailing_zeros) + 1
|
|
|
|
|
assert(((V-1)/2) % (1 << twoadicity) == 0)
|
2019-09-15 08:59:45 -07:00
|
|
|
|
tmp = (1<<(L+1)) - 3*V^2
|
2019-09-10 08:24:08 -07:00
|
|
|
|
if tmp < 0: continue
|
2019-09-17 10:31:34 -07:00
|
|
|
|
Tbase = isqrt(tmp) >> trailing_zeros
|
|
|
|
|
for Toffset in symmetric_range(100000):
|
|
|
|
|
T = ((Tbase + Toffset) << trailing_zeros) + 1
|
|
|
|
|
assert(((T-1)/2) % (1<<twoadicity) == 0)
|
|
|
|
|
if T % 6 != 1:
|
2019-09-10 08:24:08 -07:00
|
|
|
|
continue
|
2019-09-17 10:31:34 -07:00
|
|
|
|
p4 = 3*V^2 + T^2
|
2019-09-10 08:24:08 -07:00
|
|
|
|
assert(p4 % 4 == 0)
|
|
|
|
|
p = p4//4
|
|
|
|
|
assert(p % (1<<twoadicity) == 1)
|
2019-09-17 03:25:41 -07:00
|
|
|
|
if REQUIRE_HALFZERO and p>>(L//2) != 1<<(L - 1 - L//2):
|
|
|
|
|
continue
|
|
|
|
|
|
2019-09-15 08:59:45 -07:00
|
|
|
|
if p > 1<<(L-1) and p % 6 == 1 and is_pseudoprime(p):
|
2019-09-17 10:31:34 -07:00
|
|
|
|
yield (p, T, V)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
|
|
|
|
def symmetric_range(n, base=0, step=1):
|
2020-04-25 09:38:14 -07:00
|
|
|
|
for i in range(base, n, step):
|
2019-09-10 08:24:08 -07:00
|
|
|
|
yield -i
|
|
|
|
|
yield i+1
|
|
|
|
|
|
2020-11-19 11:54:53 -08:00
|
|
|
|
SWAP_SIGNS = maketrans("+-", "-+")
|
|
|
|
|
|
|
|
|
|
def find_nice_curves(strategy, L, twoadicity, stretch, requireisos, sortpq, twistsec, wid, processes):
|
2019-09-17 10:31:34 -07:00
|
|
|
|
for (p, T, V) in strategy(L, max(0, twoadicity-stretch), wid, processes):
|
2020-09-26 13:32:27 -07:00
|
|
|
|
if p % (1<<twoadicity) != 1:
|
|
|
|
|
continue
|
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
sys.stdout.write('.')
|
|
|
|
|
sys.stdout.flush()
|
2019-09-15 08:59:45 -07:00
|
|
|
|
|
2019-09-17 10:31:34 -07:00
|
|
|
|
for (q, qdesc) in ((p + 1 - T, "p + 1 - T"),
|
|
|
|
|
(p + 1 + (T-3*V)//2, "p + 1 + (T-3*V)/2")):
|
2020-09-27 13:18:47 -07:00
|
|
|
|
if strategy == near_powerof2_order and REQUIRE_HALFZERO and q>>(L//2) != 1<<(L - 1 - L//2):
|
2019-09-17 03:25:41 -07:00
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if q not in (p, p+1, p-1) and q > 1<<(L-1) and q % 6 == 1 and q % (1<<twoadicity) == 1 and is_prime(q) and is_prime(p):
|
2020-11-19 11:54:53 -08:00
|
|
|
|
if sortpq and q < p:
|
|
|
|
|
(p, q) = (q, p)
|
|
|
|
|
qdesc = qdesc.translate(SWAP_SIGNS)
|
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
(Ep, bp) = find_curve(p, q)
|
2019-09-15 08:59:45 -07:00
|
|
|
|
if bp == None: continue
|
2020-09-26 13:43:31 -07:00
|
|
|
|
(Eq, bq) = find_curve(q, p, (bp,))
|
2019-09-15 08:59:45 -07:00
|
|
|
|
if bq == None: continue
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
|
|
|
|
sys.stdout.write('*')
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
|
|
|
|
|
primp = (Mod(bp, p).multiplicative_order() == p-1)
|
|
|
|
|
if REQUIRE_PRIMITIVE and not primp: continue
|
|
|
|
|
primq = (Mod(bq, q).multiplicative_order() == q-1)
|
|
|
|
|
if REQUIRE_PRIMITIVE and not primq: continue
|
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
(twsecp, twembedp) = twist_security(p, q)
|
2020-09-26 13:43:31 -07:00
|
|
|
|
if twsecp < twistsec: continue
|
2019-09-17 09:33:53 -07:00
|
|
|
|
(twsecq, twembedq) = twist_security(q, p)
|
2020-09-26 13:43:31 -07:00
|
|
|
|
if twsecq < twistsec: continue
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
(secp, embedp) = curve_security(p, q)
|
|
|
|
|
(secq, embedq) = curve_security(q, p)
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
|
|
|
|
zetap = GF(p).zeta(3)
|
|
|
|
|
zetap = min(zetap, zetap^2)
|
|
|
|
|
assert(zetap**3 == Mod(1, p))
|
|
|
|
|
|
|
|
|
|
zetaq = GF(q).zeta(3)
|
|
|
|
|
P = Ep.gens()[0]
|
|
|
|
|
zP = endo(Ep, zetap, P)
|
|
|
|
|
if zP != int(zetaq)*P:
|
|
|
|
|
zetaq = zetaq^2
|
|
|
|
|
assert(zP == int(zetaq)*P)
|
|
|
|
|
assert(zetaq**3 == Mod(1, q))
|
|
|
|
|
|
|
|
|
|
Q = Eq.gens()[0]
|
|
|
|
|
assert(endo(Eq, zetaq, Q) == int(zetap)*Q)
|
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
embeddivp = (q-1)/embedp
|
|
|
|
|
embeddivq = (p-1)/embedq
|
|
|
|
|
twembeddivp = (2*p + 1 - q)/twembedp
|
|
|
|
|
twembeddivq = (2*q + 1 - p)/twembedq
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2020-11-19 11:54:53 -08:00
|
|
|
|
iso_Ep = find_iso(Ep)
|
|
|
|
|
iso_Eq = find_iso(Eq)
|
|
|
|
|
if requireisos and (iso_Ep is None or iso_Eq is None):
|
|
|
|
|
continue
|
2020-09-26 13:43:31 -07:00
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
yield (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq,
|
2020-11-19 11:54:53 -08:00
|
|
|
|
embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq)
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
|
|
|
|
def endo(E, zeta, P):
|
|
|
|
|
(xp, yp) = P.xy()
|
|
|
|
|
return E(zeta*xp, yp)
|
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
def find_curve(p, q, b_range=None):
|
|
|
|
|
for b in (b_range or COEFFICIENT_RANGE):
|
2019-09-10 08:24:08 -07:00
|
|
|
|
E = EllipticCurve(GF(p), [0, b])
|
|
|
|
|
if E.count_points() == q:
|
2019-09-17 03:25:41 -07:00
|
|
|
|
return (E, b)
|
|
|
|
|
return (None, None)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
def find_gcd_primes(p):
|
|
|
|
|
return (r for r in GCD_PRIMES if gcd(p-1, r) == 1)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
pi_12 = (pi/12).numerical_approx()
|
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
def curve_security(p, q):
|
2019-09-17 03:25:41 -07:00
|
|
|
|
sys.stdout.write('!')
|
|
|
|
|
sys.stdout.flush()
|
2019-09-17 09:33:53 -07:00
|
|
|
|
r = factor(q)[-1][0]
|
|
|
|
|
return (log(pi_12 * r, 4), embedding_degree(p, r))
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
|
|
|
|
def twist_security(p, q):
|
2019-09-17 09:33:53 -07:00
|
|
|
|
return curve_security(p, 2*(p+1) - q)
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
def embedding_degree(p, r):
|
2019-09-17 03:25:41 -07:00
|
|
|
|
sys.stdout.write('#')
|
|
|
|
|
sys.stdout.flush()
|
2019-09-17 09:33:53 -07:00
|
|
|
|
assert(gcd(p, r) == 1)
|
|
|
|
|
Z_q = Integers(r)
|
2019-09-17 03:25:41 -07:00
|
|
|
|
u = Z_q(p)
|
2019-09-17 09:33:53 -07:00
|
|
|
|
d = r-1
|
2019-09-17 03:25:41 -07:00
|
|
|
|
V = factor(d)
|
|
|
|
|
for (v, k) in V:
|
|
|
|
|
while d % v == 0:
|
|
|
|
|
if u^(d/v) != 1: break
|
|
|
|
|
d /= v
|
|
|
|
|
|
2019-09-17 09:33:53 -07:00
|
|
|
|
return d
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
def find_iso(E):
|
|
|
|
|
# Based on <https://eprint.iacr.org/2019/403.pdf> Appendix A.
|
|
|
|
|
# Look for isogenous curves having j-invariant not in {0, 1728}.
|
2020-11-19 11:54:53 -08:00
|
|
|
|
for degree in primes(ISOGENY_DEGREE_MAX+1):
|
2020-09-26 13:43:31 -07:00
|
|
|
|
sys.stdout.write('~')
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
for iso in E.isogenies_prime_degree(degree):
|
|
|
|
|
if iso.codomain().j_invariant() not in (0, 1728):
|
|
|
|
|
return iso.dual()
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
def format_weight(x, detail=True):
|
|
|
|
|
X = format(abs(x), 'b')
|
|
|
|
|
if detail:
|
|
|
|
|
assert(X.endswith('1'))
|
|
|
|
|
detailstr = " (bitlength %d, weight %d, 2-adicity %d)" % (len(X), sum([int(c) for c in X]),
|
|
|
|
|
len(X) - len(X[:-1].rstrip('0')))
|
|
|
|
|
else:
|
|
|
|
|
detailstr = " (bitlength %d)" % (len(X),)
|
|
|
|
|
|
|
|
|
|
return "%s0b%s%s" % ("-" if x < 0 else "", X, detailstr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2019-09-17 03:18:04 -07:00
|
|
|
|
args = sys.argv[1:]
|
|
|
|
|
strategy = near_powerof2_order if "--nearpowerof2" in args else low_hamming_order
|
|
|
|
|
processes = 1 if "--sequential" in args else cpu_count()
|
2020-09-26 13:43:31 -07:00
|
|
|
|
if processes >= 6:
|
|
|
|
|
processes -= 2
|
2020-11-19 11:54:53 -08:00
|
|
|
|
requireisos = "--requireisos" in args
|
|
|
|
|
sortpq = "--sortpq" in args
|
2020-09-26 13:43:31 -07:00
|
|
|
|
twistsec = 0 if "--ignoretwist" in args else DEFAULT_TWIST_SECURITY
|
2019-09-17 03:18:04 -07:00
|
|
|
|
args = [arg for arg in args if not arg.startswith("--")]
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
|
|
|
|
if len(args) < 1:
|
2020-09-26 13:43:31 -07:00
|
|
|
|
print("""
|
2020-11-19 11:54:53 -08:00
|
|
|
|
Usage: sage amicable.sage [--sequential] [--requireisos] [--sortpq] [--ignoretwist] [--nearpowerof2] <min-bitlength> [<min-2adicity> [<stretch]]
|
2020-09-26 13:43:31 -07:00
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
--sequential Use only one thread, avoiding non-determinism in the output order.
|
2020-11-19 11:54:53 -08:00
|
|
|
|
--requireisos Require isogenies useful for a "simplified SWU" hash to curve.
|
|
|
|
|
--sortpq Sort p smaller than q.
|
2020-09-26 13:43:31 -07:00
|
|
|
|
--ignoretwist Ignore twist security.
|
|
|
|
|
--nearpowerof2 Search for primes near a power of 2, rather than with low Hamming weight.
|
|
|
|
|
<min-bitlength> Both primes should have this minimum bit length.
|
|
|
|
|
<min-2adicity> Both primes should have this minimum 2-adicity.
|
|
|
|
|
<stretch> Find more candidates, by filtering from 2-adicity smaller by this many bits.
|
|
|
|
|
""")
|
2019-09-10 08:24:08 -07:00
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
L = int(args[0])
|
|
|
|
|
twoadicity = int(args[1]) if len(args) > 1 else DEFAULT_TWOADICITY
|
|
|
|
|
stretch = int(args[2]) if len(args) > 2 else DEFAULT_STRETCH
|
|
|
|
|
|
|
|
|
|
print("Using %d processes." % (processes,))
|
|
|
|
|
pool = Pool(processes=processes)
|
|
|
|
|
|
|
|
|
|
try:
|
2020-04-25 09:38:14 -07:00
|
|
|
|
for wid in range(processes):
|
2020-11-19 11:54:53 -08:00
|
|
|
|
pool.apply_async(worker, (strategy, L, twoadicity, stretch, requireisos, sortpq, twistsec, wid, processes))
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
sleep(1000)
|
|
|
|
|
except (KeyboardInterrupt, SystemExit):
|
|
|
|
|
pass
|
|
|
|
|
finally:
|
|
|
|
|
pool.terminate()
|
|
|
|
|
|
|
|
|
|
def worker(*args):
|
|
|
|
|
try:
|
|
|
|
|
real_worker(*args)
|
|
|
|
|
except (KeyboardInterrupt, SystemExit):
|
|
|
|
|
pass
|
|
|
|
|
except:
|
|
|
|
|
print_exc()
|
|
|
|
|
|
|
|
|
|
def real_worker(*args):
|
2019-09-17 03:25:41 -07:00
|
|
|
|
for (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq,
|
2020-11-19 11:54:53 -08:00
|
|
|
|
embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq) in find_nice_curves(*args):
|
2019-09-10 08:24:08 -07:00
|
|
|
|
output = "\n"
|
|
|
|
|
output += "p = %s\n" % format_weight(p)
|
|
|
|
|
output += "q = %s\n" % format_weight(q)
|
2019-09-15 08:59:45 -07:00
|
|
|
|
output += " = %s\n" % qdesc
|
2019-09-17 03:25:41 -07:00
|
|
|
|
output += "ζ_p = %s (mod p)\n" % format_weight(int(zetap), detail=False)
|
|
|
|
|
output += "ζ_q = %s (mod q)\n" % format_weight(int(zetaq), detail=False)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
output += "Ep/Fp : y^2 = x^3 + %d\n" % (bp,)
|
|
|
|
|
output += "Eq/Fq : y^2 = x^3 + %d\n" % (bq,)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
output += "gcd(p-1, α) = 1 for α ∊ {%s}\n" % (", ".join(map(str, find_gcd_primes(p))),)
|
|
|
|
|
output += "gcd(q-1, α) = 1 for α ∊ {%s}\n" % (", ".join(map(str, find_gcd_primes(q))),)
|
2019-09-10 08:24:08 -07:00
|
|
|
|
|
2019-09-17 03:25:41 -07:00
|
|
|
|
output += "%d is %ssquare and %sprimitive in Fp\n" % (bp, "" if Mod(bp, p).is_square() else "non", "" if primp else "non")
|
2020-05-24 11:23:13 -07:00
|
|
|
|
output += "%d is %ssquare and %sprimitive in Fq\n" % (bq, "" if Mod(bq, q).is_square() else "non", "" if primq else "non")
|
2019-09-17 03:25:41 -07:00
|
|
|
|
|
|
|
|
|
output += "Ep security = %.1f, embedding degree = (q-1)/%d\n" % (secp, embeddivp)
|
|
|
|
|
output += "Eq security = %.1f, embedding degree = (p-1)/%d\n" % (secq, embeddivq)
|
|
|
|
|
|
|
|
|
|
output += "Ep twist security = %.1f, embedding degree = (2p + 1 - q)/%d\n" % (twsecp, twembeddivp)
|
|
|
|
|
output += "Eq twist security = %.1f, embedding degree = (2q + 1 - p)/%d\n" % (twsecq, twembeddivq)
|
|
|
|
|
|
2020-09-26 13:43:31 -07:00
|
|
|
|
if iso_Ep is not None:
|
|
|
|
|
output += "iso_Ep = %r\n" % (iso_Ep,)
|
|
|
|
|
output += "iso_Ep maps = %r\n" % (iso_Ep.rational_maps(),)
|
2020-11-19 11:54:53 -08:00
|
|
|
|
elif ISOGENY_DEGREE_MAX > 0:
|
2020-09-26 13:43:31 -07:00
|
|
|
|
output += "No Ep isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,)
|
|
|
|
|
|
|
|
|
|
if iso_Eq is not None:
|
|
|
|
|
output += "iso_Eq = %r\n" % (iso_Eq,)
|
|
|
|
|
output += "iso_Eq maps = %r\n" % (iso_Eq.rational_maps(),)
|
2020-11-19 11:54:53 -08:00
|
|
|
|
elif ISOGENY_DEGREE_MAX > 0:
|
2020-09-26 13:43:31 -07:00
|
|
|
|
output += "No Eq isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,)
|
|
|
|
|
|
2019-09-10 08:24:08 -07:00
|
|
|
|
print(output) # one syscall to minimize tearing
|
|
|
|
|
|
|
|
|
|
main()
|