Guida Test di primalità di Miller-Rabin

_ _

Utente Gold
16 Aprile 2013
367
15
208
210
Per renderizzare la notazione matematica presente nel post cliccate qui e aggiungete il secondo link "render mathjax" ai segnalibri, cliccatelo poi mentre siete su questa pagina e dovrebbe ricaricarla con la notazione a postohttp://www.math.ucla.edu/~robjohn/math/mathjax.html

Controllare se un numero è primo o meno è un problema che si presenta in svariate applicazioni, soprattutto di tipo crittografico e per il quale sono quindi stati sviluppati diversi algoritmi.


Solamente nel 2002 è stato dimostrato, da Agrawal, Kayal e Saxena, che controllare se un numero è primo è un problema in P tuttavia l'algoritmo di Miller-Rabin è di gran lunga il test di primalità più utilizzato nella pratica anche se è un test probabilistico per questioni di efficenza (se l'algoritmo decide che un numero non è primo allora non lo è sicuramente, mentre se decide che un numero è primo c'è una piccola probabilità che in realtà non lo sia).

Un paio di osservazioni preliminari
Per prima cosa notiamo che se $p$ è primo allora le uniche radici di $1$ modulo $p$ sono $\pm 1$, infatti $X^2-1\in\mathbb{Z}/p\mathbb{Z}[x]$ può avere al massimo $2$ radici essendo un polinomio di secondo grado a coefficenti in un campo.

Ricordiamo poi il piccolo teorema di fermat, per cui $a^{p-1}\equiv 1\pmod p$ per $p$ primo e $a$ positivo non divisibile per $p$

Il test
Sia $n>2$ primo, $n-1$ è pari ed scrivibile come $2^sd$.
Inoltre per ogni $a\in(\mathbb{Z}/p\mathbb{Z})*$ vale una delle seguenti congruenze:

$a^d\equiv 1 \pmod p$
$a^{2^rd}\equiv -1\pmod p$ per qualche $r$ con $0\le r\le s-1$

infatti per il piccolo teorema di Fermat sappiamo che $a^{p-1}\equiv 1\pmod p$ dunque $a^{2^sd}\equiv 1\pmod p$ e quindi se continuiamo ad estrarre radici quadrate dei due lati otteniamo a sinistra $a^{2^{s-1}d}$, $a^{2^{s-2}d}$ e così via mentra a destra dobbiamo continuare ad ottenere $\pm 1$ per la prima osservazione, se arriviamo a $-1$ vale la seconda equazione, mentre se il risultato è sempre $1$ ad un certo punto finiremo di poter estrarre radici quadrate (avendo esaurito le $s$ potenze di $2$) e varrà quindi la prima equazione.

Viste le osservazioni di poco fa sappiamo che se troviamo un $a$ tale che:
$a^d\not\equiv 1\pmod n$
$a^{2^rd}\not\equiv -1\pmod n$ per ogni $0\le r\le s-1$
allora $n$ non può essere primo e in questo caso chiamiamo $a$ un testimone della compositezza di $n$, altrimenti $n$ è uno pseudoprimo per la base $a$.

Per ogni $n$ non primo ci sono tanti testimoni, ma non si conosce nessun metodo efficente per generarne uno, quindi la soluzione è di rendere il test probabilistico, proviamo $k$ numeri più piccoli di $n$ e se anche un solo test fallisce allora $n$ non è primo, altrimenti lo è molto probabilmente.

In pseudocodice, dove continue è l'istruzione che interrompe l'iterazione corrente di un ciclo for per passare subito alla successiva otteniamo una cosa del genere:
Codice:
for i=1 to k do                 //k=numero di basi che testiamo
   scegli a a caso in [2,n-2]
    x=a^d mod p
    if x==1 or x==-1 then
          continue
    for i=1 to r-1
         x=x^2 mod n
         if x==1 then
               return "non primo"
         if x==n-1 then
               continue
    return "non primo"
return "probabilmente primo"

Se si usa quello che in inglese vien chiamato "exponentation by squaring" e che in Italiano io conosco come "metodo del contadino russo" ma non so se ha un nome ufficiale si vede facilmente che la complessità risulta essere $O(\log^3n)$

Resta da stimare la probabilità che questo test commetta un errore, si può dimostrare (posso aggiungerlo se a qualcuno interessa, ma non volevo appesantire troppo matematicamente il post), che per ogni $n$ dispari non primo ci sono almeno $3(n-1)/4$ testimoni quindi scegliendone $k$ a caso la probabilità che $n$ non sia primo ma che ogni iterazione del test lo scambi per primo è nel caso peggiore $1/4^k$, che è praticamente trascurabile per ogni scopo pratico.

Inoltre è stato mostrato che se il numero di cui vogliamo controllare la primalità è inferiore a $2^{64}$ allora basta controllare $a=2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31$ e $37$ per essere sicuri di non dichiarare primi numeri che non lo sono, rendendo il test di fatto deterministico ed estremamente veloce se è noto a priori un limite sui valori da testare.
 
  • Mi piace
Reazioni: MichPower e 0xbro