Ryan Rueger

ryan@rueg.re / picture / key / home
aboutsummaryrefslogtreecommitdiffhomepage
path: root/theta_lib/isogenies/Kani_clapoti.py
diff options
context:
space:
mode:
authorPierrick-Dartois <pierrickdartois@icloud.com>2025-05-22 18:51:58 +0200
committerPierrick-Dartois <pierrickdartois@icloud.com>2025-05-22 18:51:58 +0200
commitcb6080eaa4f326d9fce5f0a9157be46e91d55e09 (patch)
tree4d080ade8db9faa0da5268ab420dad2b02a4e248 /theta_lib/isogenies/Kani_clapoti.py
parentd40de259097c5e8d8fd35539560ca7c3d47523e7 (diff)
downloadpegasis-cb6080eaa4f326d9fce5f0a9157be46e91d55e09.tar.gz
pegasis-cb6080eaa4f326d9fce5f0a9157be46e91d55e09.tar.bz2
pegasis-cb6080eaa4f326d9fce5f0a9157be46e91d55e09.zip
Clean up PEGASIS submodule inclusion
Diffstat (limited to 'theta_lib/isogenies/Kani_clapoti.py')
-rw-r--r--theta_lib/isogenies/Kani_clapoti.py258
1 files changed, 0 insertions, 258 deletions
diff --git a/theta_lib/isogenies/Kani_clapoti.py b/theta_lib/isogenies/Kani_clapoti.py
deleted file mode 100644
index 66030e2..0000000
--- a/theta_lib/isogenies/Kani_clapoti.py
+++ /dev/null
@@ -1,258 +0,0 @@
-from sage.all import *
-import itertools
-
-from ..basis_change.kani_base_change import clapoti_cob_splitting_matrix
-from ..basis_change.base_change_dim4 import base_change_theta_dim4
-from ..theta_structures.Tuple_point import TuplePoint
-from ..theta_structures.montgomery_theta import null_point_to_montgomery_coeff, theta_point_to_montgomery_point
-from ..theta_structures.theta_helpers_dim4 import product_to_theta_points_dim4
-from ..utilities.supersingular import torsion_basis_to_Fp_rational_point
-from .Kani_gluing_isogeny_chain_dim4 import KaniClapotiGluing
-from .isogeny_chain_dim4 import IsogenyChainDim4
-
-class KaniClapotiIsog(IsogenyChainDim4):
- r"""Class representing the 4-dimensional isogeny obtained via Kani's lemma F: Eu^2*Ev^2 --> Ea^2*A
- where Ea=[\mf{a}]*E is the result of the ideal class group action by \mf{a} when given relevant
- constants and torsion point information.
-
- INPUT:
- - Pu, Qu = phi_u(P, Q)\in Eu;
- - Pv, Qv = phi_v*phi_{ck}*\hat{\phi}_{bk}(P, Q)\in Ev;
- - gu, xu, yu, gv, xv, yv, Nbk, Nck, e: positive integers;
- where:
- * gu(xu^2+yu^2)Nbk+gv(xv^2+yv^2)Nck=2^e;
- * gcd(u*Nbk,v*Nck)=1 with u:=gu(xu^2+yu^2) and v:=gv(xv^2+yv^2);
- * xu and xv are odd and yu and yv are even;
- * \mf{b}=\mf{be}*\mf{bk} is a product of ideals of norms Nbe and Nbk respectively,
- where Nbe is a product of small Elkies primes;
- * \mf{c}=\mf{ce}*\mf{ck} is a product of ideals of norms Nce and Nck respectively,
- where Nbe is a product of small Elkies primes;
- * phi_{bk}: E --> E1 and phi_{ck}: E --> E2 are induced by the action of
- ideals \mf{bk} and \mf{ck} respectively;
- * <P,Q>=E_1[2^{e+2}];
- * phi_u: E1 --> Eu and phi_v: E2 --> Ev are gu and gv-isogenies respectively.
-
- OUTPUT: F: Eu^2*Ev^2 --> Ea^2*A is the isogeny:
-
- F := [[Phi_{bp}*\tilde{Phi}_u, Phi_{cp}*\tilde{Phi}_v],
- [-Psi, \tilde{Phi}]]
-
- obtained from the Kani isogeny diamond:
-
- A --------------------Phi------------------> Ev^2
- ^ ^
- | |
- | Phi_v
- | |
- Psi E2^2
- | ^
- | |
- | \tilde{Phi}_{ck}
- | |
- Eu^2 --\tilde{Phi}_{u}--> E1^2 --Phi_{bk}--> Ea^2
-
- where Phi_{bk}:=Diag(phi_{bk},phi_{bk}), Phi_{ck}:=Diag(phi_{ck},phi_{ck}),
-
- Phi_u := [[xu, -yu],
- [yu, xu]] * Diag(phi_u,phi_u)
-
- Phi_v := [[xv, -yv],
- [yv, xv]] * Diag(phi_v,phi_v)
- """
-
- def __init__(self,points,integers,strategy=None):
- gu,xu,yu,gv,xv,yv,Nbk,Nck,e = integers
- Pu,Qu,Pv,Qv = points
- if gu*(xu**2+yu**2)*Nbk+gv*(xv**2+yv**2)*Nck!=2**e:
- raise ValueError("Wrong parameters: gu(xu^2+yu^2)Nbk + gv(xv^2+yv^2)Nck != 2^e")
- if gcd(ZZ(gu*(xu**2+yu**2)*Nbk),ZZ(gv*(xv**2+yv**2)*Nck))!=1:
- raise ValueError("Non coprime parameters: gcd(gu(xu^2+yu^2)Nbk, gv(xv^2+yv^2)Nck) != 1")
- if xu%2==0:
- xu,yu=yu,xu
- if xv%2==0:
- xv,yv=yv,xv
-
- self.Eu = Pu.curve()
- self.Ev = Pv.curve()
- Fp2 = parent(Pu[0])
- Fp = Fp2.base_ring()
-
- # Number of dimension 2 steps before dimension 4 gluing Am^2-->B
- m=valuation(xv*yu-xu*yv,2)
- integers=[gu,xu,yu,gv,xv,yv,Nbk,Nck,e,m]
-
- points_mp3=[(2**(e-m-1))*P for P in points]
- points_mp2=[2*P for P in points_mp3]
- points_4=[(2**m)*P for P in points_mp2]
-
- self.Ru_Fp = torsion_basis_to_Fp_rational_point(self.Eu,points_4[0],points_4[1],4)
-
- self.gluing_isogeny_chain = KaniClapotiGluing(points_mp3,points_mp2,points_4,integers, coerce=Fp)
-
- xuNbk = xu*Nbk
- yuNbk = yu*Nbk
- two_ep2 = 2**(e+2)
- inv_Nbk = inverse_mod(Nbk,two_ep2)
- u = gu*(xu**2+yu**2)
- inv_u = inverse_mod(u,4)
- lambxu = ((1-2**e*inv_u*inv_Nbk)*xu)%two_ep2
- lambyu = ((1-2**e*inv_u*inv_Nbk)*yu)%two_ep2
- xv_Nbk = (xv*inv_Nbk)%two_ep2
- yv_Nbk = (yv*inv_Nbk)%two_ep2
-
-
- B_Kpp = [TuplePoint(xuNbk*Pu,yuNbk*Pu,xv*Pv,yv*Pv),
- TuplePoint(-yuNbk*Pu,xuNbk*Pu,-yv*Pv,xv*Pv),
- TuplePoint(lambxu*Qu,lambyu*Qu,xv_Nbk*Qv,yv_Nbk*Qv),
- TuplePoint(-lambyu*Qu,lambxu*Qu,-yv_Nbk*Qv,xv_Nbk*Qv)]
-
- IsogenyChainDim4.__init__(self, B_Kpp, self.gluing_isogeny_chain, e, m, splitting=True, strategy=strategy)
-
- # Splitting
- M_split = clapoti_cob_splitting_matrix(integers)
-
- self.N_split = base_change_theta_dim4(M_split,self.gluing_isogeny_chain.e4)
-
- self.codomain_product = self._isogenies[-1]._codomain.base_change_struct(self.N_split)
-
- # Extracting the group action image Ea=[\mathfrak{a}]*E from the codomain Ea^2*E'^2
- self.theta_null_Ea, self.theta_null_Ep, self.Ea, self.Ep = self.extract_montgomery_curve()
-
-
-
- def extract_montgomery_curve(self):
-
- # Computing the theta null point of Ea
- null_point=self.codomain_product.zero()
- Fp2=parent(null_point[0])
- Fp = Fp2.base_ring()
- for i3, i4 in itertools.product([0,1],repeat=2):
- if null_point[4*i3+8*i4]!=0:
- i30=i3
- i40=i4
- theta_Ea_0=Fp(null_point[4*i3+8*i4])
- theta_Ea_1=Fp(null_point[1+4*i3+8*i4])
- break
- for i1, i2 in itertools.product([0,1],repeat=2):
- if null_point[i1+2*i2]!=0:
- i10=i1
- i20=i2
- theta_Ep_0=Fp(null_point[i1+2*i2])
- theta_Ep_1=Fp(null_point[i1+2*i2+4])
- break
-
- # Sanity check: is the codomain of F a product of the form Ea^2*E'^2 ?
- theta_Ea=[Fp(theta_Ea_0),Fp(theta_Ea_1)]
- theta_Ep=[Fp(theta_Ep_0),Fp(theta_Ep_1)]
-
- theta_Ea2Ep2=[0 for i in range(16)]
- for i1,i2,i3,i4 in itertools.product([0,1],repeat=4):
- theta_Ea2Ep2[i1+2*i2+4*i3+8*i4]=theta_Ea[i1]*theta_Ea[i2]*theta_Ep[i3]*theta_Ep[i4]
- theta_Ea2Ep2=self.codomain_product(theta_Ea2Ep2)
-
- assert theta_Ea2Ep2.is_zero()
-
- A_Ep = null_point_to_montgomery_coeff(theta_Ep_0,theta_Ep_1)
- Ep = EllipticCurve([0,A_Ep,0,1,0])
-
- ## ## Recovering Ea over Fp and not Fp2
- ## self.find_Fp_rational_theta_struct_Ea()
-
- ## theta_Ea = self.iso_Ea(theta_Ea)
- ## A_Ea = null_point_to_montgomery_coeff(theta_Ea[0],theta_Ea[1])
-
- ## # Sanity check : the curve Ea should be defined over Fp
- ## # assert A_Ea[1] == 0
-
- ## # Twisting Ea if necessary: if A_Ea+2 is not a square in Fp, then we take the twist (A_Ea --> -A_Ea)
- ## p=self.Eu.base_field().characteristic()
- ## self.twist = False
- ## if (A_Ea+2)**((p-1)//2)==-1:
- ## A_Ea = -A_Ea
- ## self.twist = True
-
- ## Ea = EllipticCurve([0,A_Ea,0,1,0])
-
- A = null_point_to_montgomery_coeff(theta_Ea_0, theta_Ea_1)
- Ab = null_point_to_montgomery_coeff(theta_Ea_0+theta_Ea_1, theta_Ea_0-theta_Ea_1)
- Acan = min([A, -A, Ab, -Ab])
- Acan = A
- if (Acan == A or Acan == -A):
- # 'Id' corresponds to the point on the twist
- self.iso_type = 'Id'
- else:
- # 'Hadamard' corresponds to the point on the curve
- self.iso_type = 'Hadamard'
- if ((self.iso_type == 'Hadamard' and not (Acan+2).is_square()) or (self.iso_type == 'Id' and (Acan+2).is_square())):
- Acan=-Acan
- if (Acan == A or Acan == Ab):
- self.twist = False
- else:
- self.twist = True
- Ea = EllipticCurve([0,Acan,0,1,0])
-
- # Find the dual null point
- return theta_Ea, theta_Ep, Ea, Ep
-
- def eval_rational_point_4_torsion(self):
- T = TuplePoint(self.Ru_Fp,self.Eu(0),self.Ev(0),self.Ev(0))
-
- FPu_4 = self.evaluate_isogeny(T)
- FPu_4=self.codomain_product.base_change_coords(self.N_split,FPu_4)
- FPu_4=product_to_theta_points_dim4(FPu_4)
-
- return FPu_4[0]
-
- def find_Fp_rational_theta_struct_Ea(self):
- Pa = self.eval_rational_point_4_torsion()
-
- HPa = (Pa[0]+Pa[1],Pa[0]-Pa[1])
- i = self.Eu.base_field().gen()
- self.i = i
- iHPa = (Pa[0]+i*Pa[1],Pa[0]-i*Pa[1])
-
- if Pa[0]==0 or Pa[1]==0:
- self.iso_type='Id'
- elif HPa[0]==0 or HPa[1]==0:
- self.iso_type='Hadamard'
- elif iHPa[0]==0 or iHPa[1]==0:
- self.iso_type='iHadamard'
- else:
- raise ValueError("A rational theta point should be mapped to (0:1) or (1:0) after change of theta coordinates on Ea.")
-
- def iso_Ea(self,P):
- # Change of theta coordinates to obtain Fp-rational theta coordinates on Ea
-
- if self.iso_type == 'Id':
- return P
- elif self.iso_type == 'Hadamard':
- return (P[0]+P[1],P[0]-P[1])
- else:
- return (P[0]+self.i*P[1],P[0]-self.i*P[1])
-
-
- def evaluate(self,P):
- FP=self.evaluate_isogeny(P)
- FP=self.codomain_product.base_change_coords(self.N_split,FP)
-
- FP=product_to_theta_points_dim4(FP)
- FP=TuplePoint([theta_point_to_montgomery_point(self.Ea,self.theta_null_Ea,self.iso_Ea(FP[0]),self.twist),
- theta_point_to_montgomery_point(self.Ea,self.theta_null_Ea,self.iso_Ea(FP[1]),self.twist),
- theta_point_to_montgomery_point(self.Ep,self.theta_null_Ep,FP[2]),
- theta_point_to_montgomery_point(self.Ep,self.theta_null_Ep,FP[3])])
-
- return FP
-
- def __call__(self,P):
- return self.evaluate(P)
-
-
-
-
-
-
-
-
-
-
-