-
Notifications
You must be signed in to change notification settings - Fork 31
/
base58.go
150 lines (121 loc) · 3.54 KB
/
base58.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package base58
import (
"fmt"
)
// Encode encodes the passed bytes into a base58 encoded string.
func Encode(bin []byte) string {
return FastBase58EncodingAlphabet(bin, BTCAlphabet)
}
// EncodeAlphabet encodes the passed bytes into a base58 encoded string with the
// passed alphabet.
func EncodeAlphabet(bin []byte, alphabet *Alphabet) string {
return FastBase58EncodingAlphabet(bin, alphabet)
}
// FastBase58Encoding encodes the passed bytes into a base58 encoded string.
func FastBase58Encoding(bin []byte) string {
return FastBase58EncodingAlphabet(bin, BTCAlphabet)
}
// FastBase58EncodingAlphabet encodes the passed bytes into a base58 encoded
// string with the passed alphabet.
func FastBase58EncodingAlphabet(bin []byte, alphabet *Alphabet) string {
size := len(bin)
zcount := 0
for zcount < size && bin[zcount] == 0 {
zcount++
}
// It is crucial to make this as short as possible, especially for
// the usual case of bitcoin addrs
size = zcount +
// This is an integer simplification of
// ceil(log(256)/log(58))
(size-zcount)*555/406 + 1
out := make([]byte, size)
var i, high int
var carry uint32
high = size - 1
for _, b := range bin {
i = size - 1
for carry = uint32(b); i > high || carry != 0; i-- {
carry = carry + 256*uint32(out[i])
out[i] = byte(carry % 58)
carry /= 58
}
high = i
}
// Determine the additional "zero-gap" in the buffer (aside from zcount)
for i = zcount; i < size && out[i] == 0; i++ {
}
// Now encode the values with actual alphabet in-place
val := out[i-zcount:]
size = len(val)
for i = 0; i < size; i++ {
out[i] = alphabet.encode[val[i]]
}
return string(out[:size])
}
// Decode decodes the base58 encoded bytes.
func Decode(str string) ([]byte, error) {
return FastBase58DecodingAlphabet(str, BTCAlphabet)
}
// DecodeAlphabet decodes the base58 encoded bytes using the given b58 alphabet.
func DecodeAlphabet(str string, alphabet *Alphabet) ([]byte, error) {
return FastBase58DecodingAlphabet(str, alphabet)
}
// FastBase58Decoding decodes the base58 encoded bytes.
func FastBase58Decoding(str string) ([]byte, error) {
return FastBase58DecodingAlphabet(str, BTCAlphabet)
}
// FastBase58DecodingAlphabet decodes the base58 encoded bytes using the given
// b58 alphabet.
func FastBase58DecodingAlphabet(str string, alphabet *Alphabet) ([]byte, error) {
if len(str) == 0 {
return nil, fmt.Errorf("zero length string")
}
zero := alphabet.encode[0]
b58sz := len(str)
var zcount int
for i := 0; i < b58sz && str[i] == zero; i++ {
zcount++
}
var t, c uint64
// the 32bit algo stretches the result up to 2 times
binu := make([]byte, 2*((b58sz*406/555)+1))
outi := make([]uint32, (b58sz+3)/4)
for _, r := range str {
if r > 127 {
return nil, fmt.Errorf("high-bit set on invalid digit")
}
if alphabet.decode[r] == -1 {
return nil, fmt.Errorf("invalid base58 digit (%q)", r)
}
c = uint64(alphabet.decode[r])
for j := len(outi) - 1; j >= 0; j-- {
t = uint64(outi[j])*58 + c
c = t >> 32
outi[j] = uint32(t & 0xffffffff)
}
}
// initial mask depends on b58sz, on further loops it always starts at 24 bits
mask := (uint(b58sz%4) * 8)
if mask == 0 {
mask = 32
}
mask -= 8
outLen := 0
for j := 0; j < len(outi); j++ {
for mask < 32 { // loop relies on uint overflow
binu[outLen] = byte(outi[j] >> mask)
mask -= 8
outLen++
}
mask = 24
}
// find the most significant byte post-decode, if any
for msb := zcount; msb < len(binu); msb++ {
if binu[msb] > 0 {
return binu[msb-zcount : outLen], nil
}
}
// it's all zeroes
return binu[:outLen], nil
}