【Bitcoin】3つのビットコインアドレスとその作り方について

ビットコインを送金するためには、ビットコインアドレス（以下アドレス）という口座番号代わりの値を使って送金先を指定します。

この値は "1" か "3" から始まる 27～34 文字の英数字から成り立っている文字列で、画像のQRコードの下がアドレスの値です。
<img width="200" alt="IMG_1036.PNG" style="text-align:center; margin:0 auto;" src="https://qiita-image-store.s3.amazonaws.com/0/178137/56298043-fe60-cbca-f0b1-80947da898bd.png">

今回の記事ではアドレスの種類と、それぞれの生成（暗号化）手法についてご紹介していきます！

# 1．ビットコインと公開鍵暗号
ビットコインでは自分の所持しているコインへアクセスする際に、[公開鍵暗号](https://ja.wikipedia.org/wiki/%E5%85%AC%E9%96%8B%E9%8D%B5%E6%9A%97%E5%8F%B7)で認証されています。
公開鍵暗号では公開鍵と秘密鍵という2つの鍵がペアで存在していて、それぞれ以下のような役割を持っています。

```
公開鍵： この値を暗号化しアドレスを生成する
秘密鍵： 支払うことを証明する署名をする際に使われる
```

つまり秘密鍵を所持していれば、その秘密鍵から生成されたアドレス宛のコインを支払う意思を証明できるようになってしまうため、「秘密鍵を他人に知られてしまう = 他人に財布を握られる」という意味になります。

また、公開鍵は特定のロジックによって秘密鍵から生成されており、アドレスはその公開鍵を更に暗号化することで生成されています。
各値は元の値へ戻すことはできないようになっていますが、数学的関係が保たれているため、それぞれの正当性を検証できるようになっています。

公開鍵と秘密鍵、アドレスの関係は図のような形です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/178137/a4ad8574-4a55-66eb-0e63-681e30b08b0b.png)

## 1-1．秘密鍵の作り方
秘密鍵は「1~2の256乗」から無作為に選ばれる数値で、ビットコインではOSの乱数生成器を用いて、256ビットのランダム性を作り出しています。

「2の256乗」という値はとてつもなく大きな値で、78桁（10の77乗）の数値になっているのでどれだけの人数で生成しても、重複することは難しい値となっています。
※ちなみに宇宙で観測可能な原子の数は10の80乗で見積もられていることから、その数の膨大さが分かるかと思います。

## 1-2．公開鍵の作り方
公開鍵は楕円曲線暗号を用いて秘密鍵から生成される値となっており、公開鍵から秘密鍵への逆の計算はできないようになっています。

@quincedaddy さんの以下の投稿が非常にわかりやすかったので、詳しく知りたい方はこちらをご覧ください。
→ [ビットコインアドレスを自分の手で作って理解する](https://qiita.com/quincedaddy/items/2e54f35683facb519446)

最終的には以下の式となります。

```
K: 公開鍵 = k: 秘密鍵 * G: 生成元(secp256k1標準で定められた、全ビットコインユーザー共通の定数)
```


## 1-3．ビットコインアドレスの作り方
前述した通り、アドレスは秘密鍵から生成された公開鍵を更に暗号化することで生成されています。
こちらも一方向のみの暗号化となるため、アドレスから公開鍵を算出することはできません。

アドレス生成の際に使われるアルゴリズムは[SHA256](https://ja.wikipedia.org/wiki/SHA-2)と[RIPEMD160](http://gaiax-blockchain.com/ripemd-160)というもので、公開鍵の`SHA256`ハッシュを計算し、更にこの結果から`RIPEMD160`ハッシュを求めることで、160ビットの数字を作り出します。

```
A: アドレス = RIPEMD160(SHA256(K: 公開鍵))
```

これでアドレスの生成は終わりではありません。
160ビットの数字がそのままアドレスとして使われると、とても読みにくく入力ミスの多い口座番号となってしまうため、[Base58](https://ja.wikipedia.org/wiki/Base58)と呼ばれる人が読みやすい値だけで形成された文字列にエンコードされます。

`Base58`は以下の文字列から形成され、人が区別しにくい l （小文字 L）と 1 のような値を除外していることが特徴です。
`123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`

また、さらに`Base58`でエンコードされた文字列の最後に[チェックサム](https://ja.wikipedia.org/wiki/%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%82%B5%E3%83%A0)を追加した、[Base58Check](https://qiita.com/quincedaddy/items/6988bfd65738b66a6fb2)形式が使われます。

このチェクサムはアドレスの入力形式チェックに使われます。
デコードされる際にチェクサムのみをその場で計算し、与えられたデータに元から含まれているチェックサムと比較します。
これらの値が一致しなかったとき、アドレスの打ち間違いが発生したと判断され、存在しないアドレス宛の送金を防ぐことができるのです。

チェックサムの計算式は以下です。

```
checksum = SHA256(SHA256(Base58形式のアドレスのバイト列)) の最初の4バイト
```
右辺で算出された32バイトのハッシュから、最初の4バイトだけを取り出した値がチェックサムとなり、`Base58`形式のアドレスの最後に追加されることとなります。

# 2．ビットコインアドレスの種類
一重にビットコインアドレスと言っても、暗号化手法によって種類は異なります。
この章ではそれぞれの種類と暗号化手法をご紹介していきます。

## 2-1．暗号化秘密鍵（BIP38）
ウォレットをバックアップしたり、移行したりするときなど、秘密鍵が生の値のまま晒されるタイミングは存在します。
バックアップした秘密鍵を誰かに盗まれたりすることもあります。

`BIP38`はそんな状況にも対応できるようにパスフレーズで秘密鍵を暗号化し、さらに`Base58Check`でエンコードする標準規格を提案しています。

バックアップを行うために出力された秘密鍵は、まずプレフィックス「5」を伴い`Base58Check`形式で`WIF（Wallet Import Format）`にエンコードされます。
その後、英数字でできた複雑な文字列で構成されるパスフレーズを用いて、「6P」から始まる暗号化秘密鍵へ暗号化されます。

秘密鍵を扱わなければいけないタイミングでもこの暗号化秘密鍵を利用すれば、万が一流出したとしてもパスフレーズがなければ複合できない値となります。

`BIP38`の主な利用用途はペーパーウォレット作成時です。
暗号化秘密鍵のバックアップを紙に保管しておくことで、非常に安全な状態にすることが可能になります。

`BIP38`暗号化のソースは以下githubにあるので、中身が気になる方はこちらをご覧ください。
→ https://github.com/bitcoinjs/bip38

## 2-2．Pay-to-Script-Hash（P2SH）（BIP16）
通常、ビットコインアドレスは「1」から始まる値になりますが、「3」から始まるアドレスも存在します。
この形式を`Pay-to-Script-Hash`（P2SH）アドレスといい、マルチシグネチャのための1つの方法となります。

「1」から始まるアドレスでは、1つの公開鍵ハッシュと1つの秘密鍵署名を使って、所有権を認証するのですが、P2SHアドレスは以下のようなフローで作成されるため、コインを扱うために複数の公開鍵と署名が必要となります。

```
Pubkeys -> Redeem Script -> Locking Script（Script Pubkey） -> P2SHアドレス

# Pubkeys: 認証に必要とする公開鍵のリスト
# Redeem Script: 未使用のトランザクションの解除条件 (2 Pubkey1 Pubkey2 Pubkey3 Pubkey4 Pubkey5 OP_CHECKMULTISIG)
# Locking Script: Redeem Script のハッシュ値 (OP_HASH160 Redeem Script のハッシュ値(20バイト))
# P2SHアドレス: Locking Script を Base58Check でエンコードし、アドレスを算出
```


## 2-3．Vanity Address
アドレスに文字列指定を加えることで、人間が読むことができるメッセージを含んだアドレスを`Vanity Address`といいます。
例）`1LoveBPzzD72PUXLzCkYAtGFYmK5vYNR33`

その生成方法は秘密鍵をランダムに生成して、公開鍵とアドレスを導出し、`Vanity`パターンに合っているかどうかをチェックし続け合致した場合に採用するような形です。

# 3．おわりに
「実際に触ってみたい！」という方は`bitcore-lib`という Node.js のライブラリが使いやすかったのでこちらで触ってみることをオススメします。
→ https://github.com/bitpay/bitcore-lib


# 4．参考文献
- [ビットコインウォレットのパスフレーズの互換性の話（簡単なHDウォレットの仕組み）](http://www.jpbitcoinblog.info/entry/20160522/1463905035)
- [ビットコインアドレスを自分の手で作って理解する](https://qiita.com/quincedaddy/items/2e54f35683facb519446)
- [マルチシグの仕組み（P2SH方式）](https://qiita.com/you21979@github/items/795236fde38d510bbdd1)
- [BIP16 Wiki](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)
- [BIP38 Wiki](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki)
- [ビットコインとブロックチェーン:暗号通貨を支える技術](http://amzn.asia/fOPoyPb)