base58
This commit is contained in:
parent
62acddda5e
commit
86c01659d7
@ -32,7 +32,13 @@ echo ""
|
|||||||
|
|
||||||
git add --verbose .
|
git add --verbose .
|
||||||
|
|
||||||
git commit -a -m "v${next_ver}"
|
msg="v${next_ver}"
|
||||||
|
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
msg="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git commit -a -m "${msg}"
|
||||||
|
|
||||||
git tag "v${next_ver}"
|
git tag "v${next_ver}"
|
||||||
|
|
||||||
|
178
langext/base58.go
Normal file
178
langext/base58.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package langext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// shamelessly stolen from https://github.com/btcsuite/
|
||||||
|
|
||||||
|
type B58Encoding struct {
|
||||||
|
bigRadix [11]*big.Int
|
||||||
|
bigRadix10 *big.Int
|
||||||
|
alphabet string
|
||||||
|
alphabetIdx0 byte
|
||||||
|
b58 [256]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var Base58DefaultEncoding = newBase58Encoding("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
||||||
|
var Base58FlickrEncoding = newBase58Encoding("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
|
||||||
|
var Base58RippleEncoding = newBase58Encoding("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz")
|
||||||
|
var Base58BitcoinEncoding = newBase58Encoding("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
||||||
|
|
||||||
|
func newBase58Encoding(alphabet string) *B58Encoding {
|
||||||
|
bigRadix10 := big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58)
|
||||||
|
enc := &B58Encoding{
|
||||||
|
alphabet: alphabet,
|
||||||
|
alphabetIdx0: '1',
|
||||||
|
bigRadix: [...]*big.Int{
|
||||||
|
big.NewInt(0),
|
||||||
|
big.NewInt(58),
|
||||||
|
big.NewInt(58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
|
||||||
|
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
|
||||||
|
bigRadix10,
|
||||||
|
},
|
||||||
|
bigRadix10: bigRadix10,
|
||||||
|
}
|
||||||
|
|
||||||
|
b58 := make([]byte, 0, 256)
|
||||||
|
|
||||||
|
for i := byte(0); i < 32; i++ {
|
||||||
|
for j := byte(0); j < 8; j++ {
|
||||||
|
|
||||||
|
b := i*8 + j
|
||||||
|
|
||||||
|
idx := bytes.IndexByte([]byte(alphabet), b)
|
||||||
|
if idx == -1 {
|
||||||
|
b58 = append(b58, 255)
|
||||||
|
} else {
|
||||||
|
b58 = append(b58, byte(idx))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enc.b58 = *((*[256]byte)(b58))
|
||||||
|
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *B58Encoding) EncodeString(src string) (string, error) {
|
||||||
|
v, err := enc.Encode([]byte(src))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *B58Encoding) Encode(src []byte) ([]byte, error) {
|
||||||
|
x := new(big.Int)
|
||||||
|
x.SetBytes(src)
|
||||||
|
|
||||||
|
// maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58)
|
||||||
|
maxlen := int(float64(len(src))*1.365658237309761) + 1
|
||||||
|
answer := make([]byte, 0, maxlen)
|
||||||
|
mod := new(big.Int)
|
||||||
|
for x.Sign() > 0 {
|
||||||
|
// 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, enc.bigRadix10, mod)
|
||||||
|
if x.Sign() == 0 {
|
||||||
|
// When x = 0, we need to ensure we don't add any extra zeros.
|
||||||
|
m := mod.Int64()
|
||||||
|
for m > 0 {
|
||||||
|
answer = append(answer, enc.alphabet[m%58])
|
||||||
|
m /= 58
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m := mod.Int64()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
answer = append(answer, enc.alphabet[m%58])
|
||||||
|
m /= 58
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// leading zero bytes
|
||||||
|
for _, i := range src {
|
||||||
|
if i != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
answer = append(answer, enc.alphabetIdx0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse
|
||||||
|
alen := len(answer)
|
||||||
|
for i := 0; i < alen/2; i++ {
|
||||||
|
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *B58Encoding) DecodeString(src string) (string, error) {
|
||||||
|
v, err := enc.Decode([]byte(src))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *B58Encoding) Decode(src []byte) ([]byte, error) {
|
||||||
|
answer := big.NewInt(0)
|
||||||
|
scratch := new(big.Int)
|
||||||
|
|
||||||
|
for t := src; len(t) > 0; {
|
||||||
|
n := len(t)
|
||||||
|
if n > 10 {
|
||||||
|
n = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
total := uint64(0)
|
||||||
|
for _, v := range t[:n] {
|
||||||
|
if v > 255 {
|
||||||
|
return []byte{}, errors.New("invalid char in input")
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := enc.b58[v]
|
||||||
|
if tmp == 255 {
|
||||||
|
return []byte{}, errors.New("invalid char in input")
|
||||||
|
}
|
||||||
|
total = total*58 + uint64(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.Mul(answer, enc.bigRadix[n])
|
||||||
|
scratch.SetUint64(total)
|
||||||
|
answer.Add(answer, scratch)
|
||||||
|
|
||||||
|
t = t[n:]
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpval := answer.Bytes()
|
||||||
|
|
||||||
|
var numZeros int
|
||||||
|
for numZeros = 0; numZeros < len(src); numZeros++ {
|
||||||
|
if src[numZeros] != enc.alphabetIdx0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flen := numZeros + len(tmpval)
|
||||||
|
val := make([]byte, flen)
|
||||||
|
copy(val[numZeros:], tmpval)
|
||||||
|
|
||||||
|
return val, nil
|
||||||
|
}
|
67
langext/base58_test.go
Normal file
67
langext/base58_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package langext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func _encStr(t *testing.T, enc *B58Encoding, v string) string {
|
||||||
|
v, err := enc.EncodeString(v)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func _decStr(t *testing.T, enc *B58Encoding, v string) string {
|
||||||
|
v, err := enc.DecodeString(v)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58DefaultEncoding(t *testing.T) {
|
||||||
|
assertEqual(t, _encStr(t, Base58DefaultEncoding, "Hello"), "9Ajdvzr")
|
||||||
|
assertEqual(t, _encStr(t, Base58DefaultEncoding, "If debugging is the process of removing software bugs, then programming must be the process of putting them in."), "48638SMcJuah5okqPx4kCVf5d8QAdgbdNf28g7ReY13prUENNbMyssjq5GjsrJHF5zeZfqs4uJMUJHr7VbrU4XBUZ2Fw9DVtqtn9N1eXucEWSEZahXV6w4ysGSWqGdpeYTJf1MdDzTg8vfcQViifJjZX")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58DefaultDecoding(t *testing.T) {
|
||||||
|
assertEqual(t, _decStr(t, Base58DefaultEncoding, "9Ajdvzr"), "Hello")
|
||||||
|
assertEqual(t, _decStr(t, Base58DefaultEncoding, "48638SMcJuah5okqPx4kCVf5d8QAdgbdNf28g7ReY13prUENNbMyssjq5GjsrJHF5zeZfqs4uJMUJHr7VbrU4XBUZ2Fw9DVtqtn9N1eXucEWSEZahXV6w4ysGSWqGdpeYTJf1MdDzTg8vfcQViifJjZX"), "If debugging is the process of removing software bugs, then programming must be the process of putting them in.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58RippleEncoding(t *testing.T) {
|
||||||
|
assertEqual(t, _encStr(t, Base58RippleEncoding, "Hello"), "9wjdvzi")
|
||||||
|
assertEqual(t, _encStr(t, Base58RippleEncoding, "If debugging is the process of removing software bugs, then programming must be the process of putting them in."), "h3as3SMcJu26nokqPxhkUVCnd3Qwdgbd4Cp3gfReYrsFi7N44bMy11jqnGj1iJHEnzeZCq1huJM7JHifVbi7hXB7ZpEA9DVtqt894reXucNWSNZ26XVaAhy1GSWqGdFeYTJCrMdDzTg3vCcQV55CJjZX")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58RippleDecoding(t *testing.T) {
|
||||||
|
assertEqual(t, _decStr(t, Base58RippleEncoding, "9wjdvzi"), "Hello")
|
||||||
|
assertEqual(t, _decStr(t, Base58RippleEncoding, "h3as3SMcJu26nokqPxhkUVCnd3Qwdgbd4Cp3gfReYrsFi7N44bMy11jqnGj1iJHEnzeZCq1huJM7JHifVbi7hXB7ZpEA9DVtqt894reXucNWSNZ26XVaAhy1GSWqGdFeYTJCrMdDzTg3vCcQV55CJjZX"), "If debugging is the process of removing software bugs, then programming must be the process of putting them in.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58BitcoinEncoding(t *testing.T) {
|
||||||
|
assertEqual(t, _encStr(t, Base58BitcoinEncoding, "Hello"), "9Ajdvzr")
|
||||||
|
assertEqual(t, _encStr(t, Base58BitcoinEncoding, "If debugging is the process of removing software bugs, then programming must be the process of putting them in."), "48638SMcJuah5okqPx4kCVf5d8QAdgbdNf28g7ReY13prUENNbMyssjq5GjsrJHF5zeZfqs4uJMUJHr7VbrU4XBUZ2Fw9DVtqtn9N1eXucEWSEZahXV6w4ysGSWqGdpeYTJf1MdDzTg8vfcQViifJjZX")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58BitcoinDecoding(t *testing.T) {
|
||||||
|
assertEqual(t, _decStr(t, Base58BitcoinEncoding, "9Ajdvzr"), "Hello")
|
||||||
|
assertEqual(t, _decStr(t, Base58BitcoinEncoding, "48638SMcJuah5okqPx4kCVf5d8QAdgbdNf28g7ReY13prUENNbMyssjq5GjsrJHF5zeZfqs4uJMUJHr7VbrU4XBUZ2Fw9DVtqtn9N1eXucEWSEZahXV6w4ysGSWqGdpeYTJf1MdDzTg8vfcQViifJjZX"), "If debugging is the process of removing software bugs, then programming must be the process of putting them in.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58FlickrEncoding(t *testing.T) {
|
||||||
|
assertEqual(t, _encStr(t, Base58FlickrEncoding, "Hello"), "9aJCVZR")
|
||||||
|
assertEqual(t, _encStr(t, Base58FlickrEncoding, "If debugging is the process of removing software bugs, then programming must be the process of putting them in."), "48638rmBiUzG5NKQoX4KcuE5C8paCFACnE28F7qDx13PRtennAmYSSJQ5gJSRihf5ZDyEQS4UimtihR7uARt4wbty2fW9duTQTM9n1DwUBevreyzGwu6W4YSgrvQgCPDxsiE1mCdZsF8VEBpuHHEiJyw")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase58FlickrDecoding(t *testing.T) {
|
||||||
|
assertEqual(t, _decStr(t, Base58FlickrEncoding, "9aJCVZR"), "Hello")
|
||||||
|
assertEqual(t, _decStr(t, Base58FlickrEncoding, "48638rmBiUzG5NKQoX4KcuE5C8paCFACnE28F7qDx13PRtennAmYSSJQ5gJSRihf5ZDyEQS4UimtihR7uARt4wbty2fW9duTQTM9n1DwUBevreyzGwu6W4YSgrvQgCPDxsiE1mCdZsF8VEBpuHHEiJyw"), "If debugging is the process of removing software bugs, then programming must be the process of putting them in.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEqual(t *testing.T, actual string, expected string) {
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user