AA(Account Abstraction)における署名集約技術の活用

2022/12/22に公開約13,400字

SIVIRA Inc. 執行役員兼エンジニアの m0t0k1ch1 です。Ethereum Advent Calendar 2022 の 23 日目の記事として、本記事を書かせていただきます。

はじめに

こちらの記事 を執筆した約 1 年前は、"AA" と言って意味が通じる人はまだ少なかったように思いますが、Devcon 6 が開催された今年 10 月頃からじわじわとその認知は加速を始め、先日開催された ETHIndia において日本のチームが実装したコントラクトウォレットが Ethereum Foundation からトッププライズを受賞したことをきっかけに、国内における認知度の向上にも拍車がかかってきたように思います。そんなこんなを経て、"AA" は、Ethereum に興味のある人の多くが一度は聴いたことがある・目にしたことがある言葉になってきたように思います。

...とは言え、AA への長い道のりはまだ始まったばかりです。どのように普及が進むのかを想像することもまだ難しい段階だと思います。

実際、AA を実現するための規格である ERC4337 は、今年に入ってからも何度かアップデートされており、その提案から 1 年以上経過した今もなおステータスは Draft のままです。また、ERC4337 のコアとなるコントラクト群の実装現時点における最新バージョンの仕様書 よりも先に進んでいるように見える、つまり、まだ仕様書に落ちてきていない変更があるように見えるため、来年も仕様書のアップデートは続くことでしょう。

ゆえに、自分含め、AA という大きなゲームチェンジに取り組むプレイヤーは、しっかりと腰を据えて、引き続き最新の動向をキャッチアップしながら、AA に至る道のりやその先にある世界の解像度を高めていく必要があると思われます。

そこで本記事では、AA 関連の開発に取り組んでいる・取り組もうとしている技術者の方々に向けて、今年 ERC4337 に入ったアップデートの中でも特に重要だと考えられる 集約署名のサポート について解説していきたいと思います。

なお、本記事は ERC4337 の技術仕様に対する理解を前提として話を進めます。ERC4337 自体についての詳細な解説は行いませんので、そもそも ERC4337 がよく分からないという方は、冒頭にも記載した以下の記事を一読いただいてから本記事に戻ってきていただくのがよいかと思います。

https://zenn.dev/sivira/articles/d041f1ac44ca1e

1. 署名集約技術とは

詳細な理論は省略しますが、以下のようなことを実現するための技術と言えます。

  • 複数の電子署名を集約して、できるだけデータサイズの小さい電子署名(集約署名)をつくる
  • 集約署名の検証によって、集約された署名全ての検証を完了させる
    • この検証は、集約された署名全てを 1 つ 1 つ検証していくよりも高効率となる

オンチェーンで課題になりがちなデータ格納コストと検証処理コストの双方を大きく低減するポテンシャルを秘めているということであれば、今後、AA に限らずブロックチェーン領域で広く活用されていく可能性が高い技術の 1 つとなりそうです。

実際、Ethereum のコンセンサスレイヤー(旧称 Eth2)では、既に BLS 署名 をベースとした署名集約技術の活用が始まっているようです。コンセンサスレイヤーにおける主要クライアントの 1 つである Prysm のドキュメント には以下のような記載があります。

As mentioned, Ethereum uses the BLS signature scheme to facilitate secure cryptography within the protocol. This method allows validators to sign messages, and these resulting signatures are then aggregated and verified at scale. This enables a full Proof-of-Stake system with a massive number of validators to function efficiently in production.

2. 署名集約技術を導入する理由

ERC4337 のような "プロトコルレイヤーの改修を必要としない AA" においては、コントラクトレイヤーで user operation の検証を行うことになるため、従来のトランザクション処理と比べると、

  • user operation の検証に必要なデータ(電子署名など)を calldata 領域に格納するために要する gas
  • user operation の検証に要する gas

が余分にかかることになります。

つまり、user operation 処理は、従来のトランザクション処理よりも gas コストが高いという課題を抱えているわけです。当然、この gas コストはユーザーの負担増につながるため、AA 普及の足枷となってしまいます。

署名集約技術は、この gas コストを低減するために導入されました。

ERC-4337 Progress report #1 では、この導入によって期待される効果が以下のように表現されています。

Signature aggregation promises a great savings in both calldata and, eventually, execution gas, and going from “Account Abstraction gives you more flexibility but costs a little bit more gas” to “Account Abstraction gives you more flexibility AND saves you gas” will help us eventually overtake the EOAs.

最終的に従来のトランザクション処理よりも gas コストを低く抑えられる可能性があるというのは非常に魅力的です。機能面だけでなくコスト面でも EOA を上回ることができれば、ERC4337 アカウントの普及も進みやすくなりそうです。

3. 署名集約技術の活用

(ERC4337 の技術仕様を理解している方であれば、ここまでの話から概ね察しがつくと思いますが)ERC4337 では、署名集約技術を以下のように活用しようとしています。

  • 各 user operation に含まれる電子署名を集約し、そのデータサイズを小さくする(bundle transaction が使用する calldata 領域を小さくする)
  • 集約署名の検証によって複数の user operation の検証をまとめて完了させることで、その処理コストを低減する

もちろん、これらは user operation 処理に要する gas コストの低減に直結します。

データサイズの削減に関しては、以下の Vitalik ツイートに添付されている図を見るとイメージしやすいかもしれません。

この図を見ると、ERC-4337 with aggregation において、signature のサイズがかなり小さくなっていることが分かります。

なお、集約署名を活用する場合、各 user operation に signature は付随しませんが、上図では、他のケースと比較しやすくするために集約署名のサイズを 1 バッチに含まれるだろう user operation の数で等分して付随させているようです。1 バッチあたりの user operation 数については、図の右下にある注意書きを参照してください(ここで 16 というコンサバな数を仮定するあたり、Vitalik らしいなと思います)。

3-1. コントラクト仕様

署名集約技術がどのように活用されているかをより具体的に把握するため、関連するコントラクト群の仕様を確認していきたいと思います。

まずは、集約署名のサポートにあたって新しく追加された Aggregator コントラクトです。

このコントラクトは、集約署名の作成・検証 という重要な役割を担います。言葉で説明するよりもインターフェースを見た方が話が早いと思うので、まずはそちらをご覧ください。

interface IAggregator {
    function aggregateSignatures(
        UserOperation[] calldata userOps
    ) external view returns (bytes memory aggregatesSignature);

    function validateSignatures(
        UserOperation[] calldata userOps,
	bytes calldata signature
    ) external view;

    function validateUserOpSignature(
        UserOperation calldata userOp
    ) external view returns (bytes memory sigForUserOp);
}
  • aggregateSignaturesuserOps の要素である各 UserOperation に含まれる署名から集約署名を作成する
  • validateSignaturessignature(集約署名)の正当性を検証する
  • validateUserOpSignatureuserOp.signature の検証を行った上で、validateSignatures の実行に必要なデータ(sigForUserOp)があればそれを返す
    • 返り値である sigForUserOp は空となることが多いが、特定のマルチシグを活用する場合などはその検証に必要なデータを sigForUserOp として返す必要がある、とのこと

役割をほぼそのまま体現したような分かりやすいインターフェースですね。

次は EntryPoint コントラクトです。こちらは全て記載すると冗長になってしまうので、今回重要となるインターフェースのみをピックアップします。

struct UserOpsPerAggregator {
    UserOperation[] userOps;
    IAggregator aggregator;
    bytes signature;
}
function handleOps(
    UserOperation[] calldata ops,
    address payable beneficiary
) external;

function handleAggregatedOps(
    UserOpsPerAggregator[] calldata opsPerAggregator,
    address payable beneficiary
) external;

function simulateValidation(
    UserOperation calldata userOp
) external;

当初は存在していなかった handleAggregatedOps という関数が追加されています。これはその名の通り、"集約署名をサポートした handleOps" です。

なお、handleAggregatedOps の引数である opsPerAggregator は、aggregator ごとに UserOperation と集約署名をまとめた構造体 UserOpsPerAggregator の配列です。つまり、handleAggregatedOps は、引数として渡された UserOpsPerAggregator の数だけ集約署名の検証を行うことになります。この検証には、先ほど紹介した aggregator.validateSignatures が利用されます。

simulateValidation は以前から存在していましたが、少し特殊な関数なので改めて言及しておこうと思います。まずはソースコードに記載されている以下コメントを一読してみてください。

/**
 * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
 * @dev this method always revert. Successful result is SimulationResult error. other errors are failures.
 * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
 * @param userOp the user operation to validate.
 */

"this method always revert." という記載の通り、この関数は必ず revert します。つまり、オンチェーンで実行されることを想定していません。simulateValidation は、bundler が UserOperation を bundle する前にオフチェーンで実行するシミュレーション用の関数なので、このような仕様となっています。

なお、必ず revert するので、シミュレーションに成功した場合であっても、その結果は以下のようなエラーを介して渡されます。

error SimulationResult(
    uint256 preOpGas,
    uint256 prefund,
    uint256 deadline,
    StakeInfo senderInfo,
    StakeInfo factoryInfo,
    StakeInfo paymasterInfo
);

error SimulationResultWithAggregation(
    uint256 preOpGas,
    uint256 prefund,
    uint256 deadline,
    StakeInfo senderInfo,
    StakeInfo factoryInfo,
    StakeInfo paymasterInfo,
    AggregatorStakeInfo aggregatorInfo
);

最後は Account コントラクトです。これは元々 Wallet という名前だったのですが、今年の 11 月末頃に改名された ようです。

interface IAccount {
    function validateUserOp(
        UserOperation calldata userOp,
	bytes32 userOpHash,
	address aggregator,
	uint256 missingAccountFunds
    ) external returns (uint256 deadline);
}

interface IAggregatedAccount is IAccount {
    function getAggregator() external view returns (address);
}

見ての通り、validateUserOp の引数に aggregator が追加されています。

集約署名をサポートしない account は、この aggregator を無視して、従来通り、msg.senderuserOp.signature の検証や missingAccountFunds の送付を行う必要があります。

一方、集約署名をサポートする account は、同様に msg.sender の検証や missingAccountFunds の送付を行う必要はありますが、entry point が集約署名を検証してくれるため、userOp.signature の検証を行う必要はありません。その代わり、aggregator が自身に生えている getAggregator の返り値と一致するかどうかを検証する必要があります。

3-2. 処理フロー

以上のようなインターフェースを実装したコントラクト群の存在を前提として、実際の大まかな処理フローを整理してみます。これを見れば、署名集約技術がどのように活用されているかをより具体的にイメージできるようになるはずです。

3-2-1. 集約署名を使用しない従来のパターン

  • STEP1:bundler は、受け取った UserOperation に対して、(オフチェーンで)いくつかの検証を行う
    • entryPoint.simulateValidation が実行される(この中で、account.validateUserOpaggregator.validateUserOpSignature などが実行される)
  • STEP2:bundler は、検証を通過した UserOperation をまとめて bundle transaction を作成し、ブロックチェーンネットワークに対して送信する
  • STEP3:bundle transaction によって、entryPoint.handleOps が実行される
    • verification loop が実行される
      • UserOperation に対して account.validateUserOp が実行される
    • execution loop が実行される
      • UserOperationcallData を用いて、その sender である account に対してコールが行われる

3-2-2. 集約署名を使用する新しいパターン

(集約署名を使用しないパターンとの差分を 太字 で記載します)

  • STEP1:bundler は、受け取った UserOperation に対して、(オフチェーンで)いくつかの検証を行う
    • entryPoint.simulateValidation が実行される(この中で、account.validateUserOpaggregator.validateUserOpSignature などが実行される)
  • STEP2:bundler は、検証を通過した UserOperation をまとめて bundle transaction を作成し、ブロックチェーンネットワークに対して送信する
    • UserOperation はその sender に指定された account の account.getAggregator の返り値に従って aggregator ごとにまとめられ、そのまとまりに対して集約署名の作成が行われる(集約署名の作成にあたり、bundler は aggregator.aggregateSignatures を利用してもよい)
    • 上記処理の結果は UserOpsPerAggregator の配列としてまとめられる
  • STEP3:bundle transaction によって、entryPoint.handleAggregatedOps が実行される
    • verification loop が実行される
      • UserOperation に対して account.validateUserOp が実行される(が、ここで電子署名の検証は行われない
      • UserOpsPerAggregator に対して aggregator.validateSignatures が実行される
    • execution loop が実行される
      • UserOperationcallData を用いて、その sender である account に対してコールが行われる

見ての通りですが、集約署名を使用しないパターンとの大きな違いは以下となります。

  • UserOperation に含まれる電子署名は bundler(と aggregator)によって集約され、集約署名として entry point に渡されている
    • これにより、使用する calldata 領域を小さくすることができる
  • verification loop において、各 UserOperation に含まれる署名を検証する代わりに、集約署名の検証(aggregator.validateSignatures)が行われている
    • これにより、検証処理コストを低減することができる

4. 署名集約技術導入の効果

2. 署名集約技術を導入する理由 の項では、従来のトランザクション処理よりも gas コストを低減できる可能性を示唆しましたが、残念ながらその実現はまだ遠そうです。

実際、ERC-4337 Progress report #1 には、BLS 署名ベースの集約署名について以下のような注意書きがあります。

Note 2: Currently, the gas cost of verifying an aggregated BLS signature on-chain on the Ethereum mainnet is still higher than the cost of having individual ecrecover for each UserOp. It may never be worth doing on the Mainnet or maybe will require some new precompiles to be financially viable.

有意な効果を得るためには、より高効率な署名集約技術の導入や、集約署名の検証をサポートする precompiled contract の追加などが必要そうです。

また、そもそも論になってしまいますが、user operation 処理に要する総 gas に対して、calldata 領域の使用や電子署名の検証に要する gas が支配的かと言われるとそうではないように思います。よって、user operation の gas コスト削減は、"木を見て森を見ず" にならないよう注意しながら進める必要もありそうです。とは言え、こういう舵取りは Vitalik の得意分野だと思うので、自分ごときが心配する必要はないでしょう。

まとめ

  • ERC4337 は、その提案から 1 年以上経過した今もなおステータスは Draft のままであり、継続的にアップデートが実施されている
  • ERC4337 は、user operation 処理の gas コスト低減を目的として集約署名をサポートした
    • 集約署名のサポートにより、従来のトランザクション処理よりも gas コストを低減できる可能性はあるが、その実現はまだ遠いと考えられる
    • 有意な gas コスト低減効果を得るためには、高効率な署名集約技術の導入やプロトコルレイヤーの改修(集約署名の検証をサポートする precompiled contract の追加など)が必要となるだろう

一緒に AA に取り組みませんか?

Vitalik の描く AA ロードマップ の中には、

  • There should be easy-to-use browser wallets that use ERC-4337 wallets.

という項目があります。

弊社は、まさにこんなウォレットを 1 つの目標として、2 年以上前から unWallet というウォレットの開発に取り組んでいます("un" という接頭辞には、"既存ウォレットの常識にとらわれたくない" という想いが込められています)。

unWallet は、端的に言うと、ブラウザ経由で操作できるセルフカストディアルなコントラクトウォレットです。実は既に実用化されており、水面下では、MetaMask 未保有者への NFT 配布などと併せて提供を開始しています。また、本記事執筆時点では、約 3,000 のユーザーを抱えています。

今、私 m0t0k1ch1 は、そんな unWallet をさらに進化させていく仲間を探しています。

記事を読んで AA やコントラクトウォレットについて興味が湧いたエンジニアの方、本記事にマサカリを投げられるような見識をお持ちの方、ぜひ一度軽くお話しませんか?

自分の Twitter アカウント(↓)にて、DM お待ちしています。

https://twitter.com/m0t0k1ch1

参照

Discussion

ログインするとコメントできます