Hash da Chave Pública
Uma chave pública encurtada
Um hash da chave pública é o hash de uma chave pública. Então, nenhuma surpresa por aqui.
Fazer o hash produz uma versão encurtada da chave pública, o que, no fim das contas, significa que você pode criar um endereço mais curto e mais fácil de compartilhar com outras pessoas.
Esse hash da chave pública é usado dentro dos scripts de travamento P2PKH (Pay To Public Key Hash) e P2WPKH (Pay To Witness Public Key Hash), que são os scripts de travamento mais comuns usados ao enviar bitcoins para um endereço através de uma carteira de bitcoin.
Criando
Como você cria um hash da chave pública?
Um hash da chave pública é o HASH160 de uma chave pública.
Chave Pública
HASH160
Por exemplo, se esta é a sua chave pública:
02e3af28965693b9ce1228f9d468149b831d6a0540b25e8a9900f71372c11fb277
Este é o hash da chave pública:
1e51fcdc14be9a148bb0aaec9197eb47c83776fb
Código
# Função HASH160
def hash160(data)
# Converte os dados para binário antes de fazer o hash
binary = [data].pack("H*")
# SHA-256 primeiro
sha256 = Digest::SHA256.digest(binary)
# RIPEMD-160 depois
ripemd160 = Digest::RMD160.digest(sha256)
# Converte de volta de binário para hexadecimal
hash160 = ripemd160.unpack("H*").join
return hash160
end
# Chave Pública
publickey = "02e3af28965693b9ce1228f9d468149b831d6a0540b25e8a9900f71372c11fb277"
# Hash da Chave Pública
puts hash160(publickey) #=> 1e51fcdc14be9a148bb0aaec9197eb47c83776fb RIPEMD-160
O RIPEMD-160 produz um digest de 20 bytes (160 bits).
Isso é menor que a chave pública original (65 bytes não comprimida, 33 bytes comprimida).
Isso significa que o endereço que acabamos criando a partir dele conterá menos caracteres do que uma chave pública completa, tornando-o mais fácil de repassar.
SHA-256
RIPEMD-160
Uso
Como os hashes de chave pública são usados no Bitcoin?
A principal razão para fazer o hash de uma chave pública é encurtá-la antes de convertê-la em um endereço.
Endereço (Base58)
Então, quando alguém envia bitcoins para o nosso endereço usando uma carteira, na verdade essa pessoa está travando uma saída ao nosso hash da chave pública, em vez da nossa chave pública completa:
Quando vamos gastar esses bitcoins em uma transação futura, fornecemos então a chave pública original junto com uma assinatura dentro do código de destravamento da entrada:
Quando um nó valida essa transação, ele vai:
- Verificar se a chave pública resulta no hash da chave pública que está dentro do cadeado.
- Verificar a assinatura contra a chave pública normalmente.
Então, basicamente, usar um hash da chave pública adiciona um passo extra na hora de travar e destravar bitcoins, mas o que ganhamos em troca é poder usar endereços mais curtos.
Localização
Onde você encontra hashes de chave pública?
Um hash da chave pública pode ser encontrado dentro de transações que usam os scripts de travamento P2PKH e P2WPKH.
Aqui estão alguns exemplos de hashes de chave pública dentro de transações brutas na blockchain.
P2PKH
Pay To Public Key Hash
Um hash da chave pública pode ser encontrado dentro do ScriptPubKey de um P2PKH (Pay To Public Key Hash):
Bruto
0100000002f60b5e96f09422354ab150b0e506c4bffedaf20216d30059cc5a3061b4c83dff000000004a493046022100e26d9ff76a07d68369e5782be3f8532d25ecc8add58ee256da6c550b52e8006b022100b4431f5a9a4dcb51cbdcaae935218c0ae4cfc8aa903fe4e5bac4c208290b7d5d01fffffffff7272ef43189f5553c2baea50f59cde99b3220fd518884d932016d055895b62d000000004a493046022100a2ab7cdc5b67aca032899ea1b262f6e8181060f5a34ee667a82dac9c7b7db4c3022100911bc945c4b435df8227466433e56899fbb65833e4853683ecaa12ee840d16bf01ffffffff0100e40b54020000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00000000 Separado
{
"version": "01000000",
"inputcount": "02",
"inputs": [
{
"txid": "f60b5e96f09422354ab150b0e506c4bffedaf20216d30059cc5a3061b4c83dff",
"vout": "00000000",
"scriptsigsize": "4a",
"scriptsig": "493046022100e26d9ff76a07d68369e5782be3f8532d25ecc8add58ee256da6c550b52e8006b022100b4431f5a9a4dcb51cbdcaae935218c0ae4cfc8aa903fe4e5bac4c208290b7d5d01",
"sequence": "ffffffff"
},
{
"txid": "f7272ef43189f5553c2baea50f59cde99b3220fd518884d932016d055895b62d",
"vout": "00000000",
"scriptsigsize": "4a",
"scriptsig": "493046022100a2ab7cdc5b67aca032899ea1b262f6e8181060f5a34ee667a82dac9c7b7db4c3022100911bc945c4b435df8227466433e56899fbb65833e4853683ecaa12ee840d16bf01",
"sequence": "ffffffff"
}
],
"outputcount": "01",
"outputs": [
{
"amount": "00e40b5402000000",
"scriptpubkeysize": "19",
"scriptpubkey": "76a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac"
}
],
"locktime": "00000000"
} Transação: 6f7cf9580f1c2dfb3c4d5d043cdbb128c640e3f20161245aa7372e9666168516
A chave pública completa é então revelada no ScriptSig quando essa saída é usada como uma entrada em uma transação de gasto:
Bruto
01000000030dd7891efbf67da47c651531db8aab3144ed7a524e4ae1e30b773525e27ddd7b000000004948304502206f6a68710a51f77e5a1fa4d1037a23a76723724a51fd54710949e0189ee02dfa022100dad3454ade12fe84f3818e14c41ec2e02bbb154dd3136a094cdf86f67ebbe0b601ffffffff16851666962e37a75a246101f2e340c628b1db3c045d4d3cfb2d1c0f58f97c6f000000008b48304502203f004eeed0cef2715643e2f25a27a28f3c578e94c7f0f6a4df104e7d163f7f8f022100b8b248c1cfd8f77a0365107a9511d759b7544d979dd152a955c867afac0ef7860141044d05240cfbd8a2786eda9dadd520c1609b8593ff8641018d57703d02ba687cf2f187f0cee2221c3afb1b5ff7888caced2423916b61444666ca1216f26181398cffffffffffda5d38e91fd9a0d92872d51f83cb746fc7bf5d3ff13402f8d0d5ed60ddc79c0000000049483045022100b6fd43f2fa16e092678283f64d2e08fb2070b4af2b3ddfb9ca3c5e238288acaa02200c5a28e0a4fc1a540f6eeb30ccc4788050eae46964fe33ccb4500c3de1320c2501ffffffff02c0c62d00000000001976a91417194e1bd175fb5b1b2a1f9d221f6f5c29e1928388ac00c817a8040000001976a91465bda9b05f7e9a8f96a7f4ba0996a877708ef90888ac00000000 Separado
{
"version": "01000000",
"inputcount": "03",
"inputs": [
{
"txid": "0dd7891efbf67da47c651531db8aab3144ed7a524e4ae1e30b773525e27ddd7b",
"vout": "00000000",
"scriptsigsize": "49",
"scriptsig": "48304502206f6a68710a51f77e5a1fa4d1037a23a76723724a51fd54710949e0189ee02dfa022100dad3454ade12fe84f3818e14c41ec2e02bbb154dd3136a094cdf86f67ebbe0b601",
"sequence": "ffffffff"
},
{
"txid": "16851666962e37a75a246101f2e340c628b1db3c045d4d3cfb2d1c0f58f97c6f",
"vout": "00000000",
"scriptsigsize": "8b",
"scriptsig": "48304502203f004eeed0cef2715643e2f25a27a28f3c578e94c7f0f6a4df104e7d163f7f8f022100b8b248c1cfd8f77a0365107a9511d759b7544d979dd152a955c867afac0ef7860141044d05240cfbd8a2786eda9dadd520c1609b8593ff8641018d57703d02ba687cf2f187f0cee2221c3afb1b5ff7888caced2423916b61444666ca1216f26181398c",
"sequence": "ffffffff"
},
{
"txid": "ffda5d38e91fd9a0d92872d51f83cb746fc7bf5d3ff13402f8d0d5ed60ddc79c",
"vout": "00000000",
"scriptsigsize": "49",
"scriptsig": "483045022100b6fd43f2fa16e092678283f64d2e08fb2070b4af2b3ddfb9ca3c5e238288acaa02200c5a28e0a4fc1a540f6eeb30ccc4788050eae46964fe33ccb4500c3de1320c2501",
"sequence": "ffffffff"
}
],
"outputcount": "02",
"outputs": [
{
"amount": "c0c62d0000000000",
"scriptpubkeysize": "19",
"scriptpubkey": "76a91417194e1bd175fb5b1b2a1f9d221f6f5c29e1928388ac"
},
{
"amount": "00c817a804000000",
"scriptpubkeysize": "19",
"scriptpubkey": "76a91465bda9b05f7e9a8f96a7f4ba0996a877708ef90888ac"
}
],
"locktime": "00000000"
} Transação: 12e753ef5cc30925a6eee2c457aa7f53022443ca013ea81882a6b59b69e342a6
P2WPKH
Pay To Witness Public Key Hash
Um hash da chave pública pode ser encontrado dentro do ScriptPubKey de um P2WPKH (Pay To Witness Public Key Hash):
Bruto
020000000001016972546966be990440a0665b73d0f4c3c942592d1f64d1033717aaa3e2c2ec913300000000ffffffff024087100000000000160014841b80d2cc75f5345c482af96294d04fdd66b2b760e31600000000001600142e8734f8e263e516d47fcaa2dfe1bd01e0dc935802473044022042e5e3ed2a41214ae864634b6fde33ca2ff312f3d89d6aa3e14c026d50d8ed3202206c38dcd0432a0724490356fbf599cdae40e334c3667a9253f8f4cc57cf3c4480012103f465315805ed271eb972e43d84d2a9e19494d10151d9f6adb32b8534bfd764ab00000000 Separado
{
"version": "02000000",
"marker": "00",
"flag": "01",
"inputcount": "01",
"inputs": [
{
"txid": "6972546966be990440a0665b73d0f4c3c942592d1f64d1033717aaa3e2c2ec91",
"vout": "33000000",
"scriptsigsize": "00",
"scriptsig": "",
"sequence": "ffffffff"
}
],
"outputcount": "02",
"outputs": [
{
"amount": "4087100000000000",
"scriptpubkeysize": "16",
"scriptpubkey": "0014841b80d2cc75f5345c482af96294d04fdd66b2b7"
},
{
"amount": "60e3160000000000",
"scriptpubkeysize": "16",
"scriptpubkey": "00142e8734f8e263e516d47fcaa2dfe1bd01e0dc9358"
}
],
"witness": [
{
"stackitems": "02",
"0": {
"size": "47",
"item": "3044022042e5e3ed2a41214ae864634b6fde33ca2ff312f3d89d6aa3e14c026d50d8ed3202206c38dcd0432a0724490356fbf599cdae40e334c3667a9253f8f4cc57cf3c448001"
},
"1": {
"size": "21",
"item": "03f465315805ed271eb972e43d84d2a9e19494d10151d9f6adb32b8534bfd764ab"
}
}
],
"locktime": "00000000"
} Transação: c178d8dacdfb989f9d4fa45828ed188cd54a0414d625c3e61e75c5e3ac15a83a
Nota: esta transação também tem uma segunda saída P2WPKH contendo outro hash da chave pública, mas destaquei apenas o primeiro como exemplo.
A chave pública completa é então revelada na Testemunha quando essa saída é usada como uma entrada em uma transação de gasto:
Bruto
020000000001013aa815ace3c5751ee6c325d614044ad58c18ed2858a44f9d9f98fbcddad878c10000000000ffffffff01344d10000000000016001430cd68883f558464ec7939d9f960956422018f0702483045022100c7fb3bd38bdceb315a28a0793d85f31e4e1d9983122b4a5de741d6ddca5caf8202207b2821abd7a1a2157a9d5e69d2fdba3502b0a96be809c34981f8445555bdafdb012103f465315805ed271eb972e43d84d2a9e19494d10151d9f6adb32b8534bfd764ab00000000 Separado
{
"version": "02000000",
"marker": "00",
"flag": "01",
"inputcount": "01",
"inputs": [
{
"txid": "3aa815ace3c5751ee6c325d614044ad58c18ed2858a44f9d9f98fbcddad878c1",
"vout": "00000000",
"scriptsigsize": "00",
"scriptsig": "",
"sequence": "ffffffff"
}
],
"outputcount": "01",
"outputs": [
{
"amount": "344d100000000000",
"scriptpubkeysize": "16",
"scriptpubkey": "001430cd68883f558464ec7939d9f960956422018f07"
}
],
"witness": [
{
"stackitems": "02",
"0": {
"size": "48",
"item": "3045022100c7fb3bd38bdceb315a28a0793d85f31e4e1d9983122b4a5de741d6ddca5caf8202207b2821abd7a1a2157a9d5e69d2fdba3502b0a96be809c34981f8445555bdafdb01"
},
"1": {
"size": "21",
"item": "03f465315805ed271eb972e43d84d2a9e19494d10151d9f6adb32b8534bfd764ab"
}
}
],
"locktime": "00000000"
} Transação: 1674761a2b5cb6c7ea39ef58483433e8735e732f5d5815c9ef90523a91ed34a6
História
Por que usamos hashes de chave pública, afinal?
Porque foi assim que Satoshi decidiu fazer os endereços funcionarem na primeira versão do Bitcoin.
Acredito que isso provavelmente se deveu ao fato de Satoshi não saber que era possível usar chaves públicas comprimidas (33 bytes em vez de 65 bytes), de modo que fazer o hash da chave pública era uma forma de criar um endereço bem mais curto que você pudesse compartilhar com outras pessoas.
Então talvez, se Satoshi conhecesse a existência das chaves públicas comprimidas, teríamos endereços para o script de travamento P2PK, mais simples, e o P2PKH não seria necessário.
Para deixar os endereços de Bitcoin curtos, eles são um hash da chave pública, e não a própria chave pública.
É só para obter endereços mais curtos. Chaves públicas comuns têm 65 bytes de comprimento, o que é longo demais para ser conveniente. Chaves públicas comprimidas têm 33 bytes e poderiam, em tese, ser usadas no lugar dos hashes, embora sejam um pouco mais longas que os hashes de 20 bytes. Também parece provável que Satoshi não conhecesse as chaves públicas comprimidas ou não estivesse confortável em usá-las quando projetou o Bitcoin.
Teoria Alternativa: Segurança Extra
Uma teoria alternativa é que fazer o hash da chave pública fornece uma camada extra de segurança.
Por exemplo, se entregamos nossa chave pública diretamente quando queremos receber bitcoins, a "única" coisa que protege você de atacantes que tentam chegar à sua chave privada é a curva elíptica.
No entanto, se entregamos um hash da chave pública, os atacantes teriam que quebrar tanto a RIPEMD-160 quanto a SHA-256 — duas funções de hash — bem como lidar com o problema da curva elíptica.
Então, basicamente, enquanto você tem bitcoins parados na blockchain, as funções de hash funcionam como obstáculos extras que os atacantes precisam transpor para tentar chegar à nossa chave privada (e roubar nossos bitcoins).
Então a curva elíptica não é proteção suficiente?
Na verdade, é uma proteção excelente.
Graças às propriedades da multiplicação de curva elíptica, é incrivelmente difícil trabalhar de trás para frente de uma chave pública para uma chave privada. Isso é conhecido como o "problema do logaritmo discreto da curva elíptica".
No entanto, se por algum milagre esse problema for resolvido, ainda há duas funções de hash diferentes para servir de reserva na proteção da nossa chave privada.
Mas você ainda não entrega a sua chave pública?
Sim. Mas, neste sistema, a sua chave pública só é entregue no último momento (quando você vai gastar seus bitcoins).
A teoria é que, se alguém quiser quebrar a sua chave privada, terá uma pequena quantidade de tempo para fazê-lo antes que a sua transação se propague pela rede e seja minerada em um bloco. Portanto, isso é mais seguro do que deixar a sua chave pública bruta exposta desde o início.
No entanto, essa teoria não é popular com todo mundo:
Acho que essa vantagem de manter a chave pública em segredo é, na melhor das hipóteses, muito marginal, e mais comumente uma ilusão. Praticamente qualquer coisa interessante além de pagamentos simples (multisig, Lightning, ...) envolve compartilhar suas chaves públicas com partes não totalmente confiáveis. A segurança do Bitcoin depende de o ECDSA ser inquebrável mesmo quando as chaves públicas são reveladas; na minha opinião, o argumento de que "as chaves públicas só ficam expostas brevemente é uma vantagem" é culto à carga (cargo cult).
Resumo
Certamente seria mais fácil se não usássemos hashes de chave pública e simplesmente usássemos chaves públicas em vez disso.
Isso significaria que poderíamos usar apenas o script de travamento mais simples, o P2PK, em vez de termos que usar o passo extra envolvido no P2PKH e no P2WPKH, onde primeiro travamos uma saída a um hash da chave pública e só depois fornecemos a chave pública original.
No entanto, Satoshi pensava nos usuários ao desenvolver o bitcoin, e ele achava que encurtar a chave pública o máximo possível antes de convertê-la em um endereço seria mais amigável, e é por isso que continuamos a usar hashes de chave pública por todo o Bitcoin até hoje.
Então, ter scripts de travamento um pouco mais complexos ao usar hashes de chave pública em vez de apenas chaves públicas é o preço que pagamos por endereços mais curtos. É um pouco desnecessário em retrospecto, mas se você conseguiu projetar e programar um sistema revolucionário e descentralizado de pagamentos eletrônicos completamente sozinho, acho que pode ser perdoado por fazer o hash de algo quando não precisava de fato.
Em conclusão, criar um hash da chave pública é bastante simples e, quando você entende a razão por trás de encurtar a chave pública em primeiro lugar, o design do P2PKH e do P2WPKH faz muito mais sentido.