Current section

Files

Jump to
bitcoinlib lib key hd extended_public serialization.ex
Raw

lib/key/hd/extended_public/serialization.ex

defmodule BitcoinLib.Key.HD.ExtendedPublic.Serialization do
@moduledoc """
Extended public key serialization module
To test the results, use https://www.npmjs.com/package/@swan-bitcoin/xpub-cli
Serialization types: https://github.com/satoshilabs/slips/blob/master/slip-0132.md
"""
@xpub_version_bytes 0x0488B21E
@ypub_version_bytes 0x049D7CB2
@zpub_version_bytes 0x04B24746
alias BitcoinLib.Crypto
alias BitcoinLib.Key.HD.ExtendedPublic
@doc """
Serialization of a master public key into an exportable version
## Examples
values from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1
iex> %BitcoinLib.Key.HD.ExtendedPublic{
...> key: 0x339A36013301597DAEF41FBE593A02CC513D0B55527EC2DF1050E2E8FF49C85C2,
...> chain_code: 0x873DFF81C02F525623FD1FE5167EAC3A55A049DE3D314BB42EE227FFED37D508,
...> depth: 0,
...> index: 0,
...> parent_fingerprint: 0
...> }
...> |> BitcoinLib.Key.HD.ExtendedPublic.Serialization.serialize()
{
:ok,
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
}
"""
@spec serialize(%ExtendedPublic{}, atom()) :: {:ok, binary()}
def serialize(%ExtendedPublic{} = pub_key, :xpub) do
{:ok, execute(pub_key, @xpub_version_bytes)}
end
@spec serialize(%ExtendedPublic{}, atom()) :: {:ok, binary()}
def serialize(%ExtendedPublic{} = pub_key, :ypub) do
{:ok, execute(pub_key, @ypub_version_bytes)}
end
@spec serialize(%ExtendedPublic{}, atom()) :: {:ok, binary()}
def serialize(%ExtendedPublic{} = pub_key, :zpub) do
{:ok, execute(pub_key, @zpub_version_bytes)}
end
@spec serialize(%ExtendedPublic{}, atom()) :: {:error, binary()}
def serialize(%ExtendedPublic{}, _) do
{:error, "unknown serialization format"}
end
@spec execute(%ExtendedPublic{}, binary()) :: binary()
defp execute(
%ExtendedPublic{
key: key,
depth: depth,
index: index,
parent_fingerprint: parent_fingerprint,
chain_code: chain_code
},
version_bytes
) do
data = <<
version_bytes::size(32),
depth::size(8),
parent_fingerprint::size(32),
index::size(32),
chain_code::size(256),
key::size(264)
>>
<<
data::bitstring,
Crypto.checksum_bitstring(data)::bitstring
>>
|> Base58.encode()
end
end