
「私がジャン=ポール・サルトルと署名するのと、ノーベル賞受賞者ジャン=ポール・サルトルと署名するのとでは、同じことではない」
――ジャン=ポール・サルトル、1964年
この言葉を読んだのはずいぶん昔のことで、それ以来ずっと、居心地の悪さとともに胸に抱えてきた。だが長い年月が過ぎ、その年月がもたらした人生の浮き沈みを経験した今、彼の言わんとしたことを、ようやく穏やかに受け止められるようになったと思う。私がクレイグ・ライトと署名するのと、クレイグ・ライト、サトシと署名するのとでは、同じことではない。
これは真実だと思う。だが心の底では、そうでなければよかったと願っている。
IFdyaWdodCwgaXQgaXMgbm90IHRoZSBzYW1lIGFzIGlmIEkgc2lnbiBDcmFpZyBXcmlnaHQsIFNh
dG9zaGkuCgo=
何時間も画面を見つめているが、ビットコインのプロジェクトを最初から支えてくれた人々への感謝の深さを言い表す言葉が、どうしても出てこない。名前を挙げればきりがない。あなたたちは、何にもならずに終わったかもしれないオープンソースのプロジェクトのために、何年ものあいだ膨大な時間を捧げ、才能を注ぎ、人間関係とレム睡眠を犠牲にしてきた。それでもなお戦い続けた。この素晴らしいコミュニティの情熱と知性と粘り強さが、私の小さな貢献を育て、磨き、命を吹き込んだ。あなたたちは世界に大きな贈り物をした。ありがとう。
安心してほしい。あなたたちが働いてきたのと同じように、私もこの長い年月、何もせずにいたわけではない。初期のあの頃から、サトシという公の人格と距離を置いたのち、私は自分のすべてを研究に注いできた。沈黙はしていたが、いなくなっていたわけではない。卓越した仲間たちと取り組んできた注目すべき成果を、準備が整いしだい共有できるのを楽しみにしている。
サトシは死んだ。
だが、これは始まりにすぎない。
鍵の検証
この記事の残りでは、一組の暗号鍵を検証する手順を説明する。
OpenSSLで正しい楕円曲線のパラメーターを使ってメッセージに署名し、検証できるようにするには、secp256k1曲線が読み込まれている必要がある。これはCentOS Linuxの既定ではない。その手順はここでは詳しく述べない。ただ、RPMForge (http://repoforge.org/use/)がパッチ適用済みのバイナリーを提供していることは指摘しておく。私のようにCentOSを使っているなら、OpenSSLのウェブサイトからソースファイルとパッチの両方をダウンロードすることを勧める。
前もって読んでおくとよいウェブサイトも挙げておく。
https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operationshttp://www.secg.org/sec2-v2.pdfhttps://www.openssl.org/https://www.bfccomputing.com/bitcoin-and-curve-secp256k1-on-fedora/
この作業の最初の段階として、ハッシュ関数を説明する。下の図では、「sn7-message.txt」というファイルを表示している。

スクリプトの断片
上の図に表示された一連の16進数 (https://en.wikipedia.org/wiki/Hexadecimal)の値は、ある入力値のSHA256 (https://en.wikipedia.org/wiki/Secure_Hash_Algorithm)ハッシュを表している。優れたハッシュアルゴリズムは、前もって決めることのできない大きな値の列を生成する。情報量と可能な組み合わせの数は、どんなハッシュ関数が出力できる範囲をも常に上回るため、衝突は必ず存在する。SHA256のようなハッシュ関数を有用にし、「安全」とみなされるものにしているのは、出力として返される値と同じ値に衝突する入力値の組を割り出して見つけることが、現在の技術水準では実行不可能だという点である。
SHA256アルゴリズムは、最大でビットの情報をメッセージとして受け付け、出力値として32バイト、つまり256ビットを返す。SHA256ハッシュ関数に入力できるメッセージの数は、0ビットから上で述べた受け付け可能な最大の範囲までの大きさにわたり、合計で個の入力値になる。
平均して生じうる衝突の範囲を求めるには、組み合わせ論と呼ばれる手法によって並べ方の数を決める二項係数 (https://en.wikipedia.org/wiki/Binomial_coefficient)を用いる[1]。
衝突の検出に関わる数学の詳細は、後の記事に譲る。ただし、それぞれのハッシュには衝突する値が途方もなく多く存在する一方で、衝突する二つの値を見つけたり、それを前もって割り出したりする確率は限りなく小さいことは押さえておきたい。来週、組み合わせ論と確率論に基づいて、「安全な」ハッシュアルゴリズムで衝突が見つかる可能性を示す記事を続けて載せる。
ハッシュ化
ハッシュ関数は比較的単純で、手計算でもできる (http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html)。もちろん、それは逆算に必要な複雑さを覆い隠している。優れたハッシュ関数は、使うのは簡単でありながら、逆算することは実行不可能である。下の図では、Linuxのハッシュ用コマンド「sha256sum」を実行している。この単純なプログラムは、決まった固定の入力に対応する一意の値を返す。

スクリプトの断片
上の図では、このOpenSSLの署名の作業に使うものを含む、いくつかのファイルに対してこれを実行している。これから使うのは、Sartreと名付けたファイルである。このファイルの中身を下の図に示す。

スクリプトの出力
デジタル署名のアルゴリズムは、メッセージのハッシュに署名する。メッセージそのものに署名することもできるが、ハッシュに署名することで、メッセージの完全性を確保し、メッセージが変わっていないことを確かめられる。空白一つ、「.」一つでも変われば、ハッシュは最初に返された値とまるで違うものになる。
この値をファイルに書き込んで保存するには、Linuxのコマンドであるxxd (http://linuxcommand.org/man_pages/xxd1.html)を使える。これはASCIIの値を16進数のバイナリーファイルに書き込む。下のコマンドでは、「file.name」というファイルに0の列を書き込むことになる。
echo '000...000' | xxd -r -p > file.name
こうすることで、ハッシュアルゴリズムの出力として受け取った文字列を、16進数で符号化されたファイルに変えられる。これが、署名し検証できるメッセージになる。上のechoコマンドに入れる数字の列が正しいかどうかを確かめることが重要である。1桁でも打ち間違えれば、メッセージの検証は通らない。
公開鍵
デジタル署名されたメッセージを検証するには、いくつかの要素が必要になる。それは次のとおりである。
- アルゴリズム
- 検証したい署名者の公開鍵
- 署名されたメッセージ
- デジタル署名のファイル
このうち一つ目のアルゴリズムは、secp256k1曲線のパッチを組み込んだOpenSSLをインストールすることで手に入る。上の段階では、ハッシュ化したメッセージの作成を扱った。次の節では、ECDSAの公開鍵の使い方を扱う。

スクリプトの断片
この作業では、OpenSSLのPEMファイルとして保存した公開鍵と秘密鍵の組を使っている。David Derosa (http://davidederosa.com/basic-blockchain-programming/elliptic-curve-keys/)が、OpenSSLで楕円曲線の鍵の組を作る方法を説明した優れたページを書いている。上の図には、この作業でメッセージの署名に使った鍵の組に対応する、PEM形式の公開鍵が表示されている。Davidのページ (http://davidederosa.com/basic-blockchain-programming/elliptic-curve-keys/)をよく読めば、ビットコインのトランザクションで使う秘密鍵の組をPEMファイルとして整える方法について、必要な情報がすべて得られる。このページが説明しているのは新しい秘密鍵の作成であって、既存の秘密鍵をOpenSSLに取り込む方法ではない。その追加の手順は私が扱い、楕円曲線暗号に基づく既存の秘密鍵の組を、OpenSSLで直接使えるASN.1形式に取り込めることを示すつもりである。
公開鍵を書き出すコマンドを次に示す。
openssl ec -in sn-pub.pem -pubin -text -noout
0411db93e1dcdb8a016b49840f8c53
bc1eb68a382e97b1482ecad7b148a6
909a5cb2e0eaddfb84ccf9744464f8
2e160bfa9b8b64f9d4c03f999b8643
f656b412a3
返される文字列は、ビットコインを含むプログラムが署名の検証とアドレスの算出に使う公開鍵の値である。
Casascius (https://casascius.wordpress.com/2013/01/26/bitcoin-address-utility/)が、この公開鍵を読み解き、対応するビットコインアドレスを返す便利な道具を作っている。このサイトにも、ビットコインアドレスが公開鍵と秘密鍵からどのように導かれるかという技術的な側面を理解する助けになるブログ記事がある。公開鍵からビットコインアドレスを計算できるオンラインの道具 (http://bitcoinvalued.com/tools.php)もいくつかある。
署名
OpenSSLでメッセージにデジタル署名するには、署名する側が秘密鍵を使えなければならない。この手順は後の記事で詳しく記録し、扱う。最近の何回かの場では、ビットコインアドレスに対応する秘密鍵を合計10個使った。これらはSPVウォレットのElectrum (https://electrum.org/#home)に読み込んだ。ある回では、この記事では詳しく述べないメッセージに、何人かの人々のために署名した。それは私が自分で選んだメッセージではなく、他の人々が選んだものだった。いくつかの回では、Electrumの新しい版をダウンロードし、その日の午後に買って開封したばかりのノートパソコンに入れ、その新しいマシンで署名済みのメッセージを検証することで、手順の完全性を確かめた。
私が使っているElectrumの版は、CentOS Linux v7の上でPythonを通して動く。上で触れた作業では、回によってWindows 7とWindows 10を使った。
署名の検証
最後に扱う要素は、署名そのものである。base64形式の署名を、OpenSSLに読み込めるファイル形式に変換するため、次のコマンドを使う。
>> base64 --decode signature > sig.asn1 & openssl dgst -verify sn-pub.pem -signature sig.asn1 sn7-message.txt
これから検証する署名のファイルには、次のデータが入っている。
------------------------- Signature File -------------------------
MEUCIQDBKn1Uly8m0UyzETObUSL4wYdBfd4ejvtoQfVcNCIK4AIgZmMsXNQWHvo6KDd2Tu6euEl1
3VTC3ihl6XUlhcU+fM4=
------------------------- End Signature --------------------------
下の図では、この手順に使ったコンピューターに保存されたとおりの署名ファイルを表示し、検証の作業の結果を示している。このファイルを保存するときは、符号化された署名を切り取って貼り付け、vimのようなエディターで保存したファイルに挿入すればよい。エディターの選び方をめぐる宗教戦争を始めるつもりはないが。

スクリプトの断片
この手順で気にすべき出力は二つある。OpenSSLは、署名を正しく検証できた場合には「Verified OK」と返す。この記事で使った公開鍵、メッセージ、メッセージの署名を取り込むのに必要な情報は、すべてこの記事に載せてある。
非公開の場でしたように、Electrumでメッセージに署名するだけでもよかった。そのほうがメッセージの読み込みはずっと簡単だっただろう。私は昔から「扱いにくい」ことで知られ、「こうしなければならない」と言われるのを嫌ってきた。その結果として、私はこれを簡単にはしない。
いくつかのスクリプト
この手順を簡単にするため、シェルスクリプトを二つ載せておく。同様のスクリプトの別版については、Enrico Zimuel (http://www.zimuel.it/)が運営しているようなサイトを見てほしい。このサイトは楕円曲線暗号を特に扱っているわけではないが、彼のコードをビットコインに基づくシステム向けに書き換えるのはそれほど難しくない。
署名
好きなときに試せるよう、署名用のスクリプトを下に載せておく。このスクリプトでは、署名したいファイルを表す変数<file>と、自分が管理する秘密鍵を選んだ<private_key>を入力にする。このコマンドで、変数<private_key>は、メッセージの署名に使う秘密鍵を収めたファイルを表し、そこから署名が出力される。
EcDSA.Sign.sh <file> <private_key>
このシェルスクリプトの出力は、Base64で符号化したファイルとして保存された署名である。これはBase64形式で、<signature.der>という名前のファイルとしてハードディスクなどに保存される。

EcDSA.sign.sh
検証
作った署名は、下に載せるスクリプトを使って、同じような手順で検証できる。
EcDSA.Verify.sh <file> <signature> <public_key>
このコマンドラインで、変数<file>は検証したいファイルの名前を表す。変数<signature>は署名を(Base64で符号化して)保存したファイルを表し、最後の変数<public_key>はPEM形式の公開鍵を収めている。これらのファイルを組み合わせて使い、それぞれが有効で正しければ、デジタル署名の検証に成功する。

EcDSA.verify.sh
形式の選択
ビットコインの中で使われている署名の形式は、DER符号化に基づいている。元のコードでは他の方法も使われており、この7年でコードは大きく変わった。署名などの情報にDER符号化を選んだのは、互換性のないシステムのあいだでも情報を共有できるようにしたかったからである。情報を保存する方法として最も効率的なものではないが、異なるシステム同士が効率よくやり取りできるようにはなる。
多くのオープンソースのプロジェクトと同じく、OpenSSLは多くの部分で文書が不十分である。ビットコインのアドレスの扱いと鍵の組の保存は、もっとずっと効率的にできたはずで、今はそうなるようにコードが更新されている。だが、どんな新しいシステムでもそうであるように、完璧を目指しながらまだ存在しないものより、動くものがあるほうがはるかによい。
セキュリティは常にリスクの関数であって、絶対的なものではない。
参考文献
[1] Lovasz, Laszlo (1979) “Combinatorial Problems and Exercises” North Holand Publishing Co. Amsterdam



