[ERC2335] BLSキーストアの仕組みを理解しよう！

# はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、BLS12-381秘密鍵を安全かつ中立的に保存・復号するためのJSONベースのキーストアフォーマットの仕組みを提案している**ERC2335**についてまとめていきます！

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

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

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

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

# 概要

**ERC2335**は、BLS12-381曲線を使った暗号署名における秘密鍵を安全に保存・共有するための標準的なJSON形式の定義です。
この形式は「キーストア（keystore）」と呼ばれるファイルで、秘密鍵を暗号化して保存します。
ユーザーがパスワードを入力するまでは秘密鍵が暗号化された状態で守られており、安全に他のデバイスに持ち運ぶことも可能です。

この仕様はEthereum 2.0に特化したものではなく、BLS12-381署名を採用している他のプロジェクトやエコシステムでも広く利用されることを意図しています。
そのため、Ethereumに限定せず、より中立的な場所に最終的には標準として移行する計画もあります。

**ERC2335**は**EIP2333**と**ERC2334**をベースとしています。

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

https://qiita.com/cardene/items/99a51a2a78f3b774b400

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

https://qiita.com/cardene/items/4e9dc2f5af58ed01aebd

# 動機

ユーザーが自ら秘密鍵を保持・管理するという前提のもと、秘密鍵を安全に保存・共有できる仕組みは重要です。
キーストアを使うことで、ユーザー自身が秘密鍵の利用とアクセスを細かく制御できるようになります。

Ethereum 1.0では「Web3 Secret Storage Definition」がその役割を果たしていましたが、以下の理由により、今後の用途には適していないとされています。

* **Keccak256への依存**

Ethereum 1のキーストアでは、チェックサム（整合性確認）の計算にKeccak256ハッシュを使用しています。
これはEthereumとの親和性が高い一方で、BLS12-381鍵や署名はチェーンに依存しない中立的な標準であるべきです。
特定のチェーンに偏ったハッシュ関数を使用すると、他のエコシステムとの互換性が損なわれます。

* **抽象化の欠如**

Ethereum 1のキーストア仕様は、必要に応じて機能を追加してきた結果、設計全体に一貫した抽象化がありません。
将来的に異なる暗号方式や鍵特性に柔軟に対応するためには、より抽象化された設計が求められます。

このような課題を解決するため、**ERC2335**は中立的かつ柔軟性のあるキーストア標準を目指しています。

# 仕様

**ERC2335**は、BLS12-381の秘密鍵を安全に保存・復号するためのJSONフォーマットを定義しています。

## 復号プロセスの概要

秘密鍵を復号するには、以下の3つのステップを踏みます。

* **復号鍵の導出**
* **パスワードの検証**
* **秘密鍵の復号**

それぞれのステップには暗号関数やパラメータが設定されており、keystoreファイル内に記述されたモジュールによって管理されます。

## パスワード処理の仕様

### パスワード形式

パスワードは任意のUnicode文字列で入力されますが、内部処理では以下の変換を行います。

1. Unicode NFKD形式に正規化
2. 制御文字の除去
3. UTF-8形式でエンコード

### 制御文字の除去

パスワードから除去すべき制御文字は以下の通りです。

* **C0制御文字**
    * `0x00` 〜 `0x1F`（改行・タブなど）
* **C1制御文字**
    * `0x80` 〜 `0x9F`
* **Delete**
    * `0x7F`

ただし、スペース（`0x20`）は使用可能です。

## モジュール構造

**ERC2335**では、暗号処理をモジュール単位で管理します。
モジュールは以下の3要素から構成されます。

* `function`
    * 使用する暗号アルゴリズム
* `params`
    * その関数に必要なパラメータ
* `message`
    * 入力データ

これにより、将来的にアルゴリズムを差し替えても構造全体には影響を与えない柔軟な設計が実現されています。

## 復号鍵の導出（KDF）

復号鍵は、ユーザーが入力したパスワードとモジュール（kdf）に定義された関数・パラメータから導出されます。
この鍵は、復号にも、パスワードの検証にも使われます。

対応するKDF（鍵導出関数）には次があります。

* `pbkdf2`
    * **RFC2898**（パラメータ：反復回数、長さ、saltなど）
* `scrypt`
    * **RFC7914**（パラメータ：メモリコスト、スレッド数、saltなど）

## パスワード検証の仕組み

パスワードが正しいかどうかは、以下の手順で検証されます。

1. 復号鍵の16〜32バイト目を切り出す（`DK_slice`）
2. `DK_slice`に`cipher.message`を連結して`pre_image`を作成
3. それをSHA-256でハッシュし、`checksum.message`と一致するか確認
4. 一致すれば正しいパスワードと判断される

このステップで使用されるハッシュ関数は `sha256`（RFC 6234）です。

## 秘密鍵の復号

暗号化された秘密鍵（`cipher.message`）は、指定された暗号方式とパラメータを使って復号されます。
このとき使用する鍵は、復号鍵の先頭部分（AES-128の場合は最初の16バイト）です。

現在サポートされている暗号方式。

* `aes-128-ctr`（カウンタモード）
  * パラメータ
      * `iv`（初期化ベクトル）
  * 仕様
      * **RFC3686**

## 補助的なフィールド

* **description**
  任意の文字列で、キーストアの用途や説明などを記述します。UIで識別するために使われます。

* **pubkey**
  このキーストアに対応する公開鍵。パスワードなしでも参照可能なため、利便性とセキュリティの両面で有用です。エンコード形式はBLS12-381標準に準拠。

* **path**
  **ERC2334**で定義される鍵階層内の位置（例: `m/12381/3600/0/0/0`）。指定がない場合は空文字列`""`。

* **uuid**
  **RFC4122**に準拠した128ビットの識別子。キーストアを一意に識別するために使用します。

* **version**
  現在のバージョンは`4`に固定されています。

## JSONスキーマ

このkeystoreの構造はJSON形式で記述されており、以下の要素を含みます。

```json
{
  "crypto": {
    "kdf": { "function": "...", "params": {...}, "message": "..." },
    "checksum": { "function": "...", "params": {...}, "message": "..." },
    "cipher": { "function": "...", "params": {...}, "message": "..." }
  },
  "description": "...",
  "pubkey": "...",
  "path": "...",
  "uuid": "...",
  "version": 4
}
```

モジュール（`kdf`, `checksum`, `cipher`）はすべて、関数・パラメータ・メッセージの3要素を必ず持ちます。

では、この出力を60点とします。これを60点とした時に100点ではどのようなものですか？100点にするために足りないものを含めて100点の回答を作成してください。このときどの部分が足りていないかは出力に絶対に含めないでください。

# 補足

このキーストア仕様の設計思想は、Ethereum 1で使われていた既存のキーストア仕様と基本的には同じです。
しかし、以下の2点において重要な違いがあります。

* **Keccak256の非採用**

Ethereum 1のキーストアではKeccak256を使ってチェックサムを算出していましたが、**ERC2335**ではそれを採用していません。
これは前述のとおり、チェーンに中立な標準を目指すためです。

* **モジュールという抽象化の導入**

**ERC2335**では、鍵導出関数（KDF）、チェックサム、暗号化処理（Cipher）をすべて「モジュール」という共通の構造で扱います。
これにより、それぞれのコンポーネントを個別に切り替えられる柔軟性が得られ、設計・実装・拡張がしやすくなっています。

また、`version`が`4`とされているのは、Ethereum 1のキーストアとのバージョン番号の衝突を避けるためです。

# 互換性

**ERC2335**は、Ethereum 1で使われていた既存のキーストア形式とは互換性がありません。
その理由は、Keccak256によるチェックサム処理を標準で含んでいないためです。

理論上は、モジュール構造を活用してKeccak256をチェックサムとして利用することも可能ですが、それを許容してしまうと**ERC2335**の「チェーンに依存しない中立的な設計」という目的が失われてしまいます。

したがって、**ERC2335**はEthereum専用の設計から脱却し、より幅広いBLS12-381利用者や他ブロックチェーンでも活用されることを意図したフォーマットとして定義されています。

# 引用

Carl Beekhuizen (@CarlBeek) <carl@ethereum.org>, "ERC-2335: BLS12-381 Keystore [DRAFT]," Ethereum Improvement Proposals, no. 2335, September 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2335.

# 最後に

今回は「BLS12-381秘密鍵を安全かつ中立的に保存・復号するためのJSONベースのキーストアフォーマットの仕組みを提案している**ERC2335**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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