incontro del 23/03/2015 - biblioteca di Istituto

B Laboratorio con PARI / GP
B.� Introduzione a PARI / GP
���� / �� è una libreria per linguaggi ad alto livello (ad es. C, C++, Pascal, Fortran) ed
una so�sticata calcolatrice programmabile. Le sue caratteristiche principali sono l’essere
un programma libero, la rapidità (Da �� a ���� volte più rapido di altri programmi), la
possibilità di usare tipi di dati comuni nell’uso matematico, l’esteso supporto per la teoria
dei numeri. ���� / �� funziona su molte versioni di Unix (inclusi Linux e OS/X) e anche su
Windows; può Essere scaricato liberamente da http://pari.math.u-bordeaux.fr.
Da terminale invochiamo il programma come gp. Per avere una schermata di aiuto,
digitiamo ? seguito da <invio>: in particolare ?<funzione> ci dà una spiegazione ?
della funzione <funzione> , ?? mostra il manuale di ���� / ��, ?\ mostra i comandi di ??
con�gurazione di ���� / ��. Tra questi segnaliamo \l per salvare una copia della sessione \l
in pari.log oppure \r<nome_file> per leggere il �le <nome_file> .
\r
B.� Introduzione alla crittografia
Per prima cosa, ci occorre stabilire un metodo per associare ad una stringa, cioè Ad una
sequenza di caratteri, un numero. Identi�chiamo l’alfabeto di �� lettere {A, B, . . . , Z} con
Z���Z: ad A associamo �, a B associamo �, e così via, �no a Z che associamo a ��.
Il modulo crypto.gp, scaricabile da http://www.mat.unimi.it/users/otto/
mepvs, de�nisce alcune funzioni a questo scopo: s2i trasforma i caratteri {A, a} in �,
{B, b} in �, �no a {Z, z} in ��; e qualsiasi altro carattere in �� (in altre parole, sostituisce
una X a punti, spazi, ecc.). La funzione i2s trasforma l’intero � nel carattere a, e così via
? \r crypto
? s2i("A")
%1 = 0
? s2i("H")
%2 = 7
? s2i(",")
%3 = 23
? i2s(23)
%4 = "x"
In realtà, per poter lavorare più comodamente su blocchi di testo, s2i accetta anche
stringhe di più caratteri, che interpreta in base �� con la cifra meno signi�cativa a sinistra:
ad esempio, poiché m = ��, a = �, t = ��, e = �, la stringa mate vale �� + � ⋅ �� + �� ⋅ ��� +
� ⋅ ��� = �����:
? s2i("mate")
%5 = 83160
��
s2i
i2s
B Laboratorio con PARI / GP
? i2s(83160)
%6 = "mate"
Occorre notare, però, che così facendo s2i non è più iniettiva neanche sulle stringhe
formate da sole lettere minuscole: così come possiamo aggiungere un numero arbitrario
di zeri all’inizio di un espansione decimale, possiamo aggiungere un numero arbitrario
di a alla �ne di una stringa senza modi�carne il valore:
? print([s2i("m"), s2i("ma"), s2i("maaa")])
[12, 12, 12]
Fortunatamente il problema è solo apparente: se vogliamo elaborare ℓ caratteri alla volta,
non possiamo accettarne un numero inferiore: se ℓ = �, solo maaa è accettabile. Per potere
invertire correttamente s2i, la funzione i2s ha un parametro opzionale, che stabilisce la
dimensione del blocco:
? print([i2s(12), i2s(12,2), i2s(12,4)])
["m", "ma", "maaa"]
s2v
In�ne, per poter cifrare e decifrare più comodamente delle frasi, il pacchetto crypto
de�nisce anche la funzione s2v: se s è una stringa ed ℓ un intero (se ℓ = �, possiamo
ometterlo), s2v(s, ℓ) restituisce un vettore ottenuto dividendo s in blocchi di lunghezza
ℓ e considerando ciascuno come intero in base ��
? s2v("mate")
%7 = [12, 0, 19, 4]
? s2v("mate",2)
%8 = [12, 123]
? s2v("mate",3)
%9 = [12856, 4]
v2s
La funzione inversa è v2s:
? v2s([12, 0, 19, 4])
%10 = "mate"
? v2s([12, 123],2)
%11 = "mate"
? v2s([12856,4],3)
%12 = "mateaa"
Cesare
cesare
Il pacchetto crypto contiene, come esempio, un’implementazione dell’algoritmo di Cesare. Per comodità abbiamo de�nito due funzioni: la prima, cesare_, agisce sui numeri,
mentre la seconda, cesare, agisce sulle stringhe
cesare_(t, key=3) = return( (t + key) % 26)
{ cesare(s, key=3) =
local(v, V);
v = s2v(s, 1);
V = vector(#v, i, cesare_(v[i], key));
return(v2s(V))
}
��
B.� Introduzione alla crittogra�a
Spiegazione del codice. La funzione cesare_, molto semplicemente, somma la chiave
al testo modulo ��. Notiamo solo che la somma va messa fra parentesi perché l’operatore
% ha una precedenza maggiore.
La funzione cesare, invece, prende come argomento una stringa, la divide nel vettore
v, e poi crea un nuovo vettore V ottenuto da v applicando cesare_ ad ogni elemento.
L’operatore # è un abbreviazione di length, la lunghezza di un vettore. Le parentesi gra�e
che circondano la de�nizione di cesare sono necessarie: tra l’altro permettono di andare
impunemente a capo.
length
Vediamo ora qualche esempio
? cesare("Questa e’ una prova",3)
%13 = "txhvwdahaaxqdasuryd"
? cesare("txhvwdahaaxqdasuryd",-3)
%14 = "questaxexxunaxprova"
? cesare("txhvwdahaaxqdasuryd",26-3)
%15 = "questaxexxunaxprova"
Notiamo come la funzione di decifrazione non sia altro che quella di cifrazione con la
chiave cambiata di segno.
Cifrario affine
Implementiamo il cifrario a�ne: c = k� t + b mod ��. Per prima cosa mostriamo il
contenuto delle funzioni cesare e cesare_:
? ?cesare
cesare(s, key=3) = local(v, V); v=s2v(s,1);
V=vector(#v,i,cesare_(v[i],key));return(v2s(V))
? ?cesare_
cesare_(t, k=3) = return((t+k)%26)
Facendo copia e incolla modi�chiamo le due funzioni creando le funzioni affine e
affine_
affine
? affine(s, key=[3,2]) = local(v, V); v=s2v(s,1);\
V=vector(#v,i,affine_(v[i],key));return(v2s(V))
? affine_(t,k=[3,2]) = return((k[1]*t+k[2])%26)
Proviamo ora a cifrare, con le chiavi di default, un semplice brano, dopodiché contiamo
le occorrenze
c = affine("Nelmezzodelcammindinostravitamiritrovaiperunavalleoscurachel
adirittaviaerasmarrita")
%16 = "dlzblbbfjlzhdbbtdjtdfnpldttpdbtltplftdthllrddtdzzlfnhrldhrlzdjtltppdttdlldnbdlltpd"
? s=s2v(c)
%17 = [3, 11, 25, 1, 11, 1, 1, 5, 9, 11, 25, 7, 3, 1, 1, 19, 3, 9, 19,
3, 5, 13, 15, 11, 3, 19, 19, 15, 3, 1, 19, 11, 19, 15, 11, 5, 19, 3,
19, 7, 11, 11, 17, 3, 3, 19, 3, 25, 25, 11, 5, 13, 7, 17, 11, 3, 7,
17, 11, 25, 3, 9, 19, 11, 19, 15, 15, 3, 19, 19, 3, 11, 11, 3, 13, 1,
3, 11, 11, 19, 15, 3]
? dist=vector(26)
��
B Laboratorio con PARI / GP
%18 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0]
? for(i=1, #s, dist[s[i]+1] += 1)
? dist
%19 = [10, 16, 13, 17, 3, 4, 0, 10, 3, 8, 2, 19, 5, 7, 7, 10, 0, 3, 4,
14, 0, 1, 0, 1, 0, 7]
? ploth(i=1,26,dist[floor(i)])
%20 = [1.0000000000000000000, 26.000000000000000000, 0.E-307, 13.00000000000000000
? affine1(s,k)=return(affine(s,[1/k[1] % 26, - k[2]/k[1] % 26]))
? affine1(c,[3,2])
%21 = "nelmezzodelcammindinostravitamiritrovaiperunavalleoscuracheldirittaviaerasm
? affine1(s,[3,19])
%22 = "qhophccrghofdpplqglqrvwudylwdplulwurydlshuxqdydoohrvfxudfkhoglulwwdyldhudvp
Hill
RSA
Vogliamo ora implementare ���. Per prima cosa scegliamo due primi e facciamone il
prodotto: per semplicità usiamo dei valori irrealisticamente piccoli
? p = prime(100)
%23 = 541
? q = prime(105)
%24 = 571
? n = p*q
%25 = 308911
? log(n)/log(26)
%26 = 3.879813977574394819241530199
prime
eulerphi
La funzione prime(i) restituisce l’i-esimo primo, che dev’essere però tra quelli precalcolati all’avvio. L’ultima operazione ci mostra che �log�� n� = �; cioè che, con questi
paramentri, possiamo cifrare al più gruppi di tre lettere.
Dobbiamo ora trovare un’esponente e che sia relativamente primo a φ(n): per quanto
���� / �� includa una funzione eulerphi per calcolare la φ di Eulero, ricordiamo che il
suo calcolo è equivalente a fattorizzare n.
? phi=(p-1)*(q-1)
%27 = 307800
? e = 3; gcd (e, phi)
%28 = 3
? e = 5; gcd (e, phi)
%29 = 5
? e = 7; gcd (e, phi)
%30 = 1
È chiaro che e non può essere pari; facendo un po’ di prove, vediamo che e = � è accettabile.
Prendiamo pertanto (n, e) come chiave pubblica e cifriamo il testo mai:
? t = s2i("mai")
%31 = 5420
? c = Mod(t, n)^e
��
B.� Introduzione alla crittogra�a
%32 = Mod(288509, 308911)
? c = lift(c)
%33 = 288509
? i2s(c,4)
%34 = "nukq"
Per quanto per numeri di questa entità non faccia alcuna di�erenza, è importante calcolare
c prima come intero modulare e dopo sollevarlo, con la funzione lift, ad un intero.
Notiamo in�ne che c > ��� , ed infatti va rappresentato con quattro caratteri.
Proviamo ora a decifrare nukq
? d = Mod(e, phi)^(-1)
%35 = Mod(87943, 307800)
? d = lift(d)
%36 = 87943
? c = s2i("nukq")
%37 = 288509
? t = lift( Mod(c, n)^d )
%38 = 5420
? i2s(t, 3)
%39 = "mai"
Mettiamo tutte queste operazioni insieme e de�niamo una funzione rsa_. Per analogia
con cesare_, la chiave è un argomento unico: in questo caso un vettore contente n e d.
? rsa_(t, key) = local(n = key[1], e = key[2], c); \
c = lift( Mod(t,n)^e ); return(c)
? rsa_(5420, [n, e])
%40 = 288509
? rsa_(288509, [n,d])
%41 = 5420
Notiamo come, ancora una volta, la funzione di decifrazione è quella di cifrazione usata
con una chiave diversa.
Per terminare, decifriamo con gli stessi parametri di sopra il testo zvrhupco. Per prima
cosa dividiamo il testo in due blocchi di quattro lettere e leggiamo ciascuno come un
numero
? s2v("zvrhupco",4)
%42 = [135095, 247826]
Applichiamo rsa_ a ciascun componente
? rsa_(135095, [n,d])
%43 = 9001
? rsa_(247826, [n,d])
%44 = 9966
Ed in�ne convertiamo i due numeri in una stringa, ricordando che ciascun blocco ha
lunghezza tre
? v2s([9001,9966],3)
%45 = "finito"
��
lift
B Laboratorio con PARI / GP
B.� Numeri primi, compositi e fattorizzazione
Numeri di Fermat
L’n-esimo numero di Fermat è F(n) = �� + �. Fermat aveva a�ermato che F(n) è un
numero primo per ogni n, dopo avere osservato che ciò vale per n � �.
n
? F(n)=2^(2^n)+1
? F(1)
%1 = 5
? F(2)
%2 = 17
? F(3)
%3 = 257
? F(4)
%4 = 65537
È chiaro che F(�), F(�), F(�) sono primi. Veri�chiamo che lo sia anche F(�) cercandone
tutti i divisori
? n=F(4); for(d=1, n, if(n%d == 0, print(d)))
1
65537
Il quinto numero di Fermat F(�) non è primo:
? n=F(5); for(d=1, n, if(n%d == 0, print(d)))
1
641
6700417
Siamo però costretti a interrompere la ricerca perché non si conclude presto: ciò perché
√
stiamo provando tutti i divisori d < n quando sarebbe su�ciente provare i divisori d < n
? n=F(5); for(d=1, sqrt(n), if(n%d == 0, print(d)))
1
641
? n/641
%5 = 6700417
? n=641; for(d=1, sqrt(n), if(n%d == 0, print(d)))
1
? n=%5; for(d=1, sqrt(n), if(n%d == 0, print(d)))
1
Quindi F(�) = ��� ⋅ ������� dove entrambi i fattori sono primi. Il test di Fermat applicato
a F(�) ci dice che
? Fermat(2,F(5))
%6 = 1
? Fermat(3,F(5))
%7 = 0
Quindi � è un falso testimone per F(�), mentre � è un testimone per la compositezza di
F(�).
��
B.� Numeri primi, compositi e fattorizzazione
? Fermat(2,F(6))
%8 = 1
? Fermat(3,F(6))
%9 = 0
Quindi neanche F(�) è primo: quali sono i suoi fattori?
? n=F(6); for(d=1, sqrt(n), if(n%d == 0, print(d)))
1
274177
^C *** for: user interrupt after 22,442 ms.
? c6=F(6)/274177; for(d=1, sqrt(n), if(n%d == 0, print(d)))
1
^C *** if: user interrupt after 10,906 ms.
Abbiamo così scoperto che F(�) = ������c� dove ������ è necessariamente primo
(perché?) ma non sappiamo se c� è composito.
Test di Fermat
Ricordiamo che
Teorema B.� (di Fermat)
Se n è primo, a n−� ≡ � mod n per ogni intero a con ���(a, n) = �.
De�niamo allora un test di Fermat e veri�chiamo che vale per ogni base se n = ��
? Fermat(a,n)=Mod(a,n)^(n-1)==1
? Fermat(2,11)
%10 = 1
? for(a=2,11,print(a,"\t",Fermat(a,11)))
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
1
10
1
11
0
Applichiamo il test di Fermat a F(�), ottenendo così conferma che è composito:
? n=F(6)
%11 = 18446744073709551617
? Fermat(2,n)
%12 = 1
? Fermat(3,n)
%13 = 0
Per capire se c� è composito, applichiamo il test di Fermat a qualche base
��
B Laboratorio con PARI / GP
? Fermat(2,c6)
%14 = 1
? Fermat(3,c6)
%15 = 1
? Fermat(5,c6)
%16 = 1
for(i=1, 100, a=random(c6); if(Fermat(a,c6)==0, print(a)))
c� sembra essere primo, ma il test di Fermat ha il problema dei numeri di Carmichael
? n=7*11*13*41
%17 = 41041
? for(a=1, n-1, if(gcd(a,n)==1 && Fermat(a,n)==0, print(a)))
Test di Eulero
Ricordiamo che
Teorema B.� (Eulero)
a
Se n è primo, allora a(n−�)�� ≡ � � mod n
n
���� / �� implementa il simbolo di Kronecker che è l’estenzione a Z × Z del simbolo di
Legendre tramite la funzione kronecker
? euler(a,n) = Mod(a,n)^((n-1)/2) == kronecker(a,n)
? euler(17,n)
%18 = 0
Veri�chiamo ora se c� è composito
? for(i=1, 100, a=random(c6); if(euler(a,c6)==0, print(a)))
Questo ci mostra che la probabilità che c� sia composito è dell’ordine di �−��� .
B.� p − � di Pollard
Cerchiamo ora di fattorizzare i numeri di Fermat utilizzando l’algoritmo p − � di Pollard:
Algoritmo B.�
Se ���(a, n) = � e � < d = ���(a B! − �, n) < n allora d è un fattore non banale di n
Per prima cosa calcoliamo B!, o meglio, m = mcm{�, �, . . . , B} dopo aver �ssato
B = �����
? mcm(a,b)=a*b/gcd(a,b)
? m=1
%1 = 1
? B=10000
%2 = 10000
? for(i=1, B, m = mcm(m,i)); m+0.
��
%3 = 5.793339670287642968692270879 E4348
? B!+0.
%4 = 2.846259680917054518906413212 E35659
B.� X � + Y � = n
Dopodiché applichiamo l’algoritmo con basi piccole:
? n=F(6)
%5 = 18446744073709551617
? Mod(2,n)^m-1
%6 = Mod(0, 18446744073709551617)
? Mod(3,n)^m-1
%7 = Mod(5275533187106939030, 18446744073709551617)
? gcd(%,n)
%8 = Mod(274177, 18446744073709551617)
? n/lift(%)
%9 = 67280421310721
Abbiamo così recuperato rapidamente i due fattori primi che già conoscevamo. Il test
non funziona per F(�) né F(�), ma trova rapidamente un fattore di F(�).
? n=F(7)
%10 = 340282366920938463463374607431768211457
for(i=1,100, d=lift(gcd(Mod(random(),n)^m-1, n)); if (d>1 && d<n, print(d)))
? n=F(8)
%11 = 115792089237316195423570985008687907853269984665640564039457584007913129639937
? for(i=1,100, d=lift(gcd(Mod(random(),n)^m-1, n)); if (d>1 && d<n, print(d)))
? n=F(9)
%12 = 1340780792994259709957402499820584612747936582059239337772356144372176403007354697680187429816690
? for(i=1,100, d=lift(gcd(Mod(random(),n)^m-1, n)); if (d>1 && d<n, print(d)))
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
2424833
B.� X � + Y � = n
C n (Z)
Sia C n la curva a�ne de�nita dall’equazione X � + Y � = n, con n intero: lo scopo del
laboratorio è formulare delle congetture sul comportamente di C n (Q) al variare di n.
È evidente che se n < �, C n (R) = �, mentre C� (R) = {(�, �)}; supponiamo quindi
che n ∈ N. Se n = md � con m, d interi naturali allora
(a, b) ∈ C m (Q) ⇐⇒ (da, db) ∈ C n (Q)
��
B Laboratorio con PARI / GP
issquare
test
for
forprime
Possiamo perciò trascurare tutti i fattori quadratici di n: l’intero n è prodotto di primi
distinti. Poiché è su�ciente trovare un punto razionale per ottenere tutti gli altri, iniziamo
a cercare dei punti a coordinate intere sulle curve C n ; per sempli�care le cose, supponiamo
pure che n sia primo.
È chiaro che C� (Z) = {(±�, ±�)} e che C� (Z) = {(±�, ±�), (±�, ±�)}, mentre abbiamo visto nel paragrafo �.� che C� (Q) = �. In generale, se (a, b) ∈ C n (Z), allora
{(±a, ±b), (±b, ±a)} ∈ C n (Z); inoltre (a, a) ∈ C n (Z) signi�ca che �a � = n. Supponendo n = p primo dispari ci basterà quindi individuare l’insieme {(a, b) ∈ N� ∶ a <
b, a� + b� = p}. Poiché a� = p − b� < p �
− a � , abbiamo che �a � < p, quindi sarà su�ciente
�
veri�care se l’insieme {n − a ∶ � � a < p��} contiene dei quadrati perfetti. Per fare ciò
usiamo l’istruzione issquare e de�niamo una funzione test
? test(p) = local(y); for(x = 1, sqrt(p/2), if(issquare(p-x^2, &y),\
print(p, ":\t", [x,y])))
? test(3)
? test(5)
5:
[1, 2]
Spiegazione del codice. La sbarra obliqua alla �ne della prima riga serve solo per andare
a capo: possiamo pure scrivere tutto di seguito. Il ciclo for(x=a,b,seq) valuta seq
con x che assume tutti i valori interi nell’intervallo [a, b]. La funzione issquare mette
nella variabile indicata nel secondo argomento (notate la &) la radice quadrata, se esiste.
La variabile y è dichiarata locale grazie a local, per evitare di modi�care una variabile
eventualmente già de�nita; le altre variabili sono automaticamente locali.
Possiamo calcolare ora C p (Z) per un po’ di primi. La funzione forprime è analoga a
for, ma assume solo valori primi:
? forprime(p=2,100,test(p))
2:
[1, 1]
5:
[1, 2]
13:
[2, 3]
17:
[1, 4]
29:
[2, 5]
37:
[1, 6]
41:
[4, 5]
53:
[2, 7]
61:
[5, 6]
73:
[3, 8]
89:
[5, 8]
97:
[4, 9]
Congettura B.�
Se C p (Z) ≠ � con p primo dispari, allora esiste un solo punto (a, b) ∈ C p (Z) con
� < a < b.
Congettura B.�
C p (Z) = � se e solo se p ≡ � mod �.
��
B.� X � + Y � = n
C n (Q)
Noto un punto a coordinate intere, possiamo trovare tutti i punti con coordinate razionali;
non c’è motivo, però, che se C n (Z) = � allora anche C n (Q) = �.
Sia C una curva de�nita su Z e sia q un primo qualsiasi, allora abbiamo una mappa,
detta riduzione modulo q
C(Z)
(a, b)
/ C(Fq )
/ (a mod q, b mod q)
(B.�)
Segue che, se C(Fq ) = � per qualche primo q, allora anche C(Z) = �.
Non è possibile estendere questa mappa a C(Q) perché, ad esempio, ��q mod q non
ha nessun senso. D’altro canto, se n ≡� � mod q, possiamo de�nire ��n mod q come
l’unica classe di resto n′ mod q tale che nn′ ≡ � mod q: ad esempio, ��� ≡ � mod � perché
� ⋅ � ≡ � mod �; in altre parole, ��n mod q = (n mod q)−� in F∗q . Sia
O q = {m�n ∈ Q ∶ (m, n) ∈ Z × N, ���(m, n) = �, n ≡� � mod q}
l’insieme degli interi rispetto a q. Allora possiamo de�nire una mappa Oq → Fq e quindi
estendere (B.�) ad una mappa C(Oq ) → C(F p ): in questo modo possiamo sollevare
informazioni su C(F p ) a informazioni su di un vasto sottoinsieme di C(Q).
Per tracciare il gra�co di una curva su Fq , carichiamo il modulo diofantea.gp, che
possiamo scaricare da http://www.mat.unimi.it/users/otto/mepvs
? \r diofantea
? plotmod(11,x^2+y^2-7)
* C: x^2 + (y^2 - 7) ≡ 0 mod 11
___________
10|
|
9|
**
|
8|
*
* |
7|
|
6| *
* |
5| *
* |
4|
|
3|
*
* |
2|
**
|
1|
|
0|
|
----------0
5
10
Spiegazione del codice. La funzione plotmod ha cinque argomenti, di cui solo i primi plotmod
due obbligatorî: plotmod(n, p(x, y)) traccia il gra�co della curva p(x, y) = � modulo n, dove n non è necessariamente primo, mentre p è un polinomio in x ed y (è necessario usare queste variabili). La sintassi completa è plotmod(n, p� (x, y), p� (x, y),
p� (x, y), arg ): p� e p� sono altri due polinomi, mentre arg = ε x + �ε y con ε x , ε y = �, �;
se ε x = � allora le ascisse vanno da � a n − �, se ε x = �, le ascisse sono centrate in �;
analogamente per ε y .
��
B Laboratorio con PARI / GP
?
*
/
\
A
V
X
0
plotmod(29,x^2+y^2-7,x,y,3)
C1: x^2 + (y^2 - 7) ≡ 0 mod 29
C2: x ≡ 0 mod 29
C3: y ≡ 0 mod 29
C1 ∩ C2
C1 ∩ C3
C2 ∩ C3
C1 ∩ C2 ∩ C3
_____________________________
14|
/
|
13|
/
|
12|
/
|
11|
/
|
10|
*
/
*
|
9|
*
/
*
|
8|
*/*
|
7|
*
/
*
|
6|
A
|
5|
/
|
4|
*
/
*
|
3|
/
|
2|
/
|
1|
*
/
*
|
0|\\\\\\\\V\\\\\X\\\\\V\\\\\\\\|
-1|
*
/
*
|
-2|
/
|
-3|
/
|
-4|
*
/
*
|
-5|
/
|
-6|
A
|
-7|
*
/
*
|
-8|
*/*
|
-9|
*
/
*
|
-10|
*
/
*
|
-11|
/
|
-12|
/
|
-13|
/
|
-14|
/
|
-----------------------------10
-5
0
5
10
Fissiamo un primo p ≡ � mod �, per esempio p = �, e tracciamo il gra�co di C p modulo
q per un po’ di primi q
? plotmod(2,x^2+y^2-7,0,0,3)
* C: x^2 + (y^2 - 7) ≡ 0 mod 2
__
1|* |
0| *|
-0
? plotmod(3,x^2+y^2-7,0,0,3)
* C: x^2 + (y^2 - 7) ≡ 0 mod 3
��
___
1| * |
0|* *|
-1| * |
--0
? plotmod(5,x^2+y^2-7,0,0,3)
* C: x^2 + (y^2 - 7) ≡ 0 mod 5
_____
2|
|
1| * * |
0|
|
-1| * * |
-2|
|
----0
? plotmod(7,x^2+y^2-7,0,0,3)
* C: x^2 + (y^2 - 7) ≡ 0 mod 7
_______
3|
|
2|
|
1|
|
0|
*
|
-1|
|
-2|
|
-3|
|
------0
? plotmod(11,x^2+y^2-7,0,0,3)
* C: x^2 + (y^2 - 7) ≡ 0 mod 11
___________
5|
*
*
|
4|
|
3| *
* |
2|*
*|
1|
|
0|
|
-1|
|
-2|*
*|
-3| *
* |
-4|
|
-5|
*
*
|
-----------5
0
5
B.� X � + Y � = n
Ripetendo per ulteriori q e per vari primi p ≡ � mod � possiamo formulare la seguente
Congettura B.�
Sia p ≡ � mod �. Allora C p (Fq ) ha molti punti se q ≠ p, mentre C p (F p ) = {�, �}.
Notiamo che la congettura implica che se (a, b) ∈ C p (Q) allora p divide il numerato��
B Laboratorio con PARI / GP
Mod
re o il denominatore di a e b. Possiamo fare ancora meglio, però: consideriamo la riduzione modulo p� di C p data dalla mappa C p (O p ) → C p (Z�p� Z). Se diamo il comando
plotmod(49,x^2+y^2-7) vediamo che Z� (Z��� Z) = �. Lo stesso vale per p = ��, ��.
È chiaro che printmod è utilizzabile solo se p è molto piccolo: sia per via del disegno,
sia perché, per come è costruita, veri�ca se ogni punto del piano è una radice del polinomio.
Costruiamo un’analogo modulare di test, usando Mod:
? testmod(p) = for(x=0, p-1, if( issquare(Mod(p-x^2,p^2)), print(x) ) )
? forprime(p=3,1000,if(p%4==3,testmod(p)))
?
Congettura B.�
Se p ≡ � mod � è primo, allora C p (O p ) = �. In particolare, se (a, b) ∈ C p (Q) allora
p divide il denominatore di a o quello di b
Avendo visto che C� (Q) = �, possiamo chiederci se questo sia vero per ogni p ≡
� mod �: non avendo nessun motivo per supporlo vero, non osiamo neanche formulare
una congettura.
Domanda B.�
Se p ≡ � mod �, allora C p (Q) = �?
��