Chave Privada WIF
Wallet Import Format
Uma chave privada WIF (Wallet Import Format) é um formato no estilo de endereço para uma chave privada.
É usada ao exportar e importar chaves privadas entre carteiras de bitcoin.
É principalmente uma codificação Base58 da chave privada, mas também inclui alguns dados extras úteis e um checksum.
Uma chave privada WIF é só outra forma de representar a sua chave privada. Se você tem uma chave privada WIF, sempre pode convertê-la de volta para uma chave privada bruta.
Nunca revele a sua chave privada WIF. Uma chave privada WIF não é criptografada de forma alguma, então você precisa protegê-la tanto quanto protegeria uma chave privada bruta.
Benefícios
Por que usamos chaves privadas WIF?
O principal benefício da WIF é que ela é uma codificação Base58 de uma chave privada, então é mais curta e mais fácil de copiar.
Há alguns outros benefícios:
- Identificação. Uma chave privada WIF sempre começa com K, L ou 5. Isso torna um pouco mais fácil identificá-las como chaves privadas, em vez de strings hexadecimais de 32 bytes de aparência aleatória. Pessoalmente, acho que esse é o benefício mais útil de converter uma chave privada para WIF.
- Byte de compressão. Uma chave privada WIF contém um byte que indica se a chave privada está sendo usada para criar uma chave pública comprimida ou não comprimida. Assim, quando você importa a chave privada WIF em uma carteira, a carteira pode varrer a blockchain procurando moedas travadas a um endereço, em vez de ter que procurar por uma escolha de dois endereços possíveis. Isso não é tremendamente útil, já que quase todo mundo usa chaves públicas comprimidas de qualquer forma, e não demoraria muito para varrer a blockchain procurando dois tipos de chaves públicas/endereços, mas ajuda um pouco.
- Checksum. Uma chave privada WIF também contém um checksum, o que significa que você pode detectar facilmente se ela foi inserida incorretamente ao importar em uma carteira. Isso não vai ajudar a consertar nada se você a anotou errado em primeiro lugar, mas é uma pequena conveniência.
Codificação
Converter uma chave privada para WIF
Converter uma chave privada bruta para WIF é bem simples:
- Comece com uma chave privada hexadecimal de 32 bytes.
- Adicione um byte de versão no início. Isso indica se a chave privada está sendo usada em mainnet ou testnet:
80= mainnetef= testnet
- Adicione um byte de compressão no fim (opcional). Isso indica se a chave privada está sendo usada para criar uma chave pública comprimida ou não comprimida:
01= chave pública comprimida (mais comum)- (nenhum byte) = chave pública não comprimida
- Crie um checksum a partir dos dados acima e adicione-o ao fim.
- Um checksum no Bitcoin são os primeiros 4 bytes do Hash256 de alguns dados.
- Converta todos os dados acima para Base58.
E aí você tem uma chave privada WIF.
Por exemplo:
1 byte 32 bytes 1 byte (opcional) 4 bytes
byte de versão chave privada byte de compressão checksum
↓ ↓ ↓ ↓
--|--------------------------------------------------------------|--|------|
data = 80ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db20166557e53
base58encode(data) = L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6 Não use esta chave privada. Isto é apenas um exemplo. Você vai perder suas moedas se usá-la.
Chave Privada
Checksum
Base58
Código
Ruby
# ---------
# Funções
# ---------
require 'digest'
# função hash256 (checksums usam hash256)
def hash256(hex)
binary = [hex].pack("H*")
hash1 = Digest::SHA256.digest(binary)
hash2 = Digest::SHA256.digest(hash1)
result = hash2.unpack("H*")[0]
return result
end
# função checksum
def checksum(hex)
hash = hash256(hex) # passa os dados pelo SHA256 duas vezes
return hash[0...8] # retorna os primeiros 4 bytes (8 caracteres)
end
# função de codificação base58
def base58_encode(hex)
chars = %w[
1 2 3 4 5 6 7 8 9
A B C D E F G H J K L M N P Q R S T U V W X Y Z
a b c d e f g h i j k m n o p q r s t u v w x y z
]
base = chars.length
i = hex.to_i(16)
buffer = String.new
while i > 0
remainder = i % base
i = i / base
buffer = chars[remainder] + buffer
end
# adiciona '1's no início conforme o número de bytes zero à esquerda
leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
("1"*leading_zero_bytes) + buffer
end
# ----------
# WIF Encode
# ----------
# 1. comece com uma chave privada hexadecimal de 32 bytes
privatekey = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2" # exemplo, não use
# 2. adicione o prefixo (80 = mainnet, ef = testnet)
data = "80" + privatekey
# 3. adicione o byte de compressão (opcional)
data = data + "01"
# 4. adicione o checksum
data = data + checksum(data)
# 5. codifique em base58
wif = base58_encode(data)
# resultado
puts wif #=> L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6 Python
import hashlib # função de hash SHA-256
# 1. comece com uma chave privada hexadecimal de 32 bytes
privatekey = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2" # exemplo, não use
# 2. adicione o prefixo (80 = mainnet, ef = testnet)
data = "80" + privatekey
# 3. adicione o byte de compressão (opcional)
data = data + "01"
# 4. adicione o checksum (hash256 de prefixo+dados, depois pegue os primeiros 4 bytes)
hash1 = hashlib.sha256(bytes.fromhex(data)).digest() # converte a string hex em bytes brutos antes de fazer o hash
hash2 = hashlib.sha256(hash1).hexdigest() # retorna o resultado como string hex
checksum = hash2[0:8] # o checksum são os primeiros 4 bytes
data = data + checksum # adiciona o checksum ao fim dos dados
# 5. defina os caracteres base58
characters = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
# 6. converta os dados hex em inteiro para podermos convertê-los em base58
i = int(data, 16)
# 7. cria um buffer para guardar a string base58
base58 = ''
# 8. divide o inteiro por 58 repetidamente e pega o resto para descobrir cada caractere base58
while i > 0:
i, remainder = divmod(i, 58) # divide e pega o resto
base58 = characters[remainder] + base58 # usa o resto para obter o caractere e o adiciona no início da string
# nota: na codificação base58 normal você converte bytes 00 à esquerda em hex para 1s em base58, mas bytes zero à esquerda não aparecem ao criar uma chave privada WIF, então pulamos esse passo aqui
# 9. mostra o resultado (chave privada WIF)
print(base58) #=> L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6 - Na mainnet, uma WIF deve começar com K, L ou 5.
- Na testnet, uma WIF deve começar com c ou 9.
Decodificação
Converter de WIF para uma chave privada
É bem fácil extrair uma chave privada bruta de uma WIF:
- Comece com a chave privada WIF de 51 ou 52 caracteres.
- Decodifique-a de Base58.
- Isso vai lhe dar 37 ou 38 bytes hexadecimais.
- A chave privada está contida nos bytes 1 a 33 (ou seja, ignore os primeiros 2 caracteres e depois pegue os 64 caracteres seguintes).
Por exemplo:
address = L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6
base58decode(address) = 80ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db20166557e53
--|--------------------------------------------------------------|--|------|
↑ ↑ ↑ ↑
byte de versão chave privada byte de compressão checksum
1 byte 32 bytes 1 byte (opcional) 4 bytes Não use esta chave privada. Isto é apenas um exemplo. Você vai perder suas moedas se usá-la.
Chave Privada WIF
Base58
Você também pode extrair dados adicionais da chave privada WIF (se precisar):
- O primeiro byte é o byte de versão, que é usado para determinar se a chave privada deve ser usada em mainnet ou testnet.
80= mainnetef= testnet
- O byte opcional após a chave privada é o byte de compressão, que é usado para determinar se a chave privada foi usada para criar uma chave pública comprimida ou não comprimida. Se ele não estiver lá (ou seja, você tem apenas 37 bytes depois de decodificar de Base58), isso indica uma chave pública não comprimida.
01= chave pública comprimida (mais comum)- (nenhum byte) = chave pública não comprimida
- Os últimos 4 bytes são o checksum, que permite verificar se a WIF é válida ou não.
Código
Ruby
# ---------
# Funções
# ---------
# função de decodificação base58
def base58_decode(base58_string)
# caracteres base58
base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
# define o valor inteiro inicial
integer = 0
# percorre cada caractere da string, da direita para a esquerda
base58_string.reverse.each_char.with_index do |char, index|
# obtém a posição do caractere na lista de caracteres base58
char_index = base58_chars.index(char)
# verifica se é um caractere base58 válido
if !char_index
puts "Não é um caractere Base58 válido: #{char}"
exit
end
# multiplica a posição do caractere por uma potência de 58 (crescente conforme o índice de cada caractere)
integer += char_index * (58**index)
end
# converte o inteiro em uma string hexadecimal
hexadecimal = integer.to_s(16)
# completa para garantir um número par de bytes
if hexadecimal.bytesize.odd?
hexdecimal = "0" + hexadecimal
end
# ignora strings base58 vazias
if hexadecimal == "00"
hexadecimal = ""
end
# conta o número de '1's à esquerda
leading_zero_bytes = (base58_string.match(/^([1]+)/) ? $1 : '').size
# converte os '1's à esquerda em '00's à esquerda
if leading_zero_bytes > 0
hexadecimal = ("00" * leading_zero_bytes) + hexadecimal
end
# retorna os bytes hexadecimais
return hexadecimal
end
# ----------
# WIF Decode
# ----------
# 1. comece com uma chave privada WIF
wif = "L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6" # exemplo, não use
# 2. decodifique de base58
data = base58_decode(wif)
# 3. extraia a chave privada (bytes 1 a 33)
privatekey = data[2...66]
# resultado
puts privatekey #=> ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2 Python
# 1. comece com uma chave privada WIF
wif = "L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6" # exemplo, não use
# 2. defina os caracteres base58
characters = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
# 3. converte a string base58 em inteiro
# 3a. inverte a string base58 para trabalharmos da direita para a esquerda
wif = wif[::-1]
# 3b. define o valor inicial
sum = 0
# 3c. percorre cada caractere da chave privada WIF (a string base58)
for i, c in enumerate(wif):
# 3d. obtém o índice deste caractere a partir da lista de caracteres base58
for index, base58_character in enumerate(characters): # forma simples de achar a chave na lista, mas funciona
if (c == base58_character):
character_index = index
break # para de procurar
# 3e. multiplica o índice do caractere por uma potência de 58 (aumentando a potência conforme a posição do caractere na string base58) e soma ao total
sum += character_index * (58**i)
# 4. converte o inteiro em hexadecimal
hexadecimal = hex(sum)[2:] # remove o prefixo 0x usando [2:]
# nota: na decodificação base58 normal você converte 1s à esquerda em base58 para bytes 00 à esquerda em hex, mas chaves privadas WIF nunca começam com 1, então pulamos esse passo aqui
# 5. extrai a chave privada (ignora o prefixo, o byte de compressão e o checksum)
privatekey = hexadecimal[2:66]
# 6. completa a chave privada para que sempre apareça com 32 bytes (64 caracteres hexadecimais)
privatekey = privatekey.zfill(64) # zfill completa com zeros no início até o comprimento desejado
# 6. mostra o resultado
print(privatekey) #=> ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2 Uso
Onde as chaves privadas WIF são usadas no Bitcoin?
Como mencionado, a WIF é usada quando você está exportando ou importando chaves privadas entre carteiras.
Alguns exemplos de carteiras populares que usam WIF são:
Pela minha experiência, é mais comum que as carteiras exijam que você trabalhe com chaves privadas WIF em vez de permitir importar/exportar chaves privadas brutas.
História
Quando as chaves privadas WIF foram introduzidas no Bitcoin?
Pieter Wuille criou o formato WIF em 2011 para importar e exportar chaves privadas via Bitcoin Core.
https://github.com/bitcoin/bitcoin/pull/574
Agradecimentos a Murch e Ava Chow pela ajuda com a origem das chaves privadas WIF.
Resumo
A WIF foi projetada apenas para ser uma codificação mais amigável de uma chave privada.
Você consegue identificar uma chave privada WIF porque ela é uma string Base58 e começa com K ou L. Em raras ocasiões ela começa com 5 (se, por algum motivo, você estiver trabalhando com chaves públicas não comprimidas). Por exemplo:
Estes são exemplos estáticos de chaves privadas WIF. Não as use.
- Ky1BY5QkB6xb3iQQjJQmVcvqc6mkLBaZTW1xCWpf91aFGBh1kyQ7 (para uma chave pública comprimida na mainnet)
- L1Rw26ZuhBqguYDSi77zAxyfHUZ2H1JAQunf3TEbxyfcBDjUvBse (para uma chave pública comprimida na mainnet)
- 5JKZUnxc5G8toCqErCQpHiUYff3t7GvBd2my4bf6odejtZAy7hG (para uma chave pública não comprimida na mainnet)
Então, se você está trabalhando na mainnet com chaves públicas comprimidas como uma pessoa normal, procure o K ou o L no início.
Pela minha experiência, pode ser um pouco chato ter que converter entre chave privada bruta e WIF quando você quer importar uma chave privada em uma carteira, mas é prática comum as carteiras trabalharem com WIF em vez de chaves privadas brutas, então é melhor você se acostumar.
Se você trabalha com chaves privadas brutas localmente (e ocasionalmente quer importá-las/exportá-las), é uma boa ideia escrever o seu próprio codificador/decodificador WIF. A última coisa que você quer fazer é confiar suas chaves privadas a um site ou ferramenta, e não é difícil criar você mesmo uma ferramenta que converte entre WIF e uma chave privada bruta.
Isso vai economizar tempo e estresse mais adiante. Confie em mim.
Porque, como diz aquele velho ditado famoso: "Not Your Own WIF Tool, Not Your Coins" (Se a ferramenta WIF não é sua, as moedas não são suas).
Ou algo assim.
Recursos
Ferramentas
- WIF Decode, WIF Encode — Ferramentas de linha de comando práticas para converter entre uma chave privada hexadecimal e WIF no seu próprio computador.