2018/01/14

ECDSAの署名+αから公開鍵を算出したい (5)

署名から公開鍵を算出する計算についても、sec-1-v2.pdfに載っていた。
「4.1.6 Public Key Recovery Operation」だ。
まだ読んでないけど「4.1.7 Self-Signing Operation」は署名するときにrecovery idを求める方なんじゃなかろうか。


また、どこで見つけたか忘れたが、JavaScriptで実装されているところもあった。
https://github.com/cryptocoinjs/ecdsa/blob/master/lib/ecdsa.js#L165

両方あれば、何かわかるんじゃなかろうか。
README.mdにdeprecatedと書いてあってリンク先が書いてあったので、こちらかもしれん(コードは同じか)。
masterにはrecoveryする関数ごと残っていなかったので、v3になるときに消されたのかもしれん。
https://github.com/bitcoinjs/bitcoinjs-lib/blob/v2.1.4/src/ecdsa.js#L165


JavaScriptの方は、先ほどの関数の呼び元もあって、こっちは4回ループしているのだ。
https://github.com/cryptocoinjs/ecdsa/blob/master/lib/ecdsa.js#L228

前回、私が考えていた「rec_idは0~3だから、ぐるぐる回せばいいんじゃないの?」なのかもしれん。
引数Qが「正解の公開鍵」で、戻り値のQprimeと比較しているから、署名をした方が使う関数なのかな。


ソースでは4回ループしているが、PDFの方を見ると、

  • 楕円曲線のh
  • Rと-R

でループするようで、secp256k1のhは1だから、0と1の2回、Rと-Rの2回で、あわせて4回ということなのか。
rec_idに相当する引数がiのようで、b0がRの正負、b1がhの0と1になっているのかな?


気になるのは、Rと-Rだ。
PDFでは、まずRで計算して出てきた値でverifyし、ダメだったら1.6.3で-Rにしているのだ。
だから、1.6のループ内でRか-Rかにしていると思うのだが、JavaScriptの方は最初にRを作る段階でRか-Rを分けているのだが、大丈夫なんだろうか。
まあ、その段階ではnRが無限遠になることの確認だけだから、それならnRだろうと-nRだろうと結果は同じか。


では、mbedTLSでやってみよう、と作っているのだが、これがうまくいかない。。。
今詰まっているのは、-Rの計算だ。
これを mbedtls_ecp_mul()で「-1 * R」という求め方にしているのだが、エラーMBEDTLS_ERR_ECP_INVALID_KEYが返ってきてしまう。
よく考えれば、これって秘密鍵から公開鍵を求めるときの「Q=aG」と同じようなものだから、-1だとダメなんだろう。


JavaScriptでは、secp256k1.pointFromX()を使ってて、第1引数に奇数かどうか突っ込んでいる。
奇数=0x03だろうから、Y座標だけ負の数になれば良いのかな?

・・・ダメだ。
-Yにしても楕円曲線上に載ってないように見られてしまう。
計算方法自体が良くないのか??
自作している圧縮公開鍵を非圧縮に戻す関数があるのだが、そのときに先頭を0x02から0x03にすると大丈夫だった。
うーん、理論的なところがわかっていないので、それでいいのかどうか判断できん。。。


そして、そうやってやると、4回回すと1つだけ公開鍵が期待値とほぼ一致した!
「ほぼ」なのは、先頭の0x02/0x03が逆になったからだ。
私の認識では、楕円曲線はX軸に対して線対称だから、特定のXに対して、+Yと-Yがあり、+Yが0x02~、-Yが0x03~、だ。
だから、X座標はちゃんと復元できていて、Y座標の正負だけが間違っているのだと思う。


じゃあ、それはなんで?ということになると、ちゃんとPDFを読んで、JavaScriptのソースが何をしているのかを把握せねばなるまい。
場当たり的に「0x02を0x03にする」などとやってしまうと、値のパターンによってうまくいかないという将来が見えてしまうではないか。。。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。