Base58编码解码Go实现

时间:2022-06-06 13:53:00

base58和base64一样是一种二进制转可视字符串的算法,主要用来转换大整数值。区别是,转换出来的字符串,去除了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。

结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。

编码流程 (本质为大数与字符串的转化)

  1. 输入为bytes,比如:[0x00, 0xFF]

  2. 忽略前面的0x00得到数字256

  3. 256通过base58编码为字符串”5Q”,因为要处理0x00,所以得到字符串”15Q”

  4. 把字符串“15Q”转化为bytes: [0x49, 0x53, 0x81]

实现

package main

import (
    "bytes"
    "math/big"
)

var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")

func Base58Encode(input []byte) []byte {
    var result []byte

    x := big.NewInt(0).SetBytes(input)

    base := big.NewInt(int64(len(b58Alphabet)))
    zero := big.NewInt(0)
    mod := &big.Int{}

    for x.Cmp(zero) != 0 {
        x.DivMod(x, base, mod)
        result = append(result, b58Alphabet[mod.Int64()])
    }

    ReverseBytes(result)

    for _, b := range input {
        if b == 0x00 {
            result = append([]byte{b58Alphabet[0]}, result...)

        } else {
            break
        }
    }

    return result

}

func Base58Decode(input []byte) []byte {
    result := big.NewInt(0)
    zeroBytes := 0

    for _, b := range input {
        if b != b58Alphabet[0] {
            break
        }

        zeroBytes++
    }

    payload := input[zeroBytes:]
    for _, b := range payload {
        charIndex := bytes.IndexByte(b58Alphabet, b)
        result.Mul(result, big.NewInt(int64(len(b58Alphabet))))
        result.Add(result, big.NewInt(int64(charIndex)))
    }

    decoded := result.Bytes()
    decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...)

    return decoded
}

更多