2015-05-01 12:41:58 -05:00
|
|
|
// Copyright (c) 2013-2015 The btcsuite developers
|
2014-12-19 13:40:50 +01:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package base58
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/big"
|
|
|
|
)
|
|
|
|
|
2015-01-24 13:49:08 -05:00
|
|
|
//go:generate go run genalphabet.go
|
2014-12-19 13:40:50 +01:00
|
|
|
|
|
|
|
var bigRadix = big.NewInt(58)
|
2020-09-10 17:54:35 +03:00
|
|
|
var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
|
2014-12-19 13:40:50 +01:00
|
|
|
var bigZero = big.NewInt(0)
|
|
|
|
|
|
|
|
// Decode decodes a modified base58 string to a byte slice.
|
|
|
|
func Decode(b string) []byte {
|
|
|
|
answer := big.NewInt(0)
|
|
|
|
j := big.NewInt(1)
|
|
|
|
|
2015-01-24 13:49:08 -05:00
|
|
|
scratch := new(big.Int)
|
2014-12-19 13:40:50 +01:00
|
|
|
for i := len(b) - 1; i >= 0; i-- {
|
2015-01-24 13:49:08 -05:00
|
|
|
tmp := b58[b[i]]
|
|
|
|
if tmp == 255 {
|
2014-12-19 13:40:50 +01:00
|
|
|
return []byte("")
|
|
|
|
}
|
2015-01-24 13:49:08 -05:00
|
|
|
scratch.SetInt64(int64(tmp))
|
|
|
|
scratch.Mul(j, scratch)
|
|
|
|
answer.Add(answer, scratch)
|
2014-12-19 13:40:50 +01:00
|
|
|
j.Mul(j, bigRadix)
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpval := answer.Bytes()
|
|
|
|
|
|
|
|
var numZeros int
|
|
|
|
for numZeros = 0; numZeros < len(b); numZeros++ {
|
2015-01-24 13:49:08 -05:00
|
|
|
if b[numZeros] != alphabetIdx0 {
|
2014-12-19 13:40:50 +01:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
flen := numZeros + len(tmpval)
|
2017-04-19 10:14:49 -04:00
|
|
|
val := make([]byte, flen)
|
2014-12-19 13:40:50 +01:00
|
|
|
copy(val[numZeros:], tmpval)
|
|
|
|
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encode encodes a byte slice to a modified base58 string.
|
|
|
|
func Encode(b []byte) string {
|
|
|
|
x := new(big.Int)
|
|
|
|
x.SetBytes(b)
|
|
|
|
|
|
|
|
answer := make([]byte, 0, len(b)*136/100)
|
2020-09-10 17:54:35 +03:00
|
|
|
mod := new(big.Int)
|
2014-12-19 13:40:50 +01:00
|
|
|
for x.Cmp(bigZero) > 0 {
|
2020-09-10 17:54:35 +03:00
|
|
|
// Calculating with big.Int is slow for each iteration.
|
|
|
|
// x, mod = x / 58, x % 58
|
|
|
|
//
|
|
|
|
// Instead we can try to do as much calculations on int64.
|
|
|
|
// x, mod = x / 58^10, x % 58^10
|
|
|
|
//
|
|
|
|
// Which will give us mod, which is 10 digit base58 number.
|
|
|
|
// We'll loop that 10 times to convert to the answer.
|
|
|
|
|
|
|
|
x.DivMod(x, bigRadix10, mod)
|
|
|
|
if x.Cmp(bigZero) == 0 {
|
|
|
|
// When x = 0, we need to ensure we don't add any extra zeros.
|
|
|
|
m := mod.Int64()
|
|
|
|
for m > 0 {
|
|
|
|
answer = append(answer, alphabet[m%58])
|
|
|
|
m /= 58
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m := mod.Int64()
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
answer = append(answer, alphabet[m%58])
|
|
|
|
m /= 58
|
|
|
|
}
|
|
|
|
}
|
2014-12-19 13:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// leading zero bytes
|
|
|
|
for _, i := range b {
|
|
|
|
if i != 0 {
|
|
|
|
break
|
|
|
|
}
|
2015-01-24 13:49:08 -05:00
|
|
|
answer = append(answer, alphabetIdx0)
|
2014-12-19 13:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// reverse
|
|
|
|
alen := len(answer)
|
|
|
|
for i := 0; i < alen/2; i++ {
|
|
|
|
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(answer)
|
|
|
|
}
|