Crittografia e teoria dei numeri - Appunti - Parte 1, Appunti di Teoria dei Numeri e Crittografia
Kikka84
Kikka84

Crittografia e teoria dei numeri - Appunti - Parte 1, Appunti di Teoria dei Numeri e Crittografia

27 pagine
16Numero di download
1000+Numero di visite
50%su 2 votiNumero di voti
Descrizione
Appunti di Serena Cicalà². Argomenti Trattati: teoria dei numeri,sistemi temporali per eseguire calcoli aritmetici,algoritmo di Euclide,somma,moltiplicazione,sottrazione
30 punti
Punti download necessari per scaricare
questo documento
Scarica il documento
Anteprima3 pagine / 27
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali
Questa è solo un'anteprima
3 pagine mostrate su 27 totali

Appunti per un corso di

Crittografia e Teoria dei Numeri

Docenti: Prof. Andrea Caranti e Prof. Willem de Graaf

A.A. 2004/2005

Realizzati da Serena Cicalò email: cicalo@science.unitn.it

Presentazione

In queste pagine ho riportato gli appunti delle lezioni del corso di Teoria dei Numeri e Crit- tografia che ho seguito nel terzo bimestre dell’anno accademico 2004 - 2005 presso l’Università di Trento. Le prime sei lezioni le ha tenute il Professor Andrea Caranti, le restanti il Professor Willem de Graaf. Per agevolare la lettura di queste note le soluzioni degli esercizi assegnati a lezione sono riportati alla fine. Chiunque trovasse errori di ogni tipo può segnalarli all’indirizzo email cicalo@science.unitn.it facendo cosa molto gradita.

Buona lettura Serena

Crittografia e Teoria dei Numeri 1

Lezione 1 22 febbraio 2005 - Prof. Andrea Caranti

Alcuni argomenti di Teoria dei Numeri

Un sistema crittografico come l’RSA è basato sul fatto che ci sono alcune funzioni o mappe f che sono invertibili, dunque esiste un’inversa f -1, ma tali che f è “facile” da calcolare, mentre f -1 è “difficile” da calcolare.

- Facile vuol dire che f si può calcolare in un tempo ragionevole. - Difficile vuol dire che f -1 può essere calcolata solo usando un tempo che non è utile ai fini pratici.

I concetti di facile e difficile sono la prima cosa che preciseremo in questo corso. In realtà noi sceglieremo dei metodi per calcolare f o f -1 e saremo in grado di dare una stima del tempo richiesto per eseguire questo metodo. Niente vieta che esista un metodo migliore che richieda meno tempo.

Stime temporali per eseguire calcoli aritmetici

Per esempio, consideriamo il problema di calcolare il MCD di due numeri interi a e b. La funzione che vogliamo calcolare è (a, b). Quanto “tempo” ci vuole per calcolarla? Che metodo scelgo per calcolare il MCD?

Primo metodo: fattorizziamo i due numeri a e b e poi prendiamo i fattori comuni1 con il minimo esponente. Per esempio se a = 12 e b = 30 si ha

a = 22 · 31 · 50; b = 21 · 31 · 51

e quindi (a, b) = 21 · 31 · 50 = 6.

Ho ricondotto il calcolo del MCD al problema di fattorizzare un numero. Di nuovo devo scegliere un metodo per fattorizzare i numeri, vale a dire per scriverli come prodotto di numeri primi. Uso il metodo delle divisioni di prova. Provo a dividere a per 2, 3, 4, 5, . . . alla ricerca di un divisore2 e se lo trovo ripeto con quel che resta. Nel caso peggiore quante divisioni di prova sono costretto a fare? Per esempio, se il numero a è primo, dopo quante divisioni me ne accorgo?

Se a non è primo allora esistono due numeri interi positivi b, c > 1 tali che a = b · c. Affermo che uno dei due è 6

√ a.

1Posso anche non dire comuni perché posso pensare i fattori non comuni come aventi esponente 0. 2Dividere per 4 non è molto intelligiente!

Crittografia e Teoria dei Numeri 2

Dimostrazione. Cerchiamo di mostrarlo senza ricorrere all’assurdo. Se b >

√ a allora

c = a

b <

a√ a = √ a,

quindi se uno dei due fattori è > √ a l’altro è necessariamente <

√ a. 

Con questo metodo se a è primo me ne accorgo solo dopo √ a divisioni di prova.

Calcolare il MCD con questo metodo potrebbe richiedere, nel caso peggiore3 un numero di divisioni con resto pari a

√ a.

Algoritmo di Euclide Secondo metodo. Uso l’algoritmo di Euclide. Divido a per b con resto

a = bq1 + r1 0 6 r1 < b

divido poi b per r1 b = r1q2 + r2 0 6 r2 < r1 < b

divido r1 per r2 r1 = r2q3 + r3 0 6 r3 < r2 < r1 < b

e cos̀ı via. In generale divido ri per ri+1 e ottengo

ri = ri+1qi+2 + ri+2 0 6 ri+2 < ri+1 < . . . < r3 < r2 < r1 < b.

Dato che i resti continuano a diminuire a un certo punto si avrà rk = 0 per un certo k. A questo punto si vede che rk−1 6= 0 è il MCD fra a e b.

Per esempio se a = 30 e b = 12 si ha

30 = 12 · 2 + 6 12 = 6 · 2 + 0

quindi, poiché r2 = 0 il MCD è r1 = 6.

Dimostrazione. Sarà sufficiente dimostrare che (a, b) = (b, r1). Infatti, se si dimostra questo poi si avrà (a, b) = (b, r1) = (r1, r2) = . . . = (rk−1, rk) ma rk = 0 e (rk−1, 0) è il più grande fra i numeri d che dividono sia rk−1 che 0(4), quindi (rk−1, 0) è il più grande fra i divisori di rk−1 e cioè (rk−1, 0) = rk−1. Mi resta da dimostrare che se a = bq1 + r1 allora

(a, b) = (b, r1).

Basta far vedere che i divisori comuni di a e b sono gli stessi dei divisore comuni di b e r1. Se d è un divisore comune di b e r1 allora d | b e d | r1, dunque esistono due interi s e t tali che b = ds e r1 = dt, dunque

a = bq1 + r1 = dsq1 + dt = d(sq1 + t)

cioè d | a e poiché d | b segue che d è un divisore comune di a e di b. Con lo stesso ragionamento e ponendo

r1 = a− bq1 si dimostra il viceversa. 

3Quando a è primo. 4Questa condizione è vuota perché tutti i numeri dividono 0.

Crittografia e Teoria dei Numeri 3

Quante divisioni ci vogliono qui? Vado a prendere il resto ri+2. Avremo

ri = ri+1qi+2 + ri+2 ri+1 > ri+2 e qi+2 > 1

quindi ri > ri+2 · 1 + ri+2 = 2ri+2

vale a dire ri+2 <

1 2 ri.

Usando l’algoritmo di Euclide ogni due passi il resto si dimezza come minimo. Quanti passi saranno sufficienti perché l’algoritmo termini? Avremo

b = r0 > 2r2 > 22r4 > 23r6 > . . . > 2sr2s quindi r2s < b

2s .

Quando 2s > b abbiamo 0 6 r2s < 1 quindi r2s = 0. Quindi (se prendo il logaritmo in base 2)

2s > b ⇐⇒ s > log2(b) ⇐⇒ 2s > 2 log2(b),

quindi al più sono richiesti 2 log2(b) divisioni.

A questo punto confrontiamo i risultati di questi due algoritmi. Per poter confrontare i risultati supponiamo che il più grande tra a e b sia n(5). Dunque il numero di divisioni col resto necessari sono:

- primo metodo: √ n;

- secondo metodo: 2 log2(n).

Questo è un esempio di confronto tra metodo facile e metodo difficile.

Ci sono numeri n per cui è molto facile usare il secondo metodo e molto difficile usare il primo6.

Se n = 21000 usando la stima molto comoda 210 = 1024 ∼= 103 si ha n = 21000 ∼= 10300. Allora √ n ∼= 10150

che è molto grande, può richiedere ore, giorni, se non è impossibile. Invece

2 log2(n) = 2000

e questo è molto più piccolo, è alla portata di qualsiasi calcolatore. ♠

Per valutare il tempo richiesto da un algoritmo (“metodo”) occorre definire un’unità di misura. Questa unità di misura corrisponderà al tempo effettivo che un calcolatore impiega per fare una certa “operazione elementare”. Quindi la valutazione del tempo che ci vuole a eseguire un algoritmo sarà fatto in termini del numero di queste operazioni elementari che servono a eseguire l’algoritmo.

Il tempo che serve per eseguire un’operazione elementare è una variabile tecnologica7.

5Come ordine di grandezza. 6Ci sono numeri per cui entrambi sono semplici e alcuni per cui entrambi sono difficili, ma ci sono numeri

intermedi per cui capita quanto detto. 7Cioè dipende dalla tecnologia.

Crittografia e Teoria dei Numeri 4

Operazione elementare8

Input : due cifre più un eventuale riporto;

Output : una cifra più un eventuale riporto.

Per esempio per eseguire l’operazione

1 3 6 + 2 9 7 = 4 3 3

ci vogliono 3 operazioni elementari. ♠

Quante operazioni elementari ci vogliono per sommare due numeri di k cifre? Sono k. Tutto bene! Ma i calcolatori operano in base 2.

Noi siamo abituati a scrivere i numeri in base 10. Per esempio

297 = 2 · 102 + 9 · 10 + 7.

I numeri si possono scrivere rispetto a qualsiasi base intera b > 1. Ogni numero intero positivo si può scrivere nella forma

akb k + ak−1bk−1 + . . .+ a1b+ a0

con b > 1 fissato. Gli ai, 0 6 ai < b, sono le cifre b-arie. Il numero si scrive (akak−1 . . . , a1a0)b.

Quindi, in base 2 il numero intero (akak−1 . . . a1a0)2, con 0 6 ai < 2, si scrive nella forma

ak2k + ak−12k−1 + . . .+ a12 + a0.

Per esempio (1010)2 = 1 · 23 + 1 · 21 = 10.

Si ha che (10)2 = 1 · 2 + 0 = 2,

e questo vale in generale, cioè, in base b si ha

(10)b = b.

In base esadecimale le cifre sono

0 1 2 3 4 5 6 7 8 9 A B C D E F

e quindi, per esempio, si ha 15 = (F )16,

ma queste cose le riprenderemo. 8Definizione provvisoria

Crittografia e Teoria dei Numeri 5

Lezione 2 24 febbraio 2005 - Prof. Andrea Caranti

Nella lezione scorsa abbiamo mostrato che nell’algoritmo di Euclide si ha

ri+2 6 1 2 ri.

Voglio farvi un commento sul perché succede questo.

La prima volta che compare ri è nella relazione

ri−2 = ri−1qi + ri,

e poi si ha

ri−1 = riqi+1 + ri+1 e ri = ri+1qi+2 + ri+2 con ri+2 < ri+1 < ri.

Perché dico che ogni due passaggi il resto si dimezza?

Perché su un singolo passaggio non posso dire niente di meglio.

Noi abbiamo ri+1 < ri, vale a dire ri+1 6 ri−1; mettendo assieme anche l’altro passaggio si ha ri+2 6 ri− 2. Abbiamo però visto la volta scorsa che vale qualcosa di meglio, cioè ri+1 6 12ri. Quello che succede è che la disuguaglianza ri+1 6 ri − 1 non si può migliorare. Per vedere questo si può fare un esempio.

Se ri−1 = 299 e ri = 100 si ha

299︸︷︷︸ ri−1

= 100︸︷︷︸ ri

· 2︸︷︷︸ qi+1

+ 99︸︷︷︸ ri+1

quindi ri+1 = 99 = ri − 1.

La disuguaglianza ri+1 6 ri − 1 è quindi la migliore possibile. Se andiamo avanti si ha

100︸︷︷︸ ri−1

= 99︸︷︷︸ ri

· 1︸︷︷︸ qi+1

+ 1︸︷︷︸ ri+1

,

e mentre nel primo passaggio non poteva succedere molto nel secondo il resto è diventato addirittura 1.

Esistono anche esempi più semplici come nel caso di ri−1 = 7, ri = 4. ♠

Vi do una dimostrazione alternativa.

Dimostrazione. Se si ha già ri+1 6 12ri sono a posto perché ri+2 < ri+1 6 1 2ri. Se invece il

resto è più grande (cioè il resto non è calato tanto in una sola divisione), quindi ri+1 > 12ri, diventa

ri = ri+1 · 1︸︷︷︸ qi+2

+(ri − ri+1)︸ ︷︷ ︸ ri+2

.

Crittografia e Teoria dei Numeri 6

Verifichiamo che questa cosa sia corretta. Si ha

0 6 ri − ri+1 < ri − 1 2 ri =

1 2 ri < ri+1

quindi −ri+1 < −12ri e di conseguenza ri+2 = ri − ri+1 < 1 2ri. 

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

Riprendiamo ora dal punto in cui avevamo interrotto la volta scorsa. Avevamo cominciato a definire l’unità di misura della complessità di un algoritmo. Vogliamo mostrare che dato un intero b > 1 fissato, ogni numero intero a si scrive in modo unico in forma b-aria nella forma

a = dk−1bk−1 + dk−2bk−2 + . . .+ d1b+ d0

dove 0 6 di < b. La sua scrittura b-aria è (dk−1dk−2 . . . d1d0)b.

Il caso che conosciamo bene è quello decimale, quindi b = 10, in cui, per esempio, per il numero a = 1952 si ha

1952 = 1 · 103 + 9 · 102 + 5 · 10 + 2.

Per pignoleria bisognerebbe scrivere (1952)10.

Si ha che 1010 è “mille e dieci” in base 10 ma si ha

(1010)2 = 1 · 23 + 0 · 22 + 1 · 2 + 0 = (10)10

e (1010)3 = 1 · 33 + 0 · 32 + 1 · 3 + 0 = (30)10.

Diamo un algoritmo per scrivere un numero intero in base b. E’ un algoritmo ricorsivo. Poniamo:

- a0 = a;

- divido a0 per b, ottengo un resto d0 e un quoziente che chiamo a1 che è dk−1bk−2 + . . .+ d2b + d1, quindi a si può scrivere come a = (dk−1bk−2 + . . . + d2b + d1)b + d0(9). Si ha che d0 è proprio il resto perché 0 6 d0 < b.

- Ripeto ricorsivamente.

Quindi, dato che a0 diviso per b dà resto d0 ho che

a0 ≡ d0 (mod b) 9Stiamo implicitamente supponendo che la cosa si possa già scrivere in questo modo.

Crittografia e Teoria dei Numeri 7

vale a dire b divide a0 − d0. Definisco allora l’intero

a1 = a0 − d0

b

e ripeto il ragionamento. In questo modo trovo una cifra alla volta partendo da quella meno significativa (cioè quella più a destra).

Vediamo come funziona l’algoritmo in pratica. Può essere comodo usare il seguente schema

a = a0 d0 ← resto della divisione per b quoziente → a1 d1

a2 ...

...

Consideriamo 10 = (10)10. Nella tabella, sulla sinistra i numeri sono in base 10, sulla destra ci saranno le cifre binarie.

a0 = 10 0 ← d0 divido 10 per 2: il quoziente è 5 e il resto è 0; a1 = 5 1 ← d1 divido 5 per 2: il quoziente è 2 e il resto è 1; a2 = 2 0 ← d2 divido 2 per 2: il quoziente è 1 e il resto è 0. a3 = 1 1 ← d3

quindi (10)10 = (1010)2. Riporto i numeri dal basso verso l’alto perché la cifra più significativa la ottengo per ultima.

Vediamo un altro esempio. Per esempio (15)10. Si ha

15 1 7 1 3 1 1 1

quindi (15)10 = (1111)2. ♠

Questi argomenti si possono usare anche per le parti decimali. Si può far vedere che fissato un qualsiasi intero b > 1, allora ogni numero reale si può scrivere nella forma

dk−1b k−1 + . . .+ d1b+ d0 + d−1b-1 + d−2b−2 + d−3b−3 + . . .

In questo caso la rappresentazione non è unica poiché vale sempre la relazione

(1)b = (0, (b− 1)(b− 1)(b− 1) . . .)b,

cos̀ı come accade nel caso ben noto della base 10 in cui 1 = 0, 999 . . .. Per esempio il numero 0, 1237 si può anche scrivere come 0, 1236999 . . .. Analogamente, in base 2 si ha

(1)2 = (0, 111 . . .)2 1 = 1 2 +

1 4 +

1 8 + . . .

Crittografia e Teoria dei Numeri 8

e in base 3 (1)3 = (0, 222 . . .)2 1 =

1 3 +

1 9 +

1 27

+ . . .

Proviamo a scrivere π = (3, 1415926 . . .)10 in base 2, cioè nella forma

π = (d1d0, d−1d−2 . . .)2 = d1 · 2 + d0 + d−1 2

+ d−2 4

+ . . . .

Poiché (3)10 = (11)2 la parte intera di π in base 2 sarà appunto 11 per cui si avrà π = (11, . . .)2. Detto questo vogliamo scrivere la parte decimale 0, 1415926 . . . in base 2, vale a dire nella forma d−1 2 +

d−2 4 +

d−3 8 . . .. A tal scopo moltiplichiamo per 2 e si avrà

0, 2831852 . . . = d−1 + d−2 2

+ d−3 4

+ . . . .

Chiaramente il termine d−1 è un numero intero e sarà d−1 = 0, mentre si ha d−2 2 +

d−3 4 +. . . < 1,

infatti, ogni d−i < 2, per ogni i > 2 quindi si ha al massimo d−i = 1 e quindi, al massimo sarebbe d−22 +

d−3 4 + . . . =

1 2 +

1 4 + . . ., ma se la scrittura di π avesse tutti i d−i = 1 si avrebbe

π = (11, d−1111 . . .)2 = (11, (d−1 + 1))2

cioè si avrebbe 11(d−1 + 1)

2 ( 10 )

e quindi π sarebbe razionale, e sappiamo bene che questo non è vero. Quindi non si può avere d−i = 1 per ogni i > 2 e quindi

d−2 2 +

d−3 4 + . . . < 1 come volevasi dimostrare.

Quindi, abbiamo ricavato che π = (11, 0 . . .)2.

A questo punto ripetendo il ragionamento, cioè moltiplicando per 2 le parti decimali, e ripetendo le considerazioni fatte prima, cioè concludendo che d−i2 +

d−i−1 4 +

d−i−2 8 + . . . < 1

per ogni i > 1, si ha

0, 1415926 . . . = d−12 + d−2 4 +

d−3 8 +

d−4 16 + . . .

2 · 0, 1415926 . . . = 0, 2831852 . . . = d−1 + d−22 + d−3 4 +

d−4 8 + . . . =⇒ d−1 = 0

2 · 0, 2831852 . . . = 0, 5663704 . . . = d−2 + d−32 + d−4 4 +

d−5 8 + . . . =⇒ d−2 = 0

2 · 0, 5663704 . . . = 1, 1327408 . . . = d−3 + d−42 + d−5 4 +

d−6 8 + . . . =⇒ d−3 = 1

2 · 0, 1327408 . . . = 0, 2654816 . . . = d−4 + d−52 + d−6 4 +

d−7 8 + . . . =⇒ d−4 = 0

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Si noti che moltiplicando per 2 le parti decimali si avrà come parte intera al più 1 perché il massimo che si può ottenere è 9 + 9 = 18(11). ♠

Crittografia e Teoria dei Numeri 9

Si definisce bit operation l’unità di misura per la complessità degli algoritmi. E’ l’operazione che ha per Input 2 bit (cifre binarie, cioè 0 e 1) da sommare più un eventuale riporto, e come Output la somma dei precedenti nella forma di un bit come risultato e un bit come riporto.

La somma Vogliamo vedere quante bit operations sono necessari per fare la somma di due numeri di k cifre binarie.

Prendiamo due numeri scritti in base 2:

11 11 10 11 10 11 01 + 1 0 1 1 1 0 1

1 1 0 0 1 0 0 0

Si vede quindi che per sommare due numeri che hanno k cifre binare, dunque “numeri di k bit” (o anche “numeri lunghi k”) devo fare k bit operations. ♠

Voglio stimare quanto tempo ci vuole a fare la somma di due numeri. Riesco a stimare non in termini dei numeri stessi ma dei bit che possiedono.

Che relazione c’è fra il numero k di cifre di un numero e il numero stesso?

Per esempio (11011)2 è un numero di 5 bit.

In generale, un numero di k-cifre b-arie è un numero della forma

n = dk−1bk−1 + dk−2bk−2 + . . .+ d1b+ d0 = (dk−1dk−2 . . . d1d0)b

con dk−1 6= 0. Questo da una parte è > di dk−1bk−1 e quindi > di bk−1(12). D’altra parte

n = dk−1bk−1 + dk−2bk−2 + . . .+ d1b+ d0 6 (b− 1)bk−1 + (b− 1)bk−2 + . . .+ (b− 1)b+ b− 1 =

= bk − bk−1 + bk−1 − bk−2 + . . . b2 − b+ b− 1 = bk − 1.

Quindi bk−1 6 n < bk;

passando ai logaritmi trovo k − 1 6 logb(n) < k,

e usando una delle funzioni parte intera, la funzione “floor”(13) si ha

k − 1 = blogb(n)c 12Perché dk−1 > 1. 13Se α è reale floor di α è definito come

bαc = max{l ∈ Z | l 6 α}

mentre il ceiling è definito come dαe = min{l ∈ Z | l > α}.

Per esempio bπc = 3, e dπe = 4.

Crittografia e Teoria dei Numeri 10

quindi k = blogb(n)c+ 1.

Scopriremo che dell’1 che compare in quest’ultima espressione fra un po’ ce ne potremo liber- are, cioè ne potremo fare a meno.

La somma di due numeri grandi circa come n richiede al più log2(n) + 1(14) operazioni bit. Posso anche togliere il floor perché al massimo log2(n) è un po’ più grande. Il logaritmo vuol dire il numero di cifre.

La moltiplicazione Facciamo un passo più coraggioso e passiamo alla moltiplicazione. Quante operazioni bit ci vogliono per fare la moltiplicazione di due numeri scritti in base 2 che abbiano rispettivamente k ed l bit?

Bisogna sempre specificare che metodo usare. Usiamo il metodo della scuola.

Supponiamo di fare, in base 2, 7× 3 = 21. Avremo

1 1 1 × 1 1

11 1 1 11 1 1

1 0 1 0 1

Si considera trascurabile in particolare il tempo necessario per verificare se un bit x è 0 o 1. Quando moltiplico un singolo bit per un numero a ci sono infatti due possibilità:

- x = 0: in tal caso il risultato è zero e il costo di questa operazione è 0.

- x = 1: in tal caso devo ricopiare a. Anche questo si valuta a costo 0.

Nel secondo passaggio mi sposto ed è come se stessi aggiungendo uno zero sulla destra. Si assume che abbia costo zero la moltiplicazione per 2, cioè lo shift che ci porta, per esempio, dal numero 111 al numero 1110.

Nell’esempio, a questo punto, mi rimane da fare una somma di due numeri di 3 e 4 bit. Più in generale supponiamo di avere svolto la moltiplicazione

1 1 0 1 0 1 × 1 1 0 1 =

1 1 0 1 0 1 1 1 0 1 0 1 0

1 1 0 1 0 1

Quante somme devo fare al massimo?

Supponiamo di non aver tolto la riga di zeri. Posso riempire con degli zeri e ho al più k+ l−1 cifre. Vedremo queste cose più in dettaglio la prossima volta.

14Numero di cifre binarie di n.

Crittografia e Teoria dei Numeri 11

Lezione 3 25 febbraio 2005 - Prof. Andrea Caranti

La volta scorsa stavamo vedendo qual è il numero di bit operation necessarie per fare il prodotto di due numeri con il metodo della scuola. Non si può dare una complessità senza specificare il metodo.

Prendiamo un numero di k bit e uno di l bit con k > l. Le operazioni di

- ispezione di un bit (chiedersi se è 0 o 1);

- copiare;

- shiftare;

sono considerate trascurabili rispetto alle bit operations. Quanti bit avrà il risultato?

Questo è variabile, infatti, per esempio, 1 × 1 = 1 mentre 7 × 3 = 21, quindi nel primo caso ne ha 1 e nel secondo 2.

Dire che a ha k bit e b ha l bit, significa

2k−1 6 a < 2k − 1 e 2l−1 6 b < 2l − 1

quindi 2k+l−2︸ ︷︷ ︸ k+l−1 bit

6 a · b < 2k+l − 2k − 2l + 1︸ ︷︷ ︸ k+l bit(15)

.

La parte di compilazione della tabella è considerata gratuita. Dopo di che devo fare al più l somme di numeri che al più hanno k + l bit. Le somme di due numeri di s bit richiede s bit operations, dunque in totale (l − 1)(k + l) somme. Poiché k > l, si ha

(l − 1)(k + l) 6 l(k + l) 6 2kl 6 2k2.

Dobbiamo introdurre una notazione importante per fare le stime dei bit che servono per fare le operazioni. E’ basata sull’idea che in un’espressione del tipo 2k2 il fattore costante davanti non ci interessa.

Siano f e g due funzioni definite sugli interi positivi che assumano valori anche reali ma co- munque positivi16. Si scrive che f = O(g), “O grande”, se esistono due costanti B e C tali che per n > B si ha f(n) 6 Cg(n).

O grande è scritta come se fosse una funzione ma in realtà è una relazione.

16Per esempio f(n) = 2n2, f(n) = 2 log2(n), o f(n) = √ n.

Crittografia e Teoria dei Numeri 12

Se prendiamo le funzioni f(k) = 2k2 e g(k) = k2, banalmente si ha f = O(g) perché f(k) = 2k2 = 2g(k). ♠

La moltiplicazione di due numeri di k bit si può fare con O(k2) bit operations. Cioè si può fare con un certo numero f(k) di operazioni bit tali che f(k) 6 Ck2 per k > B.

Sapere che le operazioni sono O(k2) mi dice comunque che se passo da numeri a k bit a numeri a 2k bit allora avrò bisogno di 4 volte le operazioni bit. Il numero di bit viene spesso chiamato lunghezza dell’input.

La notazione O grande ha anche il vantaggio di semplificare certe scritture. Si ha per esempio

n2 + n = O(n2)

e questo è logico perché n2 + n 6 2n2 = O(n2).

Si ha anche, ad esempio n2+7n = O(n2), perché n2+7n = n(n+7) 6 2n2 quando n+7 6 2n, vale a dire per n > 7. Se ho in generale che

f(n) = ns + asns−1 + . . .+ a1n+ a0

allora posso dire che f = O(ns),

infatti, come sapete dall’analisi

f(n) ns

= 1 + as−1 n

+ . . . a1 ns−1

+ a0 ns

e per n→∞ si ha f(n)ns → 1. Se prendiamo ε = 1 esiste B tale che per n > B si ha

f(n) ns

6 1 + ε = 2

e quindi f(n) 6 2ns = O(ns).

Quindi, la notazione O grande semplifica molto le cose perché di un polinomio prende solo il termine dominante.

Abbiamo quindi che bn2 + an = O(n2).

Se ho un’operazione che richiede b moltiplicazioni e a somme con questa notazione considero solo le moltiplicazioni. Dico meglio! Nella notazione O grande quando un algoritmo richiede sia prodotti che somme posso trascurare queste ultime.

Vi faccio vedere un esempio in cui si adotta questa strategia. E’ un metodo di moltiplicazione migliore di quello elementare.

Crittografia e Teoria dei Numeri 13

Voglio moltiplicare due interi a e b lunghi k (cioè che abbiano k bit). Suppongo che k si pari, cioè che k = 2l(17). Divido sia a che b per 2l =

√ 2k

a = a22l + a1 0 6 a1 < 2l

b = b22l + b1 0 6 b1 < 2l.

Dato che a e b sono al più 2k allora a2 e b2 sono al più 2l, quindi 0 6 ai, bi < 2l, i = 1, 2. Il trucco è di fare il prodotto in questo modo

ab = a2b22k + (a1b2 + a2b1)2l + a1b1.

Dato che mi interessa un O grande del risultato trascuro le somme e conto i prodotti. Quanti prodotti ci sono qui?

Ci sono quattro prodotti di interi a l bit dunque in tutto 4 · 2l2 bit operations, quindi

4 · 2l2 = 4 · 2 ( k

2

)2 = 2k2.

Questo è esattamente il numero di bit operations che serve per moltiplicare a e b.

Apparentemente non c’è guadagno.

In realtà il guadagno c’è se uso un’altra strategia. Calcolo prima a1 + a2 e b1 + b2 (di cui trascuro il contributo), poi calcolo i seguenti prodotti

a1b1, a2b2, (a1 + a2)(b1 + b2).

Infine calcolo l’ulteriore somma (che in realtà è una differenza)

(a1 + a2)(b1 + b2)− a1b1 − a2b2

costituita da elementi già calcolati. Quello che rimane è

a1b2 + a2b1

quindi con tre prodotti e alcune somme ho calcolato

a1b1, a2b2, a1b2 + a2b1

vale a dire ab.

Vediamo se è utile. Se faccio direttamente il prodotto ab ho 2k2 bit operations, cos̀ı (contando solo il prodotti, cioè sarà un O grande) ho 3 prodotti di numeri a l bit

3 · 2l2 = 3 · 2 ( k

2

)2 =

3 4 (2k2).

17Se non è pari basta aggiungere uno zero a sinistra e non cambia niente, sto dicendo numeri che siano al più lunghi k.

Crittografia e Teoria dei Numeri 14

Apparentemente abbiamo un miglioramento, infatti abbiamo solo 34 delle operazioni bit prece- denti, ma il guaio è che, siccome sto trascurando le somme, alla fine devo usare la notazione O grande (perché è quella che mi permette di buttare le somme), quindi

3 4 (2k2) = O(k2).

Si può sfruttare meglio. Supponiamo che k sia una potenza di 2, k = 2s. Se faccio il prodotto direttamente, questo richiede

2k2 = 2 · 22s = 4 · 2(2s−1)2

operazioni bit. Col trucco appena visto mi riduco a tre prodotti di numeri a k2 = 2

s−1 bit. Il numero di operazioni bit è

3 · 2 ( k

2

)2 = 3 · 2(2s−1)2.

Ora 2 · (2s−1)2 è il numero di operazioni bit per fare il prodotto di due numeri a k2 = 2 s−1 bit.

Posso ripetere il ragionamento. Ognuno dei prodotti fra numeri a k2 = 2

s−1 bit lo posso ridurre a tre prodotti di numeri a k 4 = 2

s−2 bit, quindi mi ritroverò

3 ( 3 · 2(2s−2)2

) = 32 · 2

( k

4

)2 = 32 · 2

( k

22

)2 .

Ripeto: ogni volta passo da k 2i

a k 2i+1

e da 3i a 3i+1.

A un certo punto arrivo a 3s ·2 ( k 2s

)2 = 2·3s. Vediamo se ho un miglioramento. Con s = log2(k)

si ha 3s = 2log2(3)s = 2log2(3) log2(k) =

( 2log2(k)

)log2(3) = klog2(3).

Il vantaggio è che abbiamo fatto vedere che il prodotto di due numeri di k bit si può fare con un numero di operazioni bit pari a O(klog2(3)) e questo è un miglioramento perché log2(3) ∼= 1, 58 < 2. Ed è un miglioramento sostanziale perché, come ben sapete,

lim k→∞

klog2(3)

k2 = 0.

Questa cosa va bene quando k è relativamente grande (infatti abbiamo trascurato delle cose in k).

La migliore stima attuale è O(k log2(k) log2(log2(k)))

e questo è meno di O(k1+ε) per ogni ε > 0. Tutto dipende dal fatto che, per ogni fissato ε > 0 si ha

lim k→∞

log2(k) kε

= 0.

Vedere nelle note anche la moltiplicazione alla Montgomery.

Crittografia e Teoria dei Numeri 15

Completiamo il discorso sulla notazione O grande. Se esiste, finito, il

lim n→∞

f(n) g(n)

allora f = O(g).

Abbiamo detto che f = O(g) vuol dire che esistono B e C tali che per n > B si ha f(n) 6 Cg(n), vale a dire f(n)g(n) 6 C. Dunque esiste finito lim sup

n→∞

f(n) g(n) .

Ricordo che se h(n) > 0 è una successione posso considerare

si = sup{h(n) | n > i}

che potrebbe anche essere infinito, e si ha si+1 6 si. Se si ha almeno un valore finito allora ha limite perché è una successione decrescente che è limitata inferiormente da 0. Esiste questo limite e si ha

lim i→∞

si = lim i→∞

sup{h(n) | n > i} = lim sup n→∞

h(n).

Si può vedere anche il viceversa, e cioè che f = O(g) se e solo se esiste finito lim sup n→∞

f(n) g(n) (

18).

Più in generale, se f e g sono funzioni di t variabili intere positive a valori reali positivi, si dice, del tutto in analogia con quanto visto, che f = O(g) se esistono B e C tali che per x1, . . . , xt > B si ha che

f(x1, . . . , xt) 6 Cg(x1, . . . , xt).

Un algoritmo che opera su interi n1, n2, . . . , nt che abbiano rispettivamente k1, k2, . . . , kt bit è detto a tempo polinomiale se può essere eseguito con un numero di operazioni bit pari a O(kd11 k

d2 2 · · · k

dt t ) per opportuni interi d1, d2, . . . , dt > 0.

E’ la stessa cosa di

O(kd11 k d2 2 · · · k

dt t ) = O(log2(n1)

d1 log2(n2) d2 · · · log2(nt)dt).

Questi sono gli algoritmi “giusti”, quelli che si possono eseguire in un tempo ragionevole.

Vediamo ora un’applicazione.

Le formule “chiuse” Forse la più celebre formula chiusa è

1 + 2 + 3 + . . .+ n = n(n+ 1)

2 dovuta a Gauss19. Come mostrato da Gauss, questa è facilmente dimostrabile considerando il fatto che si ha

1 + 2 + . . . + n n + n− 1 + . . . + 1

(n+ 1) + (n+ 1) + . . . + (n+ 1) = n(n+ 1) =⇒ 1 + 2 + . . .+ n = n(n+ 1)

2 .

18La verifica è lasciata per esercizio 19Carl Friedrich Gauss, uno dei più grandi matematici della storia, fu un enfant prodige. Pare che all’età di

otto anni il maestro, per tenerlo occupato per un po’, gli avesse assegnato il compito di trovare la somma dei numeri da 1 a 100. Il maestro non aveva ancora finito di spiegare il problema, che Gauss diede la soluzione: 5050, senza eseguire alcun calcolo. Gauss aveva osservato che se si associano i numeri equidistanti dagli estremi si ottiene sempre 101; poiché le coppie sono ovviamente in numero di 50, la somma è, banalmente, 5050, un calcolo facile da fare a mente!

Crittografia e Teoria dei Numeri 16

Perché la formula chiusa n(n+1)2 è superiore a quella 1 + 2 + . . .+ n che consiste nel sommare tutti i termini?

Quanti bit ci vogliono per calcolare n(n+1)2 ?

Col metodo banale questo richiede grosso modo O(log2(n)2) operazioni bit (l’operazione per 2 non costa niente, n(n+ 1) è pari quindi basta togliere l’ultimo zero).

Quante operazioni bit ci vogliono per fare 1 + 2 + . . .+ n?

Esercizio 3.1. Stimate, usando la formula, quanto è la somma dopo aver sommato n2 termini

1 + 2 + . . .+ n

2 .

Gli altri non possono che essere più lunghi.

Crittografia e Teoria dei Numeri 17

Lezione 4 1 marzo 2005 - Prof. Andrea Caranti

Ci restano da studiare due operazioni fondamentali: la sottrazione e la divisione col resto.

La sottrazione La sottrazione richiede un tempo che in realtà sarebbe superiore a quello dell’addizione ma che comunque ha lo stesso O grande. Questo è O(k) se k è il numero di bit dei numeri coinvolti.

Se faccio una differenza c’è il solito problema del prendere in prestito. Per esempio

0 6 1 61 6 0 1 6 0 0 6 1 1 6 0 10 − 1 1 1 1 =

1 0 1 0 0

In realtà, per determinare ogni bit della differenza basta fare la somma dei due bit coinvolti tranne che può essere necessario “prendere in prestito” dalle cifre precedenti. Cioè

1 − 1 = 0

1 − 0 = 1

0 − 0 = 0

. . . 0 − 1 = 1

cos̀ı come (dimenticando i riporti) si ha

1 + 1 = 0 (più riporto) 1 + 0 = 1 0 + 0 = 0 0 + 1 = 1.

Quindi è proprio come se stessi facendo la somma senza considerare i riporti.

Ci sarebbe da valutare quanto ci costa prendere in prestito ma questo lo lascio come esercizio.

Ora, presi due numeri a e b voglio fare a− b. Cerco di ridurmi solo a somme tranne qualche piccola differenza.

Il trucco è porre a− b = a+ (2s − b)− 2s.

Cosa vuol dire fare 2s − b? Sto supponendo a > b > 0 e scelgo 2s > b (poi vedo di quando > di b lo voglio scegliere).

2s è una cosa del tipo 100 . . . 0 quindi posso porre 2s − b = [(2s − 1)− b] + 1 dove 2s − 1 sarà della forma 11 . . . 1. Per esempio se b = 110101 pongo 2s = 1000000 e quindi fare (2s − 1)− b sarà come fare

1 1 1 1 1 1 − 1 1 0 1 0 1 = 0 0 1 0 1 0

Crittografia e Teoria dei Numeri 18

e il risultato si ottiene prendendo b e invertendo i bit, cioè considerando b e mettendo dove c’è 1 metto 0 e dove c’è 0 metto 1, cioè faccio il complemento a 1, ottengo (2s − 1)− b. Questo sicuramente non costa più di una operazione bit.

Ora bisognerebbe riaggiungere 1 per ottenere 2s − b. Aggiungere 1 a un numero c significa guardare la coda di 1 di c, trasformare gli 1 in 0 fino ad arrivare al primo 0 che viene trasformato in 1 e a questo punto ci si ferma. Per esempio, se c = 100100111111 allora c+ 1 = 100101000000.

Poi faccio la somma a+ (2s − b).

Alla fine bisogna togliere 2s ma se ho scelto 2s abbastanza vicino ad a mi trovo con una sot- trazione da un numero di poche cifre.

Ho dovuto, quindi, fare la somma a+ (2s − b) e alcune operazioni di cambiamento di bit (da 0 a 1 e viceversa) e se anche conto queste operazioni di cambiamento di bit come operazioni bit mi trovo qualcosa del tipo 2 log2(a) che è sempre una cosa del tipo O(log2(a)).

La differenza è quindi un po’ più complicata ma alla fine ottengo

O(log2(a)).

La divisione con resto Quanto tempo (quante operazioni bit) ci vuole per dividere col resto un intero a con un intero b usando l’algoritmo elementare (cioè quello della scuola)?

Supponiamo di dover fare la divisione (110100)2 : (1010)2. Avremo

1 1 0 1 0 0 : 1 0 1 0 1 0 1 0 1 0 1 0 0 1 1 0 0

1 0 1 0 0 0 1 0

Abbiamo visto che dobbiamo fare tante sottrazioni fra numeri che possono essere grandi come a, ogni sottrazione costa log2(a). Quante sottrazioni devo fare?

Ci sono tante sottrazioni quante sono le cifre diverse da zero del quoziente.

Infatti, nell’esempio ha una sottrazione per la prima cifra 1 del quoziente 101, poi non c’è quella per la cifra 0 e ce n’è un’altra per l’ultima cifra 1.

Ci sono dunque log2(q) sottrazioni da fare, dove q è il quoziente a = bq + r con 0 6 r < b. La morale è che la divisione di a per b richiede un tempo che è O(log2(a) log2(q)) dove però non sappiamo a priori quanto è log2(q) quindi possiamo considerare direttamente la stima O(log2(a)2) anche se è un po’ meno fine.

Crittografia e Teoria dei Numeri 19

In realtà notate che tutte le sottrazioni che abbiamo fatto erano in pratica fra numeri con log2(b) cifre, quindi in realtà ho log2(q) sottrazioni fra numeri di log2(b) cifre e quindi la stima è

O(log2(b) log2(q)) = O(log2(b) log2(a))

come nel prodotto.

La seconda è più utile a volte perché coinvolge i due numeri di partenza. La prima è più fine ma dipende da q che non conosciamo a priori.

Riassumendo

Sottrazione = Somma Divisione = Prodotto

Visto che abbiamo analizzato la divisione con resto possiamo anche valutare quanto tempo (operazioni bit) ci vuole per convertire un numero di k bit (quindi scritto in base 2) in forma decimale (cioè in base 10).

Nell’esempio avevamo 52 scritto in forma binaria (= 110100) e l’abbiamo diviso per 10 (= 1010 in forma binaria) e abbiamo ottenuto il resto (10)2 che rappresenterà la cifra dell’unità.

Se scrivo a in binario e lo divido per (1010)2 ottengo

a = (1010)2 · q + r

e il resto può essere

binario 0 1 10 11 100 101 110 111 1000 1001 decimale 0 1 2 3 4 5 6 7 8 9

Con questo trovo la cifra dell’unità e poi ripeto col quoziente. Nell’esempio ho trovato q = (101)2 = (5)10 e r = (10)2 = (2)10 e siccome q < (1010)2 lo converto direttamente e mi fermo, e avrò (110100)2 = (52)10.

Quante operazioni richiede questa conversione?

Ripeto: divido a per (1010)2 = (10)10 e trovo la cifra dell’unità. Prendo il quoziente, lo divido per (1010)2 = (10)10 e trovo la cifra delle decine, e cos̀ı via. Quante di queste divisioni devo fare?

Sto trovando, con ogni divisione, una cifra decimale di a (prima le unità, poi le decine, poi le centinaia, etc.) quindi dovrò fare tante divisioni quante sono le cifra decimali di a. Dunque circa log10(a) (la stima esatta è blog10(a)c+ 1). Come faccio a scrivere questo in base 2?

Per scriverlo come logaritmo in base 2 sfrutto il seguente fatto

log10(a) = 10 log10(a) ⇐⇒ log2(a) = log10(a) log2(10) ⇐⇒ log10(a) =

log2(a) log2(10)

quindi log10(a) = O(log2(a)) perché è log2(a) fratto una costante.

Crittografia e Teoria dei Numeri 20

Questo è il numero di divisioni col resto che devo fare. Ogni divisione richiede tempo (op- erazioni bit): divisione di a per (1010)2 che richiede log2(a) log2((1010)2) operazioni. Poiché (1010)2 ha quattro cifre binarie, si ha

log2(a) log2((1010)2) 6 log2(a) · 4 = O(log2(a)).

Quindi la conversione costa O(log2(a)

2).

Vediamo ora la conversione di un numero a scritto in base 2 nella forma scritta in base b con b arbitrario.

Divido a per b e ottengo a = bq + r 0 6 r < b

dove r è la cifra “delle unità” (cioè l’ultima cifra che scrivo), poi prendo q e ripeto il ragiona- mento.

Voglio determinare dei numeri dk in modo che valga la relazione

a = dkbk + . . .+ d1b+ d0 con0 6 di < b.

Poiché a = (dkbk−1 + . . .+ d1)b+ d0

si ha q = dkbk−1 + . . .+ d1 e r = d0. Ripetendo il ragionamento si ha

q = (dkbk−2 + . . .+ d2)b+ d1

etc. devo fare tante divisioni per b quante sono le cifre di a scritte in base b, cioè

logb(a) = log2(a) log2(b)

e ogni divisione è una divisione col resto di a (o più piccolo) per b che ha dunque costo

log2(a) log2(b).

Quindi sarà log2(a) log2(b)

· log2(a) log2(b) = O(log2(a)2).

Vale la pena di osservare che per alcuni b la conversione è immediata.

Convertire ad esempio a = (10110101110)2 in base 4 è immediato basta porre

(1 01 10 10 11 10)2 (1 1 2 2 3 2)4

perché per passare da una base 2 a una base una potenza di b basta dividere in blocchetti pari alla potenza stessa.

Crittografia e Teoria dei Numeri 21

Infatti nell’esempio si ha, raggruppando a due a due

(10110101110)2 = 1 · 210 + 0 · 29 + 1 · 28 + 1 · 27 + 0 · 26 + 1 · 25 + 0 · 24 + 1 · 23 + 1 · 22 + 1 · 2 + 0 = = 210 + 28(0 + 1) + 26(2 + 0) + 24(2 + 0) + 22(2 + 1) + 2(1 + 0) = = 1 · 45 + 1 · 44 + 2 · 43 + 2 · 42 + 3 · 4 + 2 = = (112232)4

Una procedura simile vale per la conversione di una scrittura in base 2 a una scrittura in base 2n. Spesso, per abbreviare le scritture, per esempio, i numeri vengono scritti in esadecimale, cioè in base 16.

Facciamo vedere il caso di numeri di due cifre esadecimali

a = d1 · 16 + d0 0 6 d0 < 16

dove d0 e d1 sono le “cifre” di a in base 16.

E’ necessario introdurre nuovi simboli per denominare le cifre dato che 16 > 10. Poniamo

0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15

quindi, per fare un esempio,

(FF )16 = F · 16 + F = 15 · 16 + 15 = (255)10,

oppure (10)16 = (16)10.

Se ho un numero binario è facile trasformarlo in esadecimale. Per esempio

(1011 0110)2 (B 6)16

infatti

(10110110)2 = 1 · 27 + 0 · 26 + 1 · 25 + 1 · 24 + 0 · 23 + 1 · 22 + 1 · 2 + 0 = = 24(23 + 0 + 2 + 1) + (0 + 4 + 2 + 0) = = 11 · 16 + 6 = = (B6)16

Vediamo ora una stima dell’algoritmo di Euclide.

Ne abbiamo già una. Abbiamo visto infatti che applicare l’algoritmo di Euclide ai numeri a e b con a > b > 0 richiede

2 log2(b) = O(log2(b))

divisioni col resto.

Prima stima (migliorabile). La prima divisione col resto è fra a e b, e una stima per questa è log2(a) log2(b) per cui complessivamente trovo una stima che è

O(log2(b) 2 log2(a)) = O(log2(a)

3).

Crittografia e Teoria dei Numeri 22

La possiamo scrivere cos̀ı tanto a è più grande di b.

Seconda stima (migliora notevolmente). Abbiamo notato che dividere a per b richiede (nella stima più fine) log2(a) log2(q) operazioni, dove q è il quoziente. L’algoritmo di Euclide consiste nel fare

a = bq1 + r1 b = r1q2 + r2 r1 = r2q3 + r3 . . . . . . . . . . . . . . . . . . rk−2 = rk−1qk + rk

con 0 6 rk . . . < r3 < r2 < r1 < b. Con la stima più fine il tempo richiesto (cioè il numero di operazioni bit) è, ponendo sempre log2(a) al posto di log2(b) e dei log2(ri) per ogni i (perché mi agevola nella rappresentazione)

log2(a) log2(q1) + log2(a) log2(q2) + . . .+ log2(a) log2(qk) = = log2(a)[log2(q1) + log2(q2) + . . .+ log2(qk)] = = log2(a) log2(q1q2 · · · qk)

dove ho sfruttato le proprietà dei logaritmi.

Voglio stimare q1, poi q1q2, poi q1q2q3 fino a q1q2 · qk.

Per q1 si ha

q1 = a− r1 b

< a

per q1q2 si ha

q1q2 = a− r1 b

q2 = a− r1 b

b− r2 r1

< a− r1 r1

< a perché b− r2 b

< 1

per q1q2q3 si ha

q1q2q3 = a− r1 b

b− r2 r1

q3 = a− r1 b

b− r2 r1

r1 − r3 r2

< a− r1 r2

< a perché b− r2 b

< 1 e r1 − r3 r2

< 1

In definitiva ottengo la stima q1q2 · · · qk < a

e quindi la stima per l’algoritmo di Euclide è

O(log2(a) 2).

Quella precedente aveva esponente 3.

Si potrebbe vedere che lo stesso tempo (sempre nella notazione O grande) è richiesta dal- l’algoritmo di Euclide esteso.

L’algoritmo di Euclide esteso è il seguente:

Input: due numeri interi a e b;

Crittografia e Teoria dei Numeri 23

Output: x, y, d dove d è il MCD fra a e b e

ax+ by = d.

Questo richiederebbe circa il doppio delle operazioni ma la notazione O grande cancella il fattore costante 2.

non sono stati rilasciati commenti
Questa è solo un'anteprima
3 pagine mostrate su 27 totali