Ethereum: イーサリアムのトランザクションに署名付きデータを埋め込み、コントラクトでその署名を検証する方法
この記事では、イーサリアム(Ethereum)のトランザクションに署名付きデータを埋め込み、その署名をコントラクトで検証する方法を説明する。
システム内にこの仕組みを取り入れることで、一部の処理をオフチェーンで実行でき、不要なgasの削減や処理の高速化を実現できる。
- トランザクションの署名
- トランザクション内データの署名
- 具体的な署名・検証の実装方法
- まとめ
参考資料
1. トランザクションの署名
イーサリアムのトランザクションは、必ず送信者によって署名がされている。こうすることで、誰でもそのトランザクションの送信者を検証できる。
この署名には、ECDSA(Elliptic Curve Digital Signature Algorithm)というアルゴリズムが用いられている。
2. トランザクション内データの署名
ECDSAは、Solidity側でもWeb3側でも簡単に使える仕組みが提供されている。
そのため、トランザクションの署名と同じ要領で、トランザクションの中身に署名をすると、そのトランザクションに書かれている内容の一部が、トランザクション送信者以外の誰かによって書かれた(その人物の許可を得ている)ことを検証できる。
0x Protocolでの利用例
0x ProtocolとはDEXの仕組みの1つで、0x Protocolに準拠したDEXは、注文部分をオフチェーンでおこなう。0x Protocolの仕組みは、Off-chain order relay On-chain settlementという言葉で表されている。
この仕組みを上の図に対応させる。
まず売り手(0xC)は、以下の内容(一部割愛してある)に署名をして、order(signed data)を作成する。
- 売り手のアドレス
- 売りたいtokenとその量
- 買いたいtokenとその量
作成されたorderは、order bookと呼ばれるリスト(オフチェーン)に追加される。
買い手(0xAに対応)は、order bookから好きなorderを選び、そのorderをデータとして含んだtransactionを作ることで、取引を成立させる。(オンチェーン)
このとき、最終的なtransactionは買い手によって作成されているが、取引内容は売り手が決定できていることに注意する。
このように0x Protocolでは、注文部分をオフチェーンで処理することによって、不要なgasの発生を防いでいる。(注文の作成・取り消しにかかるはずのgasを削減できている。)
3. 具体的な実装方法
トランザクション内データに署名することの有用性を理解したので、最後に具体的な実装を見ていく。ここでは、以下の流れを確認することを目的とする。
3.1. Web3を使ったオフチェーンでの署名
3.2. Web3を使ったオフチェーンでの検証 (optional)
3.3. Solidityを使ったオンチェーンでの検証
全体の実装例は、以下のリポジトリに公開している。
3.1. Web3を使ったオフチェーンでの署名
signatureを得るための関数はweb3.eth.accounts.signを使うといい。
その際、あらかじめmessageをhashしておくのがよく(bytes32にしておくのがよく)、それにはweb3.utils.soliditySha3が有用である。この関数は、引数をSolidityと同じように扱ってくれるため、後述するSolidity側での検証が可能になる。(例えば、正のnumberはuint256として扱う。)
3.2. Web3を使ったオフチェーンでの署名の検証 (optional)
署名の検証にはweb3.eth.accounts.recoverを使うといい。
この際デフォルトでは内部的に、署名対象のデータ(messageHash)がhashされる(正確には、prefixをつけてhashされる)ことに注意する。この処理を明示的に書いたのがコメントアウトされた行で、verifiedAddress
から始まる2つの行は、どちらの行をコメントアウトしても動作する。
この例では、signedAddressとverifiedAddressが同じになることが確認できる。
3.3. Solidityを使ったオンチェーンでの署名の検証
3.2. と同じことをSolidity側で行なっているのが、以下の例である。
この際、ライブラリとしてOpenZeppelinのECDSAを利用している。Solidity側では、上述の内部的なhashを明示的に記述する必要がある。 (toEthSignedMessageHash)
ここで得られるverifiedAddressは、3.2で得たverifiedAddressと同じ結果になる。
4. まとめ
トランザクションの内部データに署名をすることで、そのトランザクションに書かれている内容(の一部)が誰かの許可を得ていることを検証できる。
これらは、不要なgasの削減や処理の高速化に役立ち、Web3・OpenZeppelinのライブラリを使うことで、比較的簡単に実装することができる。