// 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 }