# [ERC8092] 複数のアカウントの関係を確認できるようにする仕組み

> 主アカウントと、ゲーム専用のアカウントを使い分ける場面を考えます。ゲーム側が2つのアドレスを見ても、同じ利用者が管理しているとは判断できません。

- URL: https://cardene.dev/articles/7976def5a388ac0f1574
- 公開日: 2026-10-18
- 更新日: 2026-10-18
- トピック: Blockchain
- タグ: ethereum, erc, web3, solidity

## はじめに

初めまして。
『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

LLMを使った仕様駆動開発を扱う書籍『LLMと進める仕様駆動開発』を発売予定です。
ハンズオンや、LLMによって開発がどう変わるのか、実践のTipsをまとめています。

https://www.amazon.co.jp/exec/obidos/ASIN/4863545231/honmori-22

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

用途やチェーンごとにアカウントを分けると、第三者は2つのアカウントが同じ利用者のものか、委任先か、無関係なのかをアドレスだけでは判断できません。
ERC8092は、2つのアカウントが認めた関係を共通の形式で記録し、利用するアプリが有効期間、署名、取り消しを確認できるようにします。

## 概要

主アカウントと、ゲーム専用のアカウントを使い分ける場面を考えます。
ゲーム側が2つのアドレスを見ても、同じ利用者が管理しているとは判断できません。
アドレスの一致だけを条件にすると、主アカウントの実績をゲーム用アカウントへ引き継げず、見た目が似た別人のアカウントを誤って結び付ける可能性もあります。

ERC8092では、関係を示したい二者が、対象となる2つのアカウント、利用できる期間、用途ごとの補足情報を1つの記録へまとめます。
二者は同じ内容へ署名でき、利用するアプリは、記録を受け取った時点で期限と取り消し状態を調べ、入力されている署名を確認します。
この記録を、アカウント同士の関連付けを示す記録として扱います。

署名が正しければ、署名した当事者が記録の内容を認めたことを確認できます。
一方、ゲーム用アカウントへ主アカウントと同じ権限を与えてよいか、実績をどこまで引き継ぐかは、利用するアプリが決めます。
ERC8092が共通化するのは、関係の内容、署名、有効期間、取り消しを受け渡して検証する形式です。

#### 二者の合意

関係の記録には、作成を始める側と、内容を承認する側が入ります。
主アカウントを承認側、ゲーム用アカウントを開始側にすると、どの2つを結ぶか、いつまで有効か、何の用途で使うかを同じ内容で確認できます。

両者が署名する運用では、片方だけが勝手に作った関係を、双方が認めた関係として扱うことを防げます。
信頼できる管理者が関係を登録する用途では、利用側の方針に応じて片方または両方の署名欄を空にすることもできます。

![ERC8092で二者が関係の記録を作り利用側が確認する流れ](/images/qiita-a8181a38-06c9-46f8-8d2b-24bf68323e9d.webp)

#### 利用側の確認

利用側は、記録が見つかったことだけを理由に関係を採用しません。
利用開始時刻を過ぎているか、期限や取り消し時刻へ達していないかを確認し、署名欄に値がある場合は指定された方式で署名を検証します。

両者の署名を必須にするかは利用側が決めます。
第三者を信頼せずに関係を確認する用途では、両者の署名を求めます。
管理されたサービス内で使う場合は、誰が保存先を運用し、誰が関係を登録できるかも判断材料になります。

## 動機

1人の利用者が1つのアドレスだけを使うとは限りません。
資産を保管するアカウント、日常操作に使うアカウント、特定のアプリだけで使うアカウントを分ければ、秘密鍵の露出や権限の範囲を抑えられます。
複数チェーンを使う場合は、アドレスの表現や署名方式も異なります。

一方、関係を示す形式がアプリごとに異なると、利用側は独自の項目、署名方法、取り消し方法を個別に実装します。
片方のサービスで作った関係を別のサービスへ持ち込めず、失効済みの関係を有効と判断する実装差も生まれます。

ERC8092は、関係の内容と署名を分けたデータ形式、検証順、保存先が満たす条件、取り消し方法を定めます。
関係が本人の別アカウント、操作の委任先、組織内の子アカウントのどれを意味するかは固定しません。
用途ごとの意味と、確認後に許可する操作は利用側が定義します。

#### 複数アカウント

アカウントを分けたまま、必要な場面だけ関係を公開できます。
ゲーム用アカウントへ資産管理の権限を渡さず、主アカウントとの関係だけを示す構成も選べます。

ただし、関係を公開すると、別々に使っていたアドレスを同じ主体の候補として追跡しやすくなります。
利用者は、引き継ぐ情報と公開による影響を比べて、用途ごとに関係を作ります。

#### 共通形式

共通形式があると、利用側は同じ順序で期間、取り消し、署名を確認できます。
保存先がオンチェーンでもオフチェーンでも、受け取った記録の各項目と検証条件は変わりません。

共通形式は、関係の意味まで統一しません。
同じ補足データを別の用途へ読み替えないように、利用側は対応する用途と形式を明示します。

## 仕様

ERC8092は、2つの構造体を使います。
内側の構造体は二者が合意する内容を固定し、外側の構造体は署名方式、署名、取り消し時刻を追加します。

### `AssociatedAccountRecord`

二者が何について合意するかを保持する内側の記録が `AssociatedAccountRecord` です。
以降ではAARと表記します。
開始側と承認側のアカウント、有効期間、用途を判別する4バイトの値、用途ごとの補足データをまとめます。

```js
struct AssociatedAccountRecord {
    bytes initiator;
    bytes approver;
    uint40 validAt;
    uint40 validUntil;
    bytes4 interfaceId;
    bytes data;
}
```

署名欄へ値を入れる当事者は、AARの内容を確認してから署名します。
署名を集めている途中で外側の項目が増えても、AARを変更しないため、二者が同じ関係へ署名したことを確認できます。

![ERC8092のAssociatedAccountRecordが保持する項目](/images/qiita-500e4625-cc14-48e9-bf7f-fc99aa9d069e.webp)

#### フィールド

| フィールド | 型 | 内容 |
| --- | --- | --- |
| `initiator` | `bytes` | 関係の作成を始めたアカウント |
| `approver` | `bytes` | 関係を承認するアカウント |
| `validAt` | `uint40` | 関係を利用できる最初の時刻 |
| `validUntil` | `uint40` | 関係を利用できる期限。0なら期限を設定しない |
| `interfaceId` | `bytes4` | `data` の読み方を識別する任意の値 |
| `data` | `bytes` | 関係の用途に応じた任意の補足データ |

`initiator` と `approver` には、チェーンとアドレス形式を1つのバイト列で識別する形式を使います。
利用側は、その値から対象チェーンとアドレスを取り出し、どのアカウントの関係かを区別します。
この形式をERC7930の相互運用アドレスと呼びます。

:::message
**ERC7930**については以下の記事を参考にしてください。
:::

[\[ERC7930\] 複数チェーンのアドレスを1つの形式で扱う仕組みを理解しよう！](/articles/e280966bf2619d25d4c8)

`interfaceId` と `data` は任意です。
委任関係を表す用途では、`interfaceId` で補足データの読み方を選び、`data` に委任できる操作や対象を符号化できます。
ERC8092自体は補足データの形式を定めないため、利用側が理解できない `interfaceId` の関係は権限判定に使いません。

### `SignedAssociationRecord`

AARへ署名と取り消し情報を加えた外側の記録が `SignedAssociationRecord` です。
以降ではSARと表記します。
利用側はSARを受け取り、内側のAARを署名対象として検証します。

```js
struct SignedAssociationRecord {
    uint40 revokedAt;
    bytes2 initiatorKeyType;
    bytes2 approverKeyType;
    bytes initiatorSignature;
    bytes approverSignature;
    AssociatedAccountRecord record;
}
```

| フィールド | 型 | 内容 |
| --- | --- | --- |
| `revokedAt` | `uint40` | 関係を取り消す時刻。未設定は0 |
| `initiatorKeyType` | `bytes2` | 開始側の署名を検証する方式 |
| `approverKeyType` | `bytes2` | 承認側の署名を検証する方式 |
| `initiatorSignature` | `bytes` | 開始側の署名 |
| `approverSignature` | `bytes` | 承認側の署名 |
| `record` | `AssociatedAccountRecord` | 署名対象となるAAR |

`revokedAt` はAARの外側にあり、署名対象には含まれません。
保存先が取り消しを受け付けた後に値を更新できる反面、利用側は署名だけで取り消し状態を確定できません。
正式な保存先から最新の値を読み直します。

#### 鍵種別

署名欄に値がある場合は、対応する鍵種別IDを使って検証方法を選びます。
鍵種別IDは2バイトです。
`0x0000` のDelegatedは、別のアカウントや外部手順へ認可を委任する例外的な値です。
残りは、暗号曲線を直接示すIDと、パスキーやコントラクトを使う検証手順のIDに分かれます。
検証手順のIDは最上位ビットを立て、`0x8000 | PROTOCOL_ID` で表します。

| Key ID | 種別 | 検証方法 |
| --- | --- | --- |
| `0x0000` | Delegated | 別のアカウント、アクセス制御、外部手順へ認可を委任する |
| `0x0001` | K1 | secp256k1 |
| `0x0002` | R1 | secp256r1 |
| `0x0003` | BLS | BLS12-381 |
| `0x0004` | EdDSA | Ed25519 |
| `0x8001` | WebAuthn | WebAuthnまたはパスキー |
| `0x8002` | ERC1271 | コントラクトアカウントの署名検証 |
| `0x8003` | ERC6492 | 未デプロイのコントラクトアカウントを含む署名検証 |

Delegatedは暗号曲線の名前ではありません。
この値を使う実装は、利用側が委任内容を解析できるように、用途固有の形式を公開します。

ERC1271は、コントラクトアカウントへ署名とメッセージのハッシュを渡し、そのコントラクトが署名を認めるか確認する方法です。
利用側は返り値から、その時点のコントラクト状態で署名が有効かを判断します。

:::message
**ERC1271**については以下の記事を参考にしてください。
:::

[\[ERC1271\] コントラクトで署名を検証する仕組みを理解しよう！](/articles/da237b1b8cc185491512)

ERC6492は、まだデプロイされていないコントラクトアカウントについて、デプロイに必要な情報と署名をまとめて検証する方法です。
利用側は、アカウントが作成される前でも、そのアカウントが認める署名かを確認できます。

:::message
**ERC6492**については以下の記事を参考にしてください。
:::

[\[ERC6492\] デプロイされていないコントラクトアカウントで署名検証する仕組みを理解しよう！](/articles/019072f96b73939a047d)

### 署名の作り方

署名欄へ値を入れる当事者は、項目名と型を含む構造化データへ署名します。
利用側は、署名がどのAARに対するものかを項目単位で復元でき、別の期間や補足データを持つAARへの差し替えを検出できます。
この署名方式がEIP712です。

:::message
**EIP712**については以下の記事を参考にしてください。
:::

[\[EIP712\] 型付き構造化データのハッシュ化と署名の仕組みを理解しよう！](/articles/f54bc85cb66de5a54257)

署名対象のハッシュは以下です。
`bytes` 型の `initiator`、`approver`、`data` は、それぞれ先にハッシュ化します。

```js
keccak256(abi.encodePacked(
    hex"1901",
    DOMAIN_SEPARATOR,
    keccak256(abi.encode(
        keccak256(
            "AssociatedAccountRecord(bytes initiator,bytes approver,uint40 validAt,uint40 validUntil,bytes4 interfaceId,bytes data)"
        ),
        keccak256(initiator),
        keccak256(approver),
        validAt,
        validUntil,
        interfaceId,
        keccak256(data)
    ))
))
```

`DOMAIN_SEPARATOR` は、名前 `AssociatedAccounts` とバージョン `1` だけで作ります。
`chainId` と保存コントラクトのアドレスを含めないため、同じ署名付き記録を別のチェーンや保存先へ移せます。
署名はAARの書き換えを防ぎますが、特定チェーンだけで使えることまでは保証しません。

![ERC8092でAARの内容を署名へ結び付ける流れ](/images/qiita-e6dfa795-d80d-485d-ac56-cfcbf10a7500.webp)

### 検証

利用側は、SARを使う時点で以下の順に確認します。
オンチェーンで確認する場合の現在時刻は `block.timestamp` です。

1. 現在時刻が `validAt` 以上であることを確認します。
2. `validUntil` が0ではない場合、現在時刻が `validUntil` より前であることを確認します。
3. `revokedAt` が0ではない場合、現在時刻が `revokedAt` より前であることを確認します。
4. `initiatorSignature` に値がある場合、`initiatorKeyType` に対応する方法で開始側の署名を検証します。
5. `approverSignature` に値がある場合、`approverKeyType` に対応する方法で承認側の署名を検証します。

署名欄が空なら、その署名の検証手順は実行しません。
そのため、署名が2つとも必須だと規格が一律に定めているわけではありません。
第三者を信頼しない場面では、利用側が両者の署名を必須条件にします。

![ERC8092の有効期間と取り消しと署名を確認する順序](/images/qiita-241b31a4-e1a5-46e0-9a6a-4e31671327ff.webp)

期限へ達した記録、すでに取り消し時刻へ達した記録、値が入っている署名の検証に失敗した記録は利用しません。
対応できない鍵種別を受け取った時も、検証を省略して採用せず、未対応として止めます。

### 保存

SARは、用途固有のコントラクトまたはオフチェーンのサービスへ保存できます。
保存場所を選べても、受信時の検証と、当事者が取り消せることは共通の条件です。

![ERC8092のオンチェーン保存とオフチェーン保存の責務](/images/qiita-c0d35f36-0d2e-43c2-a42a-e21472156730.webp)

オンチェーンの保存コントラクトはSARを検証してから、以下のイベントを発行します。

```js
event AssociationCreated(
    bytes32 indexed hash,
    bytes32 indexed initiator,
    bytes32 indexed approver,
    SignedAssociationRecord sar
);
```

| 項目 | 内容 |
| --- | --- |
| `hash` | AARのEIP712ハッシュ |
| `initiator` | ERC7930形式の開始側アカウントを `keccak256` した値 |
| `approver` | ERC7930形式の承認側アカウントを `keccak256` した値 |
| `sar` | 保存した署名付き記録 |

オンチェーンに保存する実装は、同じ場所で取り消せるようにします。
`AssociationCreated` イベントは検索に使えますが、イベントログだけを見て現在も有効だと判断せず、保存されている取り消し時刻を確認します。

オフチェーンの保存先は、想定する利用者がアクセスできる公開エンドポイントを用意し、受け取った関係を検証してから保存します。
利用側が保存先を見つけられるように、ENSのtextレコードのような標準的な取得方法で場所を公開します。

| 条件 | オンチェーン | オフチェーン |
| --- | --- | --- |
| 受信時の検証 | 保存コントラクトが実行する | 保存サービスが実行する |
| 取得方法 | コントラクトの状態とイベントログ | 公開エンドポイント |
| 取り消し | 当事者がコントラクトへ要求する | 当事者が保存サービスへ要求する |
| 主な負担 | ガス代と対応できる検証方式 | 運営者の可用性と信頼 |

### 取り消し

開始側と承認側のどちらも、有効な関係を取り消せます。
オンチェーンの保存コントラクトは、要求を受け付けたブロックの時刻と、当事者が指定した取り消し時刻を比べ、大きい方を `revokedAt` に設定します。
未来の時刻を指定すれば、その時刻まで関係を利用できる予約付きの取り消しになります。

```js
event AssociationRevoked(
    bytes32 indexed hash,
    bytes32 indexed revokedBy,
    uint256 revokedAt
);
```

| 項目 | 内容 |
| --- | --- |
| `hash` | 取り消すAARのEIP712ハッシュ |
| `revokedBy` | 取り消したアカウントを `keccak256` した値 |
| `revokedAt` | 関係が無効になる時刻 |

すでに取り消した関係に対して、別の当事者がより早い取り消し時刻を指定した場合は、早い方を優先します。
承認側が翌日を指定した後、開始側が現在時刻で取り消すと、関係は現在時刻から無効になります。
オフチェーンの保存先も両当事者からの取り消しを受け付け、`revokedAt` を更新します。

## 補足

AARとSARを分けることで、二者が確認する内容を変えずに、署名を別々の時刻に集められます。
保存先は用途に合わせて選べますが、利用側がどの情報を正しい取り消し状態として扱うかを決めておかないと、同じ署名付き記録から異なる判断が生まれます。

#### 保存先の優先順位

アプリは、関係ごとに正式な保存先を決めます。
同じ関係がオンチェーンとオフチェーンの両方に保存されている場合は、オンチェーンの情報を優先します。

オフチェーンの応答が `revokedAt = 0` を返しても、オンチェーンで取り消し済みなら関係を利用しません。
利用側は受け取ったSARだけで判断せず、正式な保存先から最新の状態を取得します。

#### 関係データの意味

`interfaceId` と `data` は、委任、親子関係、本人確認の結果といった用途固有の情報を運べます。
ERC8092は、これらの情報が事実であることや、補足データから特定の権限を与えてよいことまでは保証しません。

利用側は、対応する `interfaceId` と `data` の形式を定義し、読み取った値をどの判定へ使うか決めます。
理解できない形式や、用途が一致しない記録は採用しません。

## 互換性

ERC8092の公式仕様には、既存規格との互換性を説明する独立した節はありません。
ここでは、仕様のデータ形式と依存規格から、既存アプリへ追加する時の関係を整理します。

#### 追加方式

ERC8092は、既存アカウントのアドレスや署名方式を置き換えません。
関係を利用したいアプリがSARの取得と検証を追加し、対応しないアプリは関係記録を使わずに動作できます。

同じSARを複数のアプリで読めても、許可する操作まで同じになるとは限りません。
各アプリは、関係データの意味、必須とする署名、正式な保存先を個別に決めます。

#### 依存規格

ERC8092は、4つの既存規格を利用します。
EIP712はAARの各項目を署名対象へ固定し、ERC7930は異なるチェーンやアドレス形式のアカウントを区別します。
ERC1271とERC6492は、秘密鍵を直接持つ通常のアカウントとは異なるコントラクトアカウントの署名を確認する時に使います。

実装は、必要な鍵種別だけを対応対象にできます。
ただし、対応していない鍵種別を含むSARは、有効な関係として扱えません。

## セキュリティ

署名が正しくても、関係データが表す事実や、関係を使って許可する操作の安全性までは証明されません。
利用側は、署名の正しさ、取り消し状態、保存先への信頼、公開による影響を分けて確認します。

#### 署名の検証

鍵種別によっては、オンチェーンでの検証に多くのガスを使うか、対応する検証方法を用意できません。
利用側は対応する鍵種別を明示し、未対応の値を受け取った時は関係を採用しません。

Delegatedを使う場合は、公開された委任形式を解析し、誰が誰へ、どの操作を、いつまで認めたかを確認します。
ERC1271の検証結果はコントラクトの現在の状態に依存します。
ERC6492は未デプロイのアカウントを検証する処理を含むため、検証時に実行するコードとガス使用量も制限します。

#### 取り消し情報

`revokedAt` は署名対象のAARに含まれません。
第三者が古い `revokedAt = 0` のSARを渡しても、AARへの署名自体は有効なままです。

利用側は、取り消し状態を正式な保存先から読み直します。
キャッシュを使う場合も、権限付与や資産操作の前には更新時刻を確認し、古い状態を使う範囲を制限します。
開始側と承認側のどちらが取り消した場合も、利用側はアプリが定めた正式な保存先から同じSARの `revokedAt` を読みます。
予約付きの取り消しがある場合は、現在時刻が指定時刻へ達したかも毎回確認します。

#### 保存先の信頼

オフチェーンの保存先は、記録を返さない、更新を遅らせる、古い取り消し状態を返す可能性があります。
署名検証はAARの改ざんを検出できますが、保存先が最新の記録を返したことまでは証明しません。

高い信頼性を求める関係は、取り消し状態の一部をオンチェーンへ記録する方法も選べます。
同じ関係が両方にある場合は、オンチェーンの状態を優先します。
公開エンドポイントを複数用意しても、同じ正本から同期していることを確認できなければ、応答数だけで正しさは決まりません。
アプリは保存先の場所、更新手順、停止時に関係を拒否する条件を利用者へ示します。

#### 公開範囲

関係を公開すると、別々の用途で使っていたアカウントを同じ主体の候補として結び付けられます。
オンチェーンで取り消しても、作成時のイベントログとトランザクション履歴は残ります。

利用者は、公開してよい2つのアカウントと補足データだけを記録します。
一時的な関係や公開範囲を抑えたい関係では、有効期限とオフチェーン保存も含めて選びます。
補足データへ氏名や連絡先を直接入れると、署名と無関係に第三者が読み取れます。
用途を示す最小限の値へ絞り、公開前に2つのアカウントを結び付ける影響を利用者へ説明します。

## 最後に

ERC8092は、2つのアカウントの関係を、合意する内容、署名、有効期間、取り消しとして同じ形式で扱えるようにします。
利用側は署名だけで関係を採用せず、正式な保存先から期限と取り消し状態を確認し、用途に合う関係だけを使います。

他でも色々記事を書いているのでぜひよろしければ読んでいってください！

https://amzn.asia/d/gxvJ0Pw

LLMを使った仕様駆動開発を扱う書籍『LLMと進める仕様駆動開発』を発売予定です。
ハンズオンや、LLMによって開発がどう変わるのか、実践のTipsをまとめています。

https://www.amazon.co.jp/exec/obidos/ASIN/4863545231/honmori-22

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/

この記事で解説したデータ形式と検証条件の原文は、以下の公式仕様を参照してください。

https://eips.ethereum.org/EIPS/eip-8092
