base58-alphabets 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|