秘密鍵から公開鍵とアドレスを生成する過程

どうも、ブロックチェーンエンジニアになりたいともろうです。

今回は秘密鍵の生成から公開鍵、ビットコインアドレスの生成までの過程を学んだのでまとめてみたいと思います。

秘密鍵はビットコインを支払うためのトランザクションに署名するために使われ、公開鍵はビットコインを受け取るために使われます。

ビットコイン所有者はビットコインを使うとき、公開鍵と有効な署名(同じ秘密鍵から生成される)をトランザクションに記載します。この秘密鍵からしか作ることができない公開鍵と署名が示されることで、ビットコインネットワーク全体の参加者から、トランザクションが有効と認められます。

つまり、ビットコインの送り手がビットコインを送る時点で、そのビットコインを所有していたことが確認されるということです。

秘密鍵とは

秘密鍵は無作為に選ばれる数値です。秘密鍵は署名の生成に用いられ、その署名は、ビットコインを使うときに所有者であることの照明に必要です。

公開鍵を銀行の口座番号に例えるなら、秘密鍵はPINコードや小切手への署名のような感じです。

仮に秘密鍵が他者に漏れてしまった場合、秘密鍵によって守られるビットコインが全て他者のものになってしまいます。

公開鍵とは

公開鍵は、秘密鍵から楕円曲線上のスカラー倍算によって計算されて作られます。

楕円曲線上のスカラー倍算はハッシュ関数と同様に不可逆なので、公開鍵から秘密鍵を特定することはできないため、公開しても大丈夫です。

ビットコインアドレスとは

ビットコインを誰かが誰かに送付するときに、このビットコインアドレス宛先として利用します

ビットコインの取引で実際に目にする部分です。

ビットコインアドレスは公開鍵から作られます。公開鍵からエンコード(データの形式を変えて可読性をあげたり、曖昧さをなくす)して作られるので、ビットコインアドレスから公開鍵(公開鍵ハッシュ)を特定することは可能です。

秘密鍵からアドレス生成までの流れ

秘密鍵からビットコインアドレスを生成するまでの大まかな流れは以下です。

①乱数から秘密鍵をつくる
②楕円曲線状のスカラー倍算で秘密鍵から公開鍵をつくる
③SHA256でハッシュ化
④RIPEMD160でハッシュ化
⑤先頭に「VersionPrefix」を追加
⑥「チェックサム」を追加
⑦Base58でエンコーディングする

乱数から秘密鍵をつくる

秘密鍵は無作為に選ばれるただの数値といいましたが、重要なのは、十分なランダム性を確保することです。

鍵の生成は1から2^256の間のどれかになります。これは10進数だと約10^77になります。宇宙にある原子の数が約10^80個らしいので、とにかくめちゃくちゃに大きい数値ということです。

つまり、ランダムで同じ秘密鍵が作られる可能性はほぼないということですね。

楕円曲線状のスカラー倍算で秘密鍵から公開鍵をつくる

秘密鍵をランダムに生成された数値kとし、あらかじめ決められた生成元(generator point)をGとします。

Gは楕円曲線上にある点で、secp256k1という、ある規則に従った約2^256個の点の集合の中の一点です。そして

K=k*G

として求められる楕円曲線状にある点Kが公開鍵にあたります。

これはG自身をk回足すことと同じ意味です。楕円曲線においてある点に「自分自身を足す」とは、その点で接する接線を描き、その接線がもう一度楕円曲線に交わる点を求め、その交点をX軸に対して対象に移動した点を見つけることです。

↑楕円曲線上での整数kによるGへのスカラー倍算を可視化した図↑

Secp256k1、楕円曲線暗号については、もっと詳しくわかりやすく説明している記事があるので参考にしていただければと思います。

楕円曲線暗号の超簡単な理論の紹介
楕円曲線暗号-Wikipedia

二重ハッシュ化

ここからは、公開鍵からビットコインアドレスをつくる過程です。

まず、一方向のハッシュアルゴリズムで暗号化します。ハッシュアルゴリズムには、SHA256RIPEMD160を用います。

公開鍵KをSHA256で計算し、さらにその結果をRIPEMD160で計算することで20バイトの数字を作ります。

こうして算出された公開鍵ハッシュは、「Base58Check」という形式でエンコードされてビットコインアドレスとなります。

Base58Checkエンコードとその手順

書き間違いや転写間違いを防ぐために、通常は公開鍵ハッシュを「Base58Check」という形式ででエンコードします。
エンコードする前に、その準備をします。

先頭に「VersionPrefix」を追加

まず公開鍵ハッシュの先頭に「VersionPrefix」という1バイトをくっつけます。これは元のデータがどんな種類のデータだったのか見分けやすくするためのものです。

例えばビットコインアドレスの場合、先頭に「0x00」のVersio Prefixをつけると、エンコードされた結果の先頭は必ず「1」になります。

「チェックサム」を追加

続いて「チェックサム」を追加します。

「チェックサム」とは、打ち間違いのビットコインアドレスが有効な送信先として判断されないようにするための仕組みです。

先ほどVersionPrefixがくっついた公開鍵ハッシュを2回SHA256にかけ、その結果の先頭の4バイトを、再びVersionPrefix付きの公開鍵ハッシュの末尾にくっ付けます。

Base58でエンコーディングする

最後にBase58エンコードで、ディスプレイで見間違いしやすい「0(ゼロ)」,「O(オー)」,「l(小文字エル)」,「I(大文字アイ)」を除きます。
具体的にいうと、

[VersionPrefix(1バイト)]+[公開ハッシュ(20バイト)]+[チェックサム(4バイト)]

の25バイトの数値をBase58エンコードにかけ、ビットコインアドレスを出します。

➡︎ビットコインアドレスの完成!


今回は秘密鍵の生成から、公開鍵、ビットコインアドレスを作るまでの過程を学んでまとめてみました。正直いってまだまだ細部は理解できていないので、これから勉強しながら、この記事の内容もアップデートしていきたいと思います。