Figura 4.1: Diagrama de Comunicação
1 # ifndef BASICS_H_
2 # define BASICS_H_
3
4 # include <math .h>
5 # include " bigint .h"
6
7 # endif
Foi denido o tipo bigint, que representará números de até 512bits, apesar de as operações se basearem em 256 bits, operações como a multiplicação de 256 bits necessitam de um armazenamento de 512 bits.
As funções denidas neste módulo denem as operações básicas entre números inteiros necessárias para a implementação do protocolo ECDSA. Elas são:
Para entrada e saída:
• ler_bigint - lê um número na forma de caractere(bytes) e guarda em um bigint
• ler_hex_bigint - lê um número na forma hexadecimal e guarda em um bigint
• er_hex_bigint - lê um número em um arquivo na forma hexadecimal e guarda em um bigint
• ler_decimal - lê um número na forma decimal e guarda em um bigint
• imprime_hex_bigint - imprime um bigint na tela na forma hexadecimal
• mprime_hex_bigint - imprime um bigint em um arquivo na forma hexadecimal
• imprime_char_bigint - imprime um bigint na tela na forma de caractere(byte)
• imprime_decimal - imprime um bigint na tela na forma decimal Para Comparação:
• not_null - testa se um bigint é diferente de zero.
• eq_bigint - Testa se um bigint é igual a outro bigint
• eqi_bigint - Testa se um bigint é igual a um inteiro
• lt_bigint - Testa se um bigint é menor que outro bigint
• ltu_bigint - Testa se um bigint é menor que outro bigint na representação sem sinal
• let_bigint - Testa se um bigint é menor ou igual a outro bigint.
Para operações lógicas:
• append_int_bigint - acrescenta os bits de um inteiro no lado menos signicativo do bigint e descarta o mesmo número de bits adicionados no lado mais signicativo
• srl1_bigint - Dá um shift lógico de 1 bit à direita em um bigint
• sll1_bigint - Dá um shift lógico de 1 bit à esquerda em um bigint Para operações algébricas:
• init_bigint - Inicia um bigint com zero
• neg_bigint - Troca o sinal de um bigint
• random_bigint - Gera um bigint pseudo-aleatório
• atrib_bigint - Atribui o valor de um bigint em outro
• atribi_bigint - Atribui o valor de um inteiro em um bigint
• add_bigint - Soma dois bigint
• addi_bigint - Soma um bigint com um inteiro
• sub_bigint - Subtrai um bigint por outro
• subi_bigint - Subtrai um bigint por um inteiro
• mult_bigint - Multiplica dois bigint
• multi_bigint - Multiplica um bigint com um inteiro
• div_mod_bigint - Divide um bigint por outro, obtendo quociente e resto
• div_mod_i_bigint - Divide um bigint por um inteiro, obtendo quociente e resto
• pow_modp_bigint - Eleva um bigint por outro e este resultado é calculado mó-dulo um terceiro bigint
A seguir a descrição mais detalhada de cada uma.
4.2.1 Tipo bigint
O tipo bigint nada mais é que uma cadeia de bytes, ele é denido da seguinte maneira:
1 typedef unsigned char bigint [ TBITS +1]
Onde a constante TBITS está denido com65, 1 bit para armazenar o sinal do número mantendo 2512 −1 números positivos possíveis. Percebam que é necessário apenas um número positivo máximo de 2256−1, mas na multiplicação de 2 números deste tamanho, precisamos armazenar um número de 64 bytes.
O+1se deve a necessidade da linguagem de um byte para demarcar o m da string 3 sempre que se utiliza uma.
Antes de começar a descrever como foram implementadas as funções a seguir, é bom salientar que tais algoritmos foram retirados em sua maior parte de [14] e de [13].
4.2.2 init_bigint
Esta função tem por objetivo inicializar uma variável bigint com o valor 0. Recebe como parâmetro a variável a ser inicializada a.
Isto é feito em um loop que passa por cada byte da variável atribuindo o valor 0 a cada uma. A denição ca assim:
1 void init_bigint ( bigint a){
2 int i;
3 // loop que passa por todos os bytes da variavel
4 for(i=0;i< TBITS ;i++){
5 a[i ]=0;
3cadeia de caracteres.
6 }
7 }
4.2.3 not_null
Esta função recebe uma variável bigint a como o parâmetro e verica se ela é igual a 0 ou não, caso seja, a função retorna falso, caso contrário, retorna verdadeiro.
Isto é feito em um loop que passa por cada byte da variável testando se ela é igual a 0, caso encontre um retornará falso, se depois de todos os testes, não for encontrado um byte igual a 0retorna verdadeiro. O código ca assim:
1 bool not_null ( bigint a){
2 int i;
3 // loop que passa por todos os bytes da variavel
4 for(i=0;i< TBITS ;i++){
5 // caso o byte da vez for nao nulo , retorna verdadeiro
6 if(a[i ]!=0) {
7 return true;
8 }
9 }
10 // caso todos sejam nulos , retorna falso
11 return false;
12 }
4.2.4 neg_bigint
Esta função recebe uma variável bigint e inverte todos os bits do número. Em seguida adiciona 1 ao resultado. Método este que inverte o sinal do número representado pela forma de complemento de 2 4. O código ca assim:
1 void neg_bigint ( bigint a){
2 int i;
3 // loop que passa por todos os bytes da variavel
4 for(i=0;i< TBITS ;i++){
5 // inverte todos os bits de cada byte
6 a[i] = ~a[i];
7 }
8 // adiciona 1 ao valor de a
9 addi_bigint (a,a ,1);
10 }
A explicação da função addi_bigint estará mais adiante.
4representação de número na base 2 em que o primeiro bit além de denir uma parte do valor do número também dene se este é negativo ou positivo.
4.2.5 random_bigint
Esta função como dita anteriormente apenas simula um gerador aleatório, já que o objetivo do módulo é o protocolo do ECDSA implementado de forma simples não foi utilizado um método mais robusto.
Para simular um gerador de números aleatórios foi utilizada a função nativa da bibli-oteca stdlib como base. Para usar esta função é necessário no início do programa iniciar a semente. No código é usada a função rand() em cada byte até o 32o. Eis o código:
1 void random_bigint ( bigint a){
2 int i;
3 // loop que percorre os bytes do numero
4 for(i=0;i< TBITS ;i++){
5 // os 33 mais significativos ficam em 0, para que o numero seja de no maximo 256 bits
6 if(i <=32) {
7 a[i ]=0;
8 }else{
9 // gera um numero aleatorio para cada byte
10 a[i] = rand () %256;
11 }
12 }
13 }
4.2.6 ler_bigint
Esta função recebe como parâmetro a variável bigint que armazenará o número lido em forma de caracteres, ou seja, armazenará exatamente os caracteres lidos. Eis o código:
1 void ler_bigint ( bigint s){
2 int i,j;
3 unsigned char c;
4 i=0;
5 c = getc ( stdin );
6 //o loop ira ler cada caracter enquanto este for diferente de espaco ou enter , ou se passar do tamanho maximo do tipo
7 while(i< TBITS &&(c!='\n'&&c!=' ')){
8 s[i]=c;
9 c = getc ( stdin );
10 i++;
11 }
12 // caso o numero de caracteres forem menor que o tamnho do tipo , os bytes devem ser reposicionados
13 if(i< TBITS ){
14 i = TBITS - i;
15 }
16 // este loop reposiciona os bytes para as posicoes menos significativas .
17 // ao terminar os bytes restantes sao valorizados com zero .
18 for(j=TBITS -1;j >=0;j --){
19 if(j >=i){
20 s[j] = s[j-i];
21 }else{
22 s[j] = 0;
23 }
24 }
25 }
Perceba que ao ler uma seqüência de caracteres como abc estes caracteres cam nos bytes mais signicativos da cadeia que forma o tipo bigint, por isso, depois de ler, reposicionamos estes para os bytes menos signicativos. Como no exemplo:
Tabela 4.1: Tabela de Armazenamento do tipo bigint 0 1 2 ... TBITS-2 TBITS-1
a b c ... 0 0
depois do reposicionamento:
Tabela 4.2: Tabela de Armazenamento Reticado 0 1 ... TBITS-3 TBITS-2 TBITS-1
0 0 ... a b c
4.2.7 ler_hex_bigint
Esta função também é feita para ler do teclado o valor de um tipo bigint, mas o valor esperado na leitura é no formato hexadecimal. Para tal é utilizado uma manipulação da tabela ascii, de tal forma que caso o caracter lido for um algarismo é subtraído de seu valor 48, para que se tenha o valor correto de tal algarismo. No caso das letrasA, B, C, D, E, F, para que seus valores quem iguais a 10,11,12,13,14,15, subtrai-se 55, por m para as letras a, b, c, d, e, f, pelo mesmo motivo, subtrai-se87.
Este valor é somado à variável, inicialmente zerada e depois de cada soma, com ex-ceção da última, multiplica-se o resultado por 16. Assim fazendo a mudança de base de hexadecimal para binário. O código está abaixo:
1 void ler_hex_bigint ( bigint s){
2 unsigned char c;
3 unsigned int n;
4 // inicia -se a variavel com 0
5 init_bigint (s);
6 c = getc ( stdin );
7 // ler os caracteres ate que ache um espaco ou enter
8 while(c!='\n'&&c!=' '){
9 // multiplica o resultado por 16 para mudanca de base
10 multi_bigint (s,s ,16) ;
11 // Analisa qual o caracter e faz a operacao necessaria
12 if(c >47&&c <58) {// algarismos
13 n = c -48;
14 }else if(c >96&&c <103) {//a,b,c,d,e,f
15 n = c -87;
16 }else{//A,B,C,D,E,F
17 n = c -55;
18 }
19 // adiciona o resultado a variavel
20 addi_bigint (s,s,n);
21 c = getc ( stdin );
22 }
23 }
4.2.8 er_hex_bigint
Esta função recebe como parâmetro uma variável tipo bigint s e um ponteiro para um arquivo. Ela funciona do mesmo jeito que a anterior, com a diferença que ao invés de receber os caracteres do teclado, ele lê de um arquivo. O código segue abaixo:
1 void fler_hex_bigint ( bigint s, FILE *fp){
2 unsigned char c;
3 unsigned int n;
4 // inicia a variavel com o valor 0
5 init_bigint (s);
6 c = getc (fp);
7 // le caracter do arquivo enquanto este for diferente de espaco ou enter ou fim de arquivo
8 while(c!='\n'&&c!=' '&&! feof (fp)){
9 // multiplica o valor da variavel por 16 para mudanca de base
10 multi_bigint (s,s ,16) ;
11 // Analisa qual foi o tipo de caracter lido para transforma -lo adequadamente
12 if(c >47&&c <58) {// algarismo
13 n = c -48;
14 }else if(c >96&&c <103) {//a,b,c,d,e,f
15 n = c -87;
16 }else{//A,B,C,D,E,F
17 n = c -55;
18 }
19 // adiciona valor lido a variavel
20 addi_bigint (s,s,n);
21 c = getc (fp);
22 }
23 }
4.2.9 ler_decimal
Esta última função de leitura é semelhante às anteriores, mas a entrada esperada do teclado é um número decimal. Para tal, além de apenas fazer as contas para transformar
os caracteres dos algorismos, multiplica-se a variável a cada algorismo lido por 10, já que a mudança de base agora é de decimal para binário.
Outro caso a ser analisado é se existe o símbolo - no início do número, o que informa que o valor é negativo, para este caso, ao nal do cálculo do valor absoluto, apenas se inverte o valor com a função neg_bigint.
1 void ler_decimal ( bigint s){
2 unsigned char c;
3 unsigned int n;
4 bool nega =false;
5 // inicia o valor da variavel com 0
6 init_bigint (s);
7 c = getc ( stdin );
8 // testa se o numero lido e negativo
9 if(c=='-'){
10 nega = true;
11 c = getc ( stdin );
12 }
13 // le os algorismos ate que achar um espaco ou o enter
14 while(c!='\n'&&c!=' '){
15 // multiplica o valor da variavel por 10 para mudanca de base
16 multi_bigint (s,s ,10) ;
17 // transforma o caracter no valor do algarismo
18 n = c -48;
19 // adiciona o valor lido a variavel
20 addi_bigint (s,s,n);
21 c = getc ( stdin );
22 }
23 // caso o numero lido tiver o sinal - inverte seu valor
24 if( nega ){
25 neg_bigint (s);
26 }
27 }
4.2.10 imprime_hex_bigint
Esta função recebe como parâmetro uma variável do tipo bigint onde está armazenado o número que será escrito na forma hexadecimal no terminal. Este é feito da seguinte maneira. Do byte mais signicativo, começa-se a percorrer a cadeia enquanto não achar um byte diferente de zero. Caso todos sejam zero, imprime zero, caso contrário a partir do primeiro byte não zero, imprime o byte em forma hexadecimal. A seguir o código:
1 void imprime_hex_bigint ( bigint s){
2 int i;
3 i=0;
4 // procura o primeiro byte nao nulo .
5 while(i< TBITS &&s[i ]==0) {
6 i++;
7 }
8 // caso todos os bytes sejam zeros , imprime zero na tela
9 if(i== TBITS ){
10 printf ("%02x",0);
11 return;
12 }
13 // caso contrario , cada byte sera escrito na forma hexadecimal
14 while(i< TBITS ){
15 printf ("%02x",s[i]);
16 i++;
17 }
18 }
4.2.11 mprime_hex_bigint
A idéia desta função é a mesma da anterior, a diferença está que esta recebe como parâmetro, também, um ponteiro para arquivo, e ao invés de escrever o número em hexadecimal na tela, este será escrito no arquivo a qual o ponteiro está associado.
1 void fimprime_hex_bigint ( bigint s, FILE *fp){
2 int i;
3 i=0;
4 // procura o primeiro byte nao nulo .
5 while(i< TBITS &&s[i ]==0) {
6 i++;
7 }
8 // caso todos os bytes sejam zeros , imprime zero no arquivo
9 if(i== TBITS ){
10 fprintf (fp ,"%02x",0);
11 return;
12 }
13 // caso contrario , cada byte sera escrito na forma hexadecimal no arquivo
14 while(i< TBITS ){
15 fprintf (fp ,"%02x",s[i]);
16 i++;
17 }
18 }
4.2.12 imprime_char_bigint
Esta função novamente escreve o número armazenado na variável bigint passada como parâmetro. Mas desta vez na forma de caracter. A implementação segue a mesma lógica, mas ao invés de imprimir na forma hexadecimal, imprime na forma de caracter.
1 void imprime_char_bigint ( bigint s){
2 int i;
3 i=0;
4 // procura o primeiro byte nao nulo .
5 while(i< TBITS &&s[i ]==0) {
6 i++;
7 }
8 // caso todos os bytes sejam zeros , imprime caractere nulo na tela
9 if(i== TBITS ){
10 putc (0, stdout );
11 return;
12 }
13 // caso contrario , cada byte sera escrito na forma de caractere
14 while(i< TBITS ){
15 putc (s[i], stdout );
16 i++;
17 }
18 }
4.2.13 imprime_decimal
Esta função pega o parâmetro bigint passado para ela e a imprime na tela na forma decimal. Para esse código a lógica é um pouco mais extensa. Primeiramente, é avaliado se o número armazenado é negativo, caso seja, imprime o caracter - na tela e transforma o número em positivo, caso contrário, não faz nada.
Para o próximo passo é necessário duas variáveis bigint para auxiliar. No primeiro passo dividi-se o valor do parâmetro por 10 e guarda o quociente em um dos auxiliares e o resto em outro. Imprime o algarismo relativo ao resto e se o quociente for diferente de zero, inicia-se o seguinte loop:
Dividi-se o quociente por 10 e substitui o novo quociente no lugar do antigo, armaze-nando o novo resto no lugar do antigo também, e novamente imprime o algarismo relativo ao resto na tela. Repete-se até que o quociente seja igual a zero.
O código ca assim:
1 void imprime_decimal ( bigint s){
2 bigint q,m,x;
3 unsigned char num [80];
4 int i;
5 // atribui -se o valor do parametro a outra variavel para preservar o original
6 atrib_bigint (x,s);
7 // se o numero for zero , simplesmente imprime 0
8 if(! not_null (x)){
9 printf ("%d",0);
10 return;
11 }
12 // testa se o bit mais significativo e 1( numero negativo ), caso seja imprime "-" na tela e inverte o sinal do numero
13 if(s [0]&0 x80){
14 printf ("-");
15 neg_bigint (x);
16 }
17 i=1;
18 // armazena o resto modulo 10 do numero num vetor que sera impresso depois
19 div_mod_i_bigint (q,m,x ,10) ;
20 num [0] = m[TBITS -1]+48;
21 // loop que refaz a operacao acima enquanto o quociente for diferente de zero
22 while( not_null (q)){
23 div_mod_i_bigint (q,m,q ,10) ;
24 num[i] = m[TBITS -1]+48;
25 i++;
26 }
27 i --;
28 // imprime o vetor na ordem inversa , gerando na tela o numero correspondente ao armazenado
29 while(i >=0) {
30 putc (num[i], stdout );
31 i --;
32 }
33 }
4.2.14 eq_bigint e eqi_bigint
As funções eq_bigint e eqi_bigint testam se os dois parâmetros passados a elas possuem valores iguais. A primeira é um teste direto entre duas variáveis do tipo bigint, a segunda testa um bigint com um inteiro nativo da linguagem C++. Para esta o que se faz é atribuir o valor do inteiro em uma variável do tipo bigint e chamar a função eq_bigint, agora sim, com dois bigint.
Para testar a igualdade entre dois elementos bigint a função simplesmente percorre cada byte da cadeia de um, comparando-o com o byte correspondente do outro, caso sejam iguais continua o loop, caso contrário, interrompe o loop retornando falso. Se depois de decorrido toda a cadeia não for encontrado par de bytes diferentes retorna verdadeiro.
1 bool eq_bigint ( bigint a, bigint b){
2 int i;
3 // loop que percorre cada byte da cadeia
4 for(i=0;i< TBITS ;i++){
5 // para cada byte testa -se se seu correspondente na outra cadeia e diferente ou igual
6 if(a[i]!=b[i]){
7 // retorna falso caso encontre qualquer igual
8 return false;
9 }
10 }
11 // retorna verdadeiro caso todos sejam iguais
12 return true;
13 }
A função eqi_bigint não terá seu código exposto, visto que não há a necessidade, pois é simplesmente uma atribuição seguida de uma chamada da função acima.
4.2.15 lt_bigint e ltu_bigint
Ambas as funções lt_bigint e ltu_bigint recebem dois parâmetros do tipo bigint, o objetivo de ambas é testar se o primeiro parâmetro tem valor menor que o segundo. A única diferença entre elas é que no primeiro é considerado se os números são positivo ou negativo, enquanto no segundo, considera-se que são não sinalisados 5
Para efeito prático só será mostrado o código do lt_bigint, visto que a outra função é idêntica, apenas tirando o teste de sinal. Como então funciona o algoritmo?
Primeiro, quando há teste de sinal, testa-se se o sinal dos dois parâmetros são diferen-tes, caso sejam e o primeiro tenha sinal negativo, ou seja, bit mais signicativo igual a 1, a função termina retornando verdadeiro, caso seja positivo, ou seja, bit mais signicativo igual a 0, retorna falso.
Caso os sinais sejam iguais, percorre-se cada posição da cadeia, do mais signicativo pro menos signicativo, testando se o byte do primeiro parâmetro é maior que o seu respectivo no segundo, caso seja, signica que o segundo é menor que o primeiro, então retorna falso, se o primeiro for menor que o segundo, retorna verdadeiro. Se depois de todos os bytes testados, não for achado par de bytes diferentes, retorna falso.
1 bool lt_bigint ( bigint a, bigint b){
2 int i;
3 // testa se os sinais sao diferentes
4 if((a [0]&0 x80)!=(b [0]&0 x80)){
5 if((a [0]&0 x80) !=0) {//a e negativo , logo menor que b
6 return true;
7 }else{//a e positivo , logo maior que b
8 return false;
9 }
10 }
11 // para sinais iguais , testa -se do byte mais significativo ate o menos , qual e o maior
12 for(i=0;i< TBITS ;i++) {
13 if(a[i]<b[i]){// byte de a menor que o de b, a menor que b
14 return true;
15 }else if(a[i]>b[i]){// byte de a menor que o de b, a maior que b
16 return false;
17 }
18 }
19 // se nenhum par de bytes for diferente , a e igual a b
20 return false;
21 }
5tradução livre para unsigned, sem sinal.
4.2.16 let_bigint
Esta função testa se o primeiro dos dois parâmetros do tipo bigint que ela recebe é menor ou igual ao segundo parâmetro. Para tal, simplesmente é testado se este dois parâmetros mandados na mesma ordem que foram recebidos retornam verdadeiro para as funções eq_bigint ou lt_bigint. Caso sim retorna verdadeiro, senão falso. Visto a simplicidade da função, é desnecessário mostrar o código.
4.2.17 atrib_bigint e atribi_bigint
As funções atrib_bigint e atribi_bigint recebem dois parâmetros cada, a primeira recebe dois bigint's, a segunda recebe um bigint e um inteiro de 32 bits. Nas duas o objetivo é passar o valor do segundo parâmetro para o primeiro.
Para tal no atrib_bigint apenas se percorre cada byte da cadeia copiando o valor do byte do segundo parâmetro para seu respectivo no primeiro parâmetro, ca então assim:
1 void atrib_bigint ( bigint a, bigint b){
2 int i;
3 // loop que passa byte a byte os valores da cadeia b para a cadeia a
4 for(i=0;i< TBITS ;i++){
5 a[i] = b[i];
6 }
7 }
Para a função atribi_bigint, onde passamos um valor de um inteiro para o bigint é necessário algo mais. Primeiramente, sabe-se que na arquitetura da linguagem C++, o tipo inteiro possui 32 bits, ou seja, 4 bytes. Estes que serão copiados nos 4 bytes menos signicativos do parâmetro bigint.
Entretanto, é necessário analisar primeiro o sinal do inteiro, guarda-se a informação se este é positivo ou negativo, caso seja negativo, multiplica-se ele por -1, passando ele para o valor absoluto.
Depois simplesmente inicia-se o bigint com o valor 0. Em seguida é atribuído o valor dos 4 bytes do inteiro nos 4 bytes menos signicativos do bigint.
Ao terminar este passo, analisa-se a informação guardada sobre o inteiro, a que diz se este é positivo ou negativo, caso seja negativo, inverte-se o sinal do bigint com a função neg_bigint. O código ca assim:
1 void atribi_bigint ( bigint a, int n){
2 bool nega = false;
3 // inicia a com valor 0
4 init_bigint (a);
5 // testa se a e negativo
6 if(n <0){
7 // caso seja armazena esta informacao e transforma o numero em positivo
8 nega = true;
9 n*= -1;
10 }
11 // atribui os 4 bytes do inteiro nos 4 bytes menos significativos do bigint
12 a[TBITS -1] = n&0 xff;
13 a[TBITS -2] = (n > >8) &0 xff;
14 a[TBITS -3] = (n > >16) &0 xff;
15 a[TBITS -4] = (n > >24) &0 xff;
16 // caso o numero fosse inicialmente negativo , transforma o bigint em negativo
17 if( nega ){
18 neg_bigint (a);
19 }
20 }
4.2.18 append_int_bigint
Esta função recebe 2 parâmetros, o primeiro um bigint, o segundo um inteiro sem sinal, a idéia é concatenar os bits do bigint com os bits do inteiro. Pelo fato de ter o limite de tamanho do tipo bigint os 4 bytes mais signicativos deste serão descartados. Como ilustrado na tabela 4.3, ondea é a variável bigint e n é a variável inteira.
Tabela 4.3: Concatenação com descarte
a[0] a[1] ... a[TBITS-5] a[TBITS-4] a[TBITS-3] a[TBITS-2] a[TBITS-1]
a[4] a[5] ... a[TBITS-1] n[0] n[1] n[2] n[3]
Perceba que os bytes a[0], a[1], a[2], a[3]foram descartados.
O algoritmo para tal função funciona da seguinte forma: percorre-se o parâmetro bigint do byte 0, o mais signicativo, até o byte T BIT S−5 e para cada um deles será atribuído o valor do byte que está 4 posições a frente, assim na prática move-se todos os bytes 4 posições em direção ao lado mais signicativo. Depois apenas atribui-se nos 4 bytes menos signicativos os bytes do parâmetro inteiro inteiro.
O código ca assim:
1 void append_int_bigint ( bigint a, unsigned int n){
2 int i;
3 // move -se todos os bytes de a, 4 posicoes no sentido mais significativo
4 for(i=TBITS -32;i<TBITS -4;i++){
5 a[i] = a[i +4];
6 }
7 // atribuimos o valor de n nos bytes menos significativos de a
8 a[TBITS -4] = (n > >24) &0 xff;
9 a[TBITS -3] = (n > >16) &0 xff;
10 a[TBITS -2] = (n > >8) &0 xff;
11 a[TBITS -1] = (n)&0 xff;
12 }
4.2.19 srl1_bigint e sll1_bigint
Estas funções tem como objetivo mover todos os bits do parâmetro passado para elas uma posição à direita(lado mais signicativo) no caso da srl1_bigint ou a esquerda(lado menos signicativo) no caso da sll1_bigint.
No primeiro caso, em que se quer mover os bits para direita, percorre-se byte a byte do bigint, começando do mais signicativo, e para cada um é dado um shift 6 de 1 posição à direita, antes armazenando o bit que seria descartado.
Para o primeiro byte apenas opera-se o shift à direita, para os outros, logo depois de faze-lo, coloca-se o bit descartado no byte anterior no espaço 7obtido após o movimento.
Para o caso do sll1_bigint a idéia é a mesma, as alterações são: ao invés de para cada byte ser dado um shift a direita, é dado à esquerda, e percorre-se os bytes do bigint pelo byte menos signicativo. Assim será mostrado apenas o código referente ao srl1_bigint, visto que as alterações do outro código são triviais.
1 void srl1_bigint ( bigint a){
2 char out ,out2 ,aux;
3 int i;
4 out = 0;
5 // percorre cada byte de "a" a partir do byte mais significativo .
6 for(i=0;i< TBITS ;i++){
7 out2 = out;
8 out = a[i]<<7;// guarda o bit a ser descartado pelo shift
9 aux = a[i]>>1;// shift a direita de 1 posicao
10 //a sera a concatenacao do bit descartado
anteriormente e ele proprio dado um shift de 1 posicao a direita
11 a[i] = out2 |aux;
12 }
13 }
4.2.20 add_bigint e addi_bigint
Nas próximas funções serão implementadas as funções algébricas básicas, para estas deve-se dizer que os algoritmos usados estão descritos em [14], e especicamente os algo-ritmos de multiplicação e potenciação, foram retirados de [13]
A função add_bigint recebe 3 parâmetros, o primeiro, denominado de c, será onde será armazenado o resultado da soma, os outros dois, denominados de a e b, são os operandos da soma. Logo se tem que c=a+b. Para tal percorre-se byte a byte, a partir do menos signicativo e soma-se os bytes correspondentes de a e de b e de uma variável denominada carry, inicialmente zerada. Guarda-se a soma dos bytes em uma variável auxiliar short 8, onde o primeiro byte será posto no byte correspondente de c e o outro
6movimento lógico que signica mover todos os bits de uma variável tantas posições para algum lado.
7o shift automaticamente bota um bit 0 no bit que não tem antecessor, dizemos aqui que este é o
"espaço"obtido após o shift.
8inteiro de 2 bytes