defmodule BitcoinLib.Key.PublicKey.Deserialization do @moduledoc """ Extended public key deserialization 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 """ @bip32_mainnet_human_readable "xpub" @bip49_mainnet_human_readable "ypub" @bip84_mainnet_human_readable "zpub" @bip32_testnet_human_readable "tpub" @bip49_testnet_human_readable "upub" @bip84_testnet_human_readable "vpub" alias BitcoinLib.Key.PublicKey @doc """ Deserialization of a public key from its xpub version values from https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 ## Examples iex> "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ...> |> BitcoinLib.Key.PublicKey.deserialize() { :ok, %BitcoinLib.Key.PublicKey{ key: <<0x339A36013301597DAEF41FBE593A02CC513D0B55527EC2DF1050E2E8FF49C85C2::264>>, chain_code: <<0x873DFF81C02F525623FD1FE5167EAC3A55A049DE3D314BB42EE227FFED37D508::256>>, depth: 0, index: 0, parent_fingerprint: <<0,0,0,0>>, fingerprint: <<0x3442193e::32>> }, :mainnet, :bip32 } """ @spec deserialize(binary()) :: { :ok, %PublicKey{}, :mainnet | :testnet, :bip32 | :bip49 | :bip84 } | {:error, binary()} def deserialize(@bip32_mainnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :mainnet, :bip32} end def deserialize(@bip49_mainnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :mainnet, :bip49} end def deserialize(@bip84_mainnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :mainnet, :bip84} end def deserialize(@bip32_testnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :testnet, :bip32} end def deserialize(@bip49_testnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :testnet, :bip49} end def deserialize(@bip84_testnet_human_readable <> _data = serialized) do {:ok, execute(serialized), :testnet, :bip84} end def deserialize(_) do {:error, "unknown pub key serialization format"} end defp execute(serialized_public_key) do << _::32, depth::8, parent_fingerprint::bitstring-32, index::32, chain_code::bitstring-256, key::bitstring-264, _checksum::32 >> = serialized_public_key |> Base58.decode() %PublicKey{ key: key, chain_code: chain_code, depth: depth, index: index, parent_fingerprint: parent_fingerprint } end end