/* Questo programma fa parte di una libreria messa a disposizione dei lettori del libro Alessandro Languasco & Alessandro Zaccagnini, Introduzione alla Crittografia, Ulrico Hoepli Editore, Milano, 2004. */ #include /* Calcolo del massimo comun divisore con l'algoritmo di Euclide. Languasco & Zaccagnini, Introduzione alla Crittografia, Hoepli. Paragrafo 6.2 */ long long mcd(long long a, long long b) { // I valori assoluti assicurano che i calcoli contengono solo numeri // non negativi long long unsigned m = llabs(a); long long unsigned n = llabs(b); long long unsigned r = n; while(r != 0) { r = m % n; m = n; n = r; } return(m); } /* Calcolo del massimo comun divisore con l'algoritmo di Euclide esteso ritorna due valori "lambda" e "mi" in modo che sia soddisfatta l'uguaglianza "mcd = lambda * a + mi * b". Languasco & Zaccagnini, Introduzione alla Crittografia, Hoepli. Paragrafo 6.2 */ long long mcd_est(long long a, long long b, long long &lambda, long long &mi) { long long a1 = 1; long long a2 = 0; long long b1 = 0; long long b2 = 1; long long m = a; long long n = b; long long r = n; while(r != 0) { long long q = m / n; r = m % n; long long a3 = a1 - q * a2; long long b3 = b1 - q * b2; a1 = a2; a2 = a3; b1 = b2; b2 = b3; m = n; n = r; } lambda = a1; mi = b1; return(m); } /* Moltiplicazione "a * m mod n" usando il procedimento del raddoppiamento e dimezzamento dei due fattori. Languasco & Zaccagnini, Introduzione alla Crittografia, Hoepli. Paragrafo 6.9.1 */ long long moltiplicazione_mod_n(long long a, long long m, long long n) { long long S = 0; long long M = m; long long A = a; long long r, q; do { r = M % 2; q = M / 2; if (r == 1) { S += A; S = S % n; } A += A; A = A % n; M = q; } while(q > 0); return(S); } /* Calcolo di "a^m mod n" con il metodo dei quadrati ripetuti. Languasco & Zaccagnini, Introduzione alla Crittografia, Hoepli. Paragrafo 6.9.2 */ long long potenze_mod_n(long long a, long long m, long long n) { long long P = 1; long long M = m; long long A = a; long long r; long long q; do { r = M % 2; q = M / 2; if (r == 1) P = moltiplicazione_mod_n(P,A,n); A = moltiplicazione_mod_n(A,A,n); M = q; } while(q > 0); return(P); } /* Calcolo del quoziente "q" e del resto "r" della divisione di "N" per "M" sfruttando la divisione per "m = M - d", dove "d" è piccolo in valore assoluto (supponendo che, per qualche motivo, dividere per "m" sia efficiente). Languasco & Zaccagnini, Introduzione alla Crittografia, Hoepli. Paragrafo 6.9.4 */ void divisione(long long N, long long M, long long d, long long& q, long long& r) { long long m = M - d; long long max = d > 0 ? M : m; q = N / M; r = d * q + (N % M); long long qq; // Ripeti il ciclo finché il resto non è nell'intervallo corretto do { qq = r / M; if (r < 0) --qq; long long rr = r - M * qq; q += qq; r = d * qq + rr; } while ((r < 0) || (r >= max)); // Correggi il risultato, se necessario while (r >= m) { r -= m; ++q; } } /* Radice quadrata intera. Dato il numero intero non negativo "n", restituisce il massimo intero non negativo "m" tale che "m^2 <= n", cioè la radice quadrata intera approssimata per difetto. */ long long radice_quadrata(long long n) { if (n < 0) return(-1); long long m = int(sqrt((double) n)); return(m); }