Bitcoinの鍵とアドレスを勉強したので個人的メモ

# 秘密鍵・公開鍵・アドレスの役割
秘密鍵は、ビットコインへの所有権を表すもの。ビットコインはコインそのものが存在するわけではなく、未使用トランザクションのアウトプットとして存在していて、そのアウトプットを新たなトランザクションのインプットとして使おうとするときに、秘密鍵でそのロックを解除する必要がある。つまり、秘密鍵があればその鍵でロックされているビットコインを使うことができるということであるから、秘密鍵は「ビットコインへの所有権の源泉」と言える。
公開鍵は、ビットコインを受け取るときに使う。AliceがBobに送金するようなトランザクションを発行するときにAliceはBobの公開鍵を用いてそのトランザクションに署名を施す。これによってそのトランザクションのロックを解除してアウトプットを使用できる人は、その公開鍵に対応する秘密鍵を持っているBobのみとなる。つまり、公開鍵はビットコインを受け取るために必要な鍵であると言える。また、今の話から、公開鍵は秘密鍵と密接に関係している。
アドレスは、銀行口座番号のようなもので、ビットコインを送金する際の宛先に当たるもの。買い物するにせよ、仕送りするにせよビットコインをあるアドレスに対して送金するという形をとる。

まとめると
- **秘密鍵は所有の源泉。秘密鍵を知っていることは、それに紐づいているビットコインを使用できることと等しい**
- **公開鍵はビットコインをトランザクションを発行してビットコインを受け取るのに必要**
- **アドレスは銀行口座番号。送金の際は、アドレスに対して送金する**

# 秘密鍵
秘密鍵は、「所有権の源泉」であるから、自分以外の誰にも知られてはならない。他の誰かに知られてしまっては、そのビットコインが他の誰かによって使用されてしまうということになる。また、秘密鍵は忘れてしまっても大問題である。秘密鍵を忘れるということは、その秘密鍵によって解除できるビットコインが永久埋蔵金として使用不可能になってしまうということである。

秘密鍵は、なんてことない、ただの整数である。だが他の人に推測されては困るので、無作為に選ばれる必要がある。秘密鍵は十分なランダム性を確保する必要があるから、ビットコインを扱うクライアントソフトウェアはOSの乱数生成器を用いたりしてランダム性を確保している。平たく言えば、そんなことせずにサイコロを何回も振って決めるのだってアリ。なんならそっちの方が安全だったりする。
秘密鍵は平たく言えば「$ 1 $から$ 2^{256} $の間の整数から適当に一つ選ぶ」ことで得られる。正確に言えば「$ 1 $から$ 2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 $の間の整数から適当に一つ選ぶ」ことで得られる。ただし、十分に長くて数字の並びが不規則な数字にしないといけない。何故ならば秘密鍵は所有権の源泉だから。

ここで、「$ 1 $から$ 2^{256} $の間の整数から適当に一つ選ぶ」ってかぶっちゃったりしないの？という疑問が湧いたが、そんなことはめったに起きないと考えて良い。$ 2^{256} $とはめちゃくちゃにデカイ。

```math
2^{256}=115792089237316195423570985008687907853269984665640564039457584007913129639936
2256=115792089237316195423570985008687907853269984665640564039457584007913129639936
```
これは$ 10^{77} $のオーダーで、観測できる宇宙の中にある原子の個数が$ 10^{88} $個とされているから、まあデカイ。観測できる宇宙の中にある原子から適当に選んで同じもの選ぶことがあったら、その人たちは結婚した方がいい。運命感じちゃう。

ソフトウェア内部でのランダムに選ぶ処理は、「十分にランダムな長い文字列を用意して、それを`sha256`ハッシュ関数にかけて256ビットのハッシュ値を得て、それが$ 2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 $を超えていないかをチェックする（超えていればやり直し）」という風にするらしい。

まとめると、

- **秘密鍵の実体は、ただの整数**
- **秘密鍵の範囲は（だいたい）$ 1 $から$ 2^{256} $の間**
- **秘密鍵は他の人に見られたり推測されたりしたくないからできるだけ長くて不規則な数字の羅列がいい**
- **$ 2^{256} $って簡単にいうけどめちゃんこデカイ**

# 公開鍵
公開鍵は秘密鍵から生成される。公開鍵と秘密鍵は数学的に密接な関係がある。秘密鍵から公開鍵を与える演算は「楕円曲線上のスカラー倍算」による。「楕円曲線上のスカラー倍算」を元にした暗号が楕円曲線暗号という。
公開鍵は、数字の組である。平たく言えば$ (12,34) $みたいなもの。これを与える演算が楕円曲線上のスカラー倍算である。

まず、楕円曲線とはなんなのか。楕円曲線は、パラメタによって形が変わる次のような曲線のこと。ただの曲線。
![楕円曲線](https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/EllipticCurveCatalog.svg/784px-EllipticCurveCatalog.svg.png)

この曲線上で次のように加法（足し算）を定義する。
> ある楕円曲線$ E $上の点$ P_1 $、$ P_2 $に対して点$ P_3 = P_1 + P_2 $を次の手順で与える。
> まず、$ P_1 $、$ P_2 $を通る直線を引き、それと$ E $の交点（$ P_1 $、$ P_2 $を除く）を$ P^\prime_3 $とする。
> 次に、$ P^\prime_3 $の$ x $軸に対して対称な位置にある点を$ P_3 $とする。

このように加法を定義するとその拡張で倍算が定義できる。つまり、

> ある楕円曲線$ E $上の点$ P_1 $に対して点$ 2P_1 = P_1 + P_1 $を次の手順で与える。
> まず、$ P_1 $、$ P_1 $を通る直線つまり楕円曲線$ E $に対する点$ P_1 $における接戦を引き、それと$ E $の交点（$ P_1 $を除く）を$ P^\prime $とする。
> 次に、$ P^\prime $の$ x $軸に対して対称な位置にある点が$ 2P_1 $とする。

これを$ n $回繰り返せば$ 2^nP_1$が求められる。

で、ビットコインでは楕円曲線として`secp256k1`という曲線を採用していて、この曲線の表式は次のとおり。

```math
y^2 \space \rm{mod} \space p = (x^3 + 7)\space \rm{mod} \space p 
\\\ p = 2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
```
これは、$ \rm{mod} \space p $を取っているので曲線というよりかは点の集合になる。
点の集合を実際に見て見たいと思ったので、実際に描いて見た。以下は`R`で描いて見たときのスクリプト。`p`に適当な素数を与えてプロットされた結果を見てみる。

```R
p <- # prime number

xlist <- c()
ylist <- c()
for (x in 1:p) {
  for (y in 1:p) {
    if (((x^3 + 7 - y^2) %% p) == 0) {
      xlist[length(xlist) + 1] <- x
      ylist[length(ylist) + 1] <- y
    }
  }
}

plot(xlist,
     ylist,
     type = "p",
     main = sprintf("(x^3 + 7 - y^2) mod %d == 0", p),
     xlab = "x",
     ylab = "y",
)
```

![23.png](https://qiita-image-store.s3.amazonaws.com/0/169178/1ac7c9c3-3cff-e15d-7ca5-6f730b79cd4c.png)
![79.png](https://qiita-image-store.s3.amazonaws.com/0/169178/9bd53a88-a94e-0a45-fd89-fd6c6bfc7a4c.png)
![2411.png](https://qiita-image-store.s3.amazonaws.com/0/169178/c490d976-9918-d63f-c694-ffbe5d57aa66.png)
![9973.png](https://qiita-image-store.s3.amazonaws.com/0/169178/3ed141f1-ff61-4972-aae1-562ac6191acf.png)

デカイ素数を入れると点が無数に出てくる。この点のどれかが公開鍵に相当する。

楕円曲線上の点に対して加法を定義することができて、ビットコインではその楕円曲線として無数の点の集合を用いるらしい。

で、公開鍵$ K $はその楕円曲線上の点に対する倍算をどのように用いて与えられるのかというと、ある特定の点$ G = (55066263022277343669578718895168534326250603453777594175500187360389116729240, 32670510020758816978083085130507043184471273380659243275938904335757337482424)$（これは生成元と呼ばれる点で、定点）に対して秘密鍵を$ k $とすると、秘密鍵は所詮ただのデカい数字なので、

```math
K = k \times G
```
が計算できて、これによって与えられる$ K $が公開鍵。加法倍算ができればスカラー倍もそれらの組み合わせでできる。なお、公開鍵$K$と生成元$G$（これは定点なのでみんな知っている）から秘密鍵$k$を求める問題は離散対数問題として知られていて、まともに解けない。

# アドレス
アドレスは、送金するときの宛先。アドレスは基本的には公開鍵$K$のハッシュ値。

```math
\rm{address} = RIPEMD160(SHA256(K))
```
加えて`Base58Encode`されるが、要するにアドレスは公開鍵のハッシュ値。