Como os computadores podem calcular matemática exponencial sem erros de estouro?

32

Estudando alguns métodos de criptografia / descriptografia RSA, encontrei este artigo: Um exemplo do algoritmo RSA

É necessário que isto decrippte esta mensagem

Oresultadototalde é tão grande, para uma máquina de 64 bits / 32 bits, não acredito pode ter um valor tão grande em um registro. Como o computador faz isso sem um estouro?

This question was a Super User Question of the Week.
Read the blog entry for more details or contribute to the blog yourself

    
por Kit Ho 23.07.2012 / 17:26

5 respostas

40

Como a operação de módulo inteiro é um homomorfismo de anel ( Wikipedia ) de ℤ - > ℤ / nℤ,

(X * Y) mod N = (X mod N) * (Y mod N) mod N

Você mesmo pode verificar isso com um pouco de álgebra simples. (Observe que o% final mod no lado direito aparece devido à definição de multiplicação em um anel modular.)

Os computadores usam esse truque para calcular exponenciais em anéis modulares sem precisar computar um grande número de dígitos.

               / 1                            I = 0,
               |
(X^I) mod N = <  (X * (X^(I-1) mod N)) mod N  I odd,
               |
               \ (X^(I/2) mod N)^2 mod N      I even & I /= 0.

Em forma algorítmica,

-- compute X^I mod N
function expmod(X, I, N)
    if I is zero
        return 1
    elif I is odd
        return (expmod(X, I-1, N) * X) mod N
    else
        Y <- expmod(X, I/2, N)
        return (Y*Y) mod N
    end if
end function

Você pode usar isso para calcular (855^2753) mod 3233 com apenas registros de 16 bits, se quiser.

No entanto, os valores de X e N no RSA são muito maiores, muito grandes para caber em um registrador. Um módulo é tipicamente 1024-4096 bits! Assim, você pode fazer com que um computador faça a multiplicação do modo "longo", da mesma forma que fazemos a multiplicação à mão. Apenas em vez de usar dígitos 0-9, o computador usará "words" 0-2 16 -1 ou algo parecido. (Usando apenas 16 bits significa que podemos multiplicar dois números de 16 bits e obter o resultado completo de 32 bits sem recorrer à linguagem assembly. Na linguagem de montagem, geralmente é muito fácil obter o resultado total de 64 bits ou para um computador de 64 bits , o resultado completo de 128 bits.)

-- Multiply two bigints by each other
function mul(uint16 X[N], uint16 Y[N]):
    Z <- new array uint16[N*2]
    for I in 1..N
        -- C is the "carry"
        C <- 0
        -- Add Y[1..N] * X[I] to Z
        for J in 1..N
            T <- X[I] * Y[J] + C + Z[I + J - 1]
            Z[I + J - 1] <- T & 0xffff
            C <- T >> 16
        end
        -- Keep adding the "carry"
        for J in (I+N)..(N*2)
            T <- C + Z[J]
            Z[J] <- T & 0xffff
            C <- T >> 16
        end
    end
    return Z
end
-- footnote: I wrote this off the top of my head
-- so, who knows what kind of errors it might have

Isso multiplicará X por Y em uma quantidade de tempo aproximadamente igual ao número de palavras em X multiplicado pelo número de palavras em Y. Isso é chamado tempo O (N 2 ). Se você olhar o algoritmo acima e separá-lo, é a mesma "multiplicação longa" que eles ensinam na escola. Você não tem tabelas de tempo memorizadas com 10 dígitos, mas você ainda pode multiplicar 1.926.348 x 8.192.004 se você se sentar e resolver isso.

Multiplicação longa:

    1,234
  x 5,678
---------
    9,872
   86,38
  740,4
6,170
---------
7,006,652

Na verdade, existem alguns algoritmos mais rápidos para multiplicar ( Wikipedia ), como o método de Fourier rápido de Strassen, e alguns métodos mais simples que fazem adição e subtração extras, mas menos multiplicação, e assim terminam mais rápido no geral. Bibliotecas numéricas como o GMP são capazes de selecionar algoritmos diferentes com base em quão grandes são os números: a transformada de Fourier é apenas a mais rápida para os números maiores, números menores usam algoritmos mais simples.

    
por 23.07.2012 / 22:05
9
A resposta é simplesmente que eles não podem, não por conta própria. De fato, se você pegar o conceito de uma máquina de x bits, então há um número limitado de números que podem ser representados por um número limitado de bits, assim como há um número limitado de números que podem ser representados por 2 dígitos em o sistema decimal.

Dito isto, a representação em computador de números muito grandes é um grande componente do campo da criptografia. Há muitas maneiras de representar números muito grandes em um computador, cada um tão variado quanto o seguinte.

Cada um destes métodos tem diferentes vantagens e desvantagens, e embora eu não possa listar todos os métodos aqui, apresentarei um muito simples.

Suponha que um inteiro só possa conter valores de 0 a 99. Como alguém poderia representar o número 100? Isso pode parecer impossível no começo, mas isso é porque consideramos apenas uma única variável. Se eu tivesse um inteiro chamado units e um chamado hundreds , eu poderia facilmente representar 100: hundreds = 1; units = 0; . Eu poderia facilmente representar um número maior, como 9223: hundreds = 92; units = 23 .

Embora este seja um método fácil, pode-se argumentar que é muito ineficiente. Como a maioria dos algoritmos que ultrapassam os limites do que um computador pode fazer, geralmente é um puxão-o-guerra entre poder (representar grandes números) e eficiência (recuperação rápida / armazenamento). Como eu disse anteriormente, há muitas maneiras de representar grandes números em computadores; apenas encontre um método e experimente-o!

Espero que isso tenha respondido sua pergunta!

Leitura adicional: Este artigo e isso pode ser útil para mais informações.

    
por 23.07.2012 / 17:38
3

A maneira que isto pode ser feito (existem maneiras muito mais rápidas envolvendo repetição de quadratura e similares) é multiplicando, e após cada multiplicação, o módulo. Contanto que o módulo ao quadrado seja menor que 2 ^ 32 (ou 2 ^ 64), isso nunca terá um estouro.

    
por 23.07.2012 / 19:36
3

Da mesma forma que você pode.

Eu vou adivinhar que você não sabe de improviso o que é 342 * 189. Mas você sabe os seguintes fatos:

9 * 2 = 18
9 * 4 = 36
9 * 3 = 27
8 * 2 = 16
8 * 4 = 32
8 * 3 = 24
1 * 2 = 2
1 * 4 = 4
1 * 3 = 3

18 + 360 + 2700 + 160 + 3200 + 24000 + 200 + 4000 + 30000 = 64638

Conhecendo esses fatos simples e tendo aprendido uma técnica para manipulá-los, você pode fazer uma aritmética que de outra forma não conseguiria.

Da mesma forma, um computador que não pode lidar com mais de 64 bits de matemática por vez pode facilmente dividir os problemas maiores em pedaços menores, fazer esses pedaços menores e juntá-los novamente para formar a resposta problema maior e anteriormente irrespondível.

    
por 23.07.2012 / 23:40
0

No que diz respeito a adição e subtração, muitas CPUs têm um "carry bit" que é definido se a operação aritmética tiver transbordado. Portanto, se um resultado exigir 8 bytes para armazenar, e a CPU é de 32 bits (o que equivale a 4 bytes de 8 bits), ele pode fazer duas operações de adição, primeiro na "palavra baixa" e depois na "palavra alta". com o carry, cuidando do transbordamento. Necessário limpar o bit de transporte primeiro. Esta é uma das razões pelas quais as CPUs bit mais altas aumentam o desempenho, porque isso não precisa ser feito tanto.

Claro que isso é da minha experiência limitada de montador com CPUs de 8 bits. Eu não sei como o carry funciona com CPUs modernas com instruções de multiplicação e divisão. As CPUs RISC não-Intel também podem se comportar de maneira diferente.

Eu não sei muito sobre matemática de ponto flutuante, mas basicamente os bytes representam um número fixo de lugares, mas não lugares específicos. É por isso que é chamado ponto "flutuante". Assim, por exemplo, o número 34459234 consumiria aproximadamente o mesmo espaço de memória que 3.4459234 ou 3.4459234E + 20 (que é 3.4459234 x 10 ^ 20).

    
por 03.04.2013 / 22:14