He estado durmiendo con Silverman y Tate Puntos racionales en curvas elípticas bajo mi almohada desde hace años, sin ningún efecto. Así que aquí está el enfoque simple de codificador país. (Spoiler: sí, 108 puntos.)
Para construir el campo $\mathbb{F}_{125}$ necesitamos un irreducible cúbico sobre $\mathbb{F}_5$ . Como la irreductibilidad de un cúbico equivale simplemente a la ausencia de factores lineales, y sobre todo porque el enunciado del problema ya incluye $p(X) = X^3+X+1$ comenzamos por verificar su irreductibilidad "mod 5":
irreduciblePoly :-
for(X,0,4,1),
0 is (1 + X*(1+X*X)) mod 5,
!,
fail.
irreduciblePoly.
Se trata de un predicado Prolog que tiene éxito si no hay raíces (factores lineales) módulo 5. Utiliza un generador for/4
¡de enteros específicos de Amzi! Prolog, pero SWI-Prolog tiene una función similar en between/3
y GNU-Prolog proporciona tanto between/3
y for/3
.
Como este polinomio es correcto, aplicamos las operaciones de campo plus/3
y times/3
en términos de polinomios cuadráticos que son reducciones modulo $p(X)$ y 5. La adición de elementos de campo es sólo la adición de coeficientes similares:
plus(fElt(A0,A1,A2),fElt(B0,B1,B2),fElt(C0,C1,C2)) :-
C0 is (A0+B0) mod 5,
C1 is (A1+B1) mod 5,
C2 is (A2+B2) mod 5.
La multiplicación es más compleja, pero se deriva fácilmente de $X^3=-X-1$ y $X^4 = -X^2-X$ :
times(fElt(A0,A1,A2),fElt(B0,B1,B2),fElt(C0,C1,C2)) :-
C0 is (A0*B0 - A2*B1 - A1*B2) mod 5,
C1 is (A1*B0 + A0*B1 - A2*B1 - A1*B2 - A2*B2) mod 5,
C2 is (A2*B0 + A1*B1 + A0*B2 - A2*B2) mod 5.
Clavándome una nota en la manga para acordarme de contar el "punto en el infinito", el plan es comprobar todos los valores de $p(X)$ en $\mathbb{F}_{125}$ que son cero (un punto de la curva) o que son residuos cuadráticos (distintos de cero) (dos puntos de la curva):
points(125,P,P) :- !.
points(N,P,R) :-
intoField(N,FElt),
evalPoly(FElt,Poly),
increase(Poly,P,Q),
On is N+1,
points(On,Q,R). /* last call */
para que podamos ejecutar la consulta ?- points(0,1,Pts).
(El 1
es el punto en el infinito)
Aquí intoField/2
asigna fácilmente números enteros $0\leq N \leq 124$ en 125 elementos de campo:
intoField(N,fElt(A0,A1,A2)) :-
A0 is N mod 5,
A1 is (N // 5) mod 5,
A2 is (N // 25).
para que podamos evaluar el polinomio para cada uno de ellos:
evalPoly(FElt,Poly) :-
times(FElt,FElt,FSqr),
plus(fElt(1,0,0),FSqr,Pm),
times(FElt,Pm,Pn),
plus(fElt(1,0,0),Pn,Poly).
y ajustar el recuento de puntos en consecuencia:
increase(fElt(0,0,0),P,Q) :- !, Q is P+1.
increase(Poly,P,Q) :-
quadResidue(Poly),
!,
Q is P+2.
increase(_,P,P).
Pre-construí una "búsqueda" de residuos cuadráticos quadResidue/2
elevando al cuadrado cada elemento del campo y assert
(un mecanismo de Prolog para crear hechos dinámicamente), si no existe ya:
assertQuadraticResidues :-
for(N,1,124,1),
intoField(N,FElt),
times(FElt,FElt,QRes),
( quadResidue(QRes)
-> true
; assert(quadResidue(QRes))
),
fail.
assertQuadraticResidues.
Ahora podemos ejecutar el código de forma interpretativa:
?- assertQuadraticResidues.
yes
?- points(0,1,Pts).
Pts = 108
yes
confirmando la Respuesta más elegantemente obtenida por Jyrki.