Updates for Pallas/Vesta.

Use `sage amicable.sage --sequential --requireisos --sortpq --ignoretwist --nearpowerof2 255 32` to generate the Pallas/Vesta cycle.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2020-11-19 19:54:53 +00:00
parent 491beffc2c
commit a35294b64f
1 changed files with 26 additions and 15 deletions

View File

@ -4,8 +4,8 @@
import sys import sys
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
from traceback import print_exc from traceback import print_exc
from math import ceil
from itertools import combinations from itertools import combinations
from string import maketrans
if sys.version_info[0] == 2: range = xrange if sys.version_info[0] == 2: range = xrange
@ -22,8 +22,9 @@ COEFFICIENT_RANGE = (5,)
GCD_PRIMES = (5, 7, 11, 13, 17) GCD_PRIMES = (5, 7, 11, 13, 17)
ISOGENY_DEGREE_PRIMES = 40 # Set to a prime, or 0 to disable searching for isogenies.
ISOGENY_DEGREE_MAX = list(primes(ISOGENY_DEGREE_PRIMES))[-1] ISOGENY_DEGREE_MAX = 3
#ISOGENY_DEGREE_MAX = 37
DEFAULT_TWIST_SECURITY = 120 DEFAULT_TWIST_SECURITY = 120
REQUIRE_PRIMITIVE = True REQUIRE_PRIMITIVE = True
@ -100,7 +101,9 @@ def symmetric_range(n, base=0, step=1):
yield -i yield -i
yield i+1 yield i+1
def find_nice_curves(strategy, L, twoadicity, stretch, isogenies, twistsec, wid, processes): SWAP_SIGNS = maketrans("+-", "-+")
def find_nice_curves(strategy, L, twoadicity, stretch, requireisos, sortpq, twistsec, wid, processes):
for (p, T, V) in strategy(L, max(0, twoadicity-stretch), wid, processes): for (p, T, V) in strategy(L, max(0, twoadicity-stretch), wid, processes):
if p % (1<<twoadicity) != 1: if p % (1<<twoadicity) != 1:
continue continue
@ -114,6 +117,10 @@ def find_nice_curves(strategy, L, twoadicity, stretch, isogenies, twistsec, wid,
continue 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): 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):
if sortpq and q < p:
(p, q) = (q, p)
qdesc = qdesc.translate(SWAP_SIGNS)
(Ep, bp) = find_curve(p, q) (Ep, bp) = find_curve(p, q)
if bp == None: continue if bp == None: continue
(Eq, bq) = find_curve(q, p, (bp,)) (Eq, bq) = find_curve(q, p, (bp,))
@ -155,11 +162,13 @@ def find_nice_curves(strategy, L, twoadicity, stretch, isogenies, twistsec, wid,
twembeddivp = (2*p + 1 - q)/twembedp twembeddivp = (2*p + 1 - q)/twembedp
twembeddivq = (2*q + 1 - p)/twembedq twembeddivq = (2*q + 1 - p)/twembedq
iso_Ep = find_iso(Ep) if isogenies else None iso_Ep = find_iso(Ep)
iso_Eq = find_iso(Eq) if isogenies else None iso_Eq = find_iso(Eq)
if requireisos and (iso_Ep is None or iso_Eq is None):
continue
yield (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq, yield (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq,
embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq, isogenies) embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq)
def endo(E, zeta, P): def endo(E, zeta, P):
(xp, yp) = P.xy() (xp, yp) = P.xy()
@ -204,7 +213,7 @@ def embedding_degree(p, r):
def find_iso(E): def find_iso(E):
# Based on <https://eprint.iacr.org/2019/403.pdf> Appendix A. # Based on <https://eprint.iacr.org/2019/403.pdf> Appendix A.
# Look for isogenous curves having j-invariant not in {0, 1728}. # Look for isogenous curves having j-invariant not in {0, 1728}.
for degree in primes(ISOGENY_DEGREE_PRIMES): for degree in primes(ISOGENY_DEGREE_MAX+1):
sys.stdout.write('~') sys.stdout.write('~')
sys.stdout.flush() sys.stdout.flush()
for iso in E.isogenies_prime_degree(degree): for iso in E.isogenies_prime_degree(degree):
@ -232,17 +241,19 @@ def main():
processes = 1 if "--sequential" in args else cpu_count() processes = 1 if "--sequential" in args else cpu_count()
if processes >= 6: if processes >= 6:
processes -= 2 processes -= 2
isogenies = "--isogenies" in args requireisos = "--requireisos" in args
sortpq = "--sortpq" in args
twistsec = 0 if "--ignoretwist" in args else DEFAULT_TWIST_SECURITY twistsec = 0 if "--ignoretwist" in args else DEFAULT_TWIST_SECURITY
args = [arg for arg in args if not arg.startswith("--")] args = [arg for arg in args if not arg.startswith("--")]
if len(args) < 1: if len(args) < 1:
print(""" print("""
Usage: sage amicable.sage [--sequential] [--isogenies] [--nearpowerof2] <min-bitlength> [<min-2adicity> [<stretch]] Usage: sage amicable.sage [--sequential] [--requireisos] [--sortpq] [--ignoretwist] [--nearpowerof2] <min-bitlength> [<min-2adicity> [<stretch]]
Arguments: Arguments:
--sequential Use only one thread, avoiding non-determinism in the output order. --sequential Use only one thread, avoiding non-determinism in the output order.
--isogenies Search for and print isogenies useful for a "simplified SWU" hash to curve. --requireisos Require isogenies useful for a "simplified SWU" hash to curve.
--sortpq Sort p smaller than q.
--ignoretwist Ignore twist security. --ignoretwist Ignore twist security.
--nearpowerof2 Search for primes near a power of 2, rather than with low Hamming weight. --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-bitlength> Both primes should have this minimum bit length.
@ -260,7 +271,7 @@ Arguments:
try: try:
for wid in range(processes): for wid in range(processes):
pool.apply_async(worker, (strategy, L, twoadicity, stretch, isogenies, twistsec, wid, processes)) pool.apply_async(worker, (strategy, L, twoadicity, stretch, requireisos, sortpq, twistsec, wid, processes))
while True: while True:
sleep(1000) sleep(1000)
@ -279,7 +290,7 @@ def worker(*args):
def real_worker(*args): def real_worker(*args):
for (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq, for (p, q, bp, bq, zetap, zetaq, qdesc, primp, primq, secp, secq, twsecp, twsecq,
embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq, isogenies) in find_nice_curves(*args): embeddivp, embeddivq, twembeddivp, twembeddivq, iso_Ep, iso_Eq) in find_nice_curves(*args):
output = "\n" output = "\n"
output += "p = %s\n" % format_weight(p) output += "p = %s\n" % format_weight(p)
output += "q = %s\n" % format_weight(q) output += "q = %s\n" % format_weight(q)
@ -305,13 +316,13 @@ def real_worker(*args):
if iso_Ep is not None: if iso_Ep is not None:
output += "iso_Ep = %r\n" % (iso_Ep,) output += "iso_Ep = %r\n" % (iso_Ep,)
output += "iso_Ep maps = %r\n" % (iso_Ep.rational_maps(),) output += "iso_Ep maps = %r\n" % (iso_Ep.rational_maps(),)
elif isogenies: elif ISOGENY_DEGREE_MAX > 0:
output += "No Ep isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,) output += "No Ep isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,)
if iso_Eq is not None: if iso_Eq is not None:
output += "iso_Eq = %r\n" % (iso_Eq,) output += "iso_Eq = %r\n" % (iso_Eq,)
output += "iso_Eq maps = %r\n" % (iso_Eq.rational_maps(),) output += "iso_Eq maps = %r\n" % (iso_Eq.rational_maps(),)
elif isogenies: elif ISOGENY_DEGREE_MAX > 0:
output += "No Eq isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,) output += "No Eq isogenies for simplified SWU with degree ≤ %d\n" % (ISOGENY_DEGREE_MAX,)
print(output) # one syscall to minimize tearing print(output) # one syscall to minimize tearing