メインコンテンツへスキップ

EIP-1271: スマートコントラクト署名に対する署名と検証

eip-1271
スマートコントラクト
検証
署名(signing)
中級
Nathan H. Leung
2023年1月12日
12 分の読書

EIP-1271 (opens in a new tab)標準は、スマートコントラクトによる署名の検証を可能にします。

このチュートリアルでは、デジタル署名、EIP-1271の背景、およびSafe (opens in a new tab) (旧Gnosis Safe) が使用するEIP-1271の特定の実装の概要を説明します。 このチュートリアル全体を通して、EIP-1271を自身のコントラクトへ実装するための出発点として使うことができます。

「署名」とは何か

このチュートリアルにおいて、署名 (正確には「デジタル署名」) とは、特定の人物/送信者/アドレスから送信されたものであることを示す何らかの証拠をそのメッセージに対して加えたものです。

具体的には、デジタル署名は次のようなものです。

  1. メッセージ: 「イーサリアムウォレットを使用してこのWebサイトにログインしたい」
  2. 署名者: 私のアドレスは0x000…です。
  3. 証拠: 私(0x000…)が、このメッセージ全体を実際に作成したという証拠がこちらです(これは通常、暗号化されたものです)。

デジタル署名には、「メッセージ」と「署名」の両方が含まれていることが重要です。

それはなぜでしょうか? 具体的には、あなたが私に署名するように契約書を渡した後、私が署名のあるページを切り取り、契約事項のない署名だけを返した場合、その契約は無効なることがあげられます。

同様にデジタル署名においても、それに紐づいたメッセージがなければ意味がありません。

EIP-1271が必要な理由

イーサリアムベースのブロックチェーン上でデジタル署名を作成するには、通常、他の人が知らない秘密鍵が必要になります。 秘密鍵により、あなたの署名が自身のものになります (誰も秘密鍵を知らない限り、同じ署名を作成できません) 。

イーサリアムアカウント(i.e.、外部所有アカウント/EOA)には秘密鍵が関連付けられています。この秘密鍵は、ウェブサイトやdappが署名(例: 「イーサリアムでログイン」)を求める際に通常使用されるものです。

アプリは、ethers.jsのようなサードパーティのライブラリを使い、あなたが作成した署名を検証 (opens in a new tab)し、あなたの秘密鍵を知ることなく (opens in a new tab)、_あなた_がその署名を作成したと確信できます。

事実、EOAのデジタル署名は公開鍵暗号を使用するため、オフチェーンで生成・検証できます。 これは、ガスレスDAO投票の仕組みです。オンチェーンで投票を送信する代わりに、暗号ライブラリを使用してオフチェーンでデジタル署名を作成し、検証できます。

EOAの各アカウントには秘密鍵がありますが、スマートコントラクトアカウントにはいかなる種類の共通鍵も秘密鍵もありません (そのため、「イーサリアムでログイン」などはスマートコントラクトのアカウントにおいては、ネイティブで機能しません) 。

EIP-1271は、スマートコントラクトで署名に使う「秘密鍵」がないのであれば、スマートコントラクト署名が有効かどうかをどのように判断すればよいのかという問題を解決することを目的にしています。

EIP-1271の仕組み

スマートコントラクトには、メッセージの署名に使用する秘密鍵がありません。 署名が本物かどうかをどのようにして判断するのでしょうか?

そこで考えられるのが、署名が本物かどうかをスマートコントラクトに直接_問い合わせて_みることです。

EIP-1271が行っているのは、与えられた署名が有効かどうかをスマートコントラクトに「尋ねる」アイデアを標準化です。

EIP-1271を実装するコントラクトは、メッセージと署名を受け取るisValidSignatureという名前の関数を持つ必要があります。 次にコントラクトは、いくつかの検証ロジックを実行し (仕様書では、具体的なことを何も強制していません) 、署名が有効かどうかを示す値を返します。

isValidSignatureが有効な結果を返した場合、それはコントラクトが「はい、この署名とメッセージを承認します!」と言っているのとほぼ同じです。

インターフェース

以下がEIP-1271仕様の正確なインターフェイスです(_hashパラメータについては後述しますが、ここでは検証対象のメッセージだと考えてください):

1pragma solidity ^0.5.0;
2
3contract ERC1271 {
4
5 // bytes4(keccak256("isValidSignature(bytes32,bytes)")
6 bytes4 constant internal MAGICVALUE = 0x1626ba7e;
7
8 /**
9 * @dev 提供されたハッシュに対して、提供された署名が有効かどうかを返すべきです
10 * @param _hash 署名されるデータのハッシュ
11 * @param _signature _hashに関連付けられた署名バイト配列
12 *
13 * 関数が成功した場合、bytes4のマジック値0x1626ba7eを返さなければなりません(MUST)。
14 * 状態を変更してはいけません(MUST NOT)。(solc < 0.5の場合はSTATICCALLを使用、solc > 0.5の場合はview修飾子を使用)
15 * 外部呼び出しを許可しなければなりません(MUST)。
16 */
17 function isValidSignature(
18 bytes32 _hash,
19 bytes memory _signature)
20 public
21 view
22 returns (bytes4 magicValue);
23}
すべて表示

EIP-1271実装の例: Safe

コントラクトはさまざまな方法でisValidSignatureを実装できます。仕様では、正確な実装についてはあまり言及されていません。

EIP-1271を実装した有名なコントラクトの1つにSafe (旧Gnosis Safe) があります。

Safeのコードでは、isValidSignatureは、署名が2つの方法 (opens in a new tab)で作成・検証できるように実装 (opens in a new tab)されています:

  1. オンチェーンメッセージ
    1. 作成: Safeの所有者は、メッセージに「署名」するための新しいSafeのトランザクションを作成し、メッセージをデータとしてトランザクションに渡します。 十分な数の所有者がトランザクションに署名してマルチシグのしきい値に達すると、トランザクションがブロードキャストされて実行されます。 トランザクションには、メッセージを「承認済み」メッセージのリストに追加する (signMessage(bytes calldata _data)) というSafe関数があります。
    2. 検証: SafeコントラクトでisValidSignatureを呼び出し、検証するメッセージをメッセージパラメータとして、署名パラメータには空の値 (opens in a new tab) (i.e.、0x) を渡します。 Safeは、署名パラメータが空であることを確認し、署名を暗号的に検証する代わりに、メッセージが「承認された」メッセージのリストに存在するかのみを確認します。
  2. オフチェーンメッセージ:
    1. 作成: Safeの所有者はオフチェーンでメッセージを作成し、マルチシグの承認しきい値を超えるのに十分な署名が集まるまで、他のSafe所有者に個別にメッセージへ署名してもらいます。
    2. 検証: isValidSignatureを呼び出します。 メッセージパラメータの中に、検証するメッセージを渡します。 署名パラメーターでは、Safe所有者各自の署名をすべて連結して、一斉に渡します。 Safeは、しきい値を満たすのに十分な署名があること、かつ各署名が有効であることをチェックします。 有効であれば、署名の検証が成功したことを示す値を返します。

_hashパラメータとは正確には何ですか? およびメッセージ全体を渡さない理由

EIP-1271インターフェイス (opens in a new tab)isValidSignature関数が、メッセージ自体ではなく_hashパラメータを受け取ることに気づいたかもしれません。 これは、任意の長さのメッセージ全体をisValidSignatureに渡す代わりに、メッセージの32バイトのハッシュ(通常はkeccak256)を渡すことを意味します。

コールデータの各バイト、すなわちスマートコントラクト関数に渡される関数パラメータデータは、16ガス(ゼロバイトの場合は4ガス)のコストがかかる (opens in a new tab)ため、メッセージが長い場合は多くのガスを節約できます。

以前のEIP-1271仕様

実際には、最初のパラメータがbytes型(固定長のbytes32ではなく任意長)で、パラメータ名がmessageであるisValidSignature関数を持つEIP-1271仕様が存在します。 これは、EIP-1271標準の古いバージョン (opens in a new tab)です。

EIP-1271を各自のコントラクトにどのように実装すべきか

実装は自由にできる仕様になっています。 Safeの実装には、次のいくつかの優れたアイデアがあります。

  • コントラクト「所有者」からのEOA署名を有効とみなせる
  • 承認されたメッセージのリストを保存し、それらのメッセージのみを有効であるとみなせる

最後に、実装はスマートコントラクトデベロッパーであるあなた次第です!

まとめ

EIP-1271 (opens in a new tab)は、スマートコントラクトが署名を検証できるようにする汎用性の高い標準です。 EIP-1271により、スマートコントラクトをEOAのように動作させることができます。例えば、「イーサリアムでログイン」をスマートコントラクトで動作させる方法を提供できます。また、さまざまな方法で実装できます (考慮するのに興味深い重要な実装としてSafeがあります) 。

最終更新: 2026年1月16日

このチュートリアルは役に立ちましたか?