Base58Check编码
比特币加入了改进版的 Base58 算法—-base58check,主要为了解决 Base58 导出的字符串没有校验机制,这样,在传播过程中,如果漏写了几个字符,会检测不出来。所以使用了改进版的算法 Base58Check。校验和是从编码的数据的哈希值中得到的,可以用来检测并避免转录和输入中产生的错误。使用Base58Check编码时,解码软件会计算数据的校验和并和编码中自带的校验和进行对比。二者不匹配则表明有错误产生,那么这个Base58Check的数据就是无效的。
一、Base58Check编码原理
见上图:
1.首先对数据添加一个版本前缀,这个前缀用来识别编码的数据类型。例如,比特币地址的前缀是0(十六进制是0x00)。
2.对数据连续进行两次SHA256哈希算法
1checksum = SHA256(SHA256(prefix+data))
3.在产生的长度为32个字节(两次哈希云算)的哈希值中,取其前4个字节作为检验和添加到数据第一步产生的数据之后。
4.将数据进行Base58编码处理
在比特币中,大多数需要向用户展示的数据都使用Base58Check编码,可以实现数据压缩,易读而且有错误检验。Base58Check编码中的版本前缀是用来创造易于辨别的格式,具体的前缀分类可以参考:https://en.bitcoin.it/wiki/List_of_address_prefixes 。
二、代码实现
这里就不给python实现了(https://pypi.org/project/base58/)这里有已经实现好的,这里列一个golang实现的操作,如下:
1package main
2import (
3 "bytes"
4 "crypto/sha256"
5 "encoding/hex"
6 "errors"
7 "math/big"
8 "reflect"
9 "fmt"
10 "log"
11)
12const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
13// Encode encodes the given version and data to a base58check encoded string
14func Encode(version, data string) (string, error) {
15 prefix, err := hex.DecodeString(version)
16 if err != nil {
17 return "", err
18 }
19 dataBytes, err := hex.DecodeString(data)
20 if err != nil {
21 return "", err
22 }
23 dataBytes = append(prefix, dataBytes...)
24 // Performing SHA256 twice
25 sha256hash := sha256.New()
26 sha256hash.Write(dataBytes)
27 middleHash := sha256hash.Sum(nil)
28 sha256hash = sha256.New()
29 sha256hash.Write(middleHash)
30 hash := sha256hash.Sum(nil)
31 checksum := hash[:4]
32 dataBytes = append(dataBytes, checksum...)
33 // For all the "00" versions or any prepended zeros as base58 removes them
34 zeroCount := 0
35 for i := 0; i 0 {
36 mod := new(big.Int)
37 decimalData.DivMod(decimalData, divisor, mod)
38 encoded = string(alphabet[mod.Int64()]) + encoded
39 }
40 return encoded
41}
42func b58decode(data string) ([]byte, error) {
43 decimalData := new(big.Int)
44 alphabetBytes := []byte(alphabet)
45 multiplier := big.NewInt(58)
46 for _, value := range data {
47 pos := bytes.IndexByte(alphabetBytes, byte(value))
48 if pos == -1 {
49 return nil, errors.New("Character not found in alphabet")
50 }
51 decimalData.Mul(decimalData, multiplier)
52 decimalData.Add(decimalData, big.NewInt(int64(pos)))
53 }
54 return decimalData.Bytes(), nil
55}
56func main() {
57 encoded, err := Encode("80", "44D00F6EB2E5491CD7AB7E7185D81B67A23C4980F62B2ED0914D32B7EB1C5581")
58 if err != nil {
59 log.Fatal(err)
60 }
61 fmt.Println(encoded) // 5JLbJxi9koHHvyFEAERHLYwG7VxYATnf8YdA9fiC6kXMghkYXpk
62 decoded, err := Decode("5JLbJxi9koHHvyFEAERHLYwG7VxYATnf8YdA9fiC6kXMghkYXpk")
63 if err != nil {
64 log.Fatal(err)
65 }
66 fmt.Println(decoded)
67}
执行后返回的结果如下:
1[root@localhost golang]# go run base58check_01.go
25JLbJxi9koHHvyFEAERHLYwG7VxYATnf8YdA9fiC6kXMghkYXpk
38044d00f6eb2e5491cd7ab7e7185d81b67a23c4980f62b2ed0914d32b7eb1c5581
上面5J这段是加密后的结果,可以看出要比原数据短,后面执行后的结果中,前面的开头的80代表的是加密前缀。具体在实用时,可以直接使用别人已经实现的模块,链接地址:https://github.com/anaskhan96/base58check
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/base58check/6270.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.