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
}
|