-
Notifications
You must be signed in to change notification settings - Fork 0
/
base58.go
143 lines (117 loc) · 3.59 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
package base58
import (
"fmt"
"math"
"math/big"
)
const (
StdPadding = '1'
NoPadding = -1
ripple = "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
bitcoin = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
flickr = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
)
type CorruptInputError int64
func (c CorruptInputError) Error() string {
return fmt.Sprintf("illegal base58 data at input index: %d", c)
}
var radix = big.NewInt(58)
var zero = big.NewInt(0)
func (e *Encoding) enc(dst []byte, x *big.Int, src []byte) []byte {
if dst == nil {
dst = make([]byte, EncodedLen(x.BitLen()))
}
i := len(dst)
for x.Cmp(zero) > 0 {
i--
mod := new(big.Int)
x.DivMod(x, radix, mod)
dst[i] = e.encode[mod.Uint64()]
}
if e.padChar != NoPadding {
for src[i] == 0x00 {
i--
dst[i] = byte(e.padChar)
}
}
return dst[i:]
}
// Encode encodes x using the encoding enc, writing EncodedLen(len(src)) bytes to dst.
func (e *Encoding) EncodeBigInt(x *big.Int) []byte {
return e.enc(nil, new(big.Int).Set(x), x.Bytes())
}
// Encode encodes src using the encoding enc, writing EncodedLen(len(src)) bytes to dst.
func (e *Encoding) Encode(dst, src []byte) {
e.enc(dst, new(big.Int).SetBytes(src), src)
}
// EncodeBigIntToString returns the base58 encoding of x.
func (e *Encoding) EncodeBigIntToString(x *big.Int) string {
return string(e.EncodeBigInt(x))
}
// EncodeToString returns the base58 encoding of src.
func (e *Encoding) EncodeToString(src []byte) string {
return string(e.enc(nil, new(big.Int).SetBytes(src), src))
}
const log58 = 4.0604430105464193366005041538200881735700130482829993330423503611361744031
// EncodedLen returns the maximum encoded len in bytes of the base64 encoding
// of src with len n.
func EncodedLen(n int) int {
return int(math.Ceil(float64(n) / log58))
}
func DecodedLen(n int) int {
return int(math.Floor(float64(n) * log58 / 8))
}
// Encoding is a base58 encoding scheme defined by a 58-character
// alphabet.
type Encoding struct {
encode [58]byte
decodeMap [256]byte
padChar rune
}
// WithPadding creates a new encoding identical to enc except
// with a specified padding character, or NoPadding to disable padding.
func (e Encoding) WithPadding(c rune) *Encoding {
e.padChar = c
return &e
}
// Ripple is base58 encoding using the Ripple alphabet.
var Ripple = NewEncoding(ripple)
// RawRipple is base58 encoding using the Ripple alphabet without padding.
var RawRipple = Ripple.WithPadding(NoPadding)
// Flickr is base58 encoding using the Flickr alphabet.
var Flickr = NewEncoding(flickr).WithPadding(NoPadding)
// Bitcoin is base58 encoding using the Bitcoin alphabet.
var Bitcoin = NewEncoding(bitcoin)
// RawBitcoin is base58 encoding using the Bitcoin alphabet without padding.
var RawBitcoin = Bitcoin.WithPadding(NoPadding)
// NewEncoding returns a new padded Encoding defined by the given alphabet,
// which must be a 58-byte string. By default padding is turned off.
func NewEncoding(encoder string) *Encoding {
if len(encoder) != 58 {
panic("encoding alphabet is not 58 bytes long")
}
e := Encoding{padChar: StdPadding}
copy(e.encode[:], encoder)
for i := 0; i < len(e.decodeMap); i++ {
e.decodeMap[i] = 0xFF
}
for i := 0; i < len(encoder); i++ {
e.decodeMap[encoder[i]] = byte(i)
}
return &e
}
func (e *Encoding) Decode(src []byte) (*big.Int, error) {
j := 0
for ; j < len(src) && src[j] == byte(e.padChar); j++ {
}
n := new(big.Int)
for i := range src[j:] {
c := e.decodeMap[src[i]]
if c == 0xFF {
return nil, CorruptInputError(i)
}
n.Mul(n, radix)
n.Add(n, big.NewInt(int64(c)))
}
return n, nil
}