# [ERC1056] 分散型IDレジストリの仕組みを理解しよう！

> ERC1056は、Ethereumブロックチェーン上で軽量なID（アイデンティティ）を管理するためのレジストリの標準仕様を定義したものです。

- URL: https://cardene.dev/articles/8c69b3f439b70cb3cb4d
- 公開日: 2025-07-31
- 更新日: 2025-07-31
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、EthereumアカウントなどのIDにdelegatorや属性を追加し、IDを効率よく管理・拡張できる仕組みを提案している**ERC1056**についてまとめていきます！

:::message
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

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

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

**ERC1056**は、Ethereumブロックチェーン上で軽量なID（アイデンティティ）を管理するためのレジストリの標準仕様を定義したものです。
IDごとに複数の属性や代理人（delegate）を紐づけることができる仕組みを提供し、効率的なリソース利用を実現しています。

アイデンティティの作成には特別なガスコストは不要で、すでに存在するEthereumアカウント（公開鍵）をそのままIDとして利用できます。
つまり、Ethereumに存在するすべてのアドレスは、この仕組みにおける有効なIDとして扱えます。

また、この標準はDID（Decentralized Identifier）仕様に準拠しており、既存の分散IDフレームワークとの互換性も確保されています。

## 動機

**ERC1056**は、uPortプロジェクトにおける複数年にわたるIDシステム開発の経験を背景にしています。
従来のID管理標準である**ERC725**には、ID作成時にスマートコントラクトのデプロイが必要であり、そのため高額なガスコストがかかるという問題がありました。

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

[\[ERC725\] 実行とデータ管理を分離したコントラクトの仕組みを理解しよう！](/articles/28d8d603ccf5e9384174)

この問題を解決するために、本提案では以下の設計方針が掲げられています。

* IDの作成は無料であるべき
* オフライン環境（例：難民キャンプなど）でも利用できること
* プライマリID（アドレス）を変えずに、鍵のローテーション（変更）ができること
* オンチェーンだけでなく、オフチェーンでも使える柔軟な設計であること

このような要件を満たすことで、ブロックチェーンを用いたアイデンティティ管理を、より多くの人々やユースケースに対応可能な仕組みにしようとしています。
特に、限られた通信環境やコスト制限のある状況でも導入できる点に重点が置かれています。

## 仕様

### イベント

#### `DIDOwnerChanged`

```javascript
event DIDOwnerChanged(
  address indexed identity,
  address owner,
  uint previousChange
);
```

所有者が変更された時に発行されるイベント。
`changeOwner` または `changeOwnerSigned` の呼び出しによって、あるIDの所有者が更新された場合に発行されるイベントです。
変更前の状態を示すタイムスタンプも含まれます。

**パラメータ**

* `identity`
    * 所有者が変更された対象のIDアドレス。
* `owner`
    * 新しく設定された所有者のアドレス。
* `previousChange`
    * この変更より前に起きた最後の変更のブロックタイムスタンプ。

#### `DIDDelegateChanged`

```javascript
event DIDDelegateChanged(
  address indexed identity,
  bytes32 delegateType,
  address delegate,
  uint validTo,
  uint previousChange
);
```

delegate（代理人）の追加・削除が行われた時に発行されるイベント。
IDに対して新しいdelegateが追加されたり、既存のdelegateが削除された際に発行されるイベントです。
delegateの有効期限と、直前の変更情報が含まれます。

**パラメータ**

* `identity`
    * delegateの変更が行われたID。
* `delegateType`
    * delegateの種類を表す識別子（例: did-jwt, raidenなど）。
* `delegate`
    * 追加・削除されたdelegateのアドレス。
* `validTo`
    * delegateの有効期限（UNIXタイムスタンプ）。
* `previousChange`
    * 以前の変更が発生したブロックのタイムスタンプ。

#### `DIDAttributeChanged`

```javascript
event DIDAttributeChanged(
  address indexed identity,
  bytes32 name,
  bytes value,
  uint validTo,
  uint previousChange
);
```

属性（attribute）の追加・削除が行われた時に発行されるイベント。
IDに関連付けられている属性（例: 公開鍵やサービス情報など）が追加・更新・削除された際に発行されるイベントです。

**パラメータ**

* `identity`
    * 属性の変更が行われたID。
* `name`
    * 変更された属性の名前（ラベル）。
* `value`
    * 属性の値（バイナリ形式）。
* `validTo`
    * 属性の有効期限（UNIXタイムスタンプ）。
* `previousChange`
    * この変更より前の最後の変更タイムスタンプ。

### 関数

#### `identityOwner`

```javascript
function identityOwner(address identity) public view returns(address);
```

IDの所有者アドレスを取得する関数。
指定されたIDアドレスに対応する現在の所有者（コントローラー）のアドレスを返します。
デフォルトではID自身が所有者となりますが、`changeOwner` 関数で別のアドレスへ変更することも可能です。

**引数**

* `identity`
    * 所有者を取得したいIDアドレス。

**戻り値**

* `address`
    * IDに紐づく所有者のアドレス。

#### `changeOwner`

```javascript
function changeOwner(address identity, address newOwner) public;
```

IDの所有者を新しいアドレスに変更する関数。
対象のIDの所有者を、新しいEthereumアドレスへと変更します。
呼び出しには現在の所有者による操作が必要です。

**引数**

* `identity`
    * 所有者を変更したいIDのアドレス。
* `newOwner`
    * 新たに設定する所有者のアドレス。

#### `changeOwnerSigned`

```javascript
function changeOwnerSigned(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, address newOwner) public;
```

署名によってIDの所有者を変更する関数。
オフチェーンで署名されたデータに基づいて、IDの所有者を変更する関数です。
オフチェーン操作と署名検証を通じて、ガス節約や柔軟な所有権移転が可能になります。

**引数**

* `identity`
    * 所有者を変更したいID。
* `sigV`, `sigR`, `sigS`
    * 所有者による署名データ（ECDSA形式）。
* `newOwner`
    * 新しく設定する所有者アドレス。

#### `addDelegate`

```javascript
function addDelegate(
  address identity,
  bytes32 delegateType,
  address delegate,
  uint validity
) public;
```

指定したIDに対して、新しいdelegate（代理人）を登録する関数。
あるIDに対して、特定の機能を委任するdelegateを登録します。
delegateTypeにより、どのような用途で委任されたかを区別できます（例: `did-jwt` など）。
validityにはdelegateの有効期間（秒数）を指定します。
呼び出しはIDの所有者によって実行される必要があります。

**引数**

* `identity`
    * 対象となるID（Ethereumアドレス）。

* `delegateType`
    * delegateのタイプを識別する文字列（例: `did-jwt` を `bytes32` へ変換）。

* `delegate`
    * 登録するdelegateアドレス。

* `validity`
    * 登録から有効となる秒数（現在時刻からの相対値）。

#### `revokeDelegate`

```javascript
function revokeDelegate(
  address identity,
  bytes32 delegateType,
  address delegate
) public;
```

以前に登録されたdelegateを無効化する（revoke）関数。
`addDelegate`で追加されたdelegateを明示的に無効にする時に使用します。delegateはその有効期限内でも、所有者の意思により取り消しが可能です。

**引数**

* `identity`
    * 対象となるID。

* `delegateType`
    * 取り消すdelegateのタイプ。

* `delegate`
    * 取り消すdelegateのアドレス。

#### `setAttribute`

```javascript
function setAttribute(
  address identity,
  bytes32 name,
  bytes memory value,
  uint validity
) public;
```

IDに対して任意の属性（attribute）を追加・更新する関数。
IDに関連づけるメタ情報（例: 公開鍵、サービスURL、プロフィールなど）を追加・更新します。
名前・値・有効期間を指定し、Ethereumアドレスに紐づく属性データを保持できます。

**引数**

* `identity`
    * 属性を設定する対象ID。
* `name`
    * 属性名（例: `did/publicKey/Ed25519`）。
* `value`
    * 属性の値（例: Base64エンコードされた鍵など）。
* `validity`
    * 現在からの有効期間（秒数）。

#### `revokeAttribute`

```javascript
function revokeAttribute(
  address identity,
  bytes32 name,
  bytes memory value
) public;
```

指定された属性を削除（revoke）する関数。
すでに設定された属性の有効期限を強制的に切らすことで、削除したのと同様の状態にします。属性の変更や無効化が必要になった場合に用いられます。

**引数**

* `identity`
    * 属性を削除したいID。
* `name`
    * 削除対象の属性名。
* `value`
    * 削除対象の属性値。

#### `validDelegate`

```javascript
function validDelegate(
  address identity,
  bytes32 delegateType,
  address delegate
) public view returns (bool);
```

指定されたdelegateが有効かを確認する関数。
対象IDに対して、指定されたdelegateアドレスが現在も有効（有効期限内）かどうかを確認できます。
アプリケーション側の検証ロジックなどで利用されます。

**引数**

* `identity`
    * 対象のID。
* `delegateType`
    * delegateのタイプ。

* `delegate`
    * チェック対象のdelegateアドレス。

**戻り値**

* `bool`
    * delegateが有効であれば `true`、無効または期限切れなら `false`。

#### `changed`

```javascript
function changed(address identity) public view returns (uint);
```

対象のIDにおいて、最後に変更が加えられたブロックのタイムスタンプを取得する関数。
IDに関して、所有者・delegate・属性のいずれかが最後に更新された時刻を取得します。
データの同期や更新確認に利用されます。

**引数**

* `identity`
    * 確認したいID。

**戻り値**

* `uint`
    * 最後の変更が加えられたタイムスタンプ（UNIX形式）。

### イベント履歴の効率的な取得方法

Ethereumにおいてコントラクトのイベントは、オンチェーンの状態とは独立してオフチェーン用途に特化したデータ取得手段として広く利用されています。
しかし現行のEthereumのインデックス構造では、アドレスに関連するイベントを時系列でさかのぼって検索するのは極めて非効率的です。
とくに、`eth_getLogs` を広い範囲で呼び出す必要がある場合、検索に時間もコストもかかってしまいます。

**ERC1056**では、各イベントが過去の変更ブロックを参照するリンク構造を用いることでこの課題を解決します。
具体的には、各IDに対応する `changed` マッピング（mapping）が、最後に更新があったブロック番号（タイムスタンプ）を記録しており、この情報を使って過去の履歴を順にたどれる仕組みです。

このようにして、不要な全体検索を避け、対象のIDに関するイベントだけをブロック単位で取得していくことができます。

### イベント履歴のトレース手順

あるIDについて変更履歴（例：所有者変更・delegate追加・属性更新など）を取得するには、以下のように `changed` マッピングを活用して過去のブロックを1つずつたどっていきます。

以下はJavaScript（web3ベース）の実装例です。

```javascript
const history = []
let previousChange = await didReg.changed(identity)

while (previousChange) {
  const filter = await didReg.allEvents({
    topics: [identity],
    fromBlock: previousChange,
    toBlock: previousChange
  })

  const events = await getLogs(filter)
  previousChange = undefined

  for (let event of events) {
    history.unshift(event)
    previousChange = event.args.previousChange
  }
}
```

このコードは以下のような流れで動作します。

1. `changed(identity)` で最新の変更ブロックを取得する。
2. そのブロック内のイベントをフィルタして取得する。
3. 各イベントの `previousChange` フィールドを使って、前のブロックにさかのぼる。
4. 全ての変更履歴を `history` に時系列で格納していく。

これにより、対象のIDについて最小限のブロック数のみを走査しながら、正確な履歴を効率的に構築できます。

### DIDドキュメントの構築方法

**ERC1056**を用いて、DID（Decentralized Identifier）準拠のドキュメントを組み立てるには、いくつかのステップを踏む必要があります。

まず、IDの所有者を `identityOwner(identity)` により取得します。
この所有者アドレスがDIDドキュメント上の「**主キー**」となり、`publicKey` セクションの先頭に配置されます。

次に、`DIDDelegateChanged` イベントを読み込み、delegateとして追加されているキーを確認します。
これらはDIDの `authentication` セクションに反映させることで、署名検証用の追加キーとして機能させることができます。
どのdelegateTypeを反映させるかは、アプリケーションの仕様によって決定する必要があります。

最後に、`DIDAttributeChanged` イベントをたどることで、サービスエンドポイントや暗号化鍵など、追加のメタデータ情報（例えば `did/service/endpoint` や `did/publicKey/X25519` など）を取り出すことができます。
これにより、公開鍵ベースのエンドツーエンド暗号化や、外部APIとの連携を記述することができます。

このように、コントラクトイベントを基に構築されたDIDドキュメントは、ブロックチェーン上で管理されたID情報とシームレスに連携し、分散型アプリケーションや認証プロセスに利用される信頼性の高い構造となります。

## 補足

Ethereumでは、すべてのトランザクションが `msg.sender` を通じて署名者を検証する仕組みになっており、これはアカウント抽象化（Account Abstraction）という考え方の基礎でもあります。
つまり、スマートコントラクトか単なる鍵ペアかに関わらず、どのEthereumアカウントもトランザクションの発信者として機能します。

しかし、すべてのトランザクションはガス代を支払う必要があり、これがUXの障壁になることがあります。
そこで近年では、発信者本人ではない第三者が署名を生成し、オフチェーンで署名を取得したトランザクションをオンチェーンに中継するという方法が広く使われています。
いわゆるメタトランザクションと呼ばれる、「**リレー（Relayer）による送信**」や「**受信者支払いモデル（receiver pays）**」などがこれに該当します。

このような署名トランザクションは、鍵ペアで署名する必要があるため、スマートコントラクト自体では署名できないという制限があります。
スマートコントラクトは秘密鍵を持たないため、自身で署名を生成することができないからです。

**ERC1056**では、この問題に対してスマートコントラクトや通常のアカウントが、自身の代わりに署名できる鍵ペアを「**delegate（代理人）**」として登録する手段を提供しています。
これにより、スマートコントラクトであっても署名者としてオフチェーンやペイメントチャネルでの操作を表現できるようになります。

代理人は一時的なものにも永続的なものにもできるため、決済、セッション管理、外部サービス連携など多様な利用に適用可能です。

## 互換性

**ERC1056**は、全てのEthereumアカウントがそのままIDとして有効であるという仕様に基づいています。
つまり、既存のEthereumウォレットが生成・管理しているアカウント（鍵ペア）も、DID互換のIDとしてそのまま使用できます。

そのため、この標準を導入する上で特別なコントラクトのデプロイやアカウント作成は不要です。
すでに存在しているEthereumアドレスが、そのまま軽量なIDとして機能します。

さらに、既存のウォレットにおいても、`ethr-did` と呼ばれるライブラリを用いることで、delegate（署名代理人）や属性（attribute）の追加・検証といった機能をすぐに取り入れることができます。

今後、DID Auth（分散型ログイン）の標準がより確立されていけば、これらのウォレットもそのまま分散型ログインに対応できる環境として活用できるようになります。
**ERC1056**は、既存のインフラとの互換性を保ちつつ、段階的に高度なID機能を拡張していける柔軟な仕組みを提供しています。

## 引用

Pelle Braendgaard <pelle.braendgaard@consensys.net>, Joel Torstensson <oed@consensys.net>, "ERC-1056: Ethereum Lightweight Identity [DRAFT]," Ethereum Improvement Proposals, no. 1056, May 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1056.

## 最後に

今回は「EthereumアカウントなどのIDにdelegatorや属性を追加し、IDを効率よく管理・拡張できる仕組みを提案している**ERC1056**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
