Bechamel (Bechamel v1.1.0)

View Source

This is an implementation of BIP-0173

Bech32 address format for native v0-16 witness outputs.

See https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki for details

Summary

Functions

Convert raw binary to 5 bit per byte encoded byte string.

Create a checksum from the human readable part plus the data part.

Decode a bech32 address. You can also pass the :ignore_length keyword into the opts if you want to allow more than 90 chars for currencies like Nervos CKB.

Encode a bech32 address from the hrp and data directly (data is a raw binary with no pre-processing).

Encode address from 5 bit encoded values in each byte. In other words bytes should have a value between 0 and 31.

Get the human readable part of the address. Very little validation is done here please use decode/1 or decode/2 if you need to validate the address.

Decode a segwit bech32 address.

Encode a bech32 segwit address.

Verify the checksum of the address report success or failure. Note that this doesn't perform exhaustive validation of the address. If you need to make sure the address is well formed please use decode/1 or decode/2 instead.

Verify the checksum of the address report any errors. Note that this doesn't perform exhaustive validation of the address. If you need to make sure the address is well formed please use decode/1 or decode/2 instead.

Functions

convertbits(data, frombits \\ 8, tobits \\ 5, pad \\ true)

@spec convertbits(binary(), pos_integer(), pos_integer(), boolean()) :: binary()

Convert raw binary to 5 bit per byte encoded byte string.

Returns a binary that uses 5 bits per byte.

## Example

iex> Bechamel.convertbits(<<1, 0, 221, 231, 128, 28, 7, 61, 251, 52, 100, 199, 177, 240, 91, 128, 107, 178, 187, 184, 78, 153>>)
<<0, 4, 0, 13, 27, 25, 28, 0, 3, 16, 3, 19, 27, 30, 25, 20, 12, 19, 3, 27, 3, 28, 2, 27, 16, 1, 21, 27, 5, 14, 29, 24, 9, 26, 12, 16>>

create_checksum(hrp, data)

@spec create_checksum(String.t(), binary()) :: binary()

Create a checksum from the human readable part plus the data part.

Returns a binary that represents the checksum.

## Example

iex> Bechamel.create_checksum("ckb", <<1, 0, 221, 231, 128, 28, 7, 61, 251, 52, 100, 199, 177, 240, 91, 128, 107, 178, 187, 184, 78, 153>>)
<<4, 5, 2, 7, 25, 10>>

decode(addr, opts \\ [])

@spec decode(
  String.t(),
  keyword()
) ::
  {:ok, hrp :: String.t(), data :: binary()}
  | {:error,
     :no_separator
     | :no_hrp
     | :checksum_too_short
     | :too_long
     | :not_in_charset
     | :checksum_failed
     | :invalid_char
     | :mixed_case_char
     | :invalid_input}

Decode a bech32 address. You can also pass the :ignore_length keyword into the opts if you want to allow more than 90 chars for currencies like Nervos CKB.

Returns {:ok, hrp :: String.t(), data :: binary} or an {:error, reason} tuple. Note that we return 8 bits per byte here not 5 bits per byte.

## Example

iex> Bechamel.decode("ckb1qyq036wytncnfv0ekfjqrch7s5hzr4hkjl4qs54f7e")
{:ok, "ckb", <<1, 0, 248, 233, 196, 92, 241, 52, 177, 249, 178, 100, 1, 226, 254, 133, 46, 33, 214, 246, 151, 234>>}

encode(hrp, data)

@spec encode(String.t(), binary()) :: String.t()

Encode a bech32 address from the hrp and data directly (data is a raw binary with no pre-processing).

Returns a bech32 address as a string.

## Example

iex> Bechamel.encode("ckb", <<1, 0, 221, 231, 128, 28, 7, 61, 251, 52, 100, 199, 177, 240, 91, 128, 107, 178, 187, 184, 78, 153>>)
"ckb1qyqdmeuqrsrnm7e5vnrmruzmsp4m9wacf6vsxasryq"

encode_from_5bit(hrp, data)

@spec encode_from_5bit(String.t(), binary()) :: String.t()

Encode address from 5 bit encoded values in each byte. In other words bytes should have a value between 0 and 31.

Returns a bech32 address as a string.

## Example

iex> Bechamel.encode_from_5bit("ckb", Bechamel.convertbits(<<1, 0, 221, 231, 128, 28, 7, 61, 251, 52, 100, 199, 177, 240, 91, 128, 107, 178, 187, 184, 78, 153>>))
"ckb1qyqdmeuqrsrnm7e5vnrmruzmsp4m9wacf6vsxasryq"

get_hrp(addr)

@spec get_hrp(addr :: String.t()) :: {:ok, hrp :: String.t()} | {:error, :not_bech32}

Get the human readable part of the address. Very little validation is done here please use decode/1 or decode/2 if you need to validate the address.

Returns {:ok, hrp :: String.t()} or an {:error, reason} tuple.

## Example

iex> Bechamel.get_hrp("ckb1qyqdmeuqrsrnm7e5vnrmruzmsp4m9wacf6vsxasryq")
{:ok, "ckb"}

segwit_decode(hrp, addr)

@spec segwit_decode(hrp :: String.t(), addr :: String.t()) ::
  {:ok, witver :: non_neg_integer(), data :: binary()}
  | {:error,
     :invalid_size
     | :invalid_witness_version
     | :wrong_hrp
     | :no_seperator
     | :no_hrp
     | :checksum_too_short
     | :too_long
     | :not_in_charset
     | :checksum_failed
     | :invalid_char
     | :mixed_case_char}

Decode a segwit bech32 address.

Returns {:ok, witver :: non_neg_integer , data :: binary} or an {:error, reason} tuple. Note that we return 8 bits per byte here not 5 bits per byte.

## Example

iex> Bechamel.segwit_decode("bc", "bc1q5ul5v7jan29qkeefplasamurqg0tpzk5ljjhm6")
{:ok, 0, <<167, 63, 70, 122, 93, 154, 138, 11, 103, 41, 15, 251, 14, 239, 131, 2, 30, 176, 138, 212>>}

segwit_encode(hrp, witver, witprog)

@spec segwit_encode(String.t(), non_neg_integer(), binary()) :: String.t()

Encode a bech32 segwit address.

Returns a bech32 address as a string.

## Example

iex> Bechamel.segwit_encode("bc", 0, <<167, 63, 70, 122, 93, 154, 138, 11, 103, 41, 15, 251, 14, 239, 131, 2, 30, 176, 138, 212>>)
"bc1q5ul5v7jan29qkeefplasamurqg0tpzk5ljjhm6"

valid_predicate?(addr)

@spec valid_predicate?(any()) :: boolean()

Verify the checksum of the address report success or failure. Note that this doesn't perform exhaustive validation of the address. If you need to make sure the address is well formed please use decode/1 or decode/2 instead.

Returns true or false.

## Example

iex> Bechamel.valid_predicate?("ckb1qyqdmeuqrsrnm7e5vnrmruzmsp4m9wacf6vsxasryq")
true

verify(addr)

@spec verify(String.t()) ::
  :ok
  | {:error, :checksum_failed | :invalid_char | :not_bech32 | :invalid_input}

Verify the checksum of the address report any errors. Note that this doesn't perform exhaustive validation of the address. If you need to make sure the address is well formed please use decode/1 or decode/2 instead.

Returns :ok or an {:error, reason} tuple.

## Example

iex> Bechamel.verify("ckb1qyqdmeuqrsrnm7e5vnrmruzmsp4m9wacf6vsxasryq")
:ok