go port
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
// Package base58 implements Bitcoin-style base58 and base58check encoding on
|
||||
// top of math/big and crypto/sha256. It is the address encoding used by TRON.
|
||||
package base58
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
// ErrInvalidByte is returned when a byte is not part of the base58 alphabet.
|
||||
var ErrInvalidByte = errors.New("base58: invalid byte")
|
||||
|
||||
// ErrChecksum indicates a base58check payload with a wrong checksum.
|
||||
var ErrChecksum = errors.New("base58: checksum mismatch")
|
||||
|
||||
var decodeMap = buildDecodeMap()
|
||||
|
||||
func buildDecodeMap() [256]int16 {
|
||||
var m [256]int16
|
||||
for i := range m {
|
||||
m[i] = -1
|
||||
}
|
||||
for i := 0; i < len(alphabet); i++ {
|
||||
m[alphabet[i]] = int16(i)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Encode converts a byte slice to a base58 string.
|
||||
func Encode(b []byte) string {
|
||||
x := new(big.Int).SetBytes(b)
|
||||
base := big.NewInt(58)
|
||||
mod := new(big.Int)
|
||||
out := make([]byte, 0, len(b)*137/100+1)
|
||||
for x.Sign() > 0 {
|
||||
x.DivMod(x, base, mod)
|
||||
out = append(out, alphabet[mod.Int64()])
|
||||
}
|
||||
for _, c := range b {
|
||||
if c != 0 {
|
||||
break
|
||||
}
|
||||
out = append(out, alphabet[0])
|
||||
}
|
||||
for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
|
||||
out[i], out[j] = out[j], out[i]
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// Decode converts a base58 string to a byte slice.
|
||||
func Decode(s string) ([]byte, error) {
|
||||
x := big.NewInt(0)
|
||||
base := big.NewInt(58)
|
||||
for i := 0; i < len(s); i++ {
|
||||
d := decodeMap[s[i]]
|
||||
if d < 0 {
|
||||
return nil, ErrInvalidByte
|
||||
}
|
||||
x.Mul(x, base)
|
||||
x.Add(x, big.NewInt(int64(d)))
|
||||
}
|
||||
was := x.Bytes()
|
||||
pad := 0
|
||||
for pad < len(s) && s[pad] == alphabet[0] {
|
||||
pad++
|
||||
}
|
||||
out := make([]byte, pad+len(was))
|
||||
copy(out[pad:], was)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func checksum(payload []byte) []byte {
|
||||
h1 := sha256.Sum256(payload)
|
||||
h2 := sha256.Sum256(h1[:])
|
||||
return h2[:4]
|
||||
}
|
||||
|
||||
// CheckEncode returns the base58check encoding of payload.
|
||||
func CheckEncode(payload []byte) string {
|
||||
buf := make([]byte, 0, len(payload)+4)
|
||||
buf = append(buf, payload...)
|
||||
buf = append(buf, checksum(payload)...)
|
||||
return Encode(buf)
|
||||
}
|
||||
|
||||
// CheckDecode decodes a base58check string, verifying its checksum.
|
||||
func CheckDecode(s string) ([]byte, error) {
|
||||
raw, err := Decode(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(raw) < 5 {
|
||||
return nil, ErrChecksum
|
||||
}
|
||||
payload := raw[:len(raw)-4]
|
||||
want := checksum(payload)
|
||||
got := raw[len(raw)-4:]
|
||||
for i := 0; i < 4; i++ {
|
||||
if want[i] != got[i] {
|
||||
return nil, ErrChecksum
|
||||
}
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// IsValid reports whether s is a well-formed base58check string.
|
||||
func IsValid(s string) bool {
|
||||
if len(s) == 0 || strings.IndexByte(s, ' ') >= 0 {
|
||||
return false
|
||||
}
|
||||
_, err := CheckDecode(s)
|
||||
return err == nil
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package base58
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
cases := [][]byte{
|
||||
{0x00},
|
||||
{0x00, 0x00, 0x01},
|
||||
bytes.Repeat([]byte{0xff}, 32),
|
||||
[]byte("hello world"),
|
||||
{},
|
||||
}
|
||||
for _, in := range cases {
|
||||
enc := Encode(in)
|
||||
got, err := Decode(enc)
|
||||
if err != nil {
|
||||
t.Fatalf("Decode(%q): %v", enc, err)
|
||||
}
|
||||
if !bytes.Equal(got, in) {
|
||||
t.Fatalf("round trip mismatch: in=%x enc=%q got=%x", in, enc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckEncodeKnownAddress(t *testing.T) {
|
||||
raw, err := hex.DecodeString("4143d75ee7cdcd7f2fcd4fc3b4eb574b6bdc2a3fcb")
|
||||
if err != nil {
|
||||
t.Fatalf("decode raw: %v", err)
|
||||
}
|
||||
if got := CheckEncode(raw); got != "TG9vH8c2jBWq2wSnksrq5mVyq2wjhG4A1n" {
|
||||
t.Fatalf("CheckEncode = %s", got)
|
||||
}
|
||||
payload, err := CheckDecode("TG9vH8c2jBWq2wSnksrq5mVyq2wjhG4A1n")
|
||||
if err != nil {
|
||||
t.Fatalf("CheckDecode: %v", err)
|
||||
}
|
||||
if !bytes.Equal(payload, raw) {
|
||||
t.Fatalf("CheckDecode = %x, want %x", payload, raw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckDecodeRejectsBadChecksum(t *testing.T) {
|
||||
if _, err := CheckDecode("TG9vH8c2jBWq2wSnksrq5mVyq2wjhG4A1m"); err == nil {
|
||||
t.Fatalf("expected checksum error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeRejectsInvalidByte(t *testing.T) {
|
||||
if _, err := Decode("0OIl"); err == nil {
|
||||
t.Fatalf("expected invalid byte error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user