ARPABLE
アープらしいエンジニア、それを称賛する言葉・・・アーパボー!
ブロックチェーン

ブロックチェーンウォレットとは

ウォレットについて

今回はブロックチェーンのウオレットについてです。

ブロックチェーンの中でもビットコインにフォーカスして基本的なロジックを分かりやすく説明ます。

ウォレットの仕組みの話に進む前に、前提知識として「秘密鍵」「公開鍵」「ブロックチェーンアドレス」について簡単におさらいしておきましょう。

サトシ・ナカモトが生み出したビットコインは全ての情報を公開しても不正や2重支払が起きないよう様々な暗号学の知見が駆使されてます。

例えば、秘密鍵、公開鍵、ハッシュ、電子署名等です。

秘密鍵は自分だけが知っている鍵のことで、公開鍵はまさに公開して使ってもらう為の鍵でしたね。
使い方としては、「秘密鍵で暗号化して、公開鍵で復号化する」といった具合です。

ハッシュ値は、どんな長さの文字列もあらかじめ決められた長さの数値に変換でき、更にその数値から元の字列を導くことはできないという性質が備わっていました。

これら公開鍵、秘密鍵、ハッシュ値を組み合わせて、本人確認や改ざん検知を可能とした仕組みが電子署名でした。

これらの技術や、ブロックチェーンアドレスに関する詳細は以下のブログをご参考下さい。

❶ハッシュ値とは

ブロックチェーンアドレスとは

ブロックチェーンのウォレット

ブロックチェーンにはウォレットという概念があります。

直訳すると財布なので例えばビットコインのような仮想通貨(正式には暗号資産)を補完するイメージがありますが、実はそうではなく「秘密鍵」 を保持し管理しています。

ブロックチェーンアドレスの稿でも説明しましたが、秘密鍵から公開鍵が生成され、更に公開鍵からアドレスが生成されるため「秘密鍵」は大変重要なデータです。

言い換えれば「秘密鍵」を持っていさえすればブロックチェーンで管理されている資産を持っていることとほぼ同じことになるわけです。

逆に「秘密鍵」を忘れると自分の資産は凍結、つまり全く使えなくなり、漏洩すると盗まれてしまいます。

ウォレットの種類

ウォレットにはweb上で利用できる利便性の高いウェブウォレット、PC等で利用できるデスクトップウォレット、USB等の装置で利用できるハードウエアウォレット、紙に印刷して保管するペーパウォレット等の種類があります。

管理方式としては、インターネットに常時接続しているホットウォレット、オフラインで管理されるコールドウォレットの2種類があります。

ホットウォレットは一見便利そうですが、セキュリティ上、攻撃を受けやすいというデメリットもあります。

一方コールドウォレットは外部から攻撃されることはありませんが、送金をする場合にはいちいちオンラインに戻してから行うことになり利便性は高くないということになります。

このような特性を踏まえて自分に一番合った方式を選ぶ事になりますね。
例えば秘密鍵はコールドウォレット、公開鍵はホットウォレットで保管すれば「安全性」と「利便性」がある程度担保されることになります。

非決定性ウォレットと決定性ウォレット

ウォレットは鍵の生成及び管理手法に関して以下の2種類が存在します。

  • 非決定性ウォレット
  • 決定性ウォレット

ランダムウォレットはビットコインが開発された初期の頃に用いられていたウォレットで、現在主流なのが決定性ウォレットです。

非決定性ウォレット

非決定性ウォレット とは、秘密鍵と公開鍵を1対1の関係で生成し管理するウォレットのことです。

公開鍵の数だけ秘密鍵が必要となり、ウォレットが管理すべき秘密鍵の数が多くなります。ランダムに公開鍵を生成することから「ランダムウォレット」と呼ばれることもあります。

この方式はビットコインの初期に用いられていましたが、今は次に説明する決定性ウオレットが主流となってます。

ところで、100個のアドレスを生成するためには100個の秘密鍵を用いる必要があるわけですが、何故それほどアドレスが必要なのでしょうか?
これはブロックチェーンアドレスの稿でも説明しましたが、全ての取引情報を公開している関係上、同じ人の取引でもアドレスは頻繁に変わります

例えば、取引ごとにアドレスが変わることがありますし、支払いをした際の釣銭のアドレスは異なることがあります。

アドレスは銀行の口座と似ているといわれますが、この点に関してはその概念が大きく異なりますね。

そこで、より効率よく公開鍵を導く方法が考えられました。

決定性ウォレット

決定性ウォレットとはシードと呼ばれる1つの乱数をもとに複数の鍵を次々に生成する方式のウォレットです。

シードから、親の秘密鍵を生成し、所定のルールにより子供にあたる秘密鍵、孫にあたる秘密鍵を生成できるのでおおもとのシードさえ管理しておけば全ての秘密鍵が復元できるというわけです。

これならウォレットのポータビリティが良くなりますし、簡単に多くの公開鍵を生成することができますね。

この決定性ウォレットの仕組みを更に発展させたのが解凍的決定性ウォレット(HDウオレット)です。

階層的決定性ウォレット(HDウオレット)

階層的決定性ウォレット(以下、HDウオレット)を利用すれば、秘密鍵や公開鍵の管理コストがさらに下がり、利便性が向上します。
※)HDはHierarchy Deterministic(階層的決定性)​の略です。

HDウォレットは、決定性ウォレットの同様に1つの「シード (Seed) 」と呼ばれる値から秘密鍵を生成しますが、それを階層構造で管理するウォレットのことです。

決定性ウォレットとの違いは、一つの親鍵から生成される子鍵を無制限に生成することができる点です。
また、1つのシードから、ツリー構造のように層状に鍵を生成していくので、それぞれのブランチを特定の用途に使用することができます。

※)詳細はキーチェーンの導出を定義している仕様BIP32に関してはこちらをご参照ください。

マスター鍵の生成方法

HDウォレットで最初に生成される秘密鍵、公開鍵、チェーンコードをそれぞれマスター秘密鍵、マスター公開鍵、マスターチェーンコードと呼びます。

これらは以下のように生成されます。

 

上図を用いてマスターキーの作成手順を以下に示ます。

❶32バイトの乱数を発生しこれをSeedとします。
Pythonではos.urandam(32)を使用します。

❷root_Keyを設定します。
ビットコインでは”Bitcoin seed”を設定します。

❸シード(乱数)とroot_keyからハッシュ値を計算します。
Pythonではhashlib.sha2561を使用してます。

❹ハッシュ値からマスターキーを生成します。
前半32バイトをマスター秘密鍵、後半32バイトをマスターチェーンコートとします。

❺楕円曲線暗号を用いてマスター秘密鍵からマスター公開鍵を生成します。
Pythonではecdsa.SPEC256k1を使用してます。

❻非圧縮形式で64バイトのマスター公開鍵を33バイトの圧縮形式に変換します。
偶数の時(正の数)はプレフィックスに”02”、奇数(負の数)の時は”03″を先頭に付加する。

マスターキーを生成してみよう

それでは上述した手順をPythonを使用して実際にマスターキーとマスターチェーンコードを作成してみましょう。
コメント文の❶~❻は上図の説明に対応しております。

【プログラム】

import os
import binascii
import hashlib
import ecdsa
import hmac

# generate seed for secret key (❶)
seed = os.urandom(32)

# set root_key_value for Bitcoin(❷)
root_key_value = b”Bitcoin seed”

# generate previous master
# by sha512(seed,”Bitcoin seed”) (❸)
previous_master = hmac.new( seed, root_key_value, \
   hashlib.sha512 ).digest()

# generate master_secretkey:=first half(❹)
master_secretkey = previous_master[:32]

# generate master_chaincode:=back half(❹)
master_chaincode = previous_master[32:]

# generate master public key by ecdsa.SECP256k1(❺)
master_publickey = ecdsa.SigningKey.from_string( \
   master_secretkey, curve=ecdsa.SECP256k1 ).\
   verifying_key.to_string()

master_publickey_integer = int.from_bytes( \
   master_publickey[32:], byteorder=”big”)

# generate compressed public key(❻)
if master_publickey_integer % 2 == 0:
   master_publickey_x = b”\x02″ + master_publickey[:32]
else:
   master_publickey_x = b”\x03″ + master_publickey[:32]

# Print sequence
print(“master private key = \
   “,binascii.hexlify(master_secretkey),”\n”)
print(“master chain code = \
   “,binascii.hexlify(master_chaincode),”\n”)
print(“master public key = \
   “,binascii.hexlify(master_publickey_x))

【実行後】

master private key =    b'18cbca2e09330f9673153bb97a6bf4c8e7d110 ➡
c2a76b2212555bfab69b00e3c7' 

master chain code =    b'19596329eefbee006dca87426822537d09cbd2ea ➡
4a0b36b2f017a64d9372f404' 

master public key =    b'03a4c0a97b29169f3ef0355d2a718d3e0f435dc03 ➡
a37877ea947c3d17d74213d5e'

 

※)「➡」はブログサイトでは表示できなかったため強制的に改行した場所 

 

(アーパボー)