Chave Pública
Um ponto na curva elíptica
Uma chave pública é a parte "pública" de um par de chave privada e chave pública.
Ela é calculada a partir da chave privada, o que significa que há uma conexão matemática entre as duas.
A chave pública é usada para que você possa "receber" bitcoins. Ao fazer uma transação, uma saída pode ser travada a uma chave pública, de modo que só o dono da chave privada consiga destravá-la e gastá-la em uma transação futura.
Criando
Como você cria uma chave pública?
Uma chave pública é criada por meio de multiplicação de curva elíptica.
Em termos técnicos, você multiplica um ponto inicial (o ponto gerador) na curva elíptica secp256k1 pela chave privada (um número aleatório), e isso resulta em um novo conjunto de coordenadas x e y, que é a chave pública.
Chave Privada
Multiplicação na Curva Elíptica
Então uma chave pública é apenas um ponto na curva elíptica.
Não vou entediá-lo com os detalhes da matemática de curvas elípticas neste momento, porque você não precisa entendê-la para conseguir criar suas próprias chaves públicas. Mas você pode se aprofundar nela se quiser, e a matemática não é tão difícil quanto parece.
Código
# exemplo de chave privada
private_key = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2"
# --------------------------
# Parâmetros da curva Secp256k1
# --------------------------
# y^2 = x^3 + ax + b
$a = 0
$b = 7 # usando variáveis globais por conveniência
# módulo primo
$p = 2 ** 256 - 2 ** 32 - 2 ** 9 - 2 ** 8 - 2 ** 7 - 2 ** 6 - 2 ** 4 - 1
# número de pontos na curva
$n = 115792089237316195423570985008687907852837564279074904382605163141518161494337
# ponto gerador (o ponto inicial na curva usado para todos os cálculos)
$g = {
x: 55066263022277343669578718895168534326250603453777594175500187360389116729240,
y: 32670510020758816978083085130507043184471273380659243275938904335757337482424,
}
# --------------------------
# Matemática de Curva Elíptica
# --------------------------
# Inverso Modular - O Ruby não tem uma função embutida para encontrar inversos modulares, então aqui vai uma usando o algoritmo de Euclides estendido.
def modinv(a, m = $p)
m_orig = m # guarda o módulo original
a = a % m if a < 0 # garante que a é positivo
y_prev = 0
y = 1
while a > 1
q = m / a
y_before = y # guarda o valor atual de y
y = y_prev - q * y # calcula o novo valor de y
y_prev = y_before # define o y anterior como o y antigo
a_before = a # guarda o valor atual de a
a = m % a # calcula o novo valor de a
m = a_before # define m como o a antigo
end
return y % m_orig
end
# Dobrar - Soma um ponto da curva a ele mesmo.
def double(point)
# inclinação = (3x^2 + a) / 2y
slope = ((3 * point[:x] ** 2) * modinv((2 * point[:y]))) % $p # usa o inverso modular para fazer a "divisão"
# novo x = inclinação^2 - 2x
x = (slope ** 2 - (2 * point[:x])) % $p
# novo y = inclinação * (x - novo x) * y
y = (slope * (point[:x] - x) - point[:y]) % $p
# retorna as coordenadas x, y do ponto
return { x: x, y: y }
end
# Somar - Soma dois pontos.
def add(point1, point2)
# dobra se os dois pontos forem iguais
return double(point1) if point1 == point2
# inclinação = (y1 - y2) / (x1 - x2)
slope = ((point1[:y] - point2[:y]) * modinv(point1[:x] - point2[:x])) % $p
# novo x = inclinação^2 - x1 - x2
x = (slope ** 2 - point1[:x] - point2[:x]) % $p
# novo y = inclinação * (x1 - novo x) - y1
y = ((slope * (point1[:x] - x)) - point1[:y]) % $p
# retorna as coordenadas x, y do ponto
return { x: x, y: y }
end
# Multiplicar - Usa as operações de dobrar e somar para multiplicar rapidamente um ponto por um inteiro (ex.: uma chave privada).
def multiply(k, point = $g) # multiplica o ponto gerador por padrão
# cria uma cópia do ponto inicial (para uso na soma mais adiante)
current = point
# converte o inteiro para sua representação binária (para uso no algoritmo de dobrar e somar)
binary = k.to_s(2)
# algoritmo de dobrar e somar para multiplicação rápida
binary.split("").drop(1).each do |char| # ignora o primeiro caractere binário
# 0 = dobrar
current = double(current)
# 1 = dobrar e somar
if char == "1"
current = add(current, point)
end
end
# retorna o ponto final
return current
end
# -------------------------
# Chave Privada Para Chave Pública
# -------------------------
# converte a chave privada para um inteiro
k = private_key.to_i(16)
# multiplica o ponto gerador por essa chave privada
point = multiply(k, $g) # este ponto é a chave pública
# converte os valores x e y deste ponto para hexadecimal
x = point[:x].to_s(16).rjust(64, "0")
y = point[:y].to_s(16).rjust(64, "0")
# formato de chave pública não comprimida (pouco usado hoje em dia, só mostrando como fica)
public_key_uncompressed = "04" + x + y
# formato de chave pública comprimida (todo valor x tem um y que pode ser um de dois pontos possíveis)
if (point[:y] % 2 == 0)
prefix = "02" # se y é par
else
prefix = "03" # se y é ímpar
end
public_key_compressed = prefix + x # usa apenas a coordenada x completa
# -------
# Resultados
# -------
puts private_key #=> ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2
puts public_key_compressed #=> 02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737 Bibliotecas
Na maioria das linguagens você pode usar uma biblioteca de curva elíptica já existente para ajudar a criar chaves públicas (em vez de ter que programar a matemática você mesmo). Por exemplo:
require 'ecdsa' # sudo gem install ecdsa
# Esta chave privada é só um exemplo
privatekey = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2"
# Multiplicação de curva elíptica
group = ECDSA::Group::Secp256k1 # Seleciona a curva usada no Bitcoin
point = group.generator.multiply_by_scalar(privatekey.to_i(16)) # Multiplica por inteiro (não por hex)
# Converte o ponto da chave pública para uma chave pública hexadecimal comprimida
publickey = ECDSA::Format::PointOctetString.encode(point, compression: true).unpack("H*").join
puts publickey Conceitos básicos da curva elíptica
O uso da multiplicação de curva elíptica dá uma conexão matemática da sua chave privada para a sua chave pública.
Ela também tem duas propriedades importantes:
1. Não se sabe como trabalhar de trás para frente para obter a chave privada.
Você pode ir para frente usando a multiplicação de curva elíptica, mas não dá para fazer a matemática para voltar.
Isso significa que há uma conexão matemática indo da sua chave privada para a sua chave pública, mas ninguém consegue usar sua chave pública para descobrir qual é a sua chave privada.
Portanto, você pode divulgar sua chave pública e, ao mesmo tempo, manter sua chave privada em segredo.
2. Você pode provar que tem a chave privada sem revelá-la.
Basicamente, usando um pouco mais de matemática de curvas elípticas, você pode criar uma assinatura digital que prova que você tem a chave privada correspondente a uma chave pública, sem nunca ter que revelar sua chave privada de verdade.
É como dizer que você tem a senha de uma conta, mas sem ter que mostrar a ninguém sua senha de verdade para provar isso.
Isso é graças à mágica da matemática de curvas elípticas.
Formatos
Como é uma chave pública?
Uma chave pública é apenas uma coordenada x e uma coordenada y, então, no fim das contas, são só dois números de 256 bits muito grandes:
x: 81591541406288143274758265124625798440200740391102527151086648448953253267255
y: 64573953342291915951744135406509773051817879333910826118626860448948679381492 No entanto, ao exibir uma chave pública, normalmente começamos convertendo esses números em dois valores hexadecimais de 32 bytes:
x: b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737
y: 8ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4 Em seguida, concatenamos essas coordenadas x-y e adicionamos um prefixo 02, 03 ou 04 para indicar se estamos usando uma chave pública comprimida ou não comprimida:
chave pública (não comprimida): 04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4
chave pública (comprimida): 02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737 Chave pública não comprimida (legada)
Uma chave pública não comprimida tem 65 bytes de comprimento e contém as coordenadas x e y completas. Ela tem um byte de prefixo 04 para indicar que é uma chave pública não comprimida.
Por exemplo:
x: b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737
y: 8ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4
chave pública (não comprimida): 04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4 As chaves públicas não comprimidas eram usadas nas primeiras versões do bitcoin, antes de descobrirmos que poderíamos usar chaves públicas comprimidas de 33 bytes, mais curtas.
Então não há motivo para usar chaves públicas não comprimidas hoje em dia, a menos que você realmente queira ou precise por algum motivo.
Você não pode usar chaves públicas não comprimidas dentro dos scripts de travamento modernos P2WPKH ou P2WSH. Porém, você ainda pode usá-las em scripts de travamento legados, como P2PK, P2PKH, P2SH e P2MS.
Chave pública comprimida
Uma chave pública comprimida tem 33 bytes de comprimento. Ela contém a coordenada x completa e um prefixo para indicar se a coordenada y é par ou ímpar.
02= y é par03= y é ímpar
x: b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737
y: 8ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4
chave pública (comprimida): 02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737 Veja bem, devido à estrutura da curva elíptica, quando você calcula a chave pública a coordenada y só pode ser um de dois valores possíveis. Então, em vez de armazenar a coordenada y completa, só precisamos indicar qual dos dois valores possíveis é a coordenada y.
E acontece que a coordenada y será sempre par ou ímpar.
Você deve usar chaves públicas comprimidas por padrão. Elas são mais curtas (o que economiza espaço dentro dos dados brutos da transação) e você evita problemas de compatibilidade com scripts de travamento modernos (ex.: P2WPKH e P2WSH só permitem usar chaves públicas comprimidas).
Descomprimir a chave pública
Você pode descomprimir uma chave pública comprimida resolvendo a equação da curva y2 = x3 + 7.
Isso vai lhe dar os dois valores possíveis de y para a chave não comprimida. Você pode então usar o prefixo da chave comprimida para determinar qual valor de y usar.
# Chave pública comprimida
compressed = "02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737"
# Separa a chave comprimida em prefixo e coordenada x
prefix = compressed[0..1] #=> 02
x = compressed[2..-1] #=> b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737
# Converte a coordenada x de string hexadecimal para inteiro
x = x.to_i(16)
# Parâmetros da curva Secp256k1
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f # corpo primo
# Calcula os valores de y usando a equação da curva y^2 = x^3 + 7
y_sq = (x**3 + 7) % p # tudo é módulo p
# A Secp256k1 é escolhida de uma forma especial para que a raiz quadrada de y seja y^((p+1)/4)
y = y_sq.pow((p+1)/4, p) # usa exponenciação modular
# Usa o prefixo para selecionar o valor correto de y
# * prefixo 02 = y é par
# * prefixo 03 = y é ímpar
if (prefix == "02" && y % 2 != 0) # se o prefixo é 02 e y não é par, usa o outro valor de y
y = (p - y) % p
end
if (prefix == "03" && y % 2 == 0) # se o prefixo é 03 e y é par, usa o outro valor de y
y = (p - y) % p
end
# Constrói a chave pública não comprimida
x = x.to_s(16).rjust(64, "0") # converte para hex e garante que tem 32 bytes (64 caracteres)
y = y.to_s(16).rjust(64, "0")
uncompressed = "04" + x + y
# Resultado
puts uncompressed #=> 04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4 Existem dois valores possíveis de y por causa da raiz quadrada usada para resolver a equação. Isso ocorre porque a raiz quadrada de qualquer número tem duas respostas possíveis (ex.: √16=+4 ou -4).
Uso
Como as chaves públicas são usadas no Bitcoin?
Uma chave pública é usada quando você quer "receber" bitcoins.
Quando alguém lhe envia bitcoins em uma transação, essa pessoa coloca sua chave pública dentro do cadeado em cima de uma das saídas. Isso efetivamente "trava" aquela saída à sua chave pública, e ela só pode ser destravada usando a chave privada para criar uma assinatura que prova que você é o dono da chave pública.
Isso porque há uma conexão matemática entre a chave privada e a chave pública, e as assinaturas que você gera usando a chave privada também terão uma conexão matemática com a chave pública. Essa conexão matemática entre a chave pública e a assinatura é o bastante para "destravar" a saída e gastá-la mais tarde.
Esta é uma explicação simplificada. No mundo real, a chave pública é primeiro convertida em um endereço antes de ser compartilhada com outras pessoas. No entanto, o mecanismo subjacente é o mesmo.
Os seguintes scripts de travamento travam saídas diretamente a uma chave pública:
Os seguintes scripts de travamento também normalmente contêm uma chave pública:
Localização
Onde você encontra chaves públicas?
Chaves públicas podem ser encontradas dentro do ScriptPubKey ou do ScriptSig de transações brutas.
A chave pública estará em um local diferente dependendo do tipo de script de travamento colocado em uma saída. Estes são alguns exemplos de locais típicos de chaves públicas dentro da blockchain:
P2PK
Pay To Public Key
A chave pública de um P2PK fica dentro do ScriptPubKey, na saída:
Bruto
01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804233fa04e028b12ffffffff0130490b2a010000004341047eda6bd04fb27cab6e7c28c99b94977f073e912f25d1ff7165d9c95cd9bbe6da7e7ad7f2acb09e0ced91705f7616af53bee51a238b7dc527f2be0aa60469d140ac00000000 Separado
{
"version": "01000000",
"inputcount": "01",
"inputs": [
{
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": "ffffffff",
"scriptsigsize": "08",
"scriptsig": "04233fa04e028b12",
"sequence": "ffffffff"
}
],
"outputcount": "01",
"outputs": [
{
"amount": "30490b2a01000000",
"scriptpubkeysize": "43",
"scriptpubkey": "41047eda6bd04fb27cab6e7c28c99b94977f073e912f25d1ff7165d9c95cd9bbe6da7e7ad7f2acb09e0ced91705f7616af53bee51a238b7dc527f2be0aa60469d140ac"
}
],
"locktime": "00000000"
} Transação: 18a16d322b235f636ab90e62e79a9f20a0b9c14e8da51e9dc0974f99f82ee444
Nota: este script de travamento P2PK contém uma chave pública não comprimida.
O P2PK é o script de travamento mais simples para travar uma saída a uma chave pública, pois o script de travamento contém a chave pública diretamente.
Estes scripts de travamento P2PK são bem menos comuns que os mais populares P2PKH e P2WPKH. Esses scripts P2PK são encontrados com mais frequência dentro de transações coinbase antigas, entre 2009 e 2011.
P2MS
Pay To Multisig
A(s) chave(s) pública(s) de um P2MS ficam dentro do ScriptPubKey, na saída:
Bruto
01000000014563f26698c0ea3ebd85d4767457370d7e2ebbe922a7736dbf70e1d0f8a9aa9c000000008a473044022039294d5c8843a6776d4a2032cf03549f41c634ba5e65898c7816973919e485b902205af1f61f6d7d6a5f32cbe46676303c141fe499288b1be0d8f0c4e80d4c0ecb5701410454ffbc96ef3c26acffa431066915308865d990e044c507e0ab3d26af34a8ba5b4cb3028fe7c91926bb8be47d652dc70ab300e3022f8259db5f79306b601fc66effffffff0190c9190000000000c9524104d81fd577272bbe73308c93009eec5dc9fc319fc1ee2e7066e17220a5d47a18314578be2faea34b9f1f8ca078f8621acd4bc22897b03daa422b9bf56646b342a24104ec3afff0b2b66e8152e9018fe3be3fc92b30bf886b3487a525997d00fd9da2d012dce5d5275854adc3106572a5d1e12d4211b228429f5a7b2f7ba92eb0475bb14104b49b496684b02855bc32f5daefa2e2e406db4418f3b86bca5195600951c7d918cdbe5e6d3736ec2abf2dd7610995c3086976b2c0c7b4e459d10b34a316d5a5e753ae00000000 Separado
{
"version": "01000000",
"inputcount": "01",
"inputs": [
{
"txid": "4563f26698c0ea3ebd85d4767457370d7e2ebbe922a7736dbf70e1d0f8a9aa9c",
"vout": "00000000",
"scriptsigsize": "8a",
"scriptsig": "473044022039294d5c8843a6776d4a2032cf03549f41c634ba5e65898c7816973919e485b902205af1f61f6d7d6a5f32cbe46676303c141fe499288b1be0d8f0c4e80d4c0ecb5701410454ffbc96ef3c26acffa431066915308865d990e044c507e0ab3d26af34a8ba5b4cb3028fe7c91926bb8be47d652dc70ab300e3022f8259db5f79306b601fc66e",
"sequence": "ffffffff"
}
],
"outputcount": "01",
"outputs": [
{
"amount": "90c9190000000000",
"scriptpubkeysize": "c9",
"scriptpubkey": "524104d81fd577272bbe73308c93009eec5dc9fc319fc1ee2e7066e17220a5d47a18314578be2faea34b9f1f8ca078f8621acd4bc22897b03daa422b9bf56646b342a24104ec3afff0b2b66e8152e9018fe3be3fc92b30bf886b3487a525997d00fd9da2d012dce5d5275854adc3106572a5d1e12d4211b228429f5a7b2f7ba92eb0475bb14104b49b496684b02855bc32f5daefa2e2e406db4418f3b86bca5195600951c7d918cdbe5e6d3736ec2abf2dd7610995c3086976b2c0c7b4e459d10b34a316d5a5e753ae"
}
],
"locktime": "00000000"
} Transação: 581d30e2a73a2db683ac2f15d53590bd0cd72de52555c2722d9d6a78e9fea510
Nota: este script de travamento P2MS contém 3 chaves públicas não comprimidas.
Um P2MS permite que você trave uma saída a várias chaves públicas e exige assinaturas de algumas ou de todas essas chaves públicas para destravá-la.
Um script de travamento P2MS padrão pode conter até 3 chaves públicas. Já um script de travamento multisig não padrão pode conter até 20 chaves públicas de uma vez.
É raro encontrar scripts de travamento P2MS brutos na blockchain, pois esse tipo de cadeado é mais comumente encapsulado dentro de um P2SH.
P2PKH
Pay To Public Key Hash
A chave pública de um P2PKH fica dentro do ScriptSig, na entrada:
Bruto
0200000001cc8e9c87148eae3bc918c94b13c0971d7959474e37d040c777aab7d8f621bfa2000000006a47304402204321dc44fa1207aa353ce1b0270887910c10825b284cfc5dc1e5451da43defd002204b0cab71575f765d11f52b1f03bdc3d11b00a6d94e1f2185530c6f82bdae2e7d012102e9698e55e8b3bca5aa108e094e4b0b42ce0dd697268c77ccc14ef54bd336088efeffffff02404b4c00000000001976a9148ca7043a7bf78518c3dfc9c756f3af8fef4ce6db88acc9a30a08020000001976a914b8b5866bc6828bb1e9c9ddc132fe42965355c19b88acd1bf0b00 Separado
{
"version": "02000000",
"inputcount": "01",
"inputs": [
{
"txid": "cc8e9c87148eae3bc918c94b13c0971d7959474e37d040c777aab7d8f621bfa2",
"vout": "00000000",
"scriptsigsize": "6a",
"scriptsig": "47304402204321dc44fa1207aa353ce1b0270887910c10825b284cfc5dc1e5451da43defd002204b0cab71575f765d11f52b1f03bdc3d11b00a6d94e1f2185530c6f82bdae2e7d012102e9698e55e8b3bca5aa108e094e4b0b42ce0dd697268c77ccc14ef54bd336088e",
"sequence": "feffffff"
}
],
"outputcount": "02",
"outputs": [
{
"amount": "404b4c0000000000",
"scriptpubkeysize": "19",
"scriptpubkey": "76a9148ca7043a7bf78518c3dfc9c756f3af8fef4ce6db88ac"
},
{
"amount": "c9a30a0802000000",
"scriptpubkeysize": "19",
"scriptpubkey": "76a914b8b5866bc6828bb1e9c9ddc132fe42965355c19b88ac"
}
],
"locktime": "d1bf0b00"
} Transação: faf2987fd2240d9c46575cc35c354eeca71b794c482f3cc49fba1a5f9a80808c
Nota: este script de destravamento P2PKH contém uma chave pública comprimida.
Com o P2PKH, o script de travamento inicial em uma saída (em uma transação anterior) na verdade contém um hash de chave pública. A chave pública de fato só é revelada quando você vai gastar a saída como uma entrada em uma nova transação.
Então, embora um P2PKH faça o mesmo trabalho de um P2PK ao "travar" uma saída a uma chave pública, a chave pública original é encontrada dentro do ScriptSig (script de destravamento) em vez do ScriptPubKey (script de travamento).
Esta foi a forma mais popular de travar uma saída a uma chave pública até 2016, antes de o P2WPKH ser introduzido na atualização Segregated Witness. Isso porque o P2PKH tem seu próprio formato de endereço (o que facilitava enviar bitcoins ao usar uma carteira de bitcoin), enquanto o P2PK não tem.
P2WPKH
Pay To Witness Public Key Hash
A chave pública de um P2WPKH fica dentro da Testemunha da entrada:
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
Nota: este código de destravamento P2WPKH contém uma chave pública comprimida.
O P2WPKH é funcionalmente similar ao P2PKH. A principal diferença é que o código de destravamento vai dentro do campo Testemunha da entrada, em vez do ScriptSig.
Você só pode usar chaves públicas comprimidas com um P2WPKH.
Resumo
Se você gerou sua própria chave privada, o próximo passo é usá-la para calcular a chave pública correspondente.
Isso envolve mais matemática do que gerar a chave privada inicial, porque a chave privada é só um número aleatório, mas a chave pública exige que você use a multiplicação de curva elíptica para calcular um ponto específico na curva.
Porque é só isso que uma chave pública é: um par de coordenadas x e y.
É interessante entender como a matemática de curvas elípticas funciona, mas não é essencial para conseguir gerar seu próprio conjunto de chaves para usar no Bitcoin. Então não se assuste com todo o código e os termos técnicos. O código não é, na verdade, tão complexo quanto parece, então é só tentar.
Se eu consegui descobrir como calcular uma do zero sem nenhuma experiência prévia com criptografia, você também consegue.
Daqui, tudo o que você precisa fazer é conseguir converter a chave pública em um endereço, e então você poderá começar a enviar e receber bitcoins usando chaves que você gerou inteiramente por conta própria.
Você sempre pode se aprofundar nos detalhes das curvas elípticas e afins depois, se quiser.
Boa sorte.