编码算法-Base58

❀ Base58 编码表:123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ ❀

介绍

  • Base58 是 Bitcoin 中使用的一种独特的编码方式,主要用于产生 Bitcoin 的钱包地址。
  • Base58 采用数字、大写字母、小写字母,去除歧义字符 0(零)、O(大写字母 O)、I(大写字母i)、l(小写字母L),总计58个字符作为编码的字母表。
  • Base58Check 是一种 Base58 编码格式,可在前几个字符中明确编码的数据类型(版本号 Version),并在最后几个字符中包含一个错误检测代码(校验和 Checksum)。

Base58 与 Base64 异同

相同

  • 一般都用于URL,邮件文本,可见字符显示。
  • 都会造成信息冗余,数据量增大,因此不会用于大数据传输编码。

区别

  • 编码集不同,Base58 的编码集在 Base64 的字符集的基础上去掉了比较容易混淆的字符。
  • Base64 采用直接切割 bit 的方法(8->6),而 Base58 采用大数进制转换,效率更低,使用场景更少。

【注】Base58 解码时需要将长度传入, 这点与 Base64 有区别, 在代码实现时应注意。

编码流程

将ascii编码的字符串(256进制),转换成58进制。然后按照58进制的码表转换成相应的字符。

1、将字符串的每个字节换算成ASCII(0-255) (字符串实际上就是256进制的数字组合):

  • 源字符串为:ABD
  • 换算后: 65 66 68

2、将256进制的数字转换成10进制数字:

  • 256进制数:65 66 68
  • 转成10进制:(65 * 256 + 66) * 256 + 68 = 4276804

3、将10进制数字转换成58进制数字:

  • 10进制数:4276804
  • 58进制数: 21 53 20 0

4、将58进制数字的每一位按照表格转换成对应的字符:

  • 58进制数:21 53 20 0
  • 码表:123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
  • 转换后的字符:nVm1

【注】任意进制之间的转换,先将数字转10进制再转其它进制

解码流程

按码表把字符转成58进制数字,再转256进制,按ascii把256进制数字转字符。

1、字符串每一位按码表替换成数字(58进制):

  • 源字符: nVm1
  • 58进制数:21 53 20 0

2、58进制转10进制:

  • 58进制数:21 53 20 0
  • 10进制数:4276804

3、10进制转256进制:

  • 10进制数:4276804
  • 256进制: 65 66 68

4、256进制转字符(按ascii转)

  • 256进制: 65 66 68
  • 字符:ABD

【注】任意进制之间的转换,先将数字转10进制再转其它进制

Base58 编码图示

编码算法-Base58_第1张图片
Base58 编码算法

Base58Check 编码

Base58Check 是一种常用在数字加密货币中的 Base58 编码格式,增加了错误校验码来检查数据在转录中出现的错误。

校验码长4个字节,添加到需要编码的数据之后。校验码是从需要编码的数据的哈希值中得到的,所以可以用来检测并避免转录和输入中产生的错误。

使用 Base58check 编码格式时,编码软件会计算原始数据的校验码并和结果数据中自带的校验码进行对比。二者不匹配则表明有错误产生,那么这个Base58Check格式的数据就是无效的。例如,一个错误XX币地址就不会被钱包认为是有效的地址,否则这种错误会造成资金的丢失。

Base58Check 编码图示

编码算法-Base58_第2张图片
Base58Check 编码

代码

  • PHP 代码
= $base) {
        $div = bcdiv($decimal, $base, 0);
        $mod = bcmod($decimal, $base);
        $output .= $alphabet[$mod];
        $decimal = $div;
    }
    if ($decimal > 0) {
        $output .= $alphabet[$decimal];
    }
    $output = strrev($output);

    return (string) $output;
}

function base58_decode($base58)
{
    $alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
    $base = strlen($alphabet);

    if (is_string($base58) === false || !strlen($base58)) {
        return false;
    }
    $indexes = array_flip(str_split($alphabet));
    $chars = str_split($base58);
    foreach ($chars as $char) {
        if (isset($indexes[$char]) === false) {
            return false;
        }
    }
    $decimal = $indexes[$chars[0]];
    for ($i = 1, $l = count($chars); $i < $l; ++$i) {
        $decimal = bcmul($decimal, $base);
        $decimal = bcadd($decimal, $indexes[$chars[$i]]);
    }
    $output = '';
    while ($decimal > 0) {
        $byte = bcmod($decimal, 256);
        $output = pack('C', $byte).$output;
        $decimal = bcdiv($decimal, 256, 0);
    }
    return $output;
}
  • Python
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)


def b58encode(v):
    """ encode v, which is a string of bytes, to base58.
    """

    long_value = int(v.encode("hex_codec"), 16)

    result = ''
    while long_value >= __b58base:
        div, mod = divmod(long_value, __b58base)
        result = __b58chars[mod] + result
        long_value = div
    result = __b58chars[long_value] + result

    # Bitcoin does a little leading-zero-compression:
    # leading 0-bytes in the input become leading-1s
    nPad = 0
    for c in v:
        if c == '\0':
            nPad += 1
        else:
            break

    return (__b58chars[0] * nPad) + result


def b58decode(v):
    """ decode v into a string of len bytes
    """

    long_value = 0L
    for (i, c) in enumerate(v[::-1]):
        long_value += __b58chars.find(c) * (__b58base ** i)

    result = ''
    while long_value >= 256:
        div, mod = divmod(long_value, 256)
        result = chr(mod) + result
        long_value = div
    result = chr(long_value) + result

    nPad = 0
    for c in v:
        if c == __b58chars[0]:
            nPad += 1
        else:
            break

    result = chr(0) * nPad + result
    return result

if __name__ == "__main__":
    print  b58encode("hello world")
    print  b58decode("StV1DL6CwTryKyV")

总结

欢迎留言讨论,有错误请指出,谢谢!

【联系我(QQ:3500229193)或者加入社群,请戳这里!】

参考链接

  • https://blog.csdn.net/u013517122/article/details/83793296
  • https://mistydew.github.io/blog/2018/05/base58-encoding.html
  • https://en.wikipedia.org/wiki/Base58
  • https://en.bitcoin.it/wiki/Base58Check_encoding
  • https://cloud.tencent.com/developer/news/213693

更新日志

日期 次数 备注
2019.06.22 1
2019.06.23 2

你可能感兴趣的:(编码算法-Base58)