Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode #13 #17

Merged
merged 23 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
10084f1
rename Base58encode to just Base58 to reflect the fact that we can *d…
nelsonic Apr 25, 2020
33d8705
convert any value to binary then encode as Base58 #14
nelsonic Apr 25, 2020
b70fc66
rename to exbase58
nelsonic Apr 25, 2020
b4cbb93
create .formatter.exs file to format code
nelsonic Apr 25, 2020
e9d2b05
add implementation of Base58.decode fixes #13
nelsonic Apr 25, 2020
326a5fe
rename test
nelsonic Apr 25, 2020
2d43962
bump package version to 1.0.0 (SemVer) includes decode function! #13
nelsonic Apr 25, 2020
97b46bd
update dependencies
nelsonic Apr 25, 2020
501e3e4
update module name to b58 https://github.com/dwyl/base58/issues/16
nelsonic Apr 25, 2020
42fcf6b
rename module from Base58Encode to Base58 (as we now have a decode/1 …
nelsonic Apr 25, 2020
9af3c7a
update docs in README.md with example usage for Base58.decode/1 #13
nelsonic Apr 25, 2020
18771d5
close <div align="center"> to tidy up readme
nelsonic Apr 25, 2020
19e066e
add base58 hero image in README.md
nelsonic Apr 25, 2020
f822d39
add elixir code formatting to example blocks in README.md
nelsonic Apr 25, 2020
ec2cdf6
fix module name in installation instructions :b58 #16
nelsonic Apr 25, 2020
07b11c5
add note on encoding/decoding integer values #14
nelsonic Apr 26, 2020
6ea4d4c
update version of ex_doc in mix.exs
nelsonic Apr 26, 2020
c184aea
create decode_to_int/1 to decode integer values #14
nelsonic Apr 26, 2020
279fd7a
add note on encoding/decoding integer values to README.md #14
nelsonic Apr 26, 2020
c1a484b
fix markdown errors
nelsonic Apr 26, 2020
dca4ee7
Update to_char_list > to_charlist lib/base58.ex
nelsonic Apr 27, 2020
fdf7f23
fix example and use to_charlist, #17
SimonLab Apr 27, 2020
9c23a62
Merge branch 'decode-issue#13' of github.com:dwyl/base58 into decode-…
SimonLab Apr 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
111 changes: 84 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,102 @@
# elixir-base58-encode
[![Hex pm](http://img.shields.io/hexpm/v/b58.svg?style=flat)](https://hex.pm/packages/b58)
[![Build Status](https://travis-ci.org/dwyl/base58encode.svg?branch=master)](https://travis-ci.org/dwyl/base58encode)
[![codecov](https://codecov.io/gh/dwyl/base58encode/branch/master/graph/badge.svg)](https://codecov.io/gh/dwyl/base58encode)
<div align="center">

This module provides the `Base58Encode.encode/1` function which takes an **Elixir binary** and returns its base58 String representation.
# `b58` - _Minimalist_ Elixir Base58 Encoding/Decoding Library

[![Build Status](https://img.shields.io/travis/dwyl/base58/master.svg?style=flat-square)](https://travis-ci.org/dwyl/base58)
[![codecov.io](https://img.shields.io/codecov/c/github/dwyl/base58/master.svg?style=flat-square)](http://codecov.io/github/dwyl/base58?branch=master)
[![Hex.pm](https://img.shields.io/hexpm/v/base58?color=brightgreen&style=flat-square)](https://hex.pm/packages/base58)
[![Libraries.io dependency status](https://img.shields.io/librariesio/release/hex/base58?logoColor=brightgreen&style=flat-square)](https://libraries.io/hex/base58)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/dwyl/base58/issues)
[![HitCount](http://hits.dwyl.io/dwyl/base58.svg)](http://hits.dwyl.io/dwyl/base58)
<!-- uncomment when service is working ...
[![Inline docs](http://inch-ci.org/github/dwyl/base58.svg?branch=master&style=flat-square)](http://inch-ci.org/github/dwyl/base58)
-->

![base58-encode-hero-image](https://user-images.githubusercontent.com/194400/80292242-1d2de500-874d-11ea-8514-91a8fdfabfde.jpg)


</div>

`Base58` provides two functions to
work with Base58 encoded strings: `Base58.encode/1` and `Base58.decode/1` <br />
`encode/1` takes an **Elixir binary** (_String, Number, etc._)
and returns a Base58 encoded String. <br />
`decode/1` receives a Base58 encoded String and returns a binary.

See the section [What is an Elixir binary?](#what-is-an-elixir-binary) for more information about the binary type in Elixir.

## How to use the module
## How to use the module?

### 1. Add the package to you dependencies

Open your `mix.exs` file and add the following line to your `deps`:

```elixir
defp deps do
[
{:b58, "~> 1.0"},
]
end
```

and run `mix deps.get`

### 2. Invoke the `encode/1` function with a binary as parameter:

```elixir
Base58.encode("foo")
"bQbp"
```

### 3. Invoke the `decode/1` function with a `base58` encoded string:

```elixir
Base58.encode("hello") |> Base58.decode()
"hello"
```

<br />


See `example/example.exs` file
for a simple example of how to use the module. <br />
You can also run this example with `mix run example/example.exs`


1. Add the package to you dependencies
### Note: `Integer` Values are Converted to `String`

When encoding an `Integer`
the value is converted to a `String` before encoding
so when it is decoded it will be a string e.g:

```elixir
Base58.encode(42) |> Base58.decode()
"42"
```

This isn't ideal if you _expected_ an `Integer`
but there is no way to encode the **`type`** of the data.
So if you _know_ that you need it to be an `int`,
convert it back to a numeric value with `Base58.decode_to_int/1`:

```elixir
iex(1)> Base58.encode(42) |> Base58.decode_to_int()
42
```

```
defp deps do
[b58: "~> 0.1.0"]
end
```

and run `mix deps.get`

2. Call the `encode` function with a binary as parameter:
<br /> <br />

```
Base58Encode.encode("foo")
"bQbp"
```
## Why?

if the parameter is not an Elixir binary the function will return `:error`. In
this example 42 is an Integer and not a binary (`is_binary(42)` will return `false`)

```
Base58Encode.encode(42)
:error
```

See `example/example.exs` file for a simple example on how to use the module.
You can also run this example with `mix run example/example.exs`

## What is base58?
## What is Base58?

A *base* is a set of characters used for representing numbers.
https://en.wikipedia.org/wiki/Base58

For example
- The base 2 (binary system) represents numbers with the digits ` 0 1`
Expand Down
4 changes: 3 additions & 1 deletion example/example.exs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
defmodule Example do

hello = "hello"
helloBase58 = Base58Encode.encode(hello)
helloBase58 = Base58.encode(hello)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonLab thanks for updating the example. 👍

helloBase58Decode = Base58.decode(helloBase58)

IO.puts("the \"#{hello}\" binary is represented as \"#{helloBase58}\" in base58")
IO.puts("the \"#{helloBase58Decode}\" decoded is #{hello})")

end
114 changes: 114 additions & 0 deletions lib/base58.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
defmodule Base58 do
@moduledoc """
`Base58` provides two functions: `encode/1` and `decode/1`.
`encode/1` takes an **Elixir binary** (_String, Number, etc._)
and returns a Base58 encoded String.
`decode/1` receives a Base58 encoded String and returns a binary.
"""

@doc """
## Examples

iex> Base58.encode("hello")
"Cn8eVZg"

iex> Base58.encode(42)
"4yP"
"""
def encode(""), do: ""
def encode(binary) when is_binary(binary) do
# see https://github.com/dwyl/base58/pull/3#discussion_r252291127
decimal = :binary.decode_unsigned(binary)

if decimal == 0 do
# see https://github.com/dwyl/base58/issues/5#issuecomment-459088540
leading_zeros(binary, "")
else
codes = get_codes(decimal, [])
leading_zeros(binary, "") <> codes_to_string(codes)
end
end

# If the parameter is not a binary convert it to binary before encode.
def encode(int) when is_integer(int) do
int
|> Integer.to_string()
|> encode()
end

def encode(val) when is_float(val) do
val
|> Float.to_string()
|> encode()
end

def encode(atom) when is_atom(atom) do
atom
|> Atom.to_string()
|> encode()
end

# return a list of codes (codepoint of base58)
defp get_codes(int, codes) do
rest = div(int, 58)
code = rem(int, 58)

if rest == 0 do
[code | codes]
else
get_codes(rest, [code | codes])
end
end

defp alphanum do
[ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ]
end

# match codepoints to the alphabet of base58
defp codes_to_string(codes) do
codes
|> Enum.map(&Enum.at(alphanum(), &1))
|> Enum.join()
end

# convert leading zeros to "1"
defp leading_zeros(<<0, rest::binary>>, acc) do
leading_zeros(rest, acc <> "1")
end

defp leading_zeros(_bin, acc) do
acc
end

@doc """
`decode/1` decodes the given Base58 string back to binary.
## Examples

iex> Base58.encode("hello") |> Base58.decode()
"hello"
"""
@alnum ~c(123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz)

def decode(""), do: "" # return empty string unmodified
def decode("\0"), do: "" # treat null values as empty
def decode(encoded), do: recurse(encoded |> to_charlist, 0)
defp recurse([], acc), do: acc |> :binary.encode_unsigned()
defp recurse([head | tail], acc) do
recurse(tail, (acc * 58) + Enum.find_index(@alnum, &(&1 == head)))
end

@doc """
`decode_to_int/1` decodes the given Base58 string back to an Integer.
## Examples

iex> Base58.encode(42) |> Base58.decode_to_int()
42
"""
def decode_to_int(encoded) do
decode(encoded)
|> String.to_integer()
end
end
70 changes: 0 additions & 70 deletions lib/base58encode.ex

This file was deleted.

19 changes: 10 additions & 9 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
defmodule Base58Encode.MixProject do
defmodule Base58.MixProject do
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename #16

use Mix.Project

def project do
[
app: :b58,
app: :B58,
name: "b58",
description: description(),
package: package(),
version: "0.1.1",
version: "1.0.0",
elixir: "~> 1.7",
start_permanent: Mix.env() == :prod,
deps: deps(),
Expand All @@ -16,7 +16,7 @@ defmodule Base58Encode.MixProject do
coveralls: :test,
"coveralls.json": :test
],
source_url: "https://github.com/dwyl/base58encode"
source_url: "https://github.com/dwyl/base58"
]
end

Expand All @@ -29,23 +29,24 @@ defmodule Base58Encode.MixProject do

# Run "mix help deps" to learn about dependencies.
defp deps do
[ {:excoveralls, "~> 0.10", only: :test},
[
{:excoveralls, "~> 0.12.3", only: :test},
{:basefiftyeight, "~> 0.1.0", only: :test},
{:stream_data, "~> 0.1", only: :test},
{:ex_doc, "~> 0.19.3", only: :dev}
{:stream_data, "~> 0.4.3", only: :test},
{:ex_doc, "~> 0.21.3", only: :dev}
]
end

defp description() do
"Encode an Elixir binary to its base58 representation"
"B58 lets you encode an Elixir binary to base58 and decode a base58 string."
end

defp package() do
[
name: "b58",
licenses: ["GNU GPL v2.0"],
maintainers: ["dwyl"],
links: %{"GitHub" => "https://github.com/dwyl/base58encode"}
links: %{"GitHub" => "https://github.com/dwyl/base58"}
]
end
end
Loading