Skip to content

Commit

Permalink
gh-34965: sparse strategies for composite elliptic-curve isogenies
Browse files Browse the repository at this point in the history
    
Fixes #34239.
    
URL: #34965
Reported by: Lorenz Panny
Reviewer(s): John Cremona, Kwankyu Lee, Lorenz Panny
  • Loading branch information
Release Manager committed Jun 3, 2023
2 parents 3202f65 + 17a5859 commit 43d4f83
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 19 deletions.
5 changes: 5 additions & 0 deletions src/doc/en/reference/references/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,11 @@ REFERENCES:
.. [DeVi1984] \M.-P. Delest, and G. Viennot, *Algebraic Languages and
Polyominoes Enumeration.* Theoret. Comput. Sci. 34, 169-206, 1984.
.. [DJP2014] Luca De Feo, David Jao and Jérôme Plût: Towards quantum-resistant
cryptosystems from supersingular elliptic curve isogenies. Journal
of Mathematical Cryptology, vol. 8, no. 3, 2014, pp. 209-247.
https://eprint.iacr.org/2011/506.pdf
.. [DFMS1996] Philipppe Di Francesco, Pierre Mathieu, and David Sénéchal.
*Conformal Field Theory*. Graduate Texts in Contemporary
Physics, Springer, 1996.
Expand Down
103 changes: 84 additions & 19 deletions src/sage/schemes/elliptic_curves/hom_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism

# TODO: Implement sparse strategies? (cf. the SIKE cryptosystem)


def _eval_factored_isogeny(phis, P):
"""
Expand All @@ -120,33 +118,100 @@ def _eval_factored_isogeny(phis, P):
return P


def _compute_factored_isogeny_prime_power(P, l, e):
"""
This method takes a point `P` of order `l^e` and returns
a sequence of degree-`l` isogenies whose composition has
def _compute_factored_isogeny_prime_power(P, l, n, split=.8):
r"""
This method takes a point `P` of order `\ell^n` and returns
a sequence of degree-`\ell` isogenies whose composition has
the subgroup generated by `P` as its kernel.
The optional argument ``split``, a real number between
`0` and `1`, controls the *strategy* used to compute the
isogeny: In general, the algorithm performs a number of
scalar multiplications `[\ell]` and a number of
`\ell`-isogeny evaluations, and there exist tradeoffs
between them.
- Setting ``split`` to `0` skews the algorithm towards
isogenies, minimizing multiplications.
The asymptotic complexity is `O(n \log(\ell) + n^2 \ell)`.
- Setting ``split`` to `1` skews the algorithm towards
multiplications, minimizing isogenies.
The asymptotic complexity is `O(n^2 \log(\ell) + n \ell)`.
- Values strictly between `0` and `1` define *sparse*
strategies, which balance the number of isogenies and
multiplications according to the parameter.
The asymptotic complexity is `O(n \log(n) \ell)`.
.. NOTE::
As of July 2022, good values for ``split`` range somewhere
between roughly `0.6` and `0.9`, depending on the size of
`\ell` and the cost of base-field arithmetic.
REFERENCES:
Sparse strategies were introduced in [DJP2014]_, §4.2.2.
ALGORITHM:
The splitting rule implemented here is a simple heuristic which
is usually not optimal. The advantage is that it does not rely
on prior knowledge of degrees and exact costs of elliptic-curve
arithmetic, while still working reasonably well for a fairly
wide range of situations.
EXAMPLES::
sage: from sage.schemes.elliptic_curves import hom_composite
sage: E = EllipticCurve(GF(8191), [1,0]) # optional - sage.rings.finite_rings
sage: P = E.random_point() # optional - sage.rings.finite_rings
sage: (l,e), = P.order().factor() # optional - sage.rings.finite_rings
sage: phis = hom_composite._compute_factored_isogeny_prime_power(P, l, e) # optional - sage.rings.finite_rings
sage: (l,n), = P.order().factor() # optional - sage.rings.finite_rings
sage: phis = hom_composite._compute_factored_isogeny_prime_power(P, l, n) # optional - sage.rings.finite_rings
sage: hom_composite._eval_factored_isogeny(phis, P) # optional - sage.rings.finite_rings
(0 : 1 : 0)
sage: [phi.degree() for phi in phis] == [l]*e # optional - sage.rings.finite_rings
sage: [phi.degree() for phi in phis] == [l]*n # optional - sage.rings.finite_rings
True
All choices of ``split`` produce the same result, albeit
not equally fast::
sage: E = EllipticCurve(GF(2^127 - 1), [1,0]) # optional - sage.rings.finite_rings
sage: P, = E.gens() # optional - sage.rings.finite_rings
sage: (l,n), = P.order().factor() # optional - sage.rings.finite_rings
sage: phis = hom_composite._compute_factored_isogeny_prime_power(P,l,n) # optional - sage.rings.finite_rings
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0) # optional - sage.rings.finite_rings
True
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.1) # optional - sage.rings.finite_rings
True
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.5) # optional - sage.rings.finite_rings
True
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.9) # optional - sage.rings.finite_rings
True
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=1) # optional - sage.rings.finite_rings
True
"""
E = P.curve()
phis = []
for i in range(e):
K = l**(e-1-i) * P
phi = EllipticCurveIsogeny(E, K)
E = phi.codomain()
P = phi(P)
phis.append(phi)
return phis
def rec(Q, k):

if k == 1:
# base case: Q has order l
return [EllipticCurveIsogeny(Q.curve(), Q)]

# recursive case: k > 1 and Q has order l^k

k1 = int(k * split + .5)
k1 = max(1, min(k - 1, k1)) # clamp to [1, k - 1]

Q1 = l**k1 * Q
L = rec(Q1, k - k1)

Q2 = _eval_factored_isogeny(L, Q)
R = rec(Q2, k1)

return L + R

return rec(P, n)


def _compute_factored_isogeny_single_generator(P):
Expand Down Expand Up @@ -196,7 +261,7 @@ def _compute_factored_isogeny(kernel):
phis = []
ker = list(kernel)
while ker:
K, ker = ker[0], ker[1:]
K = ker.pop(0)
psis = _compute_factored_isogeny_single_generator(K)
ker = [_eval_factored_isogeny(psis, P) for P in ker]
phis += psis
Expand Down

0 comments on commit 43d4f83

Please sign in to comment.