Edited at

Python で Bitcoin(仮想通貨)アドレスを作る【python3】

More than 1 year has passed since last update.

まずは、ベースとなる形だけ記述しておきます。

(今後使用するモジュールは最初に全部書いておきました)

イメージとしては、このコードが実行された時に秘密鍵、公開鍵、アドレスを作り出します。


address.py

#!/usr/bin/env python3

# coding: utf-8
import secrets
import ecdsa
import hashlib
import base58

class Generater():
def __init__(self):
p = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1
privkey = self.new_privkey()
pubkey = self.new_pubkey()
address = self.new_address()

def new_privkey(self, p):
pass

def new_pubkey(self, privkey):
pass

def new_address(self, version, pubkey):
pass

address = Generater()


  


秘密鍵

では順番に見ていきます。まずは、秘密鍵です。

秘密鍵は

p = 2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4-1

p より小さい数字(ランダムに選び出した)になります。


address.py

    def new_privkey(self, p):

privkey = secrets.randbelow(p)
privkey = format(privkey, 'x')
print("PrivateKey = " + privkey)
return privkey

名称
内容

randbelow
引数より小さい数字をランダムに選んでくれます。乱数の選び方は、OSによって依存しているので、安全に乱数を出力できるようにしましょう

format
16進数表示に変換します

bytes.fromhex
16進数からバイト列に変換します

  

  

  


公開鍵

続いて、公開鍵の説明になります。公開鍵は先ほどの秘密鍵とECDSAを用いて生成します。関数 new_pubkey に引数として先ほどの秘密鍵を指定します。


address.py

    def new_pubkey(self, privkey):

bin_privkey = bytes.fromhex(privkey)
signing_key = ecdsa.SigningKey.from_string(bin_privkey, curve = ecdsa.SECP256k1)
verifying_key = signing_key.get_verifying_key()
pubkey = bytes.fromhex("04") + verifying_key.to_string()
pubkey = pubkey.hex()
print("PublicKey = " + pubkey)
return pubkey

名称
内容

bytes.fromhex
16進数からバイト列に変換します

ecdsa.SigningKey
ECDSAを用いて楕円曲線から公開鍵となる値を計算する

pubkey
プレフィックスとして16進数で"04"を先頭に、ECDSAで計算結果列を後ろに付けます。最後に全体を16進数表記にすれば完成

  

  

  


アドレス

アドレスは、今回はビットコインアドレスの作り方を真似ました。引数として、先ほどの公開鍵とバージョンを指定するようにしています。ビットコインアドレスの場合16進数で "00" になります。


address.py

    def new_address(self, version, pubkey):

ba = bytes.fromhex(pubkey)
digest = hashlib.sha256(ba).digest()
new_digest = hashlib.new('ripemd160')
new_digest.update(digest)
pubkey_hash = new_digest.digest()

pre_address = version + pubkey_hash
address = hashlib.sha256(pre_address).digest()
address = hashlib.sha256(address).digest()
checksum = address[:4]
address = pre_address + checksum
address = base58.b58encode(address)
address = address.decode()
print("Address = " + address + "\n")
return address


  

ここから注意点がたくさん出てきます。まず、アドレスを作る際にチェックサムが必要になります。チェックサムを生成するために、公開鍵のハッシュ値が必要です。

pubkeyhash = ripemd160(sha256((pubkey)))

  

また、チェックサムは  

address = sha256(sha256(payload))

  

この address の前から 4バイトになります。

checksum = address[:4]

  

名称
内容

ba
16進数公開鍵をバイト列に変換

digest
baをsha256でハッシュ化してできたものを文字列にして代入

pubkey_hash
digestをripemd160でハッシュ値を取り、文字列として代入

pre_address
version(引数) + pubkey_hash

b58encode
b58encodeする

decode
デコードする

これで以上になります。全体像を最後に貼り付けておきます。

  

  


address.py

#!/usr/bin/env python3

# coding: utf-8
import secrets
import ecdsa
import hashlib
import base58

class Generater():
def __init__(self):
p = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1
privkey = self.new_privkey(p)
pubkey = self.new_pubkey(privkey)
address = self.new_address(bytes.fromhex("00"), pubkey)

def new_privkey(self, p):
privkey = secrets.randbelow(p)
privkey = format(privkey, 'x')
print("PrivateKey = " + privkey)
return privkey

def new_pubkey(self, privkey):
bin_privkey = bytes.fromhex(privkey)
signing_key = ecdsa.SigningKey.from_string(bin_privkey, curve = ecdsa.SECP256k1)
verifying_key = signing_key.get_verifying_key()
pubkey = bytes.fromhex("04") + verifying_key.to_string()
pubkey = pubkey.hex()
print("PublicKey = " + pubkey)
return pubkey

def new_address(self, version, pubkey):
ba = bytes.fromhex(pubkey)
digest = hashlib.sha256(ba).digest()
new_digest = hashlib.new('ripemd160')
new_digest.update(digest)
pubkey_hash = new_digest.digest()

pre_address = version + pubkey_hash
address = hashlib.sha256(pre_address).digest()
address = hashlib.sha256(address).digest()
checksum = address[:4]
address = pre_address + checksum
address = base58.b58encode(address)
address = address.decode()
print("Address = " + address + "\n")
return address

address = Generater()


  

では、実行して見ましょう。

PrivateKey = c31ad13427f28c429c443d6058129051614875ab5f576364e0e2866e3ab87aae

PublicKey = 048813b6143a1316041ff1fb4f3af6061a05f7803ef01e32cf3ff1a71422f95a6d600638c460a49f5c6125b11cbc5bdfff30c0545c6f208d9a1fa6ed504b2d2c29
Address = 176wVvyL4NzecB9nm7DmuQ3x5rfqXCo1n5

  

Address が「1」から始まっていれば成功です。