O problema do logaritmo discreto é encontrar o valor de x dado a, b e n tal que
$a^{x} = b (mod n)$
O algoritmo básico seria calcular todas as potências de a,a^2,a^3,..., até encontrar o valor b.
O algoritmo Shanks basea-se na reescrita de x como $x = im + j$, com $m = ceil (sqrt(n) )$ , $0<=i
$a^{im + j} = b$
$a^{im} a^{j} = b$
$a^{j} = b(a^{-m})^{i}$
O algoritmo pré-computa $a^{j}$ para alguns valores de j. Para cada valor de i, ele testa se existe algum j que
$a^{j} = b(a^{-m})^{i}$
Se sim, devolve o valor im+j
Se não, passa para o próximo valor de i
Pseudo-código
- m ← Ceiling(√n)
- para todo j onde 0 ≤ j < m:
- Compute αj mod n and armazene o par (j, αj) em uma tabela.
- Compute α−m mod n
- γ ← β. (set γ = β)
- For i = 0 to (m − 1):
- verifique se existe γ como a segunda componente (αj) de algum par na tabela.
- Se sim, devolva im + j.
- If não, γ ← γ • α−m mod n
Código
#include <stdio.h> #include <stdlib.h> #include <math.h> using namespace std; int n,a,b,m; int g; typedef struct { int index; int value; } table; //função que calcula o mdc estendido ax + by = mdc(a,b) int mdc(int a, int b, int *x, int *y); //calcula o inverso multiplicativo modulo n //a*x = 1 mod n int inverso(int a, int n); //algoritmo de exponeciacao rapida modular int fastexp(int a,int b, int n); //busca binaria do valor g no vetor giant de tamanho n int busca_binaria(int g, int n, table giant[]); //funcao usada no qsort int compara(const void *a, const void *b); int shanks(int a, int b, int n){ int g,m,r; int i,j; m = (int)ceil( sqrt(n) ); printf("valor de m: %d\n",m); table giant[m]; a = a%n; b = b%n; giant[0].index = 0; giant[0].value = 1; //Passo de Gigante for(j=1;j<m;j++){ giant[j].index = j; giant[j].value = (giant[j-1].value*a)%n; } qsort(giant, m , sizeof(table), compara ); //Passo de Gigante printf("Passo gigante\n"); for(j=0;j<m;j++){ printf("%d %d\n",giant[j].index, giant[j].value); } r = fastexp(inverso(a,n),m,n); g = b; //Passo de Baby printf("Passo de bebe\n"); for(i=0;i<m;i++){ printf("g: %d\n",g); j = busca_binaria(g,m,giant); if( j!=-1 ){ printf("j: %d\n", giant[j].index); return i*m + giant[j].index; }else{ g = (g*r)%n; } } } int main(){ int j; int r; scanf("%d %d %d",&a,&b,&n); printf("%d\n",shanks(a,b,n)); return 0; } int mdc(int a, int b, int *x, int *y) { int xx, yy, d; if(b==0) { *x=1; *y=0; return a; } d = mdc(b, a%b, &xx, &yy); *x = yy; *y = xx - a/b*yy; return d; } int inverso(int a, int n){ int x,y,d; d = mdc(a,n,&x,&y); if(x<0){ x = x+n; } return x; } int fastexp(int a,int b, int n){ long long int x; if(b==0) return 1; if(b==1) return a; if(b%2==0){ x = fastexp(a,b/2,n)%n; return (x*x)%n; }else{ return (a*fastexp(a,b-1,n))%n; } } int compara(const void *a, const void *b){ return ((table*)a)-> value - ((table*)b)->value; } int busca_binaria(int g, int n, table giant[]){ int i,f; int m; i = 0; f = n-1;
while(i<=f){ m = (i+f)/2; if(giant[m].value == g) return m; else if(giant[m].value > g){ f = m-1; }else { i = m+1; } } return -1; }
Saída
5 315 317
valor de m: 18
Passo gigante
0 1
1 5
2 25
8 81
9 88
6 92
10 123
3 125
7 143
17 154
13 159
14 161
15 171
16 221
12 222
5 272
11 298
4 308
Passo de bebe
i 0 g: 315
i 1 g: 303
i 2 g: 219
i 3 g: 265
i 4 g: 270
i 5 g: 305
i 6 g: 233
i 7 g: 46
i 8 g: 5
j: 1
145
Pressione qualquer tecla para continuar. . .
$log_{5} 315 = mi + j = 18(8) + 1 = 145 $
Calculadora de logaritmos discretos
http://www.numbertheory.org/php/discrete_log.html
Referências:
http://en.wikipedia.org/wiki/Baby-step_giant-step
http://pastebin.com/F8Nin82x
http://pt.scribd.com/doc/63892535/38/Algoritmos-para-PLD
Nenhum comentário:
Postar um comentário