crypto: use mr-tron/base58 for base58

Use more fast and reliable implementation. Add some tests for our wrappers,
deduplicate code in PublicKey.Adress(). Fixes #355.
This commit is contained in:
Roman Khimov 2019-09-09 13:09:46 +03:00
parent 450063de7d
commit 8db9d2a976
5 changed files with 26 additions and 99 deletions

1
go.mod
View file

@ -5,6 +5,7 @@ require (
github.com/go-redis/redis v6.10.2+incompatible github.com/go-redis/redis v6.10.2+incompatible
github.com/go-yaml/yaml v2.1.0+incompatible github.com/go-yaml/yaml v2.1.0+incompatible
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 // indirect github.com/golang/snappy v0.0.0-20170215233205-553a64147049 // indirect
github.com/mr-tron/base58 v1.1.2
github.com/nspcc-dev/rfc6979 v0.1.0 github.com/nspcc-dev/rfc6979 v0.1.0
github.com/onsi/gomega v1.4.2 // indirect github.com/onsi/gomega v1.4.2 // indirect
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0

2
go.sum
View file

@ -12,6 +12,8 @@ github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0a
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/nspcc-dev/rfc6979 v0.1.0 h1:Lwg7esRRoyK1Up/IN1vAef1EmvrBeMHeeEkek2fAJ6c= github.com/nspcc-dev/rfc6979 v0.1.0 h1:Lwg7esRRoyK1Up/IN1vAef1EmvrBeMHeeEkek2fAJ6c=
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=

View file

@ -2,88 +2,15 @@ package crypto
import ( import (
"bytes" "bytes"
"fmt"
"math/big"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/mr-tron/base58"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const prefix rune = '1'
var decodeMap = map[rune]int64{
'1': 0, '2': 1, '3': 2, '4': 3, '5': 4,
'6': 5, '7': 6, '8': 7, '9': 8, 'A': 9,
'B': 10, 'C': 11, 'D': 12, 'E': 13, 'F': 14,
'G': 15, 'H': 16, 'J': 17, 'K': 18, 'L': 19,
'M': 20, 'N': 21, 'P': 22, 'Q': 23, 'R': 24,
'S': 25, 'T': 26, 'U': 27, 'V': 28, 'W': 29,
'X': 30, 'Y': 31, 'Z': 32, 'a': 33, 'b': 34,
'c': 35, 'd': 36, 'e': 37, 'f': 38, 'g': 39,
'h': 40, 'i': 41, 'j': 42, 'k': 43, 'm': 44,
'n': 45, 'o': 46, 'p': 47, 'q': 48, 'r': 49,
's': 50, 't': 51, 'u': 52, 'v': 53, 'w': 54,
'x': 55, 'y': 56, 'z': 57,
}
// Base58Decode decodes the base58 encoded string.
func Base58Decode(s string) ([]byte, error) {
var (
startIndex = 0
zero = 0
)
for i, c := range s {
if c == prefix {
zero++
} else {
startIndex = i
break
}
}
var (
n = big.NewInt(0)
div = big.NewInt(58)
)
for _, c := range s[startIndex:] {
charIndex, ok := decodeMap[c]
if !ok {
return nil, fmt.Errorf(
"invalid character '%c' when decoding this base58 string: '%s'", c, s,
)
}
n.Add(n.Mul(n, div), big.NewInt(charIndex))
}
out := n.Bytes()
buf := make([]byte, zero+len(out))
copy(buf[zero:], out)
return buf, nil
}
// Base58Encode encodes a byte slice to be a base58 encoded string.
func Base58Encode(bytes []byte) string {
var (
lookupTable = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
x = new(big.Int).SetBytes(bytes)
r = new(big.Int)
m = big.NewInt(58)
zero = big.NewInt(0)
encoded string
)
for x.Cmp(zero) > 0 {
x.QuoRem(x, m, r)
encoded = string(lookupTable[r.Int64()]) + encoded
}
return encoded
}
// Base58CheckDecode decodes the given string. // Base58CheckDecode decodes the given string.
func Base58CheckDecode(s string) (b []byte, err error) { func Base58CheckDecode(s string) (b []byte, err error) {
b, err = Base58Decode(s) b, err = base58.Decode(s)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -113,5 +40,5 @@ func Base58CheckDecode(s string) (b []byte, err error) {
func Base58CheckEncode(b []byte) string { func Base58CheckEncode(b []byte) string {
b = append(b, hash.Checksum(b)...) b = append(b, hash.Checksum(b)...)
return Base58Encode(b) return base58.Encode(b)
} }

View file

@ -7,26 +7,26 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestBase58Decode(t *testing.T) { func TestBase58CheckEncodeDecode(t *testing.T) {
input := "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" var b58CsumEncoded = "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o"
var b58CsumDecodedHex = "802bfe58ab6d9fd575bdc3a624e4825dd2b375d64ac033fbc46ea79dbab4f69a3e01"
data, err := Base58Decode(input) b58CsumDecoded, _ := hex.DecodeString(b58CsumDecodedHex)
if err != nil { encoded := Base58CheckEncode(b58CsumDecoded)
t.Fatal(err) decoded, err := Base58CheckDecode(b58CsumEncoded)
assert.Nil(t, err)
assert.Equal(t, encoded, b58CsumEncoded)
assert.Equal(t, decoded, b58CsumDecoded)
} }
expected := "0099bc78ba577a95a11f1a344d4d2ae55f2f857b989ea5e5e2" func TestBase58CheckDecodeFailures(t *testing.T) {
actual := hex.EncodeToString(data) badbase58 := "BASE%*"
assert.Equal(t, expected, actual) _, err := Base58CheckDecode(badbase58)
} assert.NotNil(t, err)
func TestBase58Encode(t *testing.T) { shortbase58 := "THqY"
input := "0099bc78ba577a95a11f1a344d4d2ae55f2f857b989ea5e5e2" _, err = Base58CheckDecode(shortbase58)
assert.NotNil(t, err)
inputBytes, _ := hex.DecodeString(input) badcsum := "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9A"
_, err = Base58CheckDecode(badcsum)
data := Base58Encode(inputBytes) assert.NotNil(t, err)
expected := "F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" // Removed the 1 as it is not checkEncoding
actual := data
assert.Equal(t, expected, actual)
} }

View file

@ -203,11 +203,8 @@ func (p *PublicKey) Address() string {
var b = p.Signature() var b = p.Signature()
b = append([]byte{0x17}, b...) b = append([]byte{0x17}, b...)
csum := hash.Checksum(b)
b = append(b, csum...)
address := crypto.Base58Encode(b) return crypto.Base58CheckEncode(b)
return address
} }
// Verify returns true if the signature is valid and corresponds // Verify returns true if the signature is valid and corresponds