Skip to content

Implement algorithm=generic_small and algorithm=hybrid for elliptic curve points #40223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

user202729
Copy link
Contributor

@user202729 user202729 commented Jun 8, 2025

The main purpose of this is to be able to do the following (from doctest)

        sage: # needs sage.rings.finite_rings
        sage: p = next_prime(2^256)
        sage: q = next_prime(p)
        sage: E = EllipticCurve(GF(660*p*q-1), [1, 0])
        sage: P = E.lift_x(11) * p * q
        sage: P.order()  # not tested (pari will try to factor p*q which takes forever)
        sage: P.order(algorithm='generic_small')
        330
        sage: P.order()  # works due to caching
        330

Also fix some minor issues.

It might be preferable to upstream this to pari as well.

📝 Checklist

  • The title is concise and informative.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation and checked the documentation preview.

⌛ Dependencies

Copy link

github-actions bot commented Jun 8, 2025

Documentation preview for this PR (built with commit a305a7d; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@user202729 user202729 changed the title Implement algorithm=generic_small for elliptic curve points Implement algorithm=generic_small and algorithm=hybrid for elliptic curve points Jun 8, 2025
return generic.order_from_bounds(self, None)
elif algorithm == 'hybrid':
lb = 1
sqrt_ub = 32

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not start with 16 instead of 32 just like generic groups?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No good reason. On the other hand order_from_bounds has (much) higher constant factor than factor(limit=…), so I don't see the harm either.

if isinstance(N, Integer):
factorization = N.factor(limit=sqrt_ub)
if factorization.is_complete_factorization():
return self._compute_order(algorithm='pari')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to save on the number of factorizations performed here? One is being done here and one factorization will be performed in the pari algorithm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think it's possible. There's #3549 but if trial division works in reasonable time then the number must be very smooth so that the factorization is not a bottleneck.

if N is None and sqrt_ub >= 5000:
N = self.curve().order()
if isinstance(N, Integer):
factorization = N.factor(limit=sqrt_ub)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can factorization be re-used from previous loop runs?

Copy link
Contributor Author

@user202729 user202729 Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically possible but that probably requires some copy paste and/or strange modification to .factor() to have lower bounds on prime factors. sqrt_ub is increasing geometrically anyway, so the time wasted is not very large (at most linear in the time doing useful work)

return self._compute_order('pari')
except PariError:
pass
return self._compute_order('generic')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea how can Pari error be raised. Arguably if this line is hit it would be a pari bug.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the curve parameters can't be fit into int 64 or int 128 bits? Can Pari work with those too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes:

F = GF(2^70)
E = EllipticCurve([F.random_element() for __ in range(5)])
E.0._compute_order(algorithm='pari')

F = GF(next_prime(2^128))
E = EllipticCurve([F.random_element() for __ in range(5)])
E.0._compute_order(algorithm='pari')

R.<x> = QQ[]
F.<a> = NumberField(x^2+next_prime(2^128))
E = EllipticCurve([F.random_element() for __ in range(5)])
E.0._compute_order(algorithm='pari')  # takes forever but it probably won't error out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants