Repository navigation
Fix identity element arithmetic and add projective form for curves over rings - #15
Merged
serengil merged 2 commits intoOct 22, 2026
Merged
Conversation
serengil
deleted the
sefiks/fix-identity-element-and-add-projective-form
branch
October 22, 2026 19:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two changes:
EllipticCurvePoint. Fixes Handle the point at infinity (identity element) in point arithmetic and ECDLP #14.projectiveform for curves y² = x³ + b over Z_m where m does not need to beprime, so that LightPHE's Elliptic Curve Paillier can do its curve math in LightECC instead
of carrying its own copy.
Version is bumped to 0.0.8.
1. Identity element fix
EllipticCurvePointdidn't treat O as a special case:O / Greturnedninstead of0.-O,O * k,k * OandP - OraisedTypeErroron Weierstrass and Koblitz curves,because O is stored there as
(inf, inf)and the field arithmetic only accepts integers.Edwards wasn't affected, since its identity
(0, 1)is a normal point.This broke LightPHE's Elliptic Curve ElGamal:
decrypt(encrypt(0))returnedn, anddecrypting
encrypt(5) * 0raisedTypeError. LightPHE had workarounds for both.Changes:
EllipticCurvePoint.is_identity(). It compares againstcurve.O, so it works forevery form.
__repr__uses it now.__truediv__returns0for O. This check runs before theP / P = 1shortcut.__neg__returns O for O, which also fixesP - O.__mul__returns O for O with any integer k, which also covers__rmul__.Scalars were already reduced mod n in
double_and_add, so nothing changed there. Changinghow O is stored, instead of
(inf, inf), was left out of this PR. The float values nolonger reach the modular arithmetic in these operations.
2. Projective form
Why
Elliptic Curve Paillier (Galbraith, 2002) works on y² = x³ + b over Z_{n²} with n = pq. The
existing forms don't work for it:
(x, y)points, and their addition formulas divide. Z_{n²} is not afield, so division fails whenever a coordinate shares a factor with n.
(mn : 1 : 0)reduce to the point at infinity mod n but are distinctmod n². They have no affine form, and LightECC has only one point at infinity, so all of
them would become the same point.
config["n"]. If it were passed,double_and_addwould reduceorder × Cto0 × Cand every message would be lost.Using a custom Weierstrass config with
p = n²was tested: decryption fails withbase is not invertible for the given modulusfor every message except 0. (Boneh-Goh-Nissim isn'taffected. Its modulus is prime and only its group order is composite, so it keeps using the
Weierstrass form.)
What
point at infinity is (0 : 1 : 0). Addition uses the complete formulas of
Renes-Costello-Batina (2016), Algorithm 7 for a = 0. They work for every pair of points,
including doubling and the point at infinity, and never divide.
validated when given.
secret.
as the base point used in every encryption.
is_identity() and to_affine(). Two points are equal when one is a scalar multiple of the
other, which is checked through all three 2×2 cross-products. Checking only X1·Z2 = X2·Z1
would wrongly treat (0 : 1 : 0) and (n : 1 : 0) as the same point. There's no division,
since brute-force ECDLP needs a known order.
Point of order 2
The complete formulas assume the subgroup has no point of order 2. When P − Q has order 2,
P + Q returns (0 : 0 : 0), which used to pass the on-curve check and compare equal to every
point. While writing tests, this made find_order return 2504 instead of 5004 on a test
curve. is_on_curve now rejects any triple whose coordinates share a factor with the
modulus, so this case raises PointNotOnCurve instead of giving a wrong result. Elliptic
Curve Paillier isn't affected, because its points have odd order.
Tests
(Gn)/G == 0, G/G == 1, (G5)/G == 5, -O == O, O7 == 7*O == O, G - O == G and O + G ==
G.
All 42 tests pass. LightPHE's full suite (235 passed, 1 skipped) also passes against this
branch, with Elliptic Curve Paillier moved to the projective form and the ElGamal
workarounds removed.
Follow-up
After 0.0.8 is published to PyPI, the LightPHE PR can merge: it requires lightecc>=0.0.8.