base58-alphabets 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Manifest.txt +5 -0
- data/README.md +61 -0
- data/lib/base58-alphabets.rb +3 -3
- data/lib/base58-alphabets/base.rb +41 -0
- data/lib/base58-alphabets/base58.rb +85 -0
- data/lib/base58-alphabets/bitcoin.rb +85 -0
- data/lib/base58-alphabets/version.rb +2 -2
- data/test/helper.rb +10 -0
- data/test/test_base58_bitcoin.rb +34 -0
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 000b32a445c54f6eb556e6b6c3804bfa2d4df87c1caef2ff001b10a714b38403
|
4
|
+
data.tar.gz: 2984225c57d1514eb716eaddfb07d66079ba7edcfacf9f722ecfcf22e84015e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a71c550deb538e9928a743103435b5ac7c4f544e7d806529a84a52d4e76ff9ee49ccab0d33602a5deff93511dc92dede5e954697aa9cce59eef4c9da3c118dd
|
7
|
+
data.tar.gz: 579c12f8837066b4f4265df52ff36108341a6d290a60d152a195d532171b7fa92cc0d2da58039cd1ce4babe5ab1ac90e85865619cf01ce251193d55cd5b16ead
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -11,6 +11,67 @@ Encode / decode numbers with Bitcoin or Flickr base58 notation / alphabet
|
|
11
11
|
|
12
12
|
|
13
13
|
|
14
|
+
## What's Base 58?
|
15
|
+
|
16
|
+
|
17
|
+
> Similar to Base64, but modified to avoid both non-alphanumeric
|
18
|
+
> characters (`+` and `/`) and letters which might look ambiguous
|
19
|
+
> when printed (`0` - zero, `I` - capital i, `O` - capital o and `l` - lower case L).
|
20
|
+
> Satoshi Nakamoto invented the base58 encoding scheme when creating bitcoin.
|
21
|
+
> Some messaging and social media systems line break on non-alphanumeric
|
22
|
+
> strings. This is avoided by not using URI reserved characters such as `+`.
|
23
|
+
>
|
24
|
+
> (Source: [Base58 @ Wikipedia](https://en.wikipedia.org/wiki/Binary-to-text_encoding#Base58))
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
## Bitcoin
|
29
|
+
|
30
|
+
The bitcoin notation / alphabet (`123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`)
|
31
|
+
|
32
|
+
|
33
|
+
Triva Quiz: What characters (digits/letters) are
|
34
|
+
missing in the base 56 alphabets?
|
35
|
+
|
36
|
+
- `0` (Zero), `O` (Upper-O), `I` (Upper-I), `l` (Lower-L)
|
37
|
+
|
38
|
+
Why use base56 (and not "standard" base64)?
|
39
|
+
|
40
|
+
```
|
41
|
+
// - Don't want 0OIl characters that look the same in some fonts and
|
42
|
+
// could be used to create visually identical looking account numbers.
|
43
|
+
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
|
44
|
+
// - E-mail usually won't line-break if there's no punctuation to break at.
|
45
|
+
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
|
46
|
+
```
|
47
|
+
|
48
|
+
(Source: `base58.h` - Bitcoin Source Code Header Comments)
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
### Bitcoin (Base58) Notation
|
53
|
+
|
54
|
+
|Num |Character |Num |Character |Num |Character |Num |Character|
|
55
|
+
|----:|----------:|----:|----------:|----:|----------:|----:|--------:|
|
56
|
+
| 0 | **1** | 1 | **2** | 2 | **3** | 3 | **4** |
|
57
|
+
| 4 | **5** | 5 | **6** | 6 | **7** | 7 | **8** |
|
58
|
+
| 8 | **9** | 9 | **A** | 10 | **B** | 11 | **C** |
|
59
|
+
| 12 | **D** | 13 | **E** | 14 | **F** | 15 | **G** |
|
60
|
+
| 16 | **H** | 17 | **J** | 18 | **K** | 19 | **L** |
|
61
|
+
| 20 | **M** | 21 | **N** | 22 | **P** | 23 | **Q** |
|
62
|
+
| 24 | **R** | 25 | **S** | 26 | **T** | 27 | **U** |
|
63
|
+
| 28 | **V** | 29 | **W** | 30 | **X** | 31 | **Y** |
|
64
|
+
| 32 | **Z** | 33 | **a** | 34 | **b** | 35 | **c** |
|
65
|
+
| 36 | **d** | 37 | **e** | 38 | **f** | 39 | **g** |
|
66
|
+
| 40 | **h** | 41 | **i** | 42 | **j** | 43 | **k** |
|
67
|
+
| 44 | **m** | 45 | **n** | 46 | **o** | 47 | **p** |
|
68
|
+
| 48 | **q** | 49 | **r** | 50 | **s** | 51 | **t** |
|
69
|
+
| 52 | **u** | 53 | **v** | 54 | **w** | 55 | **x** |
|
70
|
+
| 56 | **y** | 57 | **z** |
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
14
75
|
|
15
76
|
## License
|
16
77
|
|
data/lib/base58-alphabets.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
#########
|
2
|
+
# shared code for formats / variants with single char alphabets
|
3
|
+
# e.g. Bitcoin, Flickr, ...
|
4
|
+
|
5
|
+
module Base58
|
6
|
+
class Base
|
7
|
+
|
8
|
+
# Converts a base10 integer to a base58 string.
|
9
|
+
def self.encode( num_or_bytes )
|
10
|
+
if num_or_bytes.is_a?( Array )
|
11
|
+
bytes = num_or_bytes
|
12
|
+
else
|
13
|
+
num = num_or_bytes
|
14
|
+
bytes = Base58._bytes( num )
|
15
|
+
end
|
16
|
+
|
17
|
+
bytes.reduce( String.new ) do |buf, byte|
|
18
|
+
buf << alphabet[byte]
|
19
|
+
buf
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Converts a base58 string to a base10 integer.
|
25
|
+
def self.decode( str_or_bytes )
|
26
|
+
if str_or_bytes.is_a?( Array )
|
27
|
+
bytes = str_or_bytes
|
28
|
+
else ## assume string
|
29
|
+
str = str_or_bytes
|
30
|
+
bytes = str.each_char.reduce([]) do |bytes,char|
|
31
|
+
byte = number[char]
|
32
|
+
raise ArgumentError, "Value passed not a valid base58 string - >#{char}< not found in alphabet" if byte.nil?
|
33
|
+
bytes << byte
|
34
|
+
bytes
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Base58._pack( bytes )
|
38
|
+
end
|
39
|
+
|
40
|
+
end # class Base
|
41
|
+
end # module Base58
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Base58
|
2
|
+
|
3
|
+
BASE = 58 # ALPHABET.length == 58 ## 58 chars/letters/digits
|
4
|
+
|
5
|
+
class Configuration
|
6
|
+
|
7
|
+
MAPPING = {
|
8
|
+
bitcoin: Bitcoin,
|
9
|
+
## flickr: Flickr,
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :format
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@format = Bitcoin
|
16
|
+
end
|
17
|
+
|
18
|
+
def format=(value)
|
19
|
+
if value.is_a?( Symbol )
|
20
|
+
@format = MAPPING[ value ]
|
21
|
+
else ## assume class
|
22
|
+
@format = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end # class Configuration
|
26
|
+
|
27
|
+
## lets you use
|
28
|
+
## Base58.configure do |config|
|
29
|
+
## config.format = :bitcoin
|
30
|
+
## end
|
31
|
+
|
32
|
+
def self.configuration
|
33
|
+
@configuration ||= Configuration.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.configure
|
37
|
+
yield( configuration )
|
38
|
+
end
|
39
|
+
|
40
|
+
## add convenience helper for format
|
41
|
+
def self.format() configuration.format; end
|
42
|
+
def self.format=(value) self.configuration.format = value; end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
def self.encode( num_or_bytes, klass: configuration.format )
|
48
|
+
klass.encode( num_or_bytes )
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.decode( str_or_bytes, klass: configuration.format )
|
52
|
+
klass.decode( str_or_bytes )
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
####
|
59
|
+
# (private) helper - note: leading underscore in name e.g. _bytes
|
60
|
+
def self._bytes( num )
|
61
|
+
b = []
|
62
|
+
while num >= BASE
|
63
|
+
mod = num % BASE
|
64
|
+
b << mod
|
65
|
+
num = (num - mod) / BASE
|
66
|
+
end
|
67
|
+
b << num
|
68
|
+
b = b.reverse
|
69
|
+
b
|
70
|
+
end
|
71
|
+
|
72
|
+
def self._pack( bytes )
|
73
|
+
num = 0
|
74
|
+
bytes.reverse.each_with_index do |byte,index|
|
75
|
+
num += byte * (BASE**(index))
|
76
|
+
end
|
77
|
+
num
|
78
|
+
end
|
79
|
+
|
80
|
+
## encoding alphabet - letter-to-number by index / array
|
81
|
+
def self.alphabet( klass: configuration.format ) klass.alphabet; end
|
82
|
+
|
83
|
+
## decoding letter-to-number mapping / hash
|
84
|
+
def self.number( klass: configuration.format ) klass.number; end
|
85
|
+
end # module Base58
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Base58
|
4
|
+
class Bitcoin < Base
|
5
|
+
|
6
|
+
ALPHABET = %w[ 1 2 3 4 5 6 7 8 9
|
7
|
+
A B C D E F G H J K L M N P Q R S T U V W X Y Z
|
8
|
+
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 ]
|
9
|
+
|
10
|
+
|
11
|
+
def self.alphabet() ALPHABET; end ## add alpha / char aliases - why? why not?
|
12
|
+
|
13
|
+
## Note:
|
14
|
+
## for decoding allow (misspelled) l/I for 1 - why? why not?
|
15
|
+
## and (misspelled) 0/O for o - why? why not?
|
16
|
+
|
17
|
+
|
18
|
+
NUMBER = {
|
19
|
+
'1' => 0, ## 'l' => 0, 'I' => 0,
|
20
|
+
'2' => 1,
|
21
|
+
'3' => 2,
|
22
|
+
'4' => 3,
|
23
|
+
'5' => 4,
|
24
|
+
'6' => 5,
|
25
|
+
'7' => 6,
|
26
|
+
'8' => 7,
|
27
|
+
'9' => 8,
|
28
|
+
'A' => 9,
|
29
|
+
'B' => 10,
|
30
|
+
'C' => 11,
|
31
|
+
'D' => 12,
|
32
|
+
'E' => 13,
|
33
|
+
'F' => 14,
|
34
|
+
'G' => 15,
|
35
|
+
'H' => 16,
|
36
|
+
'J' => 17,
|
37
|
+
'K' => 18,
|
38
|
+
'L' => 19,
|
39
|
+
'M' => 20,
|
40
|
+
'N' => 21,
|
41
|
+
'P' => 22,
|
42
|
+
'Q' => 23,
|
43
|
+
'R' => 24,
|
44
|
+
'S' => 25,
|
45
|
+
'T' => 26,
|
46
|
+
'U' => 27,
|
47
|
+
'V' => 28,
|
48
|
+
'W' => 29,
|
49
|
+
'X' => 30,
|
50
|
+
'Y' => 31,
|
51
|
+
'Z' => 32,
|
52
|
+
'a' => 33,
|
53
|
+
'b' => 34,
|
54
|
+
'c' => 35,
|
55
|
+
'd' => 36,
|
56
|
+
'e' => 37,
|
57
|
+
'f' => 38,
|
58
|
+
'g' => 39,
|
59
|
+
'h' => 40,
|
60
|
+
'i' => 41,
|
61
|
+
'j' => 42,
|
62
|
+
'k' => 43,
|
63
|
+
'm' => 44,
|
64
|
+
'n' => 45,
|
65
|
+
'o' => 46, ## '0' => 46, 'O' => 46,
|
66
|
+
'p' => 47,
|
67
|
+
'q' => 48,
|
68
|
+
'r' => 49,
|
69
|
+
's' => 50,
|
70
|
+
't' => 51,
|
71
|
+
'u' => 52,
|
72
|
+
'v' => 53,
|
73
|
+
'w' => 54,
|
74
|
+
'x' => 55,
|
75
|
+
'y' => 56,
|
76
|
+
'z' => 57,
|
77
|
+
}
|
78
|
+
|
79
|
+
def self.number() NUMBER; end ## add num alias - why? why not?
|
80
|
+
|
81
|
+
## add shortcuts (convenience) aliases
|
82
|
+
NUM = NUMBER
|
83
|
+
|
84
|
+
end # class Bitcoin
|
85
|
+
end # module Base58
|
data/test/helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_base58_bitcoin.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
|
9
|
+
class TestBase58Bitcoin < MiniTest::Test
|
10
|
+
|
11
|
+
|
12
|
+
def test_bitcoin
|
13
|
+
assert_equal "2j", Base58::Bitcoin.encode( 100 )
|
14
|
+
assert_equal "4fr", Base58::Bitcoin.encode( 12345 )
|
15
|
+
assert_equal "b2pH", Base58::Bitcoin.encode( 6639914 )
|
16
|
+
|
17
|
+
assert_equal 100, Base58::Bitcoin.decode( "2j" )
|
18
|
+
assert_equal 12345, Base58::Bitcoin.decode( "4fr" )
|
19
|
+
assert_equal 6639914, Base58::Bitcoin.decode( "b2pH" )
|
20
|
+
|
21
|
+
|
22
|
+
Base58.format = :bitcoin
|
23
|
+
assert_equal "2j", Base58.encode( 100 )
|
24
|
+
assert_equal "4fr", Base58.encode( 12345 )
|
25
|
+
assert_equal "b2pH", Base58.encode( 6639914 )
|
26
|
+
|
27
|
+
assert_equal 100, Base58.decode( "2j" )
|
28
|
+
assert_equal 12345, Base58.decode( "4fr" )
|
29
|
+
assert_equal 6639914, Base58.decode( "b2pH" )
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
end # class TestBase58Bitcoin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: base58-alphabets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
@@ -59,7 +59,12 @@ files:
|
|
59
59
|
- README.md
|
60
60
|
- Rakefile
|
61
61
|
- lib/base58-alphabets.rb
|
62
|
+
- lib/base58-alphabets/base.rb
|
63
|
+
- lib/base58-alphabets/base58.rb
|
64
|
+
- lib/base58-alphabets/bitcoin.rb
|
62
65
|
- lib/base58-alphabets/version.rb
|
66
|
+
- test/helper.rb
|
67
|
+
- test/test_base58_bitcoin.rb
|
63
68
|
homepage: https://github.com/rubycoco/blockchain
|
64
69
|
licenses:
|
65
70
|
- Public Domain
|