2012-06-28 10 views
6

Sto cercando di implementare il test di primalità di Miller-Rabin secondo la descrizione in FIPS 186-3 C.3.1. Non importa quello che faccio, non riesco a farlo funzionare. Le istruzioni sono piuttosto specifiche e non penso di aver perso nulla, eppure sto ottenendo true per valori non primi.Test di primaticità di Miller-Rabin Implementazione FIPS 186-3

Cosa ho fatto di sbagliato?

template <typename R, typename S, typename T> 
T POW(R base, S exponent, const T mod){ 
    T result = 1; 
    while (exponent){ 
     if (exponent & 1) 
      result = (result * base) % mod; 
     exponent >>= 1; 
     base = (base * base) % mod; 
    } 
    return result; 
} 



// used uint64_t to prevent overflow, but only testing with small numbers for now 
bool MillerRabin_FIPS186(uint64_t w, unsigned int iterations = 50){ 
    srand(time(0)); 
    unsigned int a = 0; 
    uint64_t W = w - 1; // dont want to keep calculating w - 1 
    uint64_t m = W; 
    while (!(m & 1)){ 
     m >>= 1; 
     a++; 
    } 

    // skipped getting wlen 
    // when i had this function using my custom arbitrary precision integer class, 
    // and could get len(w), getting it and using it in an actual RBG 
    // made no difference 

    for(unsigned int i = 0; i < iterations; i++){ 
     uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2 
     uint64_t z = POW(b, m, w); 
     if ((z == 1) || (z == W)) 
      continue; 
     else 
      for(unsigned int j = 1; j < a; j++){ 
       z = POW(z, 2, w); 
       if (z == W) 
        continue; 
       if (z == 1) 
        return 0;// Composite 
      } 
    } 
    return 1;// Probably Prime 
} 

questo:

std::cout << MillerRabin_FIPS186(33) << std::endl; 
std::cout << MillerRabin_FIPS186(35) << std::endl; 
std::cout << MillerRabin_FIPS186(37) << std::endl; 
std::cout << MillerRabin_FIPS186(39) << std::endl; 
std::cout << MillerRabin_FIPS186(45) << std::endl; 
std::cout << MillerRabin_FIPS186(49) << std::endl; 

mi sta dando:

0 
1 
1 
1 
0 
1 
+0

Come viene implementato 'POW()'? – sarnold

+0

Possiamo vedere 'POW'? Vedo un errore che potrebbe dichiarare alcuni numeri primi come compositi, ma nulla salta per il contrario. Per quali valori stai ottenendo risultati errati? –

+0

Dov'è la tua definizione di POW? – Antimony

risposta

5

L'unica differenza tra l'implementazione e la Wikipedia del è che ti sei dimenticato la seconda istruzione return composito. Dovresti avere un ritorno 0 alla fine del ciclo.

Modifica: Come sottolineato da Daniel, c'è una seconda differenza. Il continuo sta continuando il ciclo interno, piuttosto che il ciclo esterno come dovrebbe.

for(unsigned int i = 0; i < iterations; i++){ 
    uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2 
    uint64_t z = POW(b, m, w); 
    if ((z == 1) || (z == W)) 
     continue; 
    else{ 
     int continueOuter = 0; 
     for(unsigned int j = 1; j < a; j++){ 
      z = POW(z, 2, w); 
      if (z == W) 
       continueOuter = 1; 
       break; 
      if (z == 1) 
       return 0;// Composite 
     } 
     if (continueOuter) {continue;} 
    } 
    return 0; //This is the line you're missing. 
} 
return 1;// Probably Prime 

Inoltre, se l'ingresso è ancora, sarà sempre tornare probabilmente primo da quando a è 0. Si dovrebbe aggiungere un controllo supplementare in partenza per questo.

+3

Si spera che un test di primalità non venga usato su numeri pari. :) – sarnold

+0

Oh dai, questo sicuramente non merita un _downvote _... è un buon punto. :) – sarnold

+0

Perché il downvote? È un problema legittimo e non avevo idea di quali numeri fossero stati testati nel momento in cui l'ho scritto. – Antimony

4

Nel ciclo interno,

 for(unsigned int j = 1; j < a; j++){ 
      z = POW(z, 2, w); 
      if (z == W) 
       continue; 
      if (z == 1) 
       return 0;// Composite 
     } 

si dovrebbe break; invece di continue; quando z == W. Con continue ing, nella prossima iterazione di quel ciclo, se ce n'è uno, z diventerà 1 e il candidato potrebbe essere dichiarato erroneamente composto. Qui, ciò accade per 17, 41, 73, 89 e 97 tra i numeri primi meno di 100.

+0

http: // ideone.com/xoDHx – calccrypto

+1

Aargh, proprio mentre stavo per colpire anche send. Penso che sia questo sia il ritorno 0 se questo ciclo lo rende completamente necessario. – DSM

+0

Wow, non posso credere di averlo perso. Il continuo sta solo continuando il ciclo interno, non il ciclo esterno come dovrebbe. – Antimony