Optimize base58 decoding.
This change introduces an autogenerated base58 digit table to remove the need to find the index of a character in the modified base58 alphabet each time. Additionally, it removes some unnecessary big integer allocations to cut down on the GC churn. Before: BenchmarkBase58Encode 20 64998995 ns/op 0.08 MB/s BenchmarkBase58Decode 50 35965928 ns/op 0.19 MB/s Now: BenchmarkBase58Encode 20 64644351 ns/op 0.08 MB/s BenchmarkBase58Decode 200 7914748 ns/op 0.86 MB/s
This commit is contained in:
parent
9dcef5b30f
commit
dca623d4ef
3 changed files with 138 additions and 13 deletions
49
base58/alphabet.go
Normal file
49
base58/alphabet.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright (c) 2015 Conformal Systems LLC.
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||||
|
|
||||||
|
package base58
|
||||||
|
|
||||||
|
const (
|
||||||
|
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||||
|
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
alphabetIdx0 = '1'
|
||||||
|
)
|
||||||
|
|
||||||
|
var b58 = [256]byte{
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 0, 1, 2, 3, 4, 5, 6,
|
||||||
|
7, 8, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 255, 17, 18, 19, 20, 21, 255,
|
||||||
|
22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
|
30, 31, 32, 255, 255, 255, 255, 255,
|
||||||
|
255, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 255, 44, 45, 46,
|
||||||
|
47, 48, 49, 50, 51, 52, 53, 54,
|
||||||
|
55, 56, 57, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2013-2014 Conformal Systems LLC.
|
// Copyright (c) 2013-2015 Conformal Systems LLC.
|
||||||
// Use of this source code is governed by an ISC
|
// Use of this source code is governed by an ISC
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -6,11 +6,9 @@ package base58
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// alphabet is the modified base58 alphabet used by Bitcoin.
|
//go:generate go run genalphabet.go
|
||||||
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
||||||
|
|
||||||
var bigRadix = big.NewInt(58)
|
var bigRadix = big.NewInt(58)
|
||||||
var bigZero = big.NewInt(0)
|
var bigZero = big.NewInt(0)
|
||||||
|
@ -20,16 +18,15 @@ func Decode(b string) []byte {
|
||||||
answer := big.NewInt(0)
|
answer := big.NewInt(0)
|
||||||
j := big.NewInt(1)
|
j := big.NewInt(1)
|
||||||
|
|
||||||
|
scratch := new(big.Int)
|
||||||
for i := len(b) - 1; i >= 0; i-- {
|
for i := len(b) - 1; i >= 0; i-- {
|
||||||
tmp := strings.IndexAny(alphabet, string(b[i]))
|
tmp := b58[b[i]]
|
||||||
if tmp == -1 {
|
if tmp == 255 {
|
||||||
return []byte("")
|
return []byte("")
|
||||||
}
|
}
|
||||||
idx := big.NewInt(int64(tmp))
|
scratch.SetInt64(int64(tmp))
|
||||||
tmp1 := big.NewInt(0)
|
scratch.Mul(j, scratch)
|
||||||
tmp1.Mul(j, idx)
|
answer.Add(answer, scratch)
|
||||||
|
|
||||||
answer.Add(answer, tmp1)
|
|
||||||
j.Mul(j, bigRadix)
|
j.Mul(j, bigRadix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +34,7 @@ func Decode(b string) []byte {
|
||||||
|
|
||||||
var numZeros int
|
var numZeros int
|
||||||
for numZeros = 0; numZeros < len(b); numZeros++ {
|
for numZeros = 0; numZeros < len(b); numZeros++ {
|
||||||
if b[numZeros] != alphabet[0] {
|
if b[numZeros] != alphabetIdx0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +62,7 @@ func Encode(b []byte) string {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
answer = append(answer, alphabet[0])
|
answer = append(answer, alphabetIdx0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reverse
|
// reverse
|
||||||
|
|
79
base58/genalphabet.go
Normal file
79
base58/genalphabet.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (c) 2015 Conformal Systems LLC.
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//+build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
start = []byte(`// Copyright (c) 2015 Conformal Systems LLC.
|
||||||
|
// Use of this source code is governed by an ISC
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||||
|
|
||||||
|
package base58
|
||||||
|
|
||||||
|
const (
|
||||||
|
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||||
|
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
alphabetIdx0 = '1'
|
||||||
|
)
|
||||||
|
|
||||||
|
var b58 = [256]byte{`)
|
||||||
|
|
||||||
|
end = []byte(`}`)
|
||||||
|
|
||||||
|
alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
||||||
|
tab = []byte("\t")
|
||||||
|
invalid = []byte("255")
|
||||||
|
comma = []byte(",")
|
||||||
|
space = []byte(" ")
|
||||||
|
nl = []byte("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
func write(w io.Writer, b []byte) {
|
||||||
|
_, err := w.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fi, err := os.Create("alphabet.go")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer fi.Close()
|
||||||
|
|
||||||
|
write(fi, start)
|
||||||
|
write(fi, nl)
|
||||||
|
for i := byte(0); i < 32; i++ {
|
||||||
|
write(fi, tab)
|
||||||
|
for j := byte(0); j < 8; j++ {
|
||||||
|
idx := bytes.IndexByte(alphabet, i*8+j)
|
||||||
|
if idx == -1 {
|
||||||
|
write(fi, invalid)
|
||||||
|
} else {
|
||||||
|
write(fi, strconv.AppendInt(nil, int64(idx), 10))
|
||||||
|
}
|
||||||
|
write(fi, comma)
|
||||||
|
if j != 7 {
|
||||||
|
write(fi, space)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(fi, nl)
|
||||||
|
}
|
||||||
|
write(fi, end)
|
||||||
|
write(fi, nl)
|
||||||
|
}
|
Loading…
Reference in a new issue