# [EIP8030] P256署名をEIP7932の署名アルゴリズムとして扱う仕組みを理解しよう

> EIP8030は、新しいトランザクション型や新しいP256検証プリコンパイルを定義する提案ではありません。役割は、EIP7932の署名アルゴリズムレジストリに「P256をどう扱うか」を追加することです。

- URL: https://cardene.dev/articles/512c25f692edcfa298d0
- 公開日: 2026-06-26
- 更新日: 2026-06-26
- トピック: Blockchain
- タグ: eip, ブロックチェーン, p256, secp256r1

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

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

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

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

今回は「**EIP8030**」についてまとめていきます。

EIP8030は、EIP7932で定義される追加署名アルゴリズムのレジストリに、P256署名を`0x01`として登録する提案です。
これにより、`sigrecover`プリコンパイルがP256署名を検証し、公開鍵からEthereumアドレスを導出できるようになります。

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

## 概要

EIP8030は、新しいトランザクション型や新しいP256検証プリコンパイルを定義する提案ではありません。
役割は、EIP7932の署名アルゴリズムレジストリに「P256をどう扱うか」を追加することです。

全体像は以下です。

![EIP8030の全体像](/images/qiita-86b25411-0b3b-49e1-b0a6-46dfdf2550c9.webp)

EIP7932は、複数の署名アルゴリズムを1つの`sigrecover`プリコンパイルから扱うための土台です。
EIP8030は、その土台にP256用のエントリを追加します。
実際のP256署名検証には、EIP7951の`P256VERIFY`と同じ検証ロジックを使います。

:::message
**EIP7932: Secondary Signature Algorithms**
:::

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

:::message
[EIP7951] secp256r1プリコンパイルでApple Secure EnclaveやPasskeyをEthereumに繋ぐ仕組みを理解しよう
:::

[\[EIP7951\] secp256r1プリコンパイルでApple Secure EnclaveやPasskeyをEthereumに繋ぐ仕組みを理解しよう！](/articles/a55db75ffbc68801d968)

EIP8030が追加する値は以下です。

| 項目 | 内容 |
|------|------|
| 対象 | P256署名 |
| 署名アルゴリズム種別 | `0x01` |
| 署名コンテナサイズ | `129`バイト |
| 検証ロジック | EIP7951の`P256Verify` |
| 返す値 | `x || y`で連結した64バイト公開鍵 |

129バイトの内訳は、先頭1バイトのアルゴリズム種別と、32バイトずつの`r`、`s`、`x`、`y`です。
P256では公開鍵の復元ではなく、署名コンテナ内に含まれる公開鍵に対して署名を検証します。

## 動機

EIP7932は、secp256k1以外の署名アルゴリズムをEthereumアドレス導出に使えるようにするための共通レジストリと`sigrecover`プリコンパイルを定義します。
ただし、EIP7932本体だけでは各アルゴリズムの詳細までは決めません。
新しいアルゴリズムは、別のEIPで`ALG_TYPE`、署名サイズ、ガスコスト、検証処理を定義する必要があります。

P256は、secp256r1とも呼ばれるNIST標準の楕円曲線です。
Apple Secure Enclave、Android Keystore、FIDO2やWebAuthnの認証器などで広く使われています。
Ethereum実行クライアント側でもEIP7951のP256検証実装があるため、EIP7932の追加アルゴリズムを検証する題材として扱いやすい位置にあります。

EIP8030の狙いは、P256をEIP7932の処理モデルへ接続することです。
P256署名を受け取り、署名データを必要に応じてハッシュし、低い`s`値を確認し、EIP7951相当の検証を通して公開鍵を返します。
その公開鍵はEIP7932のアドレス導出ルールへ渡されます。

## 仕様

EIP8030の仕様は、アルゴリズム定数、ガスコスト、署名検証、分離署名の結合、`P256Verify`関数の扱いに分かれます。
EIP7932の`sigrecover`プリコンパイルは、入力の先頭バイトからアルゴリズムを選び、登録された検証処理を呼び出します。

### アルゴリズム定数

P256アルゴリズムの定数は以下です。

| 定数 | 値 | 役割 |
|------|----|------|
| `ALG_TYPE` | `Bytes1(0x01)` | EIP7932のレジストリでP256を識別する1バイト値です。 |
| `SIZE` | `129` | アルゴリズム種別を含む署名コンテナ全体のサイズです。 |
| `N` | `0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551` | P256の部分群の位数です。 |

署名コンテナは以下の順で構成されます。

| 位置 | サイズ | 内容 |
|------|--------|------|
| `0` | 1バイト | `ALG_TYPE`です。P256では`0x01`です。 |
| `1..32` | 32バイト | 署名コンポーネント`r`です。 |
| `33..64` | 32バイト | 署名コンポーネント`s`です。 |
| `65..96` | 32バイト | 公開鍵のx座標です。 |
| `97..128` | 32バイト | 公開鍵のy座標です。 |

P256の署名は、`r`と`s`だけでは公開鍵を復元できません。
そのため、EIP8030の署名コンテナには公開鍵座標も含まれます。

### ガスコスト

P256の追加ガスは、EIP7951のP256検証プリコンパイルの6900ガスから、EIP7932の基礎ガス3000ガスを引いた3900ガスを基準にします。
署名データが32バイトではない場合は、`keccak256`でハッシュする分のコストを足します。

ガス計算は以下です。

```python
def gas_cost(signing_data: Bytes) -> Uint64:
    BASE_GAS = Uint64(3900)

    if len(signing_data) == 32:
        return BASE_GAS
    else:
        minimum_word_size = (len(signing_data) + 31) // 32
        return BASE_GAS + Uint64(30 + (6 * minimum_word_size))
```

署名データが32バイトなら、すでにハッシュ済みの値として扱われます。
32バイト以外なら`keccak256`で32バイトのハッシュへ変換し、そのための追加ガスを計算します。

### 事前検証

EIP7932のアルゴリズムは、`verify`の前に`validate`を呼び出す構造です。
P256では、`validate`は追加チェックを行いません。

```python
def validate(signature: Bytes) -> None | Error:
    pass
```

P256の署名コンポーネント、公開鍵座標、曲線上の点であることの確認は、`verify`内で呼び出す`P256Verify`側に寄せられます。
そのため、EIP8030の`validate`は署名コンテナを事前に分解する処理を持ちません。

### 検証処理

署名コンテナに含まれる値と検証の関係は以下です。

![EIP8030の署名コンテナ](/images/qiita-7a44208b-fbf8-44a5-b9e6-c099bc266a60.webp)

この図では、EIP7932が受け取る署名コンテナが、方式番号、署名値、公開鍵をまとめて持つことを示しています。
P256では署名だけから公開鍵を復元せず、渡された公開鍵で署名を検証します。

P256署名検証の流れは以下です。

![P256署名検証の流れ](/images/qiita-43a58f2a-b7b9-4cc6-b2c5-bae68b132517.webp)

処理は、署名コンテナの分解、署名データのハッシュ、低い`s`値の確認、P256署名検証、公開鍵の返却という順に進みます。
EIP8030は、公開鍵を復元するのではなく、署名コンテナに含まれる`x`と`y`が署名データに対応することを確認します。

検証処理は以下です。

```python
def verify(signature: Bytes, signing_data: Bytes) -> Bytes | Error:
    if len(signing_data) != 32:
        signing_data = keccak256(signing_data)

    signature = signature[1:]

    (r, s, x, y) = (
        signature[0:32],
        signature[32:64],
        signature[64:96],
        signature[96:128],
    )

    assert(s <= N / 2)
    assert(P256Verify(signing_data, r, s, x, y) == Bytes(
        "0x0000000000000000000000000000000000000000000000000000000000000001"
    ))

    return x || y
```

最初に、`signing_data`が32バイトかどうかを確認します。
32バイトではない値は、署名検証前に`keccak256`でハッシュされます。
その後、署名コンテナの先頭1バイトを外し、残り128バイトを`r`、`s`、`x`、`y`へ分割します。

`s <= N / 2`の確認は、署名の可鍛性を抑えるための制約です。
同じECDSA署名でも`s`と`N - s`がどちらも有効になり得るため、高い`s`値を拒否して表現を1つへ寄せます。
これはEIP2がsecp256k1署名で導入した低い`s`値の制約に近い考え方です。

:::message
**EIP2: Homestead Hard-fork Changes**
:::

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

最後に、EIP7951で定義された`P256Verify`と同じロジックへ`signing_data`、`r`、`s`、`x`、`y`を渡します。
検証結果が32バイトの`1`であれば、`x || y`を連結した64バイト公開鍵を返します。
この公開鍵は、EIP7932の`pubkey_to_address`で20バイトアドレスへ変換されます。

### 分離署名の結合

EIP7932では、署名本体と公開鍵を別々に持っている場合に、アルゴリズムごとの署名コンテナへまとめる関数も定義します。
EIP8030のP256では、分離署名と公開鍵をそのまま連結します。

```python
def merge_detached_signature(detached_signature: bytes, public_key: bytes) -> bytes:
    return detached_signature + public_key
```

ここで`detached_signature`は`r || s`、`public_key`は`x || y`です。
結合後は、EIP7932の署名コンテナとして使えます。

### `P256Verify`

EIP8030の`P256Verify`は、EIP7951で定義されるP256検証プリコンパイルのロジックを指します。
ただし、EIP8030内の関数として使う時は追加でガスを課しません。
ガスはEIP7932の`sigrecover`側で、アルゴリズムごとの`gas_cost`に基づいて課されるためです。

この分離により、P256の暗号検証ロジックはEIP7951と揃えつつ、EIP7932のアルゴリズムレジストリ上では「P256署名から公開鍵を得る処理」として扱えます。

## 補足

#### P256とsecp256k1の違い

Ethereumの通常の署名では、secp256k1曲線が使われます。
一方、P256はsecp256r1とも呼ばれ、スマートフォンやセキュリティキーの認証機構で広く使われています。

EIP7932は、secp256k1以外の署名アルゴリズムも同じ`sigrecover`プリコンパイルから扱う設計です。
EIP8030は、P256をその最初の追加アルゴリズムとして登録する役割を持ちます。

#### 公開鍵を署名コンテナに含める理由

secp256k1の既存署名では、`r`、`s`、`y_parity`から公開鍵を復元できます。
そのため、署名だけで署名者の公開鍵を取り出せます。

P256では、EIP8030の処理は公開鍵復元ではなく、指定された公開鍵に対する署名検証です。
そのため、署名コンテナに`x`と`y`を含め、`P256Verify`で署名データと公開鍵の対応を確認します。

#### 32バイト以外の署名データ

P256検証そのものは32バイトのメッセージハッシュを入力にします。
EIP8030では、`signing_data`が32バイトではない場合、`keccak256(signing_data)`を計算してから検証します。

この扱いはEIP7932のsecp256k1アルゴリズムと揃っています。
アプリケーション側は、すでに32バイトのハッシュを渡す場合と、任意長の署名対象データを渡す場合の両方を扱えます。

## 互換性

EIP8030は、新しいP256アルゴリズムをEIP7932のレジストリへ追加する提案です。
既存のsecp256k1署名、既存のコントラクト、既存の`ECRECOVER`プリコンパイルの挙動は変更しません。

P256署名を使いたい処理だけが、`ALG_TYPE = 0x01`の署名コンテナを作り、EIP7932の`sigrecover`を通じて検証します。
そのため、EIP8030単体で既存アプリケーションの署名方式を置き換えるものではありません。

## セキュリティ

EIP8030で重要なのは、P256署名の可鍛性と、公開鍵を署名コンテナに含める設計です。
`s <= N / 2`の制約により、同じ署名内容に対して高い`s`値と低い`s`値の2種類が通る状態を避けます。
これにより、署名のバイト列表現が変わることによる混乱を減らせます。

公開鍵`x`と`y`は署名コンテナに含まれるため、検証処理は「この公開鍵がこの署名データへ署名したか」を確認します。
検証に成功した公開鍵だけがEIP7932のアドレス導出へ渡されます。
公開鍵と署名の対応を確認せずにアドレスを導出すると、署名者ではない公開鍵からアドレスを作る危険があります。

EIP8030はP256検証ロジックとしてEIP7951の`P256Verify`を使います。
そのため、入力長、`r`と`s`の範囲、公開鍵座標の範囲、曲線上の点であること、無限遠点ではないことは、EIP7951側の検証要件と同じ前提で扱われます。

## 引用

James Kempton (@SirSpudlington), "EIP8030: P256 algorithm support [DRAFT]," Ethereum Improvement Proposals, no. 8030, September 2025. Available: https://eips.ethereum.org/EIPS/eip-8030.

## 最後に

今回は「**EIP8030**」についてまとめてきました。

EIP8030は、P256署名をEIP7932の署名アルゴリズムとして登録する提案です。
P256の実際の検証にはEIP7951の`P256Verify`ロジックを使い、検証に成功した公開鍵をEIP7932のアドレス導出へ渡します。
P256を`sigrecover`の共通インターフェースで扱えるようにすることで、セキュアハードウェアやWebAuthn系の署名をEthereumのアドレス導出ルールへ接続しやすくなります。

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

https://amzn.asia/d/gxvJ0Pw

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

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/
