diff --git a/go.mod b/go.mod index 837176e0c..1c0295d9b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ require ( github.com/go-redis/redis v6.10.2+incompatible github.com/go-yaml/yaml v2.1.0+incompatible 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/onsi/gomega v1.4.2 // indirect github.com/pkg/errors v0.8.0 diff --git a/go.sum b/go.sum index 87bd73377..8b8e51634 100644 --- a/go.sum +++ b/go.sum @@ -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/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 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/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= diff --git a/pkg/crypto/base58.go b/pkg/crypto/base58.go index 6890aae17..9db748022 100644 --- a/pkg/crypto/base58.go +++ b/pkg/crypto/base58.go @@ -2,88 +2,15 @@ package crypto import ( "bytes" - "fmt" - "math/big" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/mr-tron/base58" "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. func Base58CheckDecode(s string) (b []byte, err error) { - b, err = Base58Decode(s) + b, err = base58.Decode(s) if err != nil { return nil, err } @@ -113,5 +40,5 @@ func Base58CheckDecode(s string) (b []byte, err error) { func Base58CheckEncode(b []byte) string { b = append(b, hash.Checksum(b)...) - return Base58Encode(b) + return base58.Encode(b) } diff --git a/pkg/crypto/base58_test.go b/pkg/crypto/base58_test.go index 7bf48cf70..5c1388754 100755 --- a/pkg/crypto/base58_test.go +++ b/pkg/crypto/base58_test.go @@ -7,26 +7,26 @@ import ( "github.com/stretchr/testify/assert" ) -func TestBase58Decode(t *testing.T) { - input := "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" +func TestBase58CheckEncodeDecode(t *testing.T) { + var b58CsumEncoded = "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o" + var b58CsumDecodedHex = "802bfe58ab6d9fd575bdc3a624e4825dd2b375d64ac033fbc46ea79dbab4f69a3e01" - data, err := Base58Decode(input) - if err != nil { - t.Fatal(err) - } - - expected := "0099bc78ba577a95a11f1a344d4d2ae55f2f857b989ea5e5e2" - actual := hex.EncodeToString(data) - assert.Equal(t, expected, actual) + b58CsumDecoded, _ := hex.DecodeString(b58CsumDecodedHex) + encoded := Base58CheckEncode(b58CsumDecoded) + decoded, err := Base58CheckDecode(b58CsumEncoded) + assert.Nil(t, err) + assert.Equal(t, encoded, b58CsumEncoded) + assert.Equal(t, decoded, b58CsumDecoded) } -func TestBase58Encode(t *testing.T) { - input := "0099bc78ba577a95a11f1a344d4d2ae55f2f857b989ea5e5e2" - inputBytes, _ := hex.DecodeString(input) - - data := Base58Encode(inputBytes) - - expected := "F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" // Removed the 1 as it is not checkEncoding - actual := data - assert.Equal(t, expected, actual) +func TestBase58CheckDecodeFailures(t *testing.T) { + badbase58 := "BASE%*" + _, err := Base58CheckDecode(badbase58) + assert.NotNil(t, err) + shortbase58 := "THqY" + _, err = Base58CheckDecode(shortbase58) + assert.NotNil(t, err) + badcsum := "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9A" + _, err = Base58CheckDecode(badcsum) + assert.NotNil(t, err) } diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index ba823839c..7335a6a2e 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -203,11 +203,8 @@ func (p *PublicKey) Address() string { var b = p.Signature() b = append([]byte{0x17}, b...) - csum := hash.Checksum(b) - b = append(b, csum...) - address := crypto.Base58Encode(b) - return address + return crypto.Base58CheckEncode(b) } // Verify returns true if the signature is valid and corresponds