LoginSignup
13
11

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-08-22

まずは、ベースとなる形だけ記述しておきます。
(今後使用するモジュールは最初に全部書いておきました)
イメージとしては、このコードが実行された時に秘密鍵、公開鍵、アドレスを作り出します。

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').zfill(64)
        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」から始まっていれば成功です。

13
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11