Função de Hash

Uma ferramenta que cria impressões digitais para dados

🛠️ Tradução em andamento — esta página mostra o conteúdo básico; a versão integral será publicada em breve.
Diagrama mostrando dados sendo colocados em uma função de hash e uma impressão digital saindo do outro lado.

Uma função de hash é uma ferramenta de programação que cria impressões digitais para dados.

Ela recebe qualquer quantidade de dados, os embaralha e retorna um resultado curto e único para esses dados.

SHA-256 (Texto)

Faz o hash de uma string de texto usando a função de hash SHA-256.

Digite qualquer sequência de caracteres

0 caracteres
SHA-256
0 bytes

Isto é apenas um exemplo rápido da função de hash SHA-256. Ela faz o hash de texto (caracteres ASCII) em vez de bytes hexadecimais. Para fazer o hash de dados brutos reais do Bitcoin com SHA-256, use SHA-256 e HASH256.

SHA = Secure Hashing Algorithm (Algoritmo de Hash Seguro), 256 = 256 bits (o tamanho do resultado do hash).

O resultado da função de hash é só um monte de bytes. As letras e números que você vê são apenas bytes de dados representados por caracteres hexadecimais, que é tipicamente como as saídas das funções de hash são exibidas.

Termos técnicos

Diagrama mostrando os termos técnicos para a entrada e saída de uma função de hash.

Aqui estão alguns termos técnicos que aparecem de vez em quando:

  • Os dados que você insere na função de hash são chamados de "mensagem" ou "pré-imagem".
  • O resultado da função de hash é às vezes chamado de "digest" ou simplesmente "hash".

"Pré-imagem" é provavelmente o termo técnico mais estranho que você vai encontrar, mas ele se refere apenas a algum dado específico que você insere na função de hash.

Prefiro usar os termos "dados" e "hash", mas não se surpreenda se você encontrar os outros termos de vez em quando.

Propriedades

O que torna uma função de hash uma função de hash?

Existem algumas propriedades que separam uma função de hash básica de uma função de hash forte.

Função de Hash Básica

Existem algumas propriedades básicas das funções de hash que você provavelmente já notou:

  1. Você sempre obtém o mesmo resultado para os mesmos dados. Se você e outra pessoa inserirem os mesmos dados na mesma função de hash, ambos obterão o mesmo resultado. Isso é conhecido como ser determinística.
    Diagrama mostrando uma função de hash produzindo a mesma saída para a mesma entrada.
    Determinística
  2. Você obtém um resultado de tamanho fixo independentemente do tamanho dos dados. Uma função de hash pode receber qualquer quantidade de dados, e ela os embaralha e comprime para produzir um resultado (geralmente) mais curto. O tamanho do hash varia entre funções de hash, mas para o SHA-256 é de 256 bits (32 bytes).
    Diagrama mostrando uma função de hash produzindo uma saída de tamanho fixo independentemente do tamanho da entrada.
    Resultado de tamanho fixo
  3. Você obtém resultados drasticamente diferentes com pequenas mudanças nos dados. O que sai da função de hash parece aleatório. Mesmo a menor mudança nos dados que você insere na função de hash produzirá resultados completamente diferentes. Isso é conhecido como efeito avalanche.
    Diagrama mostrando uma função de hash produzindo saídas drasticamente diferentes para entradas ligeiramente diferentes.
    Efeito avalanche

Essas são as características óbvias que você esperaria de uma boa "máquina de impressões digitais".

Função de Hash Forte

(também conhecida como Função de Hash Criptográfica)

Existem algumas propriedades das funções de hash fortes (ex.: SHA-256) que você pode não ter notado:

  1. Uma função de hash forte é irreversível. Se eu lhe desse um resultado de hash, você não conseguiria descobrir os dados originais que usei para criá-lo. A única maneira de esperar encontrá-lo seria tentar diferentes entradas em uma busca de força bruta, o que seria computacionalmente inviável dado o enorme intervalo de saídas possíveis. De qualquer forma, esta propriedade de não ser capaz de trabalhar de trás para frente é conhecida como one-wayness (unidirecionalidade).
    Diagrama mostrando como você é incapaz de trabalhar de trás para frente a partir da saída de uma função de hash forte para calcular a entrada.
    Unidirecionalidade
  2. Cada dado deve ter seu próprio resultado único. Obviamente isso é tecnicamente impossível, pois existem combinações infinitas de dados. No entanto, uma função de hash segura deve tornar computacionalmente inviável encontrar dois dados diferentes que produzam o mesmo hash. Esta propriedade é conhecida como resistência a colisões.
    Diagrama mostrando como duas entradas diferentes em uma função de hash forte não terão a mesma saída.
    Resistência a colisões
  3. Você não pode controlar o resultado de uma função de hash forte. Não há como descobrir como construir uma entrada para lhe dar um resultado específico a partir de uma função de hash. Se você quer um resultado específico, você só pode continuar hasheando diferentes dados até obter o tipo de resultado que deseja. Esta propriedade é conhecida como resistência à pré-imagem.
    Diagrama mostrando como você não pode manipular a entrada de uma função de hash forte para controlar os resultados da saída.
    Resistência à pré-imagem

Uma função de hash é chamada de "função de hash criptográfica" se ela alcança essas 3 propriedades fortes.

Isso significa que ela é geralmente mais lenta que uma função de hash básica (embora ainda seja bem rápida no geral), mas também significa que pode ser confiável para ser imprevisível e produzir resultados únicos para diferentes dados. O que é uma característica importante quando se trata de criptografia.

Então, como você pode imaginar, o Bitcoin usa funções de hash criptográficas:

Termos técnicos

Isto é mais para minha própria referência, pois sempre esqueço o que cada um destes termos significa ao ler sobre funções de hash seguras em livros-texto.

De qualquer forma, em termos técnicos, uma "função de hash criptográfica" deve possuir as 3 propriedades chave a seguir:

Resistência à Pré-imagem
É difícil construir uma entrada que produza uma saída específica.
Diagrama mostrando resistência à pré-imagem de uma função de hash criptográfica.
Resistência à Segunda Pré-imagem (Resistência Fraca a Colisões)
Dados alguns dados e seu resultado de hash, é difícil encontrar outro dado que produza o mesmo hash. Isso é ocasionalmente chamado de resistência fraca a colisões.
Diagrama mostrando resistência à segunda pré-imagem de uma função de hash criptográfica.
Resistência a Colisões
É difícil encontrar quaisquer dois dados que produzam o mesmo hash. Isto é similar à propriedade anterior, mas enquanto na resistência à segunda pré-imagem você está preso a alguns dados iniciais e precisa encontrar outro dado que produza o mesmo resultado, na resistência a colisões você está livre para escolher quaisquer dois dados que produzam o mesmo resultado. Isto é portanto às vezes chamado de resistência forte a colisões.
Diagrama mostrando resistência a colisões de uma função de hash criptográfica.
  • Estes três termos parecem se confundir de vez em quando (especialmente porque resistência à segunda pré-imagem é uma forma de resistência a colisões).
  • Em outras palavras, você tem resistência à pré-imagem e dois tipos de resistência a colisões.

E o que é exatamente uma pré-imagem?

Pré-imagem (matemática) — O conjunto de argumentos de uma função correspondendo a um subconjunto particular do contradomínio.
thefreedictionary.com

Portanto, uma "pré-imagem" é algo que você coloca em uma função que mapeia para um resultado específico.

Bitcoin

Quais funções de hash o Bitcoin usa?

Existem cinco métodos para hashear dados no Bitcoin:

  1. HASH256 — SHA-256 duplo (mais comum)
  2. HASH160 — SHA-256 + RIPEMD-160
  3. SHA-256 — SHA-256 único
  4. HMAC-SHA512 — HMAC com SHA-512
  5. PBKDF2 — Password Based Key Derivation Function 2

No Bitcoin hasheamos bytes de dados. Então nas ferramentas abaixo, você precisa representar bytes usando caracteres hexadecimais (onde cada byte é formado por dois caracteres hex). Veja um erro comum ao hashear para mais detalhes.

HASH256

SHA-256(SHA-256(dados))

Se você está hasheando algo no Bitcoin, você está quase sempre usando HASH256.

Isto funciona colocando os dados através do SHA-256, e então pegando o resultado e colocando através do SHA-256 novamente.

Ícone Ferramenta HASH256

HASH256

SHA-256 dupla. Usada para fazer o hash de cabeçalhos de bloco, dados de transação e de praticamente qualquer coisa que precise ser hasheada no Bitcoin.

0 bytes
SHA-256
SHA-256

SHA-256(SHA-256(dados))

0 bytes

Você pode notar que os hashes que você obtém para dados de bloco e transação parecem estar ao contrário. Isto acontece porque hashes de bloco e transação estão na verdade em ordem reversa de bytes quando você os busca usando bitcoin-cli e em exploradores de blocos.

Este é o método principal para hashear dados no Bitcoin. Às vezes é chamado de "double-SHA256" ou "SHA-256d", mas no código geralmente é chamado de hash256 para encurtar.

Aqui estão alguns exemplos de onde você encontrará HASH256 sendo usado no Bitcoin:

Código

require 'digest'

def hash256(hex)
  # converter string hexadecimal para sequência de bytes primeiro
  binary = [hex].pack("H*") # H = hex string (highest byte first), * = multiple bytes

  # SHA-256 (primeira rodada)
  hash1 = Digest::SHA256.digest(binary)

  # SHA-256 (segunda rodada)
  hash2 = Digest::SHA256.digest(hash1)

  # converter de sequência de bytes de volta para hexadecimal
  hash256 = hash2.unpack("H*")[0]

  return hash256
end

puts hash256("aa") #=> e51600d48d2f72eb428e78733e01fbd6081b349528335bf21269362edfae185d

Por que hashear duas vezes?

Satoshi nunca mencionou por que escolheu double-SHA256 ao projetar o Bitcoin.

Não há uma razão oficial, mas acredita-se que Satoshi usou SHA-256 duplo para evitar ataques de extensão de comprimento (length extension attacks).

Os detalhes: se você usa SHA-256 único, dado H = SHA-256(m) e o comprimento de m, você pode calcular SHA-256(m || padding || extra) sem saber m. Isto não é um problema para hashes de bloco (a blockchain exige que você saiba o bloco), mas poderia causar problemas em aplicações como hashes de assinatura.

O duplo SHA-256 elimina este ataque porque a saída do primeiro SHA-256 (32 bytes) é hasheada novamente. O invasor não conhece o estado interno da segunda aplicação do SHA-256, portanto não pode calcular a extensão.

No entanto, se você estivesse projetando o Bitcoin hoje do zero, você poderia usar single SHA-256 com prefixo (SHA-256(tag || dados)) em vez de hashear duas vezes. Taproot (2021) faz exatamente isso para hashes de assinatura.

Eu acho que o duplo hash foi uma escolha de design questionável... SHA-256 já é resistente a extensão de comprimento, então isso não faz sentido... Talvez Satoshi estivesse seguindo cegamente o que o padrão dizia, mas é difícil saber.
Pieter Wuille, bitcoin.stackexchange.com

Se você estivesse projetando o Bitcoin do zero hoje, não haveria benefício em usar double-SHA256. Na verdade, atualizações recentes do Bitcoin agora favorecem o uso de SHA-256 único onde possível (ex.: hashes de script em P2WSH).

HASH160

RIPEMD-160(SHA-256(dados))

HASH160 é usado com pouca frequência no Bitcoin.

Isto funciona colocando os dados através do SHA-256, e então pegando o resultado e colocando através de outra função de hash chamada RIPEMD-160.

Ícone Ferramenta HASH160

HASH160

SHA-256 + RIPEMD-160. Usado para encurtar uma chave pública ou script antes de converter em um endereço.

Uma chave pública ou script, por exemplo

0 bytes
SHA-256
RIPEMD-160

RIPEMD-160(SHA-256(dados))

0 bytes

O HASH160 é usado em:

Atualizações do Bitcoin ao longo dos anos não fizeram mais uso do HASH160 ao hashear dados, e hoje ele é usado exclusivamente para criar hashes de chave pública e endereços de script (P2SH).

Código

require 'digest'

def hash160(data)
  # converter string hexadecimal para sequência de bytes primeiro
  binary = [data].pack("H*")

  # SHA-256
  sha256 = Digest::SHA256.digest(binary)

  # RIPEMD-160
  ripemd160 = Digest::RMD160.digest(sha256)

  # converter de sequência de bytes de volta para hexadecimal
  hash160 = ripemd160.unpack("H*").join

  return hash160
end

puts hash160("aa") #=> 58d179ca6112752d00dc9b89ea4f55a585195e26

Por que RIPEMD-160?

O RIPEMD-160 é usado para encurtar o hash de 32 bytes (SHA-256) para 20 bytes (RIPEMD-160):

Tamanho
SHA-256 32 bytes
RIPEMD-160 20 bytes

O tamanho menor do hash significa endereços mais curtos para os usuários. Então RIPEMD-160 é ideal para criar impressões digitais mais curtas (mas ainda seguras) dos hashes SHA-256.

Além disso, usar dois algoritmos de hash diferentes oferece resistência a colisões mesmo que um deles seja quebrado no futuro.

Quanto a por que Satoshi escolheu RIPEMD-160 em vez de SHA-1 (que também produz 20 bytes), ninguém sabe ao certo. O SHA-1 é mais conhecido, mas na época do lançamento do Bitcoin já havia preocupações com a segurança do SHA-1 (colisões foram demonstradas publicamente em 2017). O RIPEMD-160 era uma alternativa de 160 bits sem fraquezas conhecidas.

No fim das contas, RIPEMD-160 é uma boa escolha para uso como função de hash de 160 bits, e continua sendo usado em endereços legados do Bitcoin até hoje.

A abordagem de combinar funções de hash também é usada para aumentar a segurança: se a função de hash RIPEMD-160 for quebrada no futuro, ainda há SHA-256 para fornecer proteção, e vice-versa.
Christof Paar, Understanding Cryptography
RIPEMD-160 foi escolhido porque produz o hash mais curto possível que ainda fornece segurança comparável ao SHA-256 (ou SHA-256 duplo)... Não se sabe se o RIPEMD-160 é mais ou menos seguro que o SHA-256, mas é considerado seguro o suficiente.
liamzebedee, bitcoin.stackexchange.com

O uso de SHA-256 + RIPEMD-160 ajuda a prevenir contra ataques de extensão de comprimento (length extension attacks) também (mesmo que isto seja novamente desnecessário).

SHA-256

SHA-256(dados)

A função de hash primária. Recebe dados e produz 32 bytes. É aqui que você coloca os dados através do SHA-256 uma vez. Nada de especial desta vez.

Ícone Ferramenta SHA-256

SHA-256

SHA-256 simples. Faz o hash dos bytes de dados usando a função de hash SHA-256.

0 bytes
SHA-256
0 bytes

Esta ferramenta só aceita bytes de dados na forma de caracteres hexadecimais. Isto é diferente da ferramenta SHA-256 (Texto) no topo da página, que aceita quaisquer dados de texto, mas essa é apenas uma ferramenta de exemplo e não é a forma como os dados são hasheados no Bitcoin.

O SHA-256 único é usado principalmente em:

Mudanças mais recentes no Bitcoin começaram a usar uma única rodada de SHA-256 (em vez de HASH256) em alguns lugares, como nas assinaturas Taproot (hashes de tag).

No entanto, não é nem de longe tão prevalente quanto HASH256. Então, como regra geral, se você está hasheando algo no Bitcoin, é mais provável que seja HASH256 e não SHA-256 único.

Código

require 'digest'

def sha256(hex)
  # converter string hexadecimal para sequência de bytes primeiro
  binary = [hex].pack("H*")

  # SHA-256 (único)
  hash = Digest::SHA256.digest(binary)

  # converter de sequência de bytes de volta para hexadecimal
  sha256 = hash.unpack("H*")[0]

  return sha256
end

puts sha256("aa") #=> bceef655b5a034911f1c3718ce056531b45ef03b4c7b1f15629e867294011a7d

HMAC-SHA512

HMAC com SHA-512

Usamos HMAC-SHA512 quando queremos hashear alguns dados com uma chave secreta adicional.

HMAC é um tipo de hash que usa uma chave junto com os dados. O SHA-512 é outra função de hash da família SHA-2 que produz 64 bytes.

Então SHA-512 é o algoritmo de hash real, e HMAC é o método para combinar os dois dados usando aquele algoritmo de hash.

Ícone Ferramenta HMAC-SHA512

HMAC-SHA512

Se usa al derivar chaves estendidas.

semente ou (chave privada/pública + índice de 4 bytes)

0 bytes

"Bitcoin seed" ou chain code

0 bytes
HMAC-SHA512

HMAC-SHA512(dados, chave)

0 bytes

O Bitcoin usa HMAC-SHA512 ao criar chaves estendidas em carteiras HD:

SHA-512 é usado dentro do HMAC ao criar chaves estendidas porque produz 64 bytes de resultado de hash, o que significa que você pode dividir o resultado para obter uma nova chave privada (os primeiros 32 bytes) e um novo chain code (os últimos 32 bytes) para formar a chave estendida filha.

  • Em criptografia em geral, um HMAC é usado quando você quer hashear alguns dados, mas também quer hasheá-los com uma chave secreta adicional para que você só possa obter o mesmo resultado se tiver tanto os dados originais quanto a chave secreta.
  • Usar um HMAC protege contra ataques de extensão de comprimento, o que significa que é um método mais seguro do que simplesmente anexar a chave secreta aos dados e hasheá-los dessa forma.

Código

require 'openssl'

# Dados de exemplo
data = "67f93560761e20617de26e0cb84f7234aaf373ed2e66295c3d7397e6d7ebe882ea396d5d293808b0defd7edd2babd4c091ad942e6a9351e6d075a29d4df872af"
key = "Bitcoin seed"

# HMAC-SHA512
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, key, [data].pack("H*"))
puts hmac #=> f79bb0d317b310b261a55a8ab393b4c8a1aba6fa4d08aef379caba502d5d67f9463223aac10fb13f291a1bc76bc26003d98da661cb76df61e750c139826dea8b

PBKDF2

Password Based Key Derivation Function 2

Usamos PBKDF2 quando queremos hashear dados múltiplas vezes.

Ícone Ferramenta PBKDF2

PBKDF2

(e uma passphrase opcional).>Cria a seed de uma carteira HD a partir de uma

frase mnemônica

passphrase

(a sal deve começar com o prefixo "mnemonic")
PBKDF2
  • iterações: 2048
  • algoritmo: HMAC-SHA512
  • tamanho: 64 bytes

PBKDF2(senha, sal, iterações, algoritmo, tamanho)

0 bytes

Nunca introduza sua frase mnemônica em um site, nem use uma frase mnemônica gerada por um site. Os sites podem guardar facilmente a seed e usá-la para roubar todos os seus bitcoins.

Nunca insira sua frase de seed mnemônica em um site, ou use uma frase de seed gerada por um site. Sites podem facilmente salvar a frase de seed em texto puro e usá-la para roubar seus bitcoins.

O fato de PBKDF2 usar múltiplas iterações para hashear significa que é intencionalmente lento, o que torna mais difícil realizar ataques de força bruta.

PBKDF2 não é uma função de hash por si só, mas um método que aplica repetidamente HMAC-SHA512 para tornar computacionalmente caro transformar uma senha em uma chave.

No Bitcoin, o PBKDF2 é usado no BIP39 para transformar sua frase de seed mnemônica (mais um salt opcional) na seed de 64 bytes da qual todas as chaves da sua carteira são derivadas.

O Bitcoin usa 2.048 iterações de PBKDF2 para converter uma frase mnemônica (e passphrase opcional) em uma seed. Isto torna mais demorado tentar quebrar a frase mnemônica e/ou passphrase de outra pessoa.

Código

require 'openssl'

# Dados de exemplo
mnemonic = "punch shock entire north file identify"
passphrase = ""

# Preparar dados para PBKDF2
password = mnemonic
salt = "mnemonic#{passphrase}" # "mnemonic" é sempre usado no salt com passphrase opcional anexada
iterations = 2048
keylength = 64
digest = OpenSSL::Digest::SHA512.new

# PBKDF2
result = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, keylength, digest)
seed = result.unpack("H*")[0] # converter para string hexadecimal
puts seed #=> e1ca8d8539fb054eda16c35dcff74c5f88202b88cb03f2824193f4e6c5e87dd2e24a0edb218901c3e71e900d95e9573d9ffbf870b242e927682e381d109ae882

Uso

Onde o hashing é usado no Bitcoin?

Funções de hash são uma ferramenta versátil de propósito geral na programação, e são usadas liberalmente em todo o Bitcoin.

Aqui estão os exemplos mais importantes:

Mineração

Diagrama mostrando um hash de bloco precisando ficar abaixo de um valor alvo para ser adicionado à blockchain.

Este é o uso mais famoso da função de hash no Bitcoin.

Um cabeçalho de bloco é hasheado, e o hash de bloco resultante é interpretado como um inteiro. Este inteiro deve estar abaixo de um certo valor de target para o bloco ser considerado "válido" ou "minerado".

O fato de o resultado da função de hash ser incontrolável (resistência à pré-imagem) e drasticamente diferente para cada valor de nonce (efeito avalanche) cria uma loteria em toda a rede, onde ninguém está no controle de quando o próximo bloco será minerado.

Blockchain

Diagrama mostrando como hashes de bloco são usados para criar uma cadeia de blocos.

Cada bloco na blockchain referencia o hash do bloco anterior. Isto conecta todos os blocos da blockchain, e impede que alguém altere o conteúdo de um bloco em qualquer ponto da cadeia.

Qualquer alteração em um bloco mais abaixo na cadeia mudará seu hash, e portanto os blocos acima dele não estarão mais conectados a ele e não farão mais parte da cadeia mais longa.

TXID

Diagrama mostrando um TXID sendo criado ao hashear dados de transação.

Os dados de cada transação individual são hasheados para criar um TXID (Transaction ID). Isto cria um número de referência único para cada transação (determinística).

Isto permite que você referencie moedas criadas em transações anteriores como entradas para gastar em transações futuras, além de poder pesquisar transações em um explorador de blocos.

O fato de ser difícil encontrar dois dados que produzam o mesmo hash (resistência a colisões) significa que cada transação pode ter seu próprio número de referência curto e único.

Raiz Merkle

Diagrama mostrando uma raiz merkle sendo criada ao hashear TXIDs juntos em pares e depois sendo comprometida no cabeçalho do bloco.

Cada cabeçalho de bloco inclui uma impressão digital para todos os dados de transação incluídos no bloco.

Esta impressão digital é chamada de raiz merkle, e é basicamente todos os TXIDs hasheados juntos em uma estrutura de árvore.

O hashing permite "comprometer" todos os dados de transação no cabeçalho do bloco (determinística). Portanto, se alguém alterar dados de transação no bloco, eles não corresponderão mais à impressão digital no cabeçalho (resistência a colisões), e o bloco modificado será inválido.

Checksum

Diagrama mostrando um checksum sendo criado ao hashear dados e pegar os primeiros 4 bytes do resultado.

Alguns checksums são simplesmente o hash truncado de alguns dados.

Estes checksums são agrupados com os dados para permitir verificar se os dados foram inseridos corretamente. Por exemplo, um checksum é incluído no final de um endereço bitcoin legado, então se você digitar uma parte do endereço incorretamente, os dados não corresponderão ao checksum (ou vice-versa) (efeito avalanche), e o erro pode ser detectado antes de você fazer a transação.

Checksums também são usados em rede para ajudar a garantir que o conteúdo de uma mensagem não foi perdido durante o trânsito (determinística).

Hash de Chave Pública

Diagrama mostrando uma chave pública sendo encurtada ao hasheá-la.

Uma chave pública tem 33 ou 65 bytes de tamanho. No entanto, antes de ser convertida em um endereço, ela passa por uma função de hash para ser encurtada para um hash de chave pública de 20 bytes.

Isto permite criar endereços ligeiramente mais curtos do que se você não tivesse hasheado a chave pública antes (resultado de tamanho fixo).

Chaves Estendidas

Diagrama mostrando chaves filhas sendo derivadas ao hashear uma chave estendida anterior.

Carteiras Hierárquicas Determinísticas permitem criar múltiplas chaves privadas a partir de uma única seed.

Cada chave privada estendida é criada ao hashear a chave privada estendida anterior, o que lhe dá uma chave privada completamente nova, única e independente para usar (resistência a colisões).

Isto ilustra a segurança das funções de hash, pois cada novo resultado da função de hash é confiável o suficiente para ser usado como uma chave privada, porque você não pode trabalhar de trás para frente (resistência à pré-imagem) para descobrir uma chave privada anterior a partir de outra.

Assinatura de Transações

Ao assinar uma transação, você na verdade assina um hash dos dados da transação.

Hashear dados cria uma impressão digital encurtada (resultado de tamanho fixo), e é mais eficiente assinar o hash de uma transação (isto é, 32 bytes) do que os dados completos da transação (ex.: 250+ bytes). O hash que você assina também é único para cada dado de transação (resistência a colisões), então a assinatura resultante não pode ser reutilizada dentro de uma transação diferente.

A razão pela qual as funções de hash foram inventadas em primeiro lugar foi para melhorar a eficiência da assinatura de mensagens longas.

Notas

Como funcionam as funções de hash?

Excelente pergunta, que bom que você perguntou.

A esta altura eu normalmente diria que isso está "fora do escopo deste artigo" e então distrairia você com muita terminologia técnica e gestos de mão.

Então eu fiz este vídeo sobre como o SHA-256 funciona.

Mas como eu digo, uma função de hash apenas embaralha e comprime os bits subjacentes (os 1s e 0s) dos dados de computador. E isso é tudo que você realmente precisa saber.

Um erro comum ao hashear

Um erro comum ao hashear dados no Bitcoin é inserir strings na função de hash, e não as sequências de bytes subjacentes que essas strings realmente representam.

Por exemplo, digamos que temos a string hexadecimal ab.

Se inserirmos isto diretamente na função de hash como uma string, sua linguagem de programação vai na verdade enviar a codificação ASCII de cada um destes caracteres para a função de hash, que se parece com isto em binário:

"ab" = 01100001 01100010
sha256(0110000101100010) = fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603

Byte → ASCII

Converta entre um byte e um caractere ASCII.

Funções de hash operam sobre os 1s e 0s subjacentes dos dados do computador, que é ao que estou me referindo aqui com a palavra "binário".

No entanto, para o Bitcoin, os dados são normalmente representados no formato hexadecimal, e não como texto.

Então se você tem os bytes hexadecimais ab, você precisa converter esta string hexadecimal em seus bytes reais antes de inseri-los na função de hash:

0xab = 10101011
sha256(10101011) = 087d80f7f182dd44f184aa86ca34488853ebcc04f0c60d5294919a466b463831

Bytes

Digite uma string hexadecimal e veja-a dividida em bytes individuais.

Bytes

É por isso que normalmente precisamos "empacotar" (pack) nossas strings hexadecimais em bytes antes de hashear. A maioria das linguagens de programação tem funções que permitem fazer isto. Por exemplo:

Ruby

hex = "ab"
binary = [hex].pack("H*") # H = hex string (highest byte first), * = multiple bytes

PHP

$hex = "ab";
$binary = pack("H*", $hex);

Você provavelmente verá um monte de texto ininteligível se imprimir estes valores binários convertidos diretamente. Isto faz sentido, porque sua linguagem de programação converte estes dados binários de volta para ASCII ao imprimi-los, e estes dados binários provavelmente se referem a caracteres estranhos na tabela ASCII.

Em resumo, lembre-se de que funções de hash recebem dados binários como entrada, então precisamos ser específicos sobre os dados binários que queremos inserir.

Se você esquecer de converter suas strings hexadecimais para seus bytes correspondentes antes, sua linguagem de programação assumirá que você quer enviar a representação binária dos caracteres na string, e isto produzirá um resultado de hash completamente diferente do esperado.

Este é de longe o problema mais comum que as pessoas têm ao hashear dados no Bitcoin pela primeira vez. Então se você não está obtendo os resultados de hash corretos, este é provavelmente o seu erro.

E eu deveria saber, eu mesmo já fiz faço isso.

No fim das contas, todos os dados do Bitcoin são apenas um monte de bytes. Nós usamos sua representação em string hexadecimal por conveniência ao compartilhar e exibir em sites.

Resumo

Uma função de hash é o canivete suíço da caixa de ferramentas do programador.

Você vai hashear coisas frequentemente ao trabalhar com Bitcoin, então vale a pena se familiarizar com elas em qualquer linguagem de programação que você estiver usando.

Satoshi entendia muito bem suas propriedades, e as utilizou para vários propósitos ao desenvolver o Bitcoin. Mas sua decisão mais engenhosa foi alavancar a imprevisibilidade das funções de hash para criar uma loteria em toda a rede, que é o que sustenta o mecanismo revolucionário da mineração e da tecnologia blockchain.

Então isso só mostra que se você entende as propriedades fundamentais de uma ferramenta, você pode encontrar maneiras novas e interessantes de usá-la.

Por último, se você quiser uma definição técnica adequada de uma função de hash:

Funções de hash criptográficas mapeiam strings de entrada de comprimento arbitrário (ou muito grande) para strings de saída de comprimento fixo curto.
Bart Preneel, The First 30 Years of Cryptographic Hash Functions

Mas eu prefiro pensar nelas como máquinas de criar impressões digitais para dados.