area58check v0.1.0 Area58check View Source
This module includes the needed functions to encode or decode base58check strings.
Base58check is used in Bitcoin whenever there is a need for a user to read or transcribe a number, such a bitcoin adresses, encrypted key, private key, or script hash.
Prefixed versions
The prefixed version parameter indicates what kind of binary is being
encoded. E.g. If you are encoding a private key use :wif
, if you are
encoding a bitcoin address use :p2pkh
. The version prefix will be
embeded in the encoded version.
You can also use other types described in prefix_version_type/0
Checksum
The encoded versions will include a few bytes to ensure that its correct and no transcribing errors were present.
Usage
To know the decoded binary of any encoded string just use the
encode/2
function indicating the prefix version you want:
iex> privkey = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" |> Base.decode16!()
iex> %{decoded: _decoded} = encode(privkey, <<128>>)
%Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>
}
To know the encoded string of any binary use decode/1
function:
iex> {:ok, %{encoded: _encoded}} = decode("5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb")
{:ok, %Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>
}}
Link to this section Summary
Types
Indicates the type of bitcoin string being encoded/decoded. E.g.: mainet WalletImportFormat (WIF), bitcoin address, testnet wif, etc
Functions
Decodes a previously encoded string using base58check returning the used version prefix, the original binary
Encodes a string using base58check with the provided version prefix
Link to this section Types
prefix_version_type() :: atom() | binary() | pos_integer() | [0..255, ...]
Indicates the type of bitcoin string being encoded/decoded. E.g.: mainet WalletImportFormat (WIF), bitcoin address, testnet wif, etc.
The prefixed version can be provided in several formats:
- An atom. E.g.:
:testnet_p2sh
- The hexadecimal or numeric representation. E.g.:
0x043587CF
- Character list: E.g.:
[4, 136, 178, 30]
- Binary string: E.g.:
<<4, 136, 178, 30>>
A result returned by both encode/2
and decode/1
with the prefixed
version, the encoded base58check string, and the decoded binary.
Link to this section Functions
decode(String.t()) :: {:ok, Area58check.t()} | {:error, atom()}
Decodes a previously encoded string using base58check returning the used version prefix, the original binary.
An error message will be returned in case there was a checksum error or a character is not valid.
Examples:
Decode WIP key and get the hexadecimal private key
iex> {:ok, %{decoded: decoded} } = decode("5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb")
{:ok, %Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>}}
iex> decoded |> Base.encode16
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
If any character of the key is wrong (J
), checksum will be invalid:
iex> decode("5JpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb")
{:error, :checksum_incorrect}
The null string means the checksum is nor present, nor valid:
iex> decode("")
{:error, :checksum_incorrect}
If any character is not a base58 character (E.g.: 0
)
iex> decode("50pneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb")
{:error, :incorrect_base58}
encode(String.t(), prefix_version_type()) :: t()
Encodes a string using base58check with the provided version prefix .
The argument version_prefix
can be a binary, integer or a list of
bytes (see examples next paragraph).
All available prefixes are coded in the module Area58check.Prefixes
.
Examples
iex> privkey = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" |> Base.decode16!()
iex> encode(privkey, :wif)
%Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>}
The version prefix can be indicated in several alternative ways:
iex> privkey = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" |> Base.decode16!()
iex> encode(privkey, <<128>>)
%Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>
}
iex> encode(privkey, 0x80)
%Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>
}
iex> encode(privkey, [128])
%Area58check{
encoded: "5HpneLQNKrcznVCQpzodYwAmZ4AoHeyjuRf9iAHAa498rP5kuWb",
decoded: <<1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239, 1, 35, 69, 103, 137, 171, 205, 239>>,
version: :wif,
version_bin: <<128>>
}
Example to generate an uncompresed bitcoin address from public key
iex> privkey = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" |> Base.decode16!()
iex> {uncompressed_pubkey, _priv_key} = :crypto.generate_key(:ecdh, :crypto.ec_curve(:secp256k1), privkey)
iex> uncompressed_pubkey = :crypto.hash(:ripemd160, :crypto.hash(:sha256, uncompressed_pubkey))
iex> encode(uncompressed_pubkey, <<0>>)
%Area58check{
encoded: "1CLrrRUwXswyF2EVAtuXyqdk4qb8DSUHCX",
decoded: <<124, 106, 230, 190, 9, 150, 81, 133, 169, 75, 13, 161, 139, 201, 42, 157, 252, 238, 97, 23>>,
version: :p2pkh,
version_bin: <<0>>}
If version is an atom, and is not recognized returns error:
iex> encode("Any string", :sahdkjfhkjasdfhksldjf)
** (ArgumentError) Version prefix :sahdkjfhkjasdfhksldjf is not a recognized version. You can either pass a charlist (ex: [4, 136, 178, 30]), number (ex: 70617039), hexadecimal (ex: 0x043587CF), binary version (ex: <<4, 136, 178, 30>>), or a recognized atom like any of: :bip32_privkey, :bip32_pubkey, :p2pkh, :p2sh, :tesnet_bip32_privkey, :tesnet_bip32_pubkey, :tesnet_p2pkh, :tesnet_p2sh, :tesnet_wif, :wif