[ERC5564] 送受信者のみがアクセスできるステルスアドレスの仕組みを理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、送信者と受信者のみがやり取りできる、ステルスアドレスの仕組みを提案している規格である**ERC5564**についてまとめていきます！

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

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

:::note warn
**5564**は現在（2024年1月7日）では「**Review**」段階です。
:::

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

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

# 概要

この規格では、ステルスアドレスと呼ばれるアドレスに関する提案をしています。
ステルスアドレスを使用することで、トランザクションや`transfer`を実行する送信アドレスが、受信アドレスのみアクセス可能なプライベートアカウントを非インタラクティブに生成することを可能にする仕組みが提案されています。

:::note info
非インタラクティブとは、送信アドレスと受信アドレスが直接やりとりせずに実行できるということです。
これにより、処理の手間や時間を削減しつつプライバシーが保たれます。
:::

また、この規格ではステルスアドレスプロトコルを開発するための基本的な実装方法を提供しています。
`0x55649E01B5Df198D18D95b5cc5051630cfD45564`というアドレスでデプロイされたシングルトンコントラクトを使用して、受信アドレスに必要な情報を通知する標準的な方法が提供されており、このシングルトンコントラクトをベースに、自分たちのプロジェクトにステルスアドレス機能を組み込むことができます。

さらに、この規格では**SECP256k1**曲線を使用した暗号化スキームの実装についても提案しています。
SECP256k1は、ビットコインやイーサリアムなどで使用されている暗号化技術で、ステルスアドレスの安全性とプライバシーを確保するために利用されます。

:::note info
### SECP256k1とは
SECP256k1は、暗号通貨（ビットコインやイーサリアムなど）のセキュリティを支える重要な技術です。
この技術は、「**楕円曲線暗号（Elliptic Curve Cryptography, ECC）**」と呼ばれる仕組みを使っています。

### 楕円曲線暗号（ECC）とは
ECCはデータを暗号化する技術です。
この仕組みを使用することで、データの送信や取引が安全に行われるようになります。
楕円曲線暗号では、特定の曲線上の点を使って計算を行います。

### SECP256k1の仕組み

#### 楕円曲線の形
SECP256k1で使われる楕円曲線は以下の方程式で表されます。

```math
y^2 = x^3 + 7
```

この方程式の曲線上の点を使って暗号化やデジタル署名を行います。

#### 有限体

計算は「**有限体**」と呼ばれる限られた数の要素（数）からなる特殊な数学の集合から行われます。
SECP256k1では、非常に大きな素数（約10の77乗）を使います。
これにより、計算が非常に難しくなり安全性が高まります。

### 公開鍵暗号とデジタル署名
ECCの主な利用方法には、公開鍵暗号とデジタル署名があります。

#### 公開鍵暗号
- **秘密鍵**
    - あなたが持っている秘密の数字。
    - この数字は誰にも教えてはいけないです。
- **公開鍵**
    - 秘密鍵から計算で作られるもので誰に見せても良い値です。
    - 公開鍵を使うと、秘密鍵がわからなくてもデータの暗号化や検証ができます。

例えば、あなたが友達に秘密のメッセージを送りたいとき、あなたは秘密鍵を使ってメッセージを暗号化します。
友達はあなたの公開鍵を使ってそのメッセージを解読できます。

#### デジタル署名
デジタル署名は、あなたが本当にそのメッセージを送ったことを証明するための仕組みです。

- **署名**
    - あなたは秘密鍵を使ってメッセージに署名します。
    - この署名は、メッセージと秘密鍵から計算されます。
- **検証**
    - 署名を受け取ったユーザーは、あなたの公開鍵を使って署名を検証します。
    - この検証により、メッセージが改ざんされていないことと誰が送ったものであることが確認できます。

### SECP256k1の利用例
- **ビットコイン**
    - ビットコインのトランザクション（送金）では、送信者が秘密鍵で署名してネットワークの他のユーザーが公開鍵でその署名を検証します。
- **イーサリアム**
    - イーサリアムでも、アドレスの生成やトランザクションの署名にSECP256k1が使われています。
:::

# 動機

非インタラクティブなステルスアドレス生成の標準化により、Ethereumネットワークや他のEVM互換チェーンでプライバシー機能を大幅に向上できる可能性があります。
この仕組みにより、受信アドレスが資産を受け取る時にプライバシーを保つことができるようになります。
送信アドレスがステルスアドレスを生成するためには、送信者と受信アドレスだけが知っている共有秘密（暗号技術を用いて生成）に基づいています。
送信者は、この共有秘密を使って受信者のために一時的なステルスアドレスを作成します。
このステルスアドレスは、受信アドレス専用の一時的な受け取り用アドレスです。

この方法で、外部ユーザーはステルスアドレスが特定の受信者に関連しているかどうかを知ることができません。
送信アドレスだけがステルスアドレスの受信アドレスを知っているため、受信アドレスのプライバシーが保護されます。

複数の暗号化スキームに対応する単一のコントラクトが提供され、受信アドレスはすべてのステルスアドレスを一元的に監視できます。
これにより、受信アドレスがトランザクションを見逃すことなく効率的に資産を管理できます。

# 仕様

ステルスメタアドレス（**stealth meta-address**）は、ある受信アドレスのために特別に計算されるステルスアドレスを生成する時に使われる公開鍵のセットです。
これにより、受信者のプライバシーが守られ、他人にはそのアドレスが誰のものか分からなくなります。

支出鍵（**spending key**）は、ステルスアドレスに送られた資金を使うための秘密鍵で、対応する公開鍵は支出公開鍵（**spending public key**）と呼ばれます。
一方、閲覧鍵（**viewing key**）は、ステルスアドレスに送られた資金が本当に受信者のものかを確認するための秘密鍵で、対応する公開鍵は閲覧公開鍵（**viewing public key**）です。

ステルスアドレスの形式はさまざまですが、公開鍵の長さに応じてステルスメタアドレスの長さも異なります。
例えば、公開鍵が`n`バイトの長さの場合、`n`バイトのステルスメタアドレスは支出公開鍵と閲覧公開鍵の両方として同じアドレスを使用します。
しかし、`2n`バイトのステルスメタアドレスの場合は、最初の`n`バイトが支出公開鍵として、残りの`n`バイトが閲覧公開鍵として使われます。

このような仕組みによって、受信者は自分に送られた資金が本当に自分のものか確認できるだけでなく、その資金を安全に使うことができます。
また、誰がその資金の所有者か外部からは分からないため、受信者のプライバシーがしっかりと保護されます。

```javascript
/// @notice Generates a stealth address from a stealth meta address.
/// @param stealthMetaAddress The recipient's stealth meta-address.
/// @return stealthAddress The recipient's stealth address.
/// @return ephemeralPubKey The ephemeral public key used to generate the stealth address.
/// @return viewTag The view tag derived from the shared secret.
function generateStealthAddress(bytes memory stealthMetaAddress)
  external
  view
  returns (address stealthAddress, bytes memory ephemeralPubKey, bytes1 viewTag);
```

上記のコードは、送信者が受信者のステルスメタアドレスを元に、受信者専用のステルスアドレスを生成するための関数です。
受信者のステルスメタアドレスをパラメータとして受け取ります。

この関数を呼び出すと、3つの結果が返されます。

1. `stealthAddress`
    - 受信者のために新しく生成されたステルスアドレス。
    - これは送金や通信の時に使用され、受信者のプライバシーを保護します。
2. `ephemeralPubKey`
    - ステルスアドレスを生成するために使用された一時的な公開鍵です。
    - これは一度きりの使用で、その後は廃棄されます。
3. `viewTag`
    - は共有された秘密から導出されるビュータグです。
    - これは受信者が自分に属する取引を特定するのに役立ちます。

この関数は外部から呼び出せ、読み取り専用です。
つまり、ブロックチェーン上での状態を変更せずに情報を取得するために使用されます。
送信者はこの関数を使用して、安全でプライバシーを保護した方法で資金を送るためのステルスアドレスを簡単に生成できます。

```javascript
/// @notice Returns true if funds sent to a stealth address belong to the recipient who controls
/// the corresponding spending key.
/// @param stealthAddress The recipient's stealth address.
/// @param ephemeralPubKey The ephemeral public key used to generate the stealth address.
/// @param viewingKey The recipient's viewing private key.
/// @param spendingPubKey The recipient's spending public key.
/// @return True if funds sent to the stealth address belong to the recipient.
function checkStealthAddress(
  address stealthAddress,
  bytes memory ephemeralPubKey,
  bytes memory viewingKey,
  bytes memory spendingPubKey
) external view returns (bool);
```

上記のコードは、受信者が特定のステルスアドレスが自分に属しているかどうかを確認するための関数です。
この関数を使うことで、受信者は送られてきた資金が自分のものかどうかを確認できます。

この関数には4つのパラメータがあります。
1. `stealthAddress`
    - 確認したい受信者のステルスアドレスです。
2. `ephemeralPubKey`
    - ステルスアドレスを生成する時に使用された一時的な公開鍵です。
3. `viewingKey`
    - 受信者の閲覧秘密鍵で、これを使って自分への取引を確認します。
4. `spendingPubKey`
    - 受信者の支出公開鍵です。

関数を呼び出すと、ブール値（`True`または`False`）が返されます。
もし返された値が`True`なら、そのステルスアドレスに送られた資金は確かにその受信者のものです。
この関数も外部から呼び出せ、読み取り専用なので、ブロックチェーン上の状態を変更せずに情報を確認することができます。
受信者はこの関数を使用して、送られてきた資金が自分のものであるかを安全かつ効率的に確認できます。

```javascript
/// @notice Computes the stealth private key for a stealth address.
/// @param stealthAddress The expected stealth address.
/// @param ephemeralPubKey The ephemeral public key used to generate the stealth address.
/// @param viewingKey The recipient's viewing private key.
/// @param spendingKey The recipient's spending private key.
/// @return stealthKey The stealth private key corresponding to the stealth address.
/// @dev The stealth address input is not strictly necessary, but it is included so the method
/// can validate that the stealth private key was generated correctly.
function computeStealthKey(
  address stealthAddress,
  bytes memory ephemeralPubKey,
  bytes memory viewingKey,
  bytes memory spendingKey
) external view returns (bytes memory);
```

上記のコードは、受信者がステルスアドレスのための秘密鍵を計算する時に使用する関数です。
受信者はこれを呼び出すことで自分のステルスアドレスに対応する秘密鍵を得ることができます。

関数には4つのパラメータがあります。
1. `stealthAddress`
    - 対象となるステルスアドレスです。
2. `ephemeralPubKey`
    - ステルスアドレスを生成する時に使われた一時的な公開鍵です。
3. `viewingKey`
    - 受信者の閲覧秘密鍵で、取引を確認するのに使います。
4. `spendingKey`
    - 受信者の支出秘密鍵です。

関数を実行すると、「`stealthKey`」という名前のステルス秘密鍵が返されます。
これはステルスアドレスに対応する秘密鍵で、受信者がそのアドレスに送られた資金を使用するために必要です。
また、この関数はステルスアドレスが正しく生成されたことを検証するために、ステルスアドレスの入力を必要とします。
この関数も外部からの読み取り専用の呼び出しに対応しており、状態を変更せずに情報を取得するために使用されます。
受信者はこの関数を使って、自分のステルスアドレスに対応する秘密鍵を安全かつ確実に計算できます。

ステルスアドレスを使うことで、受信者は自分のアドレスを秘密にしながら、送信者からの資金を受け取ることができます。
このシステムを実装するためには、いくつかの特定のメソッドや手順が必要です。

まず、ステルスアドレスの具体的な動作は「**スキーム**」と呼ばれる規則によって異なります。
新しいステルスアドレススキームを提案する時には、それぞれのスキームに合わせたメソッドの実装が求められます。
これらのメソッドはSolidityという言語で記述されますが、実際にはSolidity以外の言語やツールでも実装できる必要があります。

スキームを識別するために`256`ビットの整数（`schemeId`）が使われます。
新しいステルスアドレススキームを標準化する**ERC**では、`schemeId`とその詳細な仕様のマッピングが必要です。
簡単さのために`schemeId`は連続する整数を選ぶことが推奨されますが、特定の意味を持たせたり任意に選んだりすることもできます。

具体的には、以下のアルゴリズムを定義する必要があります。

- スキームの識別子
    - 各スキームが一意に識別できるように整数で表します。
- ステルスメタアドレスのエンコーディングとデコーディング
    - 支出公開鍵と閲覧公開鍵をバイト配列に変換し、その逆の変換も行う方法です。
- `generateStealthAddress`
    - 受信者のためのステルスアドレスを生成する手順です。
- `checkStealthAddress`
    - 特定のステルスアドレスが受信者のものかどうかを確認する手順です。
- `computeStealthKey`
    - ステルスアドレスに対応する秘密鍵を計算する手順です。

これらのアルゴリズムとメソッドは、ステルスアドレススキームを正確かつ安全に機能させるために不可欠です。
各スキームは独自のアプローチを必要とするため、これらの詳細は非常に重要です。

```javascript
/// @notice Interface for announcing when something is sent to a stealth address.
contract IERC5564Announcer {
  /// @dev Emitted when sending something to a stealth address.
  /// @dev See the `announce` method for documentation on the parameters.
  event Announcement (
    uint256 indexed schemeId, 
    address indexed stealthAddress, 
    address indexed caller, 
    bytes ephemeralPubKey, 
    bytes metadata
  );

  /// @dev Called by integrators to emit an `Announcement` event.
  /// @param schemeId The integer specifying the applied stealth address scheme.
  /// @param stealthAddress The computed stealth address for the recipient.
  /// @param ephemeralPubKey Ephemeral public key used by the sender.
  /// @param metadata An arbitrary field MUST include the view tag in the first byte.
  /// Besides the view tag, the metadata can be used by the senders however they like, 
  /// but the below guidelines are recommended:
  /// The first byte of the metadata MUST be the view tag.
  /// - When sending/interacting with the native token of the blockchain (cf. ETH), the metadata SHOULD be structured as follows:
  ///     - Byte 1 MUST be the view tag, as specified above.
  ///     - Bytes 2-5 are `0xeeeeeeee`
  ///     - Bytes 6-25 are the address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
  ///     - Bytes 26-57 are the amount of ETH being sent.
  /// - When interacting with ERC-20/ERC-721/etc. tokens, the metadata SHOULD be structured as follows:
  ///   - Byte 1 MUST be the view tag, as specified above.
  ///   - Bytes 2-5 are a function identifier. When a function selector (e.g.
  ///     the first (left, high-order in big-endian) four bytes of the Keccak-256
  ///     hash of the signature of the function, like Solidity and Vyper use) is
  ///     available, it MUST be used.
  ///   - Bytes 6-25 are the token contract address.
  ///   - Bytes 26-57 are the amount of tokens being sent/interacted with for fungible tokens, or
  ///     the token ID for non-fungible tokens.
  function announce (
    uint256 schemeId, 
    address stealthAddress, 
    bytes memory ephemeralPubKey, 
    bytes memory metadata
  )
    external
  {
    emit Announcement(schemeId, stealthAddress, msg.sender, ephemeralPubKey, metadata);
  }
}
```

この仕様では、ステルスアドレスに何かが送信された時にイベントを発行するための単一の**ERC5564Announcer**コントラクトが定義されています。
これはシングルトンコントラクトで、チェーンごとに1つのインスタンスが必要です。

**IERC5564Announcer**コントラクトは、ステルスアドレスに何かが送信された時に発行される「`Announcement`」というイベントを定義しています。
このイベントは、ステルスアドレススキームの識別子（`schemeId`）、計算されたステルスアドレス（`stealthAddress`）、呼び出し元のアドレス（`caller`）、一時的な公開鍵（`ephemeralPubKey`）、メタデータ（`metadata`）を含みます。

`announce` 関数は、インテグレーターによって呼び出され、`Announcement` イベントを発行するために使用されます。
この関数は、使用するステルスアドレススキームの識別子（`schemeId`）、受信者のために計算されたステルスアドレス（`stealthAddress`）、送信者によって使用される一時的な公開鍵（`ephemeralPubKey`）、メタデータ（`metadata`）をパラメータとして受け取ります。
メタデータの最初のバイトは必ずビュータグを含む必要があります。
ビュータグの後、メタデータは送信者のニーズに応じて使用されますが、特定のガイドラインに従うことが推奨されます。
例えば、ETHの送信や**ERC20**や**ERC721**などのトークンとのやり取りに応じて、メタデータの構造が異なります。

この**IERC5564Announcer**コントラクトとその`announce`関数は、ステルスアドレスへの送信が行われた時に透明性とトレーサビリティを提供するために設計されており、受信者が自分に送られた取引を監視して管理するのを助けます。

## ステルスメタアドレス形式

新しいステルスメタアドレス形式は、通常のチェーン固有のアドレス形式に「`st: (stealth)`」という特別な接頭辞を加えることで、ステルスアドレスを明確に識別します。
Ethereumのステルスメタアドレスは「`st:eth:0x<spendingKey><viewingKey>`」のような形式で表されます。
ここで「`<spendingKey>`」は支出用の公開鍵、そして「`<viewingKey>`」は閲覧用の公開鍵を意味します。

ユーザーはこれらのステルスメタアドレスを自分で管理することができ、または**ERC6538**で説明されているように、公開されているレジストリコントラクトに登録することも可能です。
このレジストリコントラクトは、ユーザーが他の人々のステルスメタアドレスを簡単に見つけられる一元化された場所を提供し、同時に受信者がステルスアドレスを使ってコミュニケーションをとる意思があることを示すことができます。

特に重要なのは、この「`st: (stealth)`」接頭辞は単にステルスアドレスを標準アドレスと区別するためのものであり、実際の計算を行う前にはこの接頭辞は取り除かれるという点です。
この仕組みによって、ステルスアドレスと標準アドレスの両方が効率的かつ正確に処理されることを保証しています。

## ビュータグ付きSECP256k1の初期実装

この**ERC**は、あらゆる特定の暗号システムに縛られない基礎を築くことを目指しており、**IERC5564Announcer**コントラクトを通じてそれを実現しています。
加えて、ビュータグと共に**SECP256k1**楕円曲線を用いることで、ステルスアドレススキームの新しい実装を初めて導入しています。
この楕円曲線はビットコインなどの多くの暗号通貨に利用されているもので、特定の数学的方程式によって定義されています。

この部分は以下の3つのセクションに分けられています。

1. **ステルスアドレスの生成**
    - これは、受信者の公開鍵と送信者の秘密情報を組み合わせて、新しいステルスアドレスを作成する過程です。
2. **アナウンスメントの解析**
    - **IERC5564Announcer**コントラクトを通じて公表された情報を解析し、どの取引が受信者に関連しているかを判定します。
3. **ステルス秘密鍵の導出**
    - 受信者は自分の秘密鍵と送信者からの情報を使い、ステルスアドレスに送られた資金を引き出すための秘密鍵を計算します。

**SECP256k1**楕円曲線は、以下の方程式で定義されています。

```math
y^2 = x^3 + 7 \pmod{p}
```

また、ここでは以下のようになります。

```math
p = 2^{256} - 2^{32} - 977
```

この**ERC**の初期実装は、ステルスアドレススキームを様々な環境に適用し、より高いプライバシーとセキュリティを確保する新しい方法を提供するための基盤を築きます。
この技術により、ユーザーは他者に知られずに取引を行うことができるようになり、プライバシー保護が強化されます。

### 生成 - ステルスメタアドレスからステルスアドレスを生成

受信者は支出用の秘密鍵 $p_{spend}$ と閲覧用の秘密鍵 $p_{view}$ を持っており、これらからそれぞれ公開鍵 $P_{spend}$ と $P_{view}$ が導出されます。
受信者はこれらの公開鍵を組み合わせてステルスメタアドレス $P_{spend}$ と $P_{view}$ を公開します。

送信者はこのステルスメタアドレスを `generateStealthAddress` 関数に渡します。
この関数は以下の計算を実行します。

1. ランダムな`32`バイトの一時秘密鍵 $p_{ephemeral}$ を生成します。
2. この一時秘密鍵から一時公開鍵 $P_{ephemeral}$ を導出します。
3. ステルスメタアドレスから支出公開鍵 $P_{spend}$ と閲覧公開鍵 $P_{view}$ を解析します。
4. 共有秘密 $s$ を $p_{ephemeral} \cdot P_{view}$ として計算します。
5. この共有秘密をハッシュ化し $s_{h} = \textrm{h}(s)$ とします。
6. ビュータグ $v$ をハッシュ化された共有秘密の最も重要なバイト $s_{h}[0]$ として抽出します。
7. ハッシュ化された共有秘密と生成点 $G$ を乗算し $S_h = s_h \cdot G$ とします。
8. 受信者のステルス公開鍵を $P_{stealth} = P_{spend} + S_h$ として計算します。
9. 受信者のステルスアドレスを $\textrm{pubkeyToAddress}(P_{stealth})$ として計算します。

この関数は最終的にステルスアドレス $a_{stealth}$、一時公開鍵 $P_{ephemeral}$ とビュータグ $v$ を返します。
これにより、送信者は受信者だけがアクセスできる秘密のアドレスに資金を送ることができ、取引のプライバシーが保たれます。

### 解析 - 自分のステルスアドレスを見つける

ユーザーは、閲覧用の秘密鍵 $p_{view}$ と支出用の公開鍵 $P_{spend}$ を持っています。
また、ユーザーは一連のアナウンスメントイベントにアクセスでき、それぞれに `checkStealthAddress` 関数を適用して自分のステルスアドレスを見つけます。

`checkStealthAddress` 関数は以下の計算を実行します。

1. 閲覧用の秘密鍵とアナウンスメントの一時公開鍵を乗算して共有秘密 $s = p_{view} * P_{ephemeral}$ を計算します。
2. この共有秘密をハッシュ化し $s_{h} = h(s)$ とします。
3. 最も重要なバイトを取り出してビュータグ $s_{h}[0]$ を抽出し、与えられたビュータグと比較します。
    - もしビュータグが一致しなければ、このアナウンスメントはユーザー宛ではないので、残りの手順をスキップします。
    - 一致する場合は続けます。
4. ハッシュ化した共有秘密と生成点 $G$ を乗算して $S_h = s_h \cdot G$ を計算します。
5. 支出公開鍵にこの新たな点を加えて、ステルス公開鍵 $P_{stealth} = P_{spend} + S_h$ を計算します。
6. このステルス公開鍵から導出されたステルスアドレス $a_{stealth}$ を $\textrm{pubkeyToAddress}(P_{stealth})$ として計算します。
7. もしアナウンスメントのステルスアドレスが導出されたステルスアドレスと一致すれば `true` を返し、そうでなければ `false` を返します。

このプロセスにより、ユーザーは自分宛の取引を効果的に識別し、秘密のステルスアドレスに送られた資金を確実に追跡できます。

### 秘密鍵の導出 - ハッシュ化された共有秘密鍵と支出秘密鍵からステルスアドレス秘密鍵を生成

ユーザーは閲覧用の秘密鍵 $p_{view}$ と支出用の秘密鍵 $p_{spend}$ を持っています。
また、ユーザーは `checkStealthAddress` 関数が `true` を返す一連のアナウンスメントイベントにアクセスできます。

`computeStealthKey` 関数は以下の計算を実行します。

1. アナウンスメントの一時公開鍵と閲覧用の秘密鍵を乗算して共有秘密 $s = p_{view} * P_{ephemeral}$ を計算します。
2. この共有秘密をハッシュ化し $s_{h} = h(s)$ とします。
3. ステルス秘密鍵を $p_{stealth} = p_{spend} + s_h$ として計算します。

このプロセスにより、ユーザーは自分宛のステルスアドレスに送られた資金にアクセスするための秘密鍵を生成できます。
この秘密鍵は、送金やその他のトランザクションを実行するために必要なものです。
この方法により、ユーザーは自分の資金を安全に管理し、プライバシーを保ちながら取引を行うことができます。

## 構文解析に関する考察

ステルスアドレスのトランザクションを受け取った時、受信者は通常、自分がその取引の対象かどうかを確認するために複数の計算操作を行う必要があります。
これには、2回の楕円曲線乗算（`ecMUL`）、2回のハッシュ計算（`HASH`）、そして1回の楕円曲線加算（`ecADD`）が含まれます。

しかし、ビュータグというアプローチを用いることで、解析時間を大幅に短縮することが可能です。
この方法では、ユーザーは各アナウンスメントを解析する時、1回の楕円曲線乗算と1回のハッシュ計算だけを行う必要があります。
これにより、1回の`ecMUL`、1回の`ecADD`、1回の`HASH`を省略できるため、計算量が大幅に減少します。

ビュータグは`1`バイト長で、非該当のアナウンスメントを効率的にフィルタリングするために必要なスペースを最小限に抑えています。
`1`バイトのビュータグを用いることで、共有秘密 $h(s)$ をハッシュ化した後、関与していないアナウンスメントに対する残りの計算を $255/256$ の確率でスキップできます。
つまり、関係ないアナウンスメントについてはほぼ確実に上記の計算を省略できるのです。

ただし、ビュータグが共有秘密の1バイトを明らかにするため、セキュリティマージンは`128`ビットから`124`ビットへと若干減少します。
これはプライバシーに影響を及ぼしますが、ステルスアドレスの安全な生成には影響しません。
このアプローチにより、ユーザーは効率的かつ安全に自分宛の取引を特定し、プライバシーを保ちつつ取引を行うことができるようになります。

# 補足

このERCは、人々が自分の身元を隠しながら所有権を移転するためのプライバシーを重視した方法を提供することを目的としています。
トークン所有権を明かすことは、個人情報を暴露するリスクがあります。
人々は特定の団体や国に寄付したいと思っても、自分と受取人の間のリンクを公開したくない場合が多いです。
ステルスアドレスの生成を標準化することは、追跡できないやり取りに向けた大きな一歩であり、プライバシーを強化するための広範な採用を達成するためには標準化が不可欠です。

ステルスアドレス仕様は、受信者との事前の連絡なしに資産の移転を可能にするプロトコルを定めています。
これにより、受信者はブロックチェーンにアクセスしたり、アカウントの残高を確認することなく、転送を受け取ったことを確認できます。
特に、ステルスアドレスは、トークンの受け取りを確認しながら受信者のプライバシーを維持することを可能にします。

著者たちは、オンチェーンとオフチェーンの効率の間のトレードオフがあることを理解しています。
モネロに似たビュータグメカニズムを取り入れることで、受信者はアナウンスメントをより効率的に解析できますが、それはアナウンスメントイベントの複雑さを増加させます。

アナウンスメントイベントには受信者のアドレスとビュータグが必須で、これによりユーザーはチェーンに問い合わせることなく、迅速に所有権を確認することができます。
これは、プライバシーを保ちつつ、効率的にトークンの移転を確認できるようにするための重要なステップです。

# 互換性

このERCは完全な互換性があります。

# セキュリティ

このERCは、DoS（サービス拒否）攻撃に対する潜在的な攻撃ベクトルを認識し、それに対処するための対策を提案しています。
ステルス転送を行う送信者は、アナウンスメントイベントの解析に計算リソースを消費するため、受信者に負担をかけます。
この解析作業はガスで補償されないため、アナウンスメントイベントをスパムすることは、解析時間を長引かせてユーザー体験を悪化させる可能性があります。
ただし、金銭的な利益が得られないため、このような攻撃を実行する動機は低いと考えられます。

それでも潜在的なスパムに対応するために、解析プロバイダーは、スパムを送信するユーザーを無視するか、アナウンスメントの順序で優先度を下げるなど、独自のDoS攻撃防止方法を採用することができます。
また、解析プロバイダーは、ステーキングメカニズムの導入や送信者に手数料を支払わせることでスパムに対抗することができます。
これにより、スパムを経済的に魅力的でなくし、効果的なフィルタリングを可能にします。

受信者の取引コストに関しては、ステルスアドレスウォレットの資金調達がプライバシーを侵害する可能性があることが指摘されています。
したがって、送信者は各ステルスアドレス取引に少量のETHを添付することで、受信者の後続の取引をサポートし、プライバシーの向上を図ることができます。
これらの対策は、DoS攻撃のリスクを軽減し、ステルスアドレスシステムの安全性と利便性を向上させるために重要です。

# 引用

Toni Wahrstätter (@nerolation), Matt Solomon (@mds1), Ben DiFrancesco (@apbendi), Vitalik Buterin (@vbuterin), "ERC-5564: Stealth Addresses [DRAFT]," Ethereum Improvement Proposals, no. 5564, August 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5564.

# 最後に

今回は「送信者と受信者のみがやり取りできる、ステルスアドレスの仕組みを提案している規格である**ERC5564**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58


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