forked from mr-tron/base58
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbase58.go
163 lines (131 loc) · 3.56 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
151
152
153
154
155
156
157
158
159
160
161
162
163
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 {
zero := alphabet.encode[0]
binsz := len(bin)
var i, j, zcount, high int
var carry uint32
for zcount < binsz && bin[zcount] == 0 {
zcount++
}
size := (binsz-zcount)*138/100 + 1
var buf = make([]uint32, size)
high = size - 1
for i = zcount; i < binsz; i++ {
j = size - 1
for carry = uint32(bin[i]); j > high || carry != 0; j-- {
carry += buf[j] << 8
buf[j] = carry % 58
carry /= 58
}
high = j
}
for j = 0; j < size && buf[j] == 0; j++ {
}
var b58 = make([]byte, size-j+zcount)
if zcount != 0 {
for i = 0; i < zcount; i++ {
b58[i] = zero
}
}
for i = zcount; j < size; i++ {
b58[i] = alphabet.encode[buf[j]]
j++
}
return string(b58)
}
// 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")
}
var (
t, c uint64
zmask uint32
zcount int
b58u = []rune(str)
b58sz = len(b58u)
outisz = (b58sz + 3) >> 2
binu = make([]byte, (b58sz+3)*3)
bytesleft = b58sz & 3
zero = rune(alphabet.encode[0])
)
if bytesleft > 0 {
zmask = 0xffffffff << uint32(bytesleft*8)
} else {
bytesleft = 4
}
var outi = make([]uint32, outisz)
for i := 0; i < b58sz && b58u[i] == zero; i++ {
zcount++
}
for _, r := range b58u {
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 := outisz - 1; j >= 0; j-- {
t = uint64(outi[j])*58 + c
c = (t >> 32) & 0x3f
outi[j] = uint32(t & 0xffffffff)
}
if c > 0 {
return nil, fmt.Errorf("output number too big (carry to the next int32)")
}
if outi[0]&zmask != 0 {
return nil, fmt.Errorf("output number too big (last int32 filled too far)")
}
}
var j, cnt int
for j, cnt = 0, 0; j < outisz; j++ {
for mask := byte(bytesleft-1) * 8; mask <= 0x18; mask, cnt = mask-8, cnt+1 {
binu[cnt] = byte(outi[j] >> mask)
}
if j == 0 {
bytesleft = 4 // because it could be less than 4 the first time through
}
}
for n, v := range binu {
if v > 0 {
start := n - zcount
if start < 0 {
start = 0
}
return binu[start:cnt], nil
}
}
return binu[:cnt], nil
}