From f8ea86748ae5eb4f57870f5d955c49fa9f23283b Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 3 Jul 2016 11:14:38 +0100 Subject: [PATCH] Switch from string to []byte slices The way I'm using the base58 required me to do a lot conversions between []byte slices and strings. Not anymore. Also switching to []byte slices allowed some nice performance improvements. Before, with strings: BenchmarkEncode-4 3000000 511 ns/op BenchmarkDecode-4 5000000 300 ns/op After, with []byte slices: BenchmarkEncode-4 5000000 256 ns/op BenchmarkDecode-4 20000000 107 ns/op --- base58.go | 30 ++++++++++++++++++++---------- base58_test.go | 14 ++++++++------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/base58.go b/base58.go index d0d43b7..d551f73 100644 --- a/base58.go +++ b/base58.go @@ -1,38 +1,41 @@ package base58 import ( + "bytes" "errors" - "strings" ) // Alphabet is the default alphabet. -const Alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" -const base = len(Alphabet) +var Alphabet = []byte( + "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", +) +var base = len(Alphabet) var errInvalidBase58 = errors.New("invalid base58") // Encode converts a base10 integer to a base58 string using the default // alphabet. -func Encode(num int) string { - str := "" +func Encode(num int) []byte { + str := []byte{} + for num >= base { mod := num % base - str = string(Alphabet[mod]) + str + str = prepend(str, Alphabet[mod]) num = (num - mod) / base } - return string(Alphabet[num]) + str + return prepend(str, Alphabet[num]) } // Decode converts a base58 string to a base10 integer using the default // alphabet. -func Decode(str string) (int, error) { +func Decode(str []byte) (int, error) { num := 0 multi := 1 for i := len(str); i > 0; i-- { - char := string(str[i-1]) - index := strings.Index(Alphabet, char) + char := str[i-1] + index := bytes.IndexByte(Alphabet, char) if index == -1 { return -1, errInvalidBase58 } @@ -42,3 +45,10 @@ func Decode(str string) (int, error) { return num, nil } + +func prepend(slice []byte, elem byte) []byte { + slice = append(slice, byte(0)) + copy(slice[1:], slice) + slice[0] = elem + return slice +} diff --git a/base58_test.go b/base58_test.go index c1a5bf5..4e39764 100644 --- a/base58_test.go +++ b/base58_test.go @@ -186,26 +186,28 @@ type Base58Suite struct { // Tests func (s *Base58Suite) TestAlphabet() { - expected := "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" - s.Equal(expected, Alphabet) + s.Equal( + []byte("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"), + Alphabet, + ) } func (s *Base58Suite) TestEncode() { for str, num := range examples { result := Encode(num) - s.Equal(str, result) + s.Equal([]byte(str), result) } } func (s *Base58Suite) TestDecode() { for str, num := range examples { - result, _ := Decode(str) + result, _ := Decode([]byte(str)) s.Equal(num, result) } } func (s *Base58Suite) TestDecodeError() { - result, err := Decode("invalid@base58.string") + result, err := Decode([]byte("invalid@base58.string")) s.Equal(-1, result) s.Equal("invalid base58", err.Error()) @@ -227,6 +229,6 @@ func BenchmarkEncode(b *testing.B) { func BenchmarkDecode(b *testing.B) { for n := 0; n < b.N; n++ { - _, _ = Decode("6hKMCS") + _, _ = Decode([]byte("6hKMCS")) } }