BTC_シリアライズ

Posted: June 25, 2022

ECDSA公開鍵をシリアライズする方法はSEC(Standard for Efficieint Cryptography)フォーマットと呼ばれる

非圧縮SECフォーマット

点P(x, y) に対する非圧縮SECフォーマットを生成する方法は以下

  1. プレフィックスバイト 0x04から始める
  2. 32バイトのビッグエンディアン整数としてx座標を追加
  3. 32バイトのビッグエンディアン整数としてy座標を追加

以下のような文字列になる

04ffe558e388852f0120e46af2d1b370f85854a8eb0841811ece0e3e03d282d57c315dc72890a4f10a1481c031b03b351b0dc79901ca18a00cf009dbdb157a1d10

圧縮SECフォーマット

点P(x, y) に対する圧縮SECフォーマットを生成する方法は以下

  1. プレフィックスバイト yが偶数の場合は0x02とし、奇数の場合は0x03とする
  2. 32バイトのビッグエンディアン整数としてx座標を追加

y座標をシングルバイト(偶数か奇数かのみを示す)に圧縮することになるので圧縮SECフォーマットと呼ぶ

x座標からyをどのように計算するのか

y2=x3+ax+by^2 = x^3 + ax + b

上記を満たす(x, y) では、(x, -y)も式を満たす(y**2なので)

さらに有限体では以下となる

yp=(py)p-y % p = (p - y)%p

つまり任意のxに対して、y座標はyもしくは、(p-y)になる必要がある

p(位数)は2より大きい素数(奇数)となるので、yが偶数の場合はp-yは奇数になり、yが奇数の時はp-yは偶数になる

有限体での平方根の計算

y2=x3+7y^2 = x^3 + 7

となるyを求める必要がある(平方根を求める必要がある)

数学的に表すと以下のようになる

vから、w2=vとなるようなwを求めよvから、w^2=vとなるようなwを求めよ

secp256k1(ビットコインの楕円曲線暗号)は p % 4 = 3 を満たす

これは (p + 1) % 4 = 0、つまり (P + 1) / 4 は整数となる

wの値を求めるためにフェルマーの小定理(w**(p-1) % p = 1)を利用する

w**2 = w**2 * 1 = w**2 * w**(p-1) = w**(p+1)

w = w**(p+1)/2 = w**2(p+1)/4 = v**(p+1)/4

(p+1)/4 は整数なので、secp256k1において、w**2 = v, w = v**(p+1)/4 が成り立つ

この式でwの値のうち1つが求まり、もう一つの解は p - w となる

DER署名

署名(rとs)をシリアライズする標準をDERフォーマット(Distinguished Encoding Rules)と呼ぶ

  1. 0x30で開始
  2. 署名の残りの長さをエンコードして(通常は0x44又は、0x45)追加
  3. マーカーバイト0x02を追加
  4. rをビッグエンディアンの整数としてエンコード。ただしrの先頭バイトが0X80以上の時は、先頭に0X00を付加する。長さをrの先頭に付加して実際の値という構成になる
  5. マーカーバイト0x02を追加
  6. sをビッグエンディアンの整数としてエンコード。ただしsの先頭バイトが0X80以上の時は、先頭に0X00を付加する。長さをsの先頭に付加して実際の値という構成になる

DERフォーマットの例

3045022037206a0610995c58074999cb9767b87af4c4978db68c06e8e6e81d282047a7c60221008ca63759c1157ebeaec0d03cecca119fc9a75bf8e6d0fa65c841c8e2738cdaec

Base58

SECフォーマットを16進数(1文字あたり4ビット)で表すと長くなる。

→Base64(1文字あたり6ビット、64進数)を使うと短くなるが似た文字がわかりづらい

 (0とO、lとI、-と_)

→Base58(Base64から上記の6文字を除外、58進数)でエンコードする

アドレス形式

SECフォーマットを使わないことでアドレスを33バイト(圧縮の場合)から20バイトに短縮できる

  1. メインネットアドレスは先頭を0x00、テストネットは0x6fで開始する
  2. SECフォーマット(圧縮または非圧縮)を取り出し、sha256操作とripemd160ハッシュ操作を行う。この組み合わせをhash160操作と呼ぶ。
  3. 1のプレフィックスと2のハッシュ操作の結果を結合する
  4. 3の結果にhash256を行い、先頭の4バイトを取得(チェックサム)
  5. 3と4を結合させてBase58でエンコードする

WIF

秘密鍵をシリアライズした形式をWIF(ウォレットインポート形式)と呼ぶ

  1. メインネット用の秘密鍵は0x80、テストネット用は0xefのプレフィックスで開始
  2. 秘密鍵を32バイトのビッグエンディアンでエンコードする
  3. 公開鍵アドレス用のSECフォーマットが圧縮形式の場合、末尾に0X01を追加する
  4. 1と2と3を順に結合する
  5. 4の結果にhash256を実行し、先頭の4バイトを取得
  6. 4と5を結合し、Base58でエンコード