🐕

【Python】ビットコインアドレス 作りました

2022/03/12に公開約3,500字

はじめに

ビットコインとは簡単にいうと「中央集権者を媒介せず素早く通貨を送金する」ための暗号通貨のプラットフォームです。

暗号通貨を安全に保管するためにはウォレットサービスを用います。

ウォレットサービスの立ち位置としては「財布」というより「秘密鍵の保管場所」となります。

暗号通貨の取引が発生する際、トランザクションの署名と検証が行われるのですがその際に秘密鍵が使用されます。

暗号通貨の取引(トランザクション)、例えばアリスさんがボブさんに1 BTC送金する際に必要なのが両者のビットコインアドレス(ウォレットアドレス)です。

環境

WSL2

Ubuntu 20.04 on Windows(11)

実装方針

  • 秘密鍵を作る
  • 公開鍵を作る
  • ビットコインアドレスを作る

プロジェクトのセットアップ

利用するモジュール

main.py
import secrets
import ecdsa
import hashlib
import base58

ターミナルで実行

sudo apt install python3-pip
sudo pip install ecdsa
sudo pip install base58

大枠のソース

main.py
# 主コード
class generateWalletAddress():
    def __init__(self):
      p = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1
      privateKey = self.getPrivatekey(p)
      publicKey = self.getPublickey(privateKey)
      walletAddress = self.getWalletAddress(bytes.fromhex("00"), publicKey)

    def getPrivatekey(self, p):
    def getPublickey(self, privateKey):
    def getWalletAddress(self, version, publicKey):

# WAを作成するに当たり関数を呼び出す
walletAddress = generateWalletAddress()

秘密鍵を作る

秘密鍵とは1~2^256までの整数値です。

2^256 より微小な数値をp(=2^256-2^32-2^9-2^8-2^7-2^6-2^4-1)と定義します。

secrets.randbelow(n)メソッドの引数にpを渡して、ランダムな整数を取得し秘密鍵を生成します。

main.py
def getPrivatekey(self, p):
    # 秘密鍵はpより小さな数字を選択する
    privateKey = secrets.randbelow(p)
    # 16進数表示に変換
    privateKey = format(privateKey, 'x')
    print("秘密鍵が生成されました:" + privateKey)
    return privateKey

公開鍵を作る

作成した秘密鍵とECDSAを用いて公開鍵を生成します。

main.py
def getPublickey(self, privateKey):
    # 16進数からバイト列に変換
    bin_privateKey = bytes.fromhex(privateKey)
    # ECDSAを用いて楕円曲線から公開鍵となる値を計算
    signing_key = ecdsa.SigningKey.from_string(bin_privateKey, curve = ecdsa.SECP256k1) # メソッドの指定
    verifying_key = signing_key.get_verifying_key()
    # 文字列の操作
    publicKey = bytes.fromhex("04") + verifying_key.to_string()
    publicKey = publicKey.hex()
    print("公開鍵が生成されました:" + publicKey)
    return publicKey

ビットコインアドレスを作る

公開鍵をハッシュ化してチェックサム処理(処理中に対象の値が意図しない誤った値となった場合に検出するための仕組み)を媒介して例外を消し、Base58でエンコーディングしてビットコインアドレスを生成します。

main.py
def getWalletAddress(self, version, publicKey):
    ba = bytes.fromhex(publicKey)
    # sha256でハッシュ化してできたものを文字列変換
    digest = hashlib.sha256(ba).digest()
    new_digest = hashlib.new('ripemd160')
    new_digest.update(digest)
    publicKey_hash = new_digest.digest()
    # main/testをversion指定する
    pre_address = version + publicKey_hash
    address = hashlib.sha256(pre_address).digest()
    address = hashlib.sha256(address).digest()
    checksum = address[:4]
    address = pre_address + checksum
    # bitocoin特有のベースエンコーディング
    address = base58.b58encode(address)
    address = address.decode()
    print("Address = " + address + "\n")
    return address

おまけ

ビットコインが仮想通貨の送受信に注目した暗号通貨プラットフォームである一方で、
イーサリアムは暗号通貨ではなくスマートコントラクトをブロックチェーン上で動かすことに注目したプラットフォームです。ブロックチェーンの対改竄性に着目すると暗号通貨の取引以外にも権利関係の移動をブロックに書き込むことでもっと汎用性のある仕組みができるのではないかという意向です、つまりアカウント指向型のプラットフォームと言えます。

スマートコントラクトとは契約情報(権利の証明や権利の移動)を自動的にブロックチェーン上に書き込むアプリケーションです。

不透明性のあるデータに関してトレーサビリティを担保するブロックチェーン技術がもっと多様なシステムに取り入れられる世の中になっていくことが楽しみですね。

参考記事

https://qiita.com/kaz1shuu2/items/921dcbebb7fbea14f085
https://nevertoolate.hatenablog.jp/entry/2020/04/02/060000

おわりに

実はビットコインのやり取りをしたことがありませんが、普段何気なくテストネットでETHやMATICのやり取りをする際にポンポンとウォレットアドレスを使っていたので今一度理解を進めようと今回記事を書いてみました。前回書いたECDSAの内容も出てきたので徐々にブロックチェーンに関わる処理内容を咀嚼できていればと思います。

最後までお読みいただきありがとうございました。

GitHubで編集を提案

Discussion

ログインするとコメントできます