-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbase58.go
104 lines (91 loc) · 2.22 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
package base58
import (
"errors"
"fmt"
"math/big"
)
// An Encoding is a radix 58 encoding/decoding scheme.
type Encoding struct {
decode [256]int64
encode [58]byte
}
// It panics if the passed string is not 58 bytes long or isn't valid ASCII.
func encoding(s string) *Encoding {
if len(s) != 58 {
panic("base58 alphabets must be 58 bytes long")
}
ret := new(Encoding)
copy(ret.encode[:], s)
for i := range ret.decode {
ret.decode[i] = -1
}
for i, b := range ret.encode {
ret.decode[b] = int64(i)
}
return ret
}
// alphabet is the encoding scheme used for Bitcoin addresses.
var alphabet = encoding("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
var (
bn0 = big.NewInt(0)
radix = big.NewInt(58)
zero = alphabet.encode[0]
)
// Encode encodes the given bytes using bitcoin base58 encoding
func Encode(src []byte) (string, error) {
if len(src) == 0 {
return "", errors.New("empty string given for encoding")
}
idx := len(src)*138/100 + 1 // log(256) / log(58), rounded up.
buf := make([]byte, idx)
mod := new(big.Int)
// Get the integer value of string to encoded
bn := new(big.Int).SetBytes(src)
// divide the integer value till you hit zero
for {
switch bn.Cmp(bn0) {
case 1:
bn, mod = bn.DivMod(bn, radix, new(big.Int))
idx--
// store the mod value
buf[idx] = alphabet.encode[mod.Int64()]
case 0:
// check for zeros
for i := range src {
if src[i] != 0 {
break
}
idx--
buf[idx] = zero
}
return string(buf[idx:]), nil
default:
return "", fmt.Errorf("expecting a positive number in base58 encoding but got %q", bn)
}
}
}
// Decode decodes the base58 encoded bytes using the bitcoin base58 encoding
func Decode(str string) ([]byte, error) {
zero := alphabet.encode[0]
// zero count
var zeros int
for i := 0; i < len(str) && str[i] == zero; i++ {
zeros++
}
leading := make([]byte, zeros)
var padChar rune = -1
src := []byte(str)
j := 0
for ; j < len(src) && src[j] == byte(padChar); j++ {
}
n := new(big.Int)
for i := range src[j:] {
c := alphabet.decode[src[i]]
if c == -1 {
return nil, errors.New("Invalid base58 character")
}
n.Mul(n, radix)
n.Add(n, big.NewInt(int64(c)))
}
return append(leading, n.Bytes()...), nil
}