-
Notifications
You must be signed in to change notification settings - Fork 1
/
base58.go
118 lines (101 loc) · 3.29 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
// Copyright (c) 2013-2015 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package base58
//go:generate go run genalphabet.go
// Decode decodes a modified base58 string to a byte slice.
func Decode(input string) []byte {
if len(input) == 0 {
return []byte("")
}
// The max possible output size is when a base58 encoding consists of
// nothing but the alphabet character at index 0 which would result in the
// same number of bytes as the number of input chars.
output := make([]byte, len(input))
// Encode to base256 in reverse order to avoid extra calculations to
// determine the final output size in favor of just keeping track while
// iterating.
var index int
for _, r := range input {
// Invalid base58 character.
val := uint32(b58[r])
if val == 255 {
return []byte("")
}
// Multiply each byte in the output by 58 and encode to base256 while
// propagating the carry.
for i, b := range output[:index] {
val += uint32(b) * 58
output[i] = byte(val)
val >>= 8
}
for ; val > 0; val >>= 8 {
output[index] = byte(val)
index++
}
}
// Account for the leading zeros in the input. They are appended since the
// encoding is happening in reverse order.
for _, r := range input {
if r != alphabetIdx0 {
break
}
output[index] = 0
index++
}
// Truncate the output buffer to the actual number of decoded bytes and
// reverse it since it was calculated in reverse order.
output = output[:index:index]
for i := 0; i < index/2; i++ {
output[i], output[index-1-i] = output[index-1-i], output[i]
}
return output
}
// Encode encodes a byte slice to a modified base58 string.
func Encode(input []byte) string {
// Since the conversion is from base256 to base58, the max possible number
// of bytes of output per input byte is log_58(256) ~= 1.37. Thus, the max
// total output size is ceil(len(input) * 137/100). Rather than worrying
// about the ceiling, just add one even if it isn't needed since the final
// output is truncated to the right size at the end.
output := make([]byte, (len(input)*137/100)+1)
// Encode to base58 in reverse order to avoid extra calculations to
// determine the final output size in favor of just keeping track while
// iterating.
var index int
for _, r := range input {
// Multiply each byte in the output by 256 and encode to base58 while
// propagating the carry.
val := uint32(r)
for i, b := range output[:index] {
val += uint32(b) << 8
output[i] = byte(val % 58)
val /= 58
}
for ; val > 0; val /= 58 {
output[index] = byte(val % 58)
index++
}
}
// Replace the calculated remainders with their corresponding base58 digit.
for i, b := range output[:index] {
output[i] = alphabet[b]
}
// Account for the leading zeros in the input. They are appended since the
// encoding is happening in reverse order.
for _, r := range input {
if r != 0 {
break
}
output[index] = alphabetIdx0
index++
}
// Truncate the output buffer to the actual number of encoded bytes and
// reverse it since it was calculated in reverse order.
output = output[:index:index]
for i := 0; i < index/2; i++ {
output[i], output[index-1-i] = output[index-1-i], output[i]
}
return string(output)
}