比特币全节点Go语言实现BTCD之地址编码解析

释放双眼,带上耳机,听听看~!

比特币地址
由一串字符和数字组成,类型主要有两种,一个是P2PKH地址,一个是P2SH地址。P2PKH地址其实是通过对160位二进制公钥哈希值进行base58check编码后的信息。

咱们看代码实现,btcd仅仅实现全节点,没有钱包功能,所以没有提供地址的创建的客户端,不过咱们可以大概分析下地址解码过程。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
2   oneIndex := strings.LastIndexByte(addr, '1')
3   if oneIndex > 1 {
4      prefix := addr[:oneIndex+1]
5      if chaincfg.IsBech32SegwitPrefix(prefix) {
6         witnessVer, witnessProg, err := decodeSegWitAddress(addr)
7         if err != nil {
8            return nil, err
9         }
10
11         // We currently only support P2WPKH and P2WSH, which is
12         // witness version 0.
13         if witnessVer != 0 {
14            return nil, UnsupportedWitnessVerError(witnessVer)
15         }
16
17         // The HRP is everything before the found '1'.
18         hrp := prefix[:len(prefix)-1]
19
20         switch len(witnessProg) {
21         case 20:
22            return newAddressWitnessPubKeyHash(hrp, witnessProg)
23         case 32:
24            return newAddressWitnessScriptHash(hrp, witnessProg)
25         default:
26            return nil, UnsupportedWitnessProgLenError(len(witnessProg))
27         }
28      }
29   }
30
31   // Serialized public keys are either 65 bytes (130 hex chars) if
32   // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed.
33   if len(addr) == 130 || len(addr) == 66 {
34      serializedPubKey, err := hex.DecodeString(addr)
35      if err != nil {
36         return nil, err
37      }
38      return NewAddressPubKey(serializedPubKey, defaultNet)
39   }
40
41   // Switch on decoded length to determine the type.
42   decoded, netID, err := base58.CheckDecode(addr)
43   if err != nil {
44      if err == base58.ErrChecksum {
45         return nil, ErrChecksumMismatch
46      }
47      return nil, errors.New("decoded address is of unknown format")
48   }
49   switch len(decoded) {
50   case ripemd160.Size: // P2PKH or P2SH
51      isP2PKH := chaincfg.IsPubKeyHashAddrID(netID)
52      isP2SH := chaincfg.IsScriptHashAddrID(netID)
53      switch hash160 := decoded; {
54      case isP2PKH && isP2SH:
55         return nil, ErrAddressCollision
56      case isP2PKH:
57         return newAddressPubKeyHash(hash160, netID)
58      case isP2SH:
59         return newAddressScriptHashFromHash(hash160, netID)
60      default:
61         return nil, ErrUnknownAddressType
62      }
63
64   default:
65      return nil, errors.New("decoded address is of unknown size")
66   }
67}
68

1
2
1decoded, netID, err := base58.CheckDecode(addr)
2

对address使用base58解码


1
2
1NewAddressPubKey(serializedPubKey, defaultNet)
2

这个是验证公钥地址


1
2
1return newAddressPubKeyHash(hash160, netID)
2

这个是返回公钥Hash地址,方法里有判断条件len(pkHash) == ripemd160.Size


1
2
1return newAddressScriptHashFromHash(hash160, netID)
2

这个返回脚本Hash地址

Base58编码代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1// Encode encodes a byte slice to a modified base58 string.
2func Encode(b []byte) string {
3   x := new(big.Int)
4   x.SetBytes(b)
5
6   answer := make([]byte, 0, len(b)*136/100)
7   for x.Cmp(bigZero) > 0 {
8      mod := new(big.Int)
9      x.DivMod(x, bigRadix, mod)
10      answer = append(answer, alphabet[mod.Int64()])
11   }
12
13   // leading zero bytes
14   for _, i := range b {
15      if i != 0 {
16         break
17}
18      answer = append(answer, alphabetIdx0)
19   }
20
21   // reverse
22   alen := len(answer)
23   for i := 0; i < alen/2; i++ {
24      answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
25   }
26
27   return string(answer)
28}
29

其中使用了alphabet字符集,如下:


1
2
3
4
5
6
7
1const (
2   // alphabet is the modified base58 alphabet used by Bitcoin.
3   alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
4
5   alphabetIdx0 = '1'
6)
7

另外,地址还分压缩地址、非压缩地址,常规交易的输入需要包含支付者的公钥,每一个压缩公钥比非压缩公钥占用空间少。

本文作者:architect.bian,欢迎收藏,转载请保留原文地址并保留版权声明!谢谢~
还没完!往下看!!!

给TA打赏
共{{data.count}}人
人已打赏
安全技术

c++ list, vector, map, set 区别与用法比较

2022-1-11 12:36:11

安全经验

Google 强制要求合作厂商提供两年的安全更新

2018-10-26 11:12:22

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索