confusing base58

confusing base58

在西湖论剑过程中碰到一题base58编码的问题,之前刚好没有碰到过base58,昨天调了半天没逆出来,现在来复现下,顺便学习下base58编码
https://www.jianshu.com/p/5c59c45d144e 这篇文章对base58做了比较详细的解释,大概就是,出入的string-》转byte流-》转大整数-》转58进制数(不断对58取余)-》去base58Table里对应的字符。
单说肯定不够真实,先看下base58的源码

__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def b58encode(v):
long_value = int(v.encode("hex_codec"), 16)#输入转大整数
result = ''
while long_value >= __b58base:
    div, mod = divmod(long_value, __b58base)#不断对58取余,也就是转58进制的过程
    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)#根据在表中的下标生成原本的58进制数
result = ''
while long_value >= 256:
    div, mod = divmod(long_value, 256)#58进制转hex过程
    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

可以看到核心的过程就是一堆进制转换,那么就根据西湖论剑那题,细细的调试看看吧

image_1d7vu0lpv4071ram1ie9cgn1r69.png-110.8kB

可以看到首先把input和400e90处的表格异或下,并且加上之前的每一位输入

image_1d7vu2acholpghn1npo14ll1h9em.png-28.9kB

然后就是一个神秘的循环,感觉其实就是判断读入的是不是空字符串,接着生成了三个数字,这三个数字是固定的,但是好像并没有用到这三个数

image_1d7vubrdsh02ast1fhb1in613cj1v.png-22.7kB

这里就是生成58进制数的过程,当时调的时候还是不大铭感,猜出了是转58进制数,但不知道是干嘛的= =,其中v9,v22,v26好像都没有用到,在第一次循环中,v11原本就是空的,因此第一位再加上0之后除58之后就是0了,直接跳出循环,
image_1d7vurblocbp12uoumq1315tti2c.png-95.6kB

取出第二位后,加上左移8位后的第一位输入,也就是0x3132

image_1d7vv4hvkev4gcl1v3v1489ku32p.png-72.9kB

然后再对58取余,结果覆盖了之前的0x31,变为了08,然后再除去58,结果就是0xd9,0xd9再次对58取余,得到了0x2b,除以58后结果为0x3,然后重复上述过程,总之就是一个0x3132转58进制的过程,也就是v11一直被用来保存取余的结果的,因此在最后,v11就是我们转58进制的结果,只不过他没有一开始直接将输入转化为一个大数,而是采用每一位取余结果左移八位后拼接下一位输入组成新的整数进行取余,还是挺有趣的

image_1d8011t25p325e2107q1jb71lhb45.png-37.4kB

后面就是正常的转换了,根据58进制数的每一位取下标,学到了base58,之前一直以为base家族的运算方式都差不多,base58还是挺特殊的。