Theta points

This module defines the base class of Theta points as elements of AbelianVariety_ThetaStructure.

AUTHORS:

  • Anna Somoza (2020-22): initial implementation

Todo

  • Add more info to the paragraph above

  • On binary operations, test that all the points belong to the same abelian variety.

class avisogenies_sage.theta_point.VarietyThetaStructurePoint(X, v)

Bases: sage.structure.element.AdditiveGroupElement, sage.schemes.generic.morphism.SchemeMorphism_point

Constructor for a point on a variety with theta structure.

INPUT:

  • X – a variety with theta structure

  • v – data determining a point (another point or a tuple of coordinates)

_repr_()

Return a string representation of this point.

_latex_()

Return a LaTeX representation of this point.

scheme()

Return the scheme of this point, i.e., the abelian variety it is on.

is_equal(Q, proj=True, factor=False)

Check whether two points are equal or not. If proj = true we compare them as projective points, and if factor = True, return as a second argument the rapport Q/P.

INPUT:

  • Q - a point.

  • proj - a boolean (default: \(True\)). Weather the comparison is done as projective points.

  • factor - a boolean (default: \(False\)). If True, as a second argument is returned, the rapport right/self.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1]) #A 1889-torsion point
sage: 1889*P
(12 : 141 : 31 : 327)
sage: A(0).is_equal(1889*P)
True

If the points are equal as projective points but not as affine points, one can obtain the factor:

sage: (1889*P).is_equal(A(0), proj=False)
False
sage: _, k = A(0).is_equal(1889*P, factor=True); k
327
_get_nonzero_coord(idx=True)
diff_add(Q, PmQ)

Not implemented for a general point.

_diff_add_PQfactor(P, Q, PmQ)

Given a representative of (P+Q), computes the raport with respect to the representative obtained as P.diff_add(Q, PmQ).

_diff_add_PQ(P, Q, PmQ)

Given a representative of (P+Q), computes the affine representative obtained with P.diff_add(Q, PmQ).

_add_(other)

Add self to other.

If we are in level two, this returns P+Q and P-Q.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,              155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: P + Q
((221*t^3 + 178*t^2 + 126*t + 27 : 32*t^3 + 17*t^2 + 175*t + 171 : 180*t^3 + 188*t^2 + 161*t + 119 : 261*t^3 + 107*t^2 + 37*t + 135),
(1 : 56*t^3 + 312*t^2 + 147*t + 287 : 277*t^3 + 295*t^2 + 7*t + 287 : 290*t^3 + 203*t^2 + 274*t + 10))

Todo

Find tests that are not level 2!

_add(other, i0=0)

Not implemented for a general point.

_neg_()

Computes the addition opposite of self.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1]); - P
(255 : 89 : 30 : 1)
_rmul_(k)

Compute scalar multiplication by \(k\) with a Montgomery ladder type algorithm.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: 42*P
(311 : 326 : 136 : 305)

Todo

Find tests that are not level 2!

_mult(k, algorithm='Montgomery')

Compute scalar multiplication by \(k\) with a Montgomery ladder type algorithm.

INPUT:

  • algorithm (default: ‘Montgomery’): The chosen algorithm for the computation. It can either be ‘Montgomery’ for a Montgomery ladder type algorithm, or ‘SquareAndMultiply’ for the usual square and multiply algorithm (only for level > 2).

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: P._mult(42)
(311 : 326 : 136 : 305)

See also

_rmul_()

Todo

Find tests that are not level 2!

diff_multadd(k, PQ, Q)

Computes k*self + Q, k*self.

EXAMPLES:

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,             155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: PmQ = A([62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,                 258*t^3 + 39*t^2 + 313*t + 150 , 1])
sage: PQ = P.diff_add(Q, PmQ)
sage: P.diff_multadd(42, PQ, Q)
((41*t^3 + 291*t^2 + 122*t + 305 : 119*t^3 + 95*t^2 + 120*t + 68 : 81*t^3 + 168*t^2 + 326*t + 24 : 202*t^3 + 251*t^2 + 246*t + 169),
(311 : 326 : 136 : 305))

Todo

If we don’t need kP, then we don’t need to compute kP, only (k/2)P, so we lose 2 differential additions. Could be optimized here.

weil_pairing(l, Q, PQ=None)

Computes the Weil pairing of P=self and Q. See also _weil_pairing_from_points() to use precomputed points.

INPUT:

  • l – An integer

  • P=self – An point of torsion \(level\)

  • Q – Another point of torsion \(level\)

  • PQ (default: None) – The addition of P and Q.

OUTPUT:

The nth power of the weil pairing of P and Q, where n is the level of the theta structure.

..todo:: Should check that points belong to same AV.

tate_pairing(l, Q, PQ=None)

Computes the Weil pairing of P=self and Q.

INPUT:

  • P=self – A point

  • l – An integer

  • Q – A point of torsion \(l\) in the same Abelian Variety as \(P\).

  • PQ (default: None) – The addition of P and Q.

OUTPUT:

The r-th power of the tate pairing of P and Q, where \(r = (p^k - 1)/l\).

..todo:

- Should check that points belong to same AV.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,              155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: PmQ = A([62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,                 258*t^3 + 39*t^2 + 313*t + 150 , 1])
sage: PQ = P.diff_add(Q, PmQ)
sage: P.tate_pairing(1889, Q, PQ)
313*t^3 + 144*t^2 + 38*t + 71
sage: Q.tate_pairing(1889, P, PQ)
130*t^3 + 124*t^2 + 49*t + 153
three_way_add(Q, R, PQ, QR, PR)

..todo:: Document

EXAMPLES:

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,             155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: PmQ = A([62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,                 258*t^3 + 39*t^2 + 313*t + 150 , 1])
sage: PQ = P.diff_add(Q, PmQ)
sage: P.diff_multadd(2, PQ, Q)[0] == P.three_way_add(P,Q,2*P, PQ, PQ)
True
scale(k)

Given an affine lift point ‘P’ and a factor ‘k’ in the field of definition, returns the affine lift given by kx.

EXAMPLE

sage: from avisogenies_sage import KummerVariety
sage: F = GF(331)
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: P.scale(5)
(282 : 114 : 150 : 5)

TEST :

If the factor to scale by is not in the field of definition, it should raise an error

sage: FF.<z> = GF(331^2)
sage: P.scale(z)
Traceback (most recent call last):
...
ValueError: The scalar factor k=z should be in the base ring R=Finite Field of size 331
compatible_lift(l, other=None, add=None)

Compute a lift of an l-torsion point that is compatible with the chosen affine lift of the theta null point.

INPUT :

  • self – an l-torsion point of the abelian variety

  • other – a list of points of the abelian variety, or None if only the lift of an l-torsion point is needed.

  • add – the list of sums self + P for all the points in P, or None if only the lift of an l-torsion point is needed.

  • l – the torsion

Todo

  • Add examples

  • Add check keyword to assert that all the quotients are equal vs just taking one.

with_theta_basis(label, **kwargs)

Let thc be a theta null point given by algebraic coordinates (i.e. AbelianVariety_ThetaStructure, KummerVariety). Compute the corresponding theta null point (i.e. AnalyticThetaNullPoint) in analytic coordinates.

TODO: check that label matches level

class avisogenies_sage.theta_point.AbelianVarietyPoint(X, v, check=False)

Bases: avisogenies_sage.theta_point.VarietyThetaStructurePoint

Constructor for a point on an abelian variety with theta structure.

INPUT:

  • X – an abelian variety

  • v – data determining a point (another point or a tuple of coordinates)

  • good_lift – a boolean (default: \(False\)); indicates if the given affine lift is a good lift, i.e. a lift compatible with the lift of the theta null point.

  • check – a boolean (default: \(False\)); indicates if computations to check the correctness of the input data should be performed, using the Riemann Relations.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1]); P
(255 : 89 : 30 : 1)
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: B = A.change_ring(F)
sage: Q = B([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,          155*t^3 + 84*t^2 + 15*t + 170, 1]); Q
(158*t^3 + 67*t^2 + 9*t + 293 : 290*t^3 + 25*t^2 + 235*t + 280 : 155*t^3 + 84*t^2 + 15*t + 170 : 1)

Todo

  • When v is a point already and check is \(True\), we should make sure that v has been checked when generated. maybe with a boolean in X (or in the point) that saves if it has been checked.

  • Make check on the point/AV a method that caches the result.

abelian_variety()

Return the abelian variety that this point is on.

EXAMPLES:

sage: from avisogenies_sage import AbelianVariety
sage: A = AbelianVariety(GF(331), 4, 1, [328 , 213 , 75 , 1]); A
Abelian variety of dimension 1 with theta null point (328 : 213 : 75 : 1) defined over Finite Field of size 331
sage: P = A([255 , 89 , 30 , 1])
sage: P.abelian_variety()
Abelian variety of dimension 1 with theta null point (328 : 213 : 75 : 1) defined over Finite Field of size 331
diff_add(Q, PmQ, check=False)

Computes the differential addition of self with given point Q.

INPUT:

  • Q - a theta point

  • PmQ - The theta point \(self - Q\).

  • check - (default: False) check with the riemann relations that the resulting point is indeed a point of the abelian variety.

OUTPUT: The theta point \(self + Q\). If \(self\), \(Q\) and \(PmQ\) are good lifts, then the output is also a good lift.

EXAMPLES

_add(other, i0=0)

Normal addition between self and other on the affine plane with respect to i0. If (self - other)[i] == 0, then it tries with another affine plane.

See also

_add_()

Todo

  • Deal with case where self or other is the thetanullpoint.

  • Find tests where P and Q are not rational in the av but rational in the kummer variety, so P+Q won’t be rational

class avisogenies_sage.theta_point.KummerVarietyPoint(X, v, check=False, **kwargs)

Bases: avisogenies_sage.theta_point.VarietyThetaStructurePoint

Constructor for a point on an kummer variety with theta structure.

INPUT:

  • X – a kummer variety

  • v – data determining a point (another point or a tuple of coordinates)

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1]); P
(255 : 89 : 30 : 1)
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: B = A.change_ring(F)
sage: Q = B([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,          155*t^3 + 84*t^2 + 15*t + 170, 1]); Q
(158*t^3 + 67*t^2 + 9*t + 293 : 290*t^3 + 25*t^2 + 235*t + 280 : 155*t^3 + 84*t^2 + 15*t + 170 : 1)

Todo

  • When v is a point already and check is \(True\), we should make sure that v has been checked when generated. maybe with a boolean in X (or in the point) that saves if it has been checked.

  • Make check on the point/AV a method that caches the result.

kummer_variety()

Return the abelian variety that this point is on.

EXAMPLES:

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1]); A
Kummer variety of dimension 2 with theta null point (328 : 213 : 75 : 1) defined over Finite Field of size 331
sage: P = A([255 , 89 , 30 , 1])
sage: P.kummer_variety()
Kummer variety of dimension 2 with theta null point (328 : 213 : 75 : 1) defined over Finite Field of size 331
_check()
diff_add(Q, PmQ)

Computes the differential addition of self with given point Q.

INPUT:

  • Q - a theta point

  • PmQ - The theta point \(self - Q\).

OUTPUT: The theta point \(self + Q\). If \(self\), \(Q\) and \(PmQ\) are good lifts, then the output is also a good lift.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,                 155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: PmQ = A([62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,                 258*t^3 + 39*t^2 + 313*t + 150 , 1])
sage: PQ = P.diff_add(Q, PmQ); PQ
(261*t^3 + 107*t^2 + 37*t + 135 : 205*t^3 + 88*t^2 + 195*t + 125 : 88*t^3 + 99*t^2 + 164*t + 98 : 159*t^3 + 279*t^2 + 254*t + 276)
_add(other, idxi0=0)

Normal addition between self and other on the affine plane with respect to i0. If (self - other)[i] == 0, then it tries with another affine plane.

See also

_add_()

Todo

  • Deal with case where self or other is the thetanullpoint.

  • Find tests where P and Q are not rational in the av but rational in the kummer variety, so P+Q won’t be rational

_neg_()

Computes the addition opposite of self.

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: A = KummerVariety(GF(331), 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1]); - P
(255 : 89 : 30 : 1)
weil_pairing(l, Q)

EXAMPLES

sage: from avisogenies_sage import KummerVariety
sage: R.<X> = PolynomialRing(GF(331))
sage: poly = X^4 + 3*X^2 + 290*X + 3
sage: F.<t> = poly.splitting_field()
sage: A = KummerVariety(F, 2, [328 , 213 , 75 , 1])
sage: P = A([255 , 89 , 30 , 1])
sage: Q = A([158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,              155*t^3 + 84*t^2 + 15*t + 170, 1])
sage: P.weil_pairing(1889, Q)
61*t^3 + 285*t^2 + 196*t + 257