# 比特币地址生成算法详解

## 1 生成过程

18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725

600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408

010966776006953D5567439E5E39F86A0D273BEE

00010966776006953D5567439E5E39F86A0D273BEE

445C7A8007A93D8733188288BB320A8FE2DEBD2AE1B47F0F50BC10BAE845C094

00010966776006953D5567439E5E39F86A0D273BEED61967F6

16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM

 1 import hashlib
2 from ecdsa import SECP256k1, SigningKey
3 import sys
4 import binascii
5
6 # 58 character alphabet used
7 BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
8
9 def from_bytes (data, big_endian = False):
10     if isinstance(data, str):
11         data = bytearray(data)
12     if big_endian:
13         data = reversed(data)
14     num = 0
15     for offset, byte in enumerate(data):
16         num += byte << (offset * 8)
17     return num
18
20     """
21     Gets a Base58Check string
22     See https://en.bitcoin.it/wiki/Base58Check_encoding
23     """
24     if sys.version_info.major > 2:
25         version = bytes.fromhex(version)
26     else:
27         version = bytearray.fromhex(version)
28     firstSHA256 = hashlib.sha256(version + public_address)
29     print("first sha256: %s"%firstSHA256.hexdigest().upper())
30     secondSHA256 = hashlib.sha256(firstSHA256.digest())
31     print("second sha256: %s"%secondSHA256.hexdigest().upper())
32     checksum = secondSHA256.digest()[:4]
35     if sys.version_info.major > 2:
37     else:
39     # count the leading 0s
41     encoded = []
42
43     while result != 0:
44         result, remainder = divmod(result, 58)
45         encoded.append(BASE58_ALPHABET[remainder])
46
48
49 def get_private_key(hex_string):
50     if sys.version_info.major > 2:
51         return bytes.fromhex(hex_string.zfill(64))
52     else:
53         return bytearray.fromhex(hex_string.zfill(64))
54
55 def get_public_key(private_key):
56     # this returns the concatenated x and y coordinates for the supplied private address
57     # the prepended 04 is used to signify that it's uncompressed
58     if sys.version_info.major > 2:
59         return (bytes.fromhex("04") + SigningKey.from_string(private_key, curve=SECP256k1).verifying_key.to_string())
60     else:
61         return (bytearray.fromhex("04") + SigningKey.from_string(private_key, curve=SECP256k1).verifying_key.to_string())
62
65     print("public key hash256: %s"%hashlib.sha256(public_key).hexdigest().upper())
66     h = hashlib.new('ripemd160')
69     print("RIPEMD-160: %s"%h.hexdigest().upper())
71
72 if __name__ == "__main__":
74     private_key = get_private_key("18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725")
75     print("private key: %s"%binascii.hexlify(private_key).decode().upper())
76     public_key = get_public_key(private_key)
77     print("public_key: %s"%binascii.hexlify(public_key).decode().upper())
80     print("Final address %s"%bitcoin_address)

## 2 关键问题

### 2.1 base58编码

Base58编码是一种二进制转可视字符串的算法，主要用来转换大整数，将整数字节流转换为58编码流，实际上它就是整数的58进制，和2进制、8进制、16进制是一样的道理，只是用58作为进制的单位了，正好和58个不容易混淆的字符对应，比特币所用的字符表如下：

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

### 2.3 比特币地址长度

接下来继续分析比特币地址最长可能，应该是00fffffffffffffffffffffffffffffffffffffffffa06820b，最后4个字节是fffffffffffffffffffffffffffffffffffffffff两次哈希结果的后4个字节，对应的base58编码地址为1QLbz7JHiBTspS962RLKV8GndWFwi5j6Qr，该地址同样是“燃烧地址”，共转入51次比特币，总数是0.012495个，如下图：

## 3 源码分析

1 inline string PubKeyToAddress(const vector<unsigned char>& vchPubKey)
2 {
4 }

1 inline uint160 Hash160(const vector<unsigned char>& vch)
2 {
3     uint256 hash1;
4     SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
5     uint160 hash2;
6     RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
7     return hash2;
8 }

 1 inline string Hash160ToAddress(uint160 hash160)
2 {
3     // add 1-byte version number to the front
5     vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160));
6     return EncodeBase58Check(vch);
7 }
8
9 inline string EncodeBase58Check(const vector<unsigned char>& vchIn)
10 {
11     // add 4-byte hash check to the end
12     vector<unsigned char> vch(vchIn);
13     uint256 hash = Hash(vch.begin(), vch.end());
14     vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
15     return EncodeBase58(vch);
16 }
17
18 inline string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
19 {
20     CAutoBN_CTX pctx;
21     CBigNum bn58 = 58;
22     CBigNum bn0 = 0;
23
24     // Convert big endian data to little endian
25     // Extra zero at the end make sure bignum will interpret as a positive number
26     vector<unsigned char> vchTmp(pend-pbegin+1, 0);
27     reverse_copy(pbegin, pend, vchTmp.begin());
28
29     // Convert little endian data to bignum
30     CBigNum bn;
31     bn.setvch(vchTmp);
32
33     // Convert bignum to string
34     string str;
35     str.reserve((pend - pbegin) * 138 / 100 + 1);
36     CBigNum dv;
37     CBigNum rem;
38     while (bn > bn0)
39     {
40         if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
41             throw bignum_error("EncodeBase58 : BN_div failed");
42         bn = dv;
43         unsigned int c = rem.getulong();
44         str += pszBase58[c];
45     }
46
47     // Leading zeroes encoded as base58 zeros
48     for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
49         str += pszBase58[0];
50
51     // Convert little endian string to big endian
52     reverse(str.begin(), str.end());
53     return str;
54 }