地址產生方法如下:
- 產生公鑰 P = s*G
- 用公鑰產生壓縮或未壓縮的 SEC 格式
- 對結果做 SHA-256,然後再做 RIPEMD160 (HASH160)
- 加上前綴
- 加上 4 bytes (32-bits) 的 checksum (double-sha256)
- Base58 編碼
實作:
def address(self, compressed=True, testnet=False):
sec = self.sec(compressed)
h160 = hash160(sec)
if testnet:
prefix = b'\x6f'
else:
prefix = b'\x00'
raw = prefix + h160
checksum = double_sha256(raw)[:4]
address = encode_base58(raw + checksum)
return address.decode('ascii')
其中的 hash 函式是由 hashlib
引入:
BASE58_ALPHABET = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def hash160(s):
return hashlib.new('ripemd160', hashlib.sha256(s).digest()).digest()
def double_sha256(s):
return hashlib.sha256(hashlib.sha256(s).digest()).digest()
def encode_base58(s):
count = 0
for c in s:
if c == 0:
count += 1
else:
break
prefix = b'1' * count
num = int(s.hex(), 16)
result = bytearray()
while num > 0:
num, mod = divmod(num, 58)
result.insert(0, BASE58_ALPHABET[mod])
return prefix + bytes(result)
私鑰也有格式,稱為 WIF (Wallet Import Format),產生方式如下:
- 私鑰本身是 256-bits 的數字
- 用 16 進位表示
- 加上前綴
- 如果是壓縮格式加上後綴
- 結尾加上 4-bytes 的 sha256 checksum
- Base58編碼
定義 PrivateKey
:
class PrivateKey:
def __init__(self, secret):
self.secret = secret
self.point = secret * G
def hex(self):
return '{:x}'.format(self.secret).zfill(64)
def wif(self, compressed=True, testnet=False):
secret_bytes = self.secret.to_bytes(32, 'big')
if testnet:
prefix = b'\xef'
else:
prefix = b'\x80'
if compressed:
suffix = b'\x01'
else:
suffix = b''
return encode_base58_checksum(prefix + secret_bytes + suffix)
順便也實作簽名方法,讓私鑰本身可以當作被簽名的訊息
def sign(self, z):
k = randint(0, 2**256)
r = (k*G).x.num
k_inv = pow(k, N-2, N)
s = (z + r*self.secret) * k_inv
if s > N/2:
s = N - s
return Signature(r, s)