Upload
duongtram
View
219
Download
2
Embed Size (px)
Citation preview
Indagini sulla fattorizzazione RSA e sul logaritmo discretoDi Cristiano Armellini, [email protected]
Fattorizzazione: metodo QR quadro
Sia = con p, q numeri primi
k dispari allora posso scrivere per un determinato valore di a:
n-kp = 2(a+n/p) e ponendo v = n-2a ho l'equazione di II grado− + = , > √Si poteva anche considerare il caso n-kp=2(n/p-a) ma è del tutto analogo con la
sola differenza che v=n+2a
k pari allora posso scrivere
n-kp = 2(a+n/p)+ 1 e ponendo v = n-2a-1 ho l'equazione di II grado− + = , > √Si poteva anche considerare il caso n-kp=2(n/p-a)+1 ma è del tutto analogo con la
sola differenza che v=n+2a-1
Nota: se k dispari allora v dispari, se k pari allora v pari
Stabilisco oltre a n anche il valore di k (k varia per ogni PC - calcolo parallelo). Il
valore di k è molto importante. L'algoritmo per funzionare ha bisogno di un valore di k
intero con k > p/q dove p> q ovvero k=2, 3, 4, 5, .... Negli RSA dove la dimensione
di p è circa quella di q ,k può assumere un valore basso da 2 a 100 (massimo). In
ogni caso k < n/8 come si può facilmente provare. Risolvo l'equazione di II grado
finché non trovo le soluzioni intere facendo variare il valore del parametro v.
Ecco una semplice applicazione in Python:
import math;
def fact(n, k):
v = math.floor(math.sqrt(8*n*k));
delta = math.sqrt(math.fabs(v*v-8*n*k));
p = (v-delta)/(2*k);
q = (v+delta)/(2*k);
while p != math.floor(p) and q != math.floor(q):
v = v+1;
delta = math.sqrt(math.fabs(v*v-8*n*k));
p = (v-delta)/(2*k);
q = (v+delta)/(2*k);
if p == math.floor(p):
print(p);
print(n/p);
else:
print(q);
print(n/q);
Con semplici considerazioni algebriche si può pervenire in modo altrettanto valido
anche alle altre equazioni del tipo + + 2 = 0, − + 2 = 0, + − 2 = 0.+ + 2 = 0 .Quindi possiamo scrivere anche (dove k>p/q, p> q , k = 1, 2, 3,
4, ,.... per numeri RSA)
import math;
def fact(n, k):
v = 0;
delta = math.sqrt(math.fabs(v*v+8*n*k));
p = (v-delta)/(2*k);
q = (v+delta)/(2*k);
while p != math.floor(p) and q != math.floor(q):
v = v+1;
delta = math.sqrt(math.fabs(v*v+8*n*k));
p = (v-delta)/(2*k);
q = (v+delta)/(2*k);
if p == math.floor(p):
print(p);
print(n/p);
else:
print(q);
print(n/q);
Algoritmi per fattorizzare i numeri con il software Mathematica
Si consiglia di usare comunque l'ultima versione del software e all'occorrenza di
impostare i calcoli con un elevato numero di cifre decimali
n := 187
b := 1
a := N[Sqrt[n+b^2]]
While[a != Floor[a], b=b+1; a := N[Sqrt[n+b^2]] ]
p := a-b
q := a+b
Print[p]
Print[q]
-----------------------
n := 187
a := Floor[N[Sqrt[n]]]
b := N[Sqrt[Abs[a^2-n]]]
While[ b != Floor[b], a = a+1; b := N[Sqrt[Abs[a^2-n]]]]
p := a-b
q := a+b
Print[p]
Print[q]
-------------------------
n := 187
i := 1
p := GCD[10^i-1, n]
While[p==1, i=i+1;p := GCD[10^i-1, n] ]
Print[p]
Print[n/p]
----------------------------
Nota
Per aumentare la precisione e il numero delle cifre significative si può usare la
funzione N[], con la specifica ad esempio N[, 100] per calcoli con 100 cifre
significative
La teoria dei numeri con il software Mathematica
Di seguito esempi di codice (anche programmazione) con il software Mathematica per
applicazioni nella teoria dei numeri
FATTORIZZAZIONE CON ALGORITMO EQUAZIONE DI II GRADO
n := 2535311
s := 2*Floor[N[Sqrt[n]]]
delta := N[Sqrt[Abs[s*s-4*n]]]
While[delta != Floor[delta],s=s+2;delta := N[Sqrt[Abs[s*s-4*n]]]]
p := (s-delta)/2
q := (s+delta)/2
Print[p]
Print[q]
FATTORIZZAZIONE CON IL FATTORIALE
n := 187
s := Floor[N[Sqrt[n]]]
GCD[n, s!]
FATTORIZZAZIONE CON ATTACCO FORZA BRUTA
n := 2535311
i = 3
While[n/i != Floor[n/i],i=i+2]
Print[i]
Print[n/i]
n := 1234567891273
i := 3
While[Mod[n, i]!=0, i= i+2]
Print[i]
Print[n/i]
LISTA DEI NUMERI PRIMI
i := 1
While[i <= 100, Print[Prime[i]]; i = i+1]
Table[Prime[n], {n, 1, 100}]
TEST DI PRIMALITA'
PrimeQ[789]
FATTORIZZAZIONE
FactorInteger[187]
PHI DI EULERO
EulerPhi [67]
POTENZE MODULO N (2^34 mod 3)
PowerMod[2, 34, 3]
LOGARITMO DISCRETO (7^i = 2 mod 11)
i := 2
While[PowerMod[7, i, 11] != 2, i=i+1]
Print[i]
DIVISORI DI UN NUMERO
Divisors[86]
VERIFICA IPOTESI DI RIEMANN
i := 1
While[i<=100, Print[Zetazero[i]]; i=i+1]
For[i= 1, i < 100, i++, Print[Zetazero[i]]
Table[N[ZetaZero[i]], {i, 1, 10}] per una verifica cliccate qui (versione on line del
Mathematica)
oppure N[Table[ZetaZero[i], {i, 1, 24}]]
a livello grafico Plot[Abs[Zeta[1/2+x*I]], {x, 0, 40}] o cliccate qui
Plot[(Re[Zeta[1/2+x*I]], Im[Zeta[1/2+x*I]]), {x, 0, 40}] o cliccate qui
Algoritmi ausiliari: calcolo potenze modulo n e calcolo periodo soluzioni inDiffie-Helmann
calcolo del periodo in ≡ ( ) mod p, p primo, MCD(a, p)= 1
programma in python
import math;
def periodo(a,p):
i = 2;
while( (a**i) % p != 1 or (p-1) % i != 0):
i = i+1;
print(i);
-------------------------------------------------
calcolo potenza a^m mod n dove:
MCD(a, n) = 1
m > phi(n)
a^m nod n
programma in PARI/GP
{potenza(a, m, n) = local(c, d);
c = m % eulerphi(n);
d = (a^c) % n;
print(d);
}
Il teorema delle soluzioni del logaritmo discreto
Vedremo più in là che nel primo caso oltre ad essere intero potrebbe anche essere
un divisore di p-1 (o p-1) , mentre nel secondo caso può essere un divisore di ( ).Oltre alle soluzioni logaritmo discreto il teorema ci suggerisce un metodo per calcolare
ad esempio : ( ), ( , ) = 1Infatti se = ( ) + => = ( )Altre applicazioni: la fattorizzazione dei numeri interi (RSA) se n=pq p, q primi
s =p+q ≡ ( ), ≡ ( ), ( ), > √Trovato s (e tutti i valori in progressione aritmetica che soddisfano ≡ ( ) i
valori di p, q si trovano risolvendo l'equazione − + =Inoltre il più piccolo intero e positivo tale che ≡ 1 ( ) deve essere un divisore
di p-1 perché p-1=ke+r con 0 ≤ < => r = 0 ( ( ) ≡ 1 , ( , ) = 1)Questo prova perché le soluzioni del logaritmo discreto sotto le opportune ipotesi di
cui sopra sono tutte equidistanti ovvero in media aritmetica con ragione e dove
e | p-1. Infatti se ≡ allora y=x+be è tale che≡ ≡ , ( , ) = 1. Quindi y = x+be è soluzione di ≡ , p
primo e x soluzione data, e = ragione della progressione delle soluzioni.
Discorso analogo per l’equazione ≡ ( ) dove MCD(a, )=1, y= x+be è
soluzione con e | ( ), x è la soluzione più piccola trovata, e = ragione della
progressione delle soluzioni. Nell'equazione ≡ , con p primo (siamo qui nelle
ipotesi di Diffie-Helmann) il periodo che caratterizza tutte le soluzioni in progressione
aritmetica si calcola trovando il valore minimo tale che ≡ 1, d = periodo della
progressione aritmetica delle soluzioni. Tale valore come sopra provato deve essere
un divisore di p-1 (o molto spesso lo stesso valore p-1)
I divisori di un numero senza ripetizioni
Nel procedimento per trovare le soluzioni dell’algoritmo di Diffie-Helmann può essere
utile trovare tutti i divisori di un numero senza ripetizioni. Applicazioni: teoria dei
numeri, logaritmo discreto
import math;
def divisori(n):
j = 1;
while (j < math.floor(math.sqrt(n))):
if n % j == 0:
print(j);
print(n/j);
j = j+1;
else:
j =j+1;
le soluzioni del Logaritmo discreto e le progressioni aritmetiche
Dato il logaritmo discreto ≡ , con a, b, n noti se esiste una soluzione allora
ne esistono infinite e tutte le soluzioni sono in progressione aritmetica MCD(a, n)=1
inoltre se n è primo la ragione d | (n-1)
mentre se n=pq con p, q primi allora la ragione d | (p-1)(q-1), | ( )In alcuni casi la condizione MCD(a,n)=1 non è indispensabile, come vedremo
negli esempi seguenti
Se n=pq, con p, q primi, da ( ) = ≡ , ( ) dove
MCD(a,n)=1 ricordiamo che = , ( ), = + > √ , ≡ , ( )Questo ci aiuta nella fattorizzazione di n spendo che i fattori si trovano ,
conosciuto s risolvendo direttamente l’equazione di II grado − + =Esempio 1)
7^x = 2 mod 11
si trova che x = 3 , x = 13, x = 23, ..... (soluzioni in progressione aritmetica con
ragione 10 =11-1, 10 | 10)
Esempio 2)
7^x = 4 mod 11
si trova che x = 6 , x = 16, x = 26, ..... (soluzioni in progressione aritmetica con
ragione 10=11-1, 10 | 10)
Esempio 3)
4^x = 9 mod 11
si trova che x = 3 , x = 8, x = 13, ..... (soluzioni in progressione aritmetica con
ragione 5, 5 | 10)
Esempio 4)
2^x = 9 mod 11
si trova che x = 6 , x = 16, x = 26, ..... (soluzioni in progressione aritmetica con
ragione 10=11-1, 10 | 10)
Esempio 5)
3^x = 15 mod 17
si trova che x = 6 , x = 22, x = 38, ..... (soluzioni in progressione aritmetica con
ragione 16=17-1, 16 | 16)
Esempio 6)
204^x = 34 mod 391
si trova che x = 15 , x = 37, x = 59, ..... (soluzioni in progressione aritmetica con
ragione 22, 22 | (17-1)(23-1) = 352) qui molte in z_n.
Esempio 7)
9^x = 15 mod 33
si trova che x = 2 , x = 7, x = 12, ..... (soluzioni in progressione aritmetica con
ragione 5, 5| (3-1)(11-1)=2*10 )
Esempio 8)
3^x = 13 mod 17
si trova che x = 4 , x = 20, x = 36, ..... (soluzioni in progressione aritmetica con
ragione 16=17-1 , 16 | 16)
quindi trovando le prime due soluzioni si ha la formula per trovare tutte le altre.
Programma BC: logaritmo discreto e fattorizzazione
FATTORIZZAZIONE CON BC (BRUTE FORCE)
n = 187;
scale = 0;
p = 3;
while ( n%p != 0 )
p = p+2;
print p;
print n/p;
LOGARITMO DISCRETO CON BC (BRUTE FORCE)
i = 80;
scale = 0;
while ((204^i) % 391 != 34)
i = i+1;
print i
in Python a^x = b mod n
import math;
def logdisc(a, b, n):
i= 1;
while(a**i % n != b):
i = i+1;
print(i);
In PARI/GP
{logdisc(a, b, n) = local(i);
i = 1;
while(a^i % n != b, i=i+1);
print(i);
}
Ancora formule per problemi RSA
Dalla relazione sempre verificata + = − 2 , s=p+q, n=pq, ottengo sapendo
che q=n/p
+ (2 − ) + = 0= + √ − 42 = − √ − 42= − 2 => > 2 , > 4
V deve essere pari perché differenza di due pari
Oppure: dalle relazioni di somma e prodotto + = − 2 , =− ( − 2 ) + = 0, = ,= , > , = , >
In generale non è molto efficiente ..... Ecco un programma in Python
import math;
def facto(n):
V = 2*n;
delta = V*V-4*n*n;
p = math.sqrt((V+math.sqrt(delta))/2);
while (n%p != 0):
V = V+2;
delta = V*V-4*n*n;
p = math.sqrt((V+math.sqrt(delta))/2);
q = n/p;
print(p);
print(q);
Crivello per la fattorizzazione con le equazioni di II grado
ogni numero primo può terminare solo con una della cifre 1, 3, 7, 9
sia n = pq dove p, q sono numeri primi
In base alla seguente tabella moltiplicativa:
X 1 3 7 91 1 3 7 93 3 9 (2)1 (2)7
7 7 (2)1 (4)9 (6)3
9 9 (2)7 (6)3 (8)1
il numero n = pq con p, q primi può terminare a sua volta con una delle seguenti
cifre finali: 1, 3, 7, 9
Sia n =pq, s = p+q, d =p-q
in base quindi alla tabella abbiamo il seguente schema:
se l'ultima cifra di n = pq è:
cifra finale di n è 3 allora abbiamo le seguenti combinazioni per le cifre finali
di p, q: (3,1), (7, 9) quindi la somma s=p+q deve terminare con una delle
cifre 4, 6; mentre la differenza d=p-q con una delle cifre 2, 8
cifra finale di n è 1 allora abbiamo le seguenti combinazioni per le cifre finali
di p, q: (9,9), (1, 1), (3, 7) quindi la somma s=p+qdeve terminare con una
delle cifre 0, 2, 8; mentre la differenzad=p-q con una delle cifre 0, 4, 6
cifra finale di n è 9 allora abbiamo le seguenti combinazioni per le cifre finali
di p, q: (3,3), (1, 9), (7, 7) quindi la somma s=p+qdeve terminare con una
delle cifre 0, 4, 6; mentre la differenzad=p-q con una delle cifre 0, 2, 8
cifra finale di n è 7 allora abbiamo le seguenti combinazioni per le cifre finali
di p, q: (3,9), (7, 1) quindi la somma s=p+q deve terminare con una delle
cifre 2, 8; mentre la differenza d=p-q con una delle cifre 6, 4
Queste considerazioni ci possono essere molto utili in algoritmi di fattorizzazione del
tipo − + = 0, = + , = , = ±√ = , . Inoltre dato che − 4 deve
essere un quadrato perfetto è facile vedere che un quadrato perfetto deve terminare
con una delle cifre 0, 1, 4, 5, 6, 9. Infatti basta osservare la tabella:
I I^20 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
e questo aumenta ulteriormente la velocità nella ricerca delle soluzioni
RSA: ancora equazioni di II grado
n= pq => RSA
p-V = 2a, con V numeri dispari fissato qualsiasi
p-V = 2(q+b) =>
p-V = 2(n/p +b) => − ( + ) − =, = + 2 ± ( + 2 ) + 82
M = V+2b => M dispari (V dispari, 2b pari) => , = ±p =MCD(n, p1)
q =MCD(n, p2)
Il metodo risulta particolarmente efficiente quando p/q è circa 1/2 e in RSA
è caso abbastanza comune
import math;
def mcd(a, b):
if b == 0:
return a;
else:
return mcd(b, a%b);
def facto(n):
m = 3;
delta = m*m+8*n;
while (math.sqrt(delta) != math.floor(math.sqrt(delta))):
m = m+2;
delta = m*m+8*n;
p = (m+math.sqrt(delta))/2;
q = (m-math.sqrt(delta))/2;
a = mcd(p, n);
b = mcd(q, n);
print(a);
print(b);
Fattorizzazione biquadratica RSA
Inoltre: − + = 0, = , , = , = +, = ± √ −
e dalla relazione
= + , = , = => − − =, = ± +
> 4√ , 4|Un esempio del primo metodo in Python
import math;
def facto(n):
V = 4 * math.floor(math.sqrt(n));
s = math.sqrt(2*n + math.sqrt(V**2 +4*n**2));
while (math.floor(s) != s):
V = V+4;
s = math.sqrt(2*n + math.sqrt(V**2 +4*n**2));
x = (s+math.sqrt(s**2-4*n))/2;
y = (s-math.sqrt(s**2-4*n))/2;
print(x);
print(y);
Il teorema della periodicità dei numeri RSA
teniamo anche presente che 4 | ( ) e che in RSA deve essere ( ) > (chiave
pubblica)
Osserviamo anche che in RSA ( ) > quindi n-s+1 > e ovvero s = p+q < n+1-e .
Questo ci può aiutare sia per limitare i valori di s sia quelli di ( ) . Ecco perché e non
può essere troppo grande altrimenti e < ( ) < n-2√ +1 potrebbe essere un
intervallo piccolo per ( ) oppure 2√ < s < n+1-e potrebbe essere anche qui troppo
piccolo il range per s.
Una implementazione in Python molto semplificata e non ottimizzata è:
import math;
def mcd(a, b):
if b == 0:
return a;
else:
return mcd(b, a%b);
def facto(m):
g = 1;
h = mcd(m, 10**g-1);
while (h == 1):
g = g+1;
h = mcd(m, 10**g-1);
print(h);
print(m/h);
Fattorizzare gli RSA con la tecnica dei numeri periodici
Ecco una applicazione in Python della fattorizzazione degli RSA usando la
periodicità dei numeri
import math;
def mcd(a, b):
if b == 0:
return a;
else:
return mcd(b, a%b);
def periodo(n):
i = 1;
while ((10**i-1) % n) != 0:
i = i+1;
return i;