10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

仮想通貨ウォレットやトランザクション周りを実装していると、
ほぼ必ず通る関門があります。

ECDSA署名

今回は、
ECDSA署名を「たった1バイト」間違えただけで、すべてが動かなくなった話を書きます。

何をしていたのか

やっていたこと自体は、よくある処理です。

  • raw transaction を組み立てる
  • 署名対象データ(sighash)を作る
  • 秘密鍵で ECDSA 署名
  • 署名を transaction に埋め込む
  • ノードに送信

理論上は、これで通るはずでした。

起きた現象

結果はこうでした。

  • rawtransaction が通らない
  • ノードから reject される
  • エラー内容が曖昧
  • 何が間違っているのか分からない

署名自体は「生成されている」し、
形式もそれっぽい。

でも、絶対に通らない

という最悪の状態でした。

原因:たった1バイトのズレ

結論から言うと、原因はこれでした。

ECDSA署名の1バイトが違っていた

  • r と s のどちらか
  • DERエンコードの長さ
  • sighash type の付け方

この 1バイトのズレ によって、

  • 署名検証が必ず失敗
  • トランザクションは即 reject

されていました。

なぜ見つからなかったのか

1. 見た目では分からない

  • 署名の長さは合っている
  • DER形式っぽい
  • 16進数で見ても違和感がない

しかし内部的には、

完全に別の署名

として扱われます。

2. エラーが親切ではない

多くの場合、

  • invalid signature
  • non-mandatory-script-verify-flag
  • signature error

など、
具体的な原因を教えてくれません

具体的にハマりやすいポイント

  • r / s の leading zero の扱い
  • DER長の計算ミス
  • sighash type を署名対象に含め忘れる
  • sighash type を末尾に付け忘れる
  • Big Endian / Little Endian の混同

どれか1つでも間違えると、
署名は即死します。

検証して分かったこと

  • 公式実装と1バイト単位で比較
  • 既存ウォレットの署名結果と比較
  • 自前実装同士でクロスチェック

特に、

署名結果をそのまま比較する

のが一番確実でした。

ECDSA署名で学んだ教訓

  • 「だいたい合ってる」は存在しない
  • 1ビットでも違えば完全に無効
  • 実装より検証が重要
  • 自前実装は必ず疑う

まとめ

  • ECDSA署名は極端にシビア
  • 1バイトの違いで全てが壊れる
  • エラーは原因を教えてくれない
  • 比較検証が最短ルート

この話が、
これから ECDSA やウォレット実装に挑戦する人の
地雷回避になれば幸いです。

10
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?