Teoria dei numeri e Crittografia: lezione del 28 aprile 2011

Teoria dei numeri e Crittografia: lezione del 19 dicembre 2011
Algoritmi di fattorizzazione.
Sono algoritmi che, dato in input un naturale n>1, calcolano tutti i fattori primi di n: a tutt’oggi non
è stato trovato un algoritmo di fattorizzazione di complessità polinomiale.
Un algoritmo di fattorizzazione in genere cerca ottenere un obiettivo intermedio: decomporre
l’input n nel prodotto n=ab, dove a,b sono naturali (non necessariamente primi) tali che 1<a,b<n
(se a,b non esistono, si conclude che n è primo). Una volta trovati a,b l’algoritmo viene riapplicato
separatamente ad a,b per decomporli ulteriormente (se possibile): dopo un numero finito di ripetute
applicazioni dell’algoritmo, si perviene al calcolo dei fattori primi di n.
Ovviamente un algoritmo “ingenuo” di fattorizzazione consiste (come nel test ingenuo di primalità)
nel testare, per ogni naturale a con 2 a  n , se a è divisore di n, e in caso affermativo porre n=
ab (dove b=n/a): il numero dei test da effettuare è però di ordine esponenziale O( 2 x) , se x=L(n)
è la lunghezza binaria di n (perché x< 2x dunque n < 2 x).
Questo algoritmo trova un divisore a di n in tempi di calcolo ragionevoli solo se n ha un fattore
relativamente “piccolo”.
Illustriamo ora un algoritmo di fattorizzazione (dovuto a Fermat) che invece è efficiente se n è
prodotto di 2 divisori relativamente “vicini fra loro” (quindi relativamente “grandi”).
Algoritmo di fattorizzazione di Fermat.
Supponiamo l’input n dispari: non è una limitazione in un algoritmo di fattorizzazione perché se n è
pari, con successive divisioni per 2 si può fattorizzare n nella forma n=2km, con m dispari, e
sostituire m al posto di n come input.
L’algoritmo si basa sul seguente risultato, il quale dimostra che fattorizzare n nel prodotto di 2
numeri naturali equivale sostanzialmente a rappresentare n come differenza di 2 quadrati:
Teorema (Fermat).
Sia n un naturale dispari, e siano:
S = { (a,b)NxN / a b, n=ab }
T = { (r,s)ZxZ / r>s 0, n=r2-s2 }
Allora la funzione f : S  T definita da f(a,b)=((a+b)/2,(a-b)/2) è biunivoca.
Dimostrazione:
Si verifica facilmente che f(a,b)T se (a,b)S.
Per dimostrare che f è biunivoca, basta costruire la funzione inversa: definiamo f-1 : T  S ponendo
f-1(r,s)=(r+s,r-s) (si verifica facilmente che f-1(r,s)S se (r,s)T).
Si verifica infine che le composizioni ff-1, f-1f sono le funzioni identiche di T ed S.
Come conseguenza del teorema precedente, è possibile implementare un algoritmo di
fattorizzazione: dato in input un intero dispari n>1, per trovare una fattorizzazione di n nel prodotto
di 2 numeri naturali a,b, basta trovare una coppia (r,s)T (quindi r,s interi, r>s0, tali che n=r2-s2)
e porre (a,b)=f-1(r,s)=(r+s,r-s).
Per trovare una coppia (r,s)T, possiamo fissare un intero r>0, e cercare un intero s 0 tale che si
abbia r2-n=s2 : se r2-n =0 allora s=0, n=r2, a=b=r; se invece r2-n >0 si può usare un algoritmo (già
esaminato in una delle precedenti lezioni) per verificare se il numero naturale r2-n è un quadrato
perfetto di base naturale opportuna s.
Dovendo essere r2-n=s2 0, si ha r n , dunque il valore minimo da fissare per r è r= n . (il
“tetto” di n , ossia il minimo intero  n ).
Per quanto riguarda il valore massimo di r, notiamo che al crescere di r, cresce il valore di s (se
esiste) perché r2-n=s2 con n costante, dunque cresce il corrispondente valore di a=r+s (se esiste)
nella coppia (a,b). Poiché a b, n=ab, in una fattorizzazione non banale di n (dispari) il valore
(teorico) minimo di b è b=3, in corrispondenza del quale il valore (teorico) massimo di a è a=n/3:
poichè r=(a+b)/2, si ottiene che il valore massimo (teorico) per r è [(n/3)+3]/2=(n+9)/6, dunque si
può limitare la ricerca di r a valori  (n+9)/6 (parte intera di (n+9)/6).
Dunque, l’algoritmo di fattorizzazione di Fermat si può implementare nel modo seguente:
- input n intero dispari >1
- per r= n ,  n  +1,……, (n+9)/6 si testa se r2-n è un quadrato perfetto di base s 0 e
in caso affermativo si esce con output “n=ab dove a=r+s, b=r-s”
- se nel ciclo precedente nessun test ha avuto esito positivo, si esce con output “non esistono
naturali a,b<n tali che n=ab, ossia n è primo,”
La complessità di tale algoritmo di Fermat è alta: il numero di valori r da testare è di ordine:
O((n+9)/6- n )=O(n)=O(2x) se x=L(n)
anche se ogni singolo test per verificare se r2-n è un quadrato perfetto si può effettuare con
l’algoritmo visto in una lezione precedente, di complessità polinomiale .
Notiamo anche, come già premesso, che il test di Fermat trova un fattore non banale di n in tempi
ragionevoli se n è prodotto di 2 divisori a,b abbastanza “vicini fra loro” perché in tale caso a,b
 n , dunque r=(a+b)/2 n , ossia il valore r che nel ciclo permette di trovare la fattorizzazione
di n è “vicino” a n , e dunque (partendo dal valore iniziale r =  n  ) tale valore viene trovato
relativamente “presto”.
Esempio.
Se l’input é n=6077,  n =78, (n+9)/6=1014, il ciclo si dovrà eseguire per r=78, 79,…., 1014 e
si ha:
r=78  r2-n =7 (non quadrato)
r=79  r2-n =164 (non quadrato)
r=80  r2-n =323 (non quadrato)
r=81  r2-n =484 =222
ottenendo la fattorizzazione n=ab dove a=r+s=81+22=103, b=r-s=81-22=59.
Algoritmo di fattorizzazione  di Pollard.
Premettiamo alcune considerazioni su un argomento di Calcolo delle Probabilità.
Siano n,m numeri naturali con 1<n<m, S un insieme finito di cardinalità m e sia data una
successione finita di n termini scelti in S (anche non distinti):
a1, a2, ……, an
in modo che gli ai siano scelti random in modo “uniforme” (dal punto di vista della probabilità) fra
gli elementi di S (nel senso che per ogni indice i, ogni elemento dell’insieme S ha la stessa
probabilità di essere scelto come elemento ai).
Vogliamo calcolare la probabilità che almeno 2 degli elementi della successione coincidano.
A tale scopo, calcoliamo dapprima la probabilità che tutti gli elementi della successione siano
distinti.
Fissato a1, la probabilità che a2 sia diverso da a1 è (m-1)/m; fissati a1,a2 distinti, la probabilità che a3
sia diverso da a1 e da a2 è (m-2)/m , quindi la probabilità che a1, a2, a3 siano tutti distinti è il
prodotto [(m-1)/m][(m-2)/m]=(1-1/m)(1-2/m)
Iterando il ragionamento si ottiene che la probabilità che a1, a2, ….., an siano tutti distinti è il
prodotto:
(1-1/m)(1-2/m)……(1-(n-1)/m).
Utilizzando lo sviluppo in serie ex=1+x+x2/2!+x3/3!+…, possiamo approssimare 1+x con la
funzione ex, di modo che ogni fattore del prodotto precedente è approssimato (ponendo x= -i/m con

n ( n -1)
2m
i=1,….,n-1) dalla funzione e . Dunque il prodotto è approssimato dalla funzione e
(tenendo
conto che 1+2+….+(n-1)=n(n-1)/2): per n “grande” possiamo approssimare n(n-1) con n2, di modo
che la probabilità che tutti gli elementi della successione siano distinti è approssimata dalla funzione
-i/m

n2
2m
e dunque la probabilità che almeno 2 degli elementi a1, a2, ….., an coincidano è (in modo
e
approssimato) la seguente funzione di n,m:
p(n,m)  1  e

n2
2m
Se allora fissiamo un valore di probabilità p con 0<p<1, il numero n degli elementi di una
successione per i quali sia p la probabilità che fra essi almeno 2 coincidano è approssimativamente:
1
)]
n  2m[log e (
1 p
In particolare per esempio se fissiamo una probabilità del 50% (p=0.5), si ottiene n  1,77 m ,
mentre se se fissiamo una probabilità del 90% (p=0.9), si ottiene n  2,14 m .
Dunque se scegliamo in successione in modo “random” elementi dell’insieme S:
a1, a2, a3, ………………..
il minimo indice n per cui l’elemento an coincide con almeno uno degli elementi che lo precedono
è, dal punto di vista probabilistico (con probabilità che si può rendere alta a piacere) di ordine
O( m )=O(m1/2).
Esempio. Un’applicazione di tale teoria é il cosiddetto “paradosso dei compleanni”: se sono scelte
random un numero n di persone con 1<n<365, la probabilità che almeno 2 fra esse compiano gli

n2
730
anni nello stesso giorno e mese dell’anno è  1  e ; inoltre, fissato un valore di probabilità p con
0<p<1, il numero n di persone (scelte random) per le quali è p la probabilità che fra esse almeno 2
1
)]
compiano gli anni nello stesso giorno e mese dell’anno è  730[log e (
1 p
(tutto questo supponendo che giorno e mese di nascita degli esseri umani siano distribuiti in modo
uniforme fra i 365 giorni dell’anno, il che non è vero in pratica).
Per esempio se la probabilità fissata è del 50% (p=0,5), n  730[log e 2]  23: scegliendo 23
persone in modo random, la probabilità che fra esse almeno 2 compiano gli anni nello stesso giorno
e mese dell’anno è  50% (abbastanza paradossale…..).
Scegliendo invece 50 persone in modo random, la probabilità che almeno 2 fra esse compiano gli
anni nello stesso giorno e mese dell’anno è addirittura  97%.
Introduciamo ora l’ Algoritmo di fattorizzazione  di Pollard.
Il metodo  di Pollard si basa sulle seguenti considerazioni.
Supponiamo di volere fattorizzare un numero intero n>1, cercando un divisore non banale di n (se
esiste, cioè se n non è primo).
Sappiamo che n ha certamente un divisore primo p n , e formalmente (pur non conoscendo p a
priori) consideriamo gli insiemi:
S={0,1,2,…,p-1}
T={0,1,2,…,n-1} S
Sia poi F: T  T una funzione che è “compatibile” con la congruenza modulo p, cioè soddisfa la
condizione:
F(xmodp)=F(x)modp per ogni xT
(vedremo in seguito scelte opportune per tale funzione F ) .
Fissato un elemento sT (seme), costruiamo una successione ai di elementi di T (con i=0,1,2,….)
ponendo induttivamente:
a0=s; ai=F(ai-1) per ogni i>0
(in pratica a partire dal seme s, si applica successivamente più volte F per ottenere i termini
seguenti).
In corrispondenza (utilizzando le riduzioni modulo p) possiamo costruire una successione bi di
elementi di S ponendo bi=aimodp .
Ora supponiamo che gli elementi di S siano distribuiti in modo uniforme (dal punto di vista
probabilistico) nella successione bi (cioè che per ogni i la probabilità che un elemento di S coincida
con bi sia uguale per tutti gli elementi): affinché tale ipotesi sia verificata, dovremo ovviamente
scegliere opportunamente la funzione F .
Per le considerazioni probabilistiche svolte in precedenza, il minimo indice k per cui bk coincide
con uno dei termini che lo precedono (cioè bj=bk per un opportuno j<k) è dal punto di vista
probabilistico di ordine O(S1/2)=O(p1/2).
Poichè bj+1=aj+1modp=F(aj)modp=F(ajmodp)=F(bj), e analogamente bk+1=F(bk), da bj=bk segue
bj+1=bk+1 . Per induzione si ottiene facilmente:
bj+m=bk+m
per ogni m 0 (*)
Se fissiamo un qualunque indice i j si ha allora, applicando la (*) con m=i-j):
bi=bj+(i-j)=bk+(i-j)=bi+(k-j)
Per induzione si ottiene facilmente:
bi =bi+t(k-j)
per ogni t 0 (fissato l’indice i j)
Comunque presi allora due indici i,r con i,r j, se ir (mod k-j) si ha bi=br (in pratica la successione
bi dall’indice j in poi diventa ciclica con “periodo” k-j, nel senso che dal termine di indice j in poi i
termini coincidono ogni k-j posizioni): infatti basta porre (se per esempio r i)
(r-i)=t(k-j) con t 0
e da quanto precede segue appunto bi =bi+t(k-j)=br .
Esempio:
se j=3, k=9, la successione diventa ciclica con periodo 6 dal termine di indice 3 in poi: infatti
dall’indice j=3 in poi, due qualunque termini della successione, i cui indici differiscano per un
multiplo di k-j=6 (cioè i cui indici siano congrui modulo 6), coincidono fra loro.
Rappresentando graficamente la situazione, si ottiene (per j=3, k=9):
b5=b11=b17=….
b4=b10=b16=….
b6=b12=b18=….
b3=b9=b15=….
b2
b1
b0
b8=b14=b20=….
b7=b13=b19=….
Notare la forma geometrica che richiama la struttura della lettera greca  (da cui il nome
dell’algoritmo).