-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
basex.go
115 lines (97 loc) · 2.3 KB
/
basex.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
// Copyright 2020 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package libkb
import (
"bytes"
"fmt"
"math/big"
"strconv"
)
const invalidBaseIndex = 0xFF
var Base30 = NewBaseX("abcdefghjkmnpqrsuvwxyz23456789")
var Base58 = NewBaseX("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
type BaseXEncoder struct {
size int
base *big.Int
alphabet string
alphabetMap [256]byte
}
func NewBaseX(alphabet string) *BaseXEncoder {
enc := &BaseXEncoder{
size: len(alphabet),
base: big.NewInt(int64(len(alphabet))),
alphabet: alphabet,
}
if enc.size > 255 {
panic("unsupported BaseX alphabet size, got " + strconv.Itoa(enc.size))
}
for i := range enc.alphabetMap {
enc.alphabetMap[i] = invalidBaseIndex
}
for i, c := range alphabet {
enc.alphabetMap[c] = uint8(i)
}
return enc
}
func reverseBuf(buf []byte) {
tot := len(buf)
mid := tot / 2
for i := 0; i < mid; i++ {
buf[i], buf[tot-i-1] = buf[tot-i-1], buf[i]
}
}
func (b *BaseXEncoder) EncodeToString(input []byte) string {
num := new(big.Int).SetBytes(input)
buf := make([]byte, 0, len(input))
rem := new(big.Int)
quo := new(big.Int)
for num.Sign() != 0 {
num, rem = quo.QuoRem(num, b.base, rem)
c := b.alphabet[rem.Uint64()]
buf = append(buf, c)
}
// Pad leading zeros...
for _, c := range input {
if c == 0x0 {
buf = append(buf, b.alphabet[0])
} else {
// Stop adding padding after the first nonzero byte.
break
}
}
reverseBuf(buf)
return string(buf)
}
func (b *BaseXEncoder) DecodeString(inp string) (outp []byte, err error) {
place := big.NewInt(1)
buf := []byte(inp)
padlen := 0
// Advance to first non-pad byte
for ; padlen < len(buf); padlen++ {
if buf[padlen] != b.alphabet[0] {
break
}
}
buf = buf[padlen:]
reverseBuf(buf)
tmp := new(big.Int)
res := big.NewInt(0)
for i, c := range buf {
charIndex := b.alphabetMap[c]
if charIndex == invalidBaseIndex {
err = fmt.Errorf("Bad character '%c' found at pos %d", c, i)
return
}
tmp.Mul(place, big.NewInt(int64(charIndex)))
res.Add(res, tmp)
if i != len(buf)-1 {
place.Mul(place, b.base)
}
}
buf = res.Bytes()
pad := bytes.Repeat([]byte{0}, padlen)
outp = make([]byte, len(pad)+len(buf))
copy(outp, pad)
copy(outp[len(pad):], buf)
return
}