Quantcast
Channel: 云原生之路
Viewing all articles
Browse latest Browse all 389

区块链算法之base58

$
0
0

一、base58编码原理

Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。base58和base64一样是一种二进制转可视字符串的算法,主要用来转换大整数值。区别是,转换出来的字符串,去除了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。看下base58的编码表:

base58

也就是字符1代表0,字符2代表1,字符3代表2…字符z代表57。然后回一下辗转相除法。

如要将1234转换为58进制;
第一步:1234除于58,商21,余数为16,查表得H
第二步:21除于58,商0,余数为21,查表得N
所以得到base58编码为:NH
如果待转换的数前面有0怎么办?直接附加编码1来代表,有多少个就附加多少个(编码表中1代表0)。

二、代码实现

golang实现 

以下是一个studygolang上看到的一个实现的golang版本,具体代码如下:

package main
import (
        "math/big"
        "fmt"
        "bytes"
)
var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
func Base58Encode(input []byte) []byte{
        var result []byte
        x:= big.NewInt(0).SetBytes(input)
  //把字节数组input转化为了大整数big.Int
        base := big.NewInt(int64(len(b58Alphabet)))
        zero := big.NewInt(0)
        //大整数的指针
        mod := &big.Int{}
        for x.Cmp(zero) != 0 {
                x.DivMod(x,base,mod)  // 对x取余数
                result =  append(result, b58Alphabet[mod.Int64()])
        }
        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=='1'{
                        zeroBytes++
                }else{
                        break
                }
        }
        payload:= input[zeroBytes:]
        for _,b := range payload{
                charIndex := bytes.IndexByte(b58Alphabet,b)  //反推出余数
                result.Mul(result,big.NewInt(58))   //之前的结果乘以58
                result.Add(result,big.NewInt(int64(charIndex)))  //加上这个余数
        }
        decoded :=result.Bytes()
        decoded =  append(bytes.Repeat([]byte{0x00},zeroBytes),decoded...)
        return decoded
}
func ReverseBytes(data []byte){
        for i,j :=0,len(data) - 1;i<j;i,j = i+1,j - 1{
                data[i],data[j] = data[j],data[i]
        }
}
func main(){
        org := []byte("qwerty")
        fmt.Println(string(org))
        ReverseBytes(org)
        fmt.Println(string(org))
        fmt.Printf("%s\n",string( Base58Encode([]byte("hello jonson"))))
        fmt.Printf("%s",string(Base58Decode([]byte("2yGEbwRFyav6CimZ7"))))
}

这里使用了反转,不是很方便,可以看后面使用一个高仿bitcoin版本的,也可以使用github上别我已经实现的版本:https://github.com/shengdoushi/base58/ (支持Bitcoin、Ripple、IPFS,缺点也是没有base58check)

比特币中的关于该算法的源码地址为:https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp (c++语言),一个高仿bitcoin源码的golang版实现的base58算法如下(不包含base58check算法):

[root@361way base58]# go run 01base58.go
kvMuJRLnworeVVrPSiY
www.361way.com

我已把代码放在github上:https://github.com/361way/golang/blob/master/base58/01base58.go 

python版本的实现

不得不说python版本写的还是不错的,base58.cpp上带的,这里都已经实现。地址为:https://pypi.org/project/base58/ (https://github.com/keis/base58)。

三、其他

base58编码不是所有的都使用的上面所列的基础码,不同的类型的里使用的编码不同,如下:

BitcoinAlphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
IPFSAlphabet    = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
FlickrAlphabet  = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
RippleAlphabet  = "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"

区块链算法之base58,首发于运维之路


Viewing all articles
Browse latest Browse all 389

Trending Articles