# [ERC7951] プリコンパイルにP-256検証を実装してデバイス署名を使える仕組みを理解しよう！

> ERC7951は、楕円曲線暗号方式であるsecp256r1（別名：P-256またはprime256v1）に基づくECDSA署名検証を、Ethereum上で効率的に行えるようにするための「プリコンパイル（precompile）」を追加する提案

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

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、Ethereumにsecp256r1（P-256）署名検証のプリコンパイルを追加し、iPhone等のハードウェア鍵やWebAuthnの署名を安全・低コストに検証できる仕組みを提案している**ERC7951**についてまとめていきます！

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

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

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

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

## 概要

**ERC7951**は、楕円曲線暗号方式である**secp256r1**（別名：P-256またはprime256v1）に基づくECDSA署名検証を、Ethereum上で効率的に行えるようにするための「**プリコンパイル（precompile）**」を追加する提案です。
プリコンパイルとは、特定の計算処理をEVM（Ethereum Virtual Machine）の内部でネイティブに実行できる仕組みであり、複雑な処理を高速かつ低コストで実行できるようになります。

この仕様により、AppleのSecure EnclaveやAndroidのKeystore、FIDO2/WebAuthnデバイスなど、最新のセキュアハードウェアで生成された署名をEthereum上で直接検証することが可能になります。
また、**ERC7951**、以前に提案された**RIP7212**で発見されたセキュリティ上の問題を解決しつつ、既存のLayer2実装との互換性を維持しています。
つまり、安全性を強化しながら、既存の仕組みを壊すことなく利用できるように設計されています。

## 動機

**ERC7951**の背景には、**secp256r1**曲線が現代のセキュアハードウェアや認証システムで広く採用されているという現実があります。
**secp256r1**は、NIST（米国標準技術研究所）によって標準化された楕円曲線であり、長年にわたり広く利用されてきました。

特に以下のようなデバイスや仕組みで標準的に使用されています。

* Apple Secure Enclave
* Android Keystore
* ハードウェアセキュリティモジュール（HSM）
* 信頼実行環境（TEE）
* FIDO2／WebAuthn認証デバイス

これらのデバイスは、鍵の生成や署名をsecp256r1ベースで行うため、Ethereumがネイティブにsecp256r1をサポートすれば、ユーザーはすでに手元にあるデバイスを利用してEthereumアカウントをより安全かつ簡単に管理できるようになります。
例えば、スマートフォンの生体認証や多要素認証をそのまま活用し、秘密鍵管理の煩雑さを大幅に減らすことができます。

また、これにより以下のような新しい活用シナリオが可能になります。

* デバイスネイティブ署名
    ユーザーが既存の端末で直接Ethereumトランザクションに署名
* 多要素認証
    複数デバイスや認証方式を組み合わせた高度なセキュリティ
* 鍵管理の簡素化
    従来の秘密鍵管理に伴うリスクや手間の軽減

さらに、secp256r1はすでに多くのブロックチェーンやプロトコルでサポートされているため、Ethereumにおいても導入することで他のシステムとの互換性が高まり、より広範な相互運用性を実現できます。

## 仕様

### プリコンパイル

新たに導入される`P256VERIFY`は、アドレス`0x100`に配置されるプリコンパイルです。
この処理は、secp256r1に基づいたECDSA署名検証を行います。
ガスコストは**6900ガス**に設定されています。

### 曲線パラメータ

secp256r1曲線は、NISTが標準化した楕円曲線であり、以下のパラメータで定義されています。

| 項目 | 値  |
| ---- | -- |
| 基本体の法 (p)  | `0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff` |
| 曲線方程式 | y² = x³ + ax + b (mod p) |
| 係数 a | `0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc` |
| 係数 b | `0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b` |
| 基点 G (x座標) | `0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296` |
| 基点 G (y座標) | `0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5` |
| サブグループ位数 n | `0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551` |
| コファクタ h | `0x1` |

これらのパラメータは「**NIST SP 800-186**」で定義されています。

### フィールドとグループ

* **有限体Fp**
    大きさpの有限体であり、要素は0からp−1までの整数です。
* **群G**
    Fp上の点(x, y)で、曲線方程式を満たすもの、または無限遠点を含みます。

### 点とエンコーディング

1. **有限体要素のエンコード**
    32バイトのBigEndian形式で表現します。
    整数はp未満でなければなりません。
2. **群Gの点のエンコード**
    x座標とy座標をそれぞれ32バイトにエンコードし、連結して64バイトとします。
3. **無限遠点のエンコード**
    (0,0)は曲線上の点ではないため、64バイトすべてゼロを用いて無限遠点を表現します。
4. **スカラーのエンコード**
    32バイトBigEndianで表現します。
    整数はサブグループ位数n以下でなくても構いません。

### 無効入力の扱い

不正な入力があった場合（エンコード形式が正しくない、点が曲線上に存在しないなど）、プリコンパイルは空の出力\`\`を返します。
リバート（処理全体の巻き戻し）は行いません。

### P256VERIFYのABI

#### 入力形式

合計160バイトで、以下を順番に連結します。

| サイズ   | 内容          |
| ----- | ----------- |
| 32バイト | メッセージハッシュ h |
| 32バイト | 署名のr成分      |
| 32バイト | 署名のs成分      |
| 32バイト | 公開鍵のx座標 qx  |
| 32バイト | 公開鍵のy座標 qy  |

#### 出力形式

| 状態          | 出力                |
| ----------- | ----------------- |
| 検証成功        | 32バイトの値 `0x...01` |
| 検証失敗または不正入力 | 空の出力 \`\`         |

### 入力バリデーション

プリコンパイルは必ず以下の検証を行い、条件を満たさない場合は失敗を返します。

1. 入力長は160バイトでなければならない。
2. 署名成分 `r`, `s` は `0 < r < n` および `0 < s < n` を満たさなければならない。
3. 公開鍵 `qx`, `qy` は `0 ≤ qx < p` および `0 ≤ qy < p` を満たさなければならない。
4. 点 (`qx`, `qy`) は曲線方程式を満たさなければならない。
5. 点 (`qx`, `qy`) は無限遠点であってはならない。

### 署名検証アルゴリズム

```python
# 入力検証
if input_length != 160:
    return
if not (0 < r < n and 0 < s < n):
    return
if not (0 ≤ qx < p and 0 ≤ qy < p):
    return 
if qy^2 ≢ qx^3 + a*qx + b (mod p):
    return
if (qx, qy) == (0, 0):
    return

# 署名検証
s1 = s^(-1) (mod n)

# 署名時のランダム点を再計算
R' = (h * s1) * G + (r * s1) * (qx, qy)

# 無限遠点チェック
if R' is the point at infinity:
    return

# x座標を抽出
r' = R'.x

# rとの比較
if r' ≡ r (mod n):
    return 0x...01
else:
    return
```

### エラーケース

* 入力長が160バイトでない
* フィールド要素のエンコードがp以上
* rやsが範囲外
* 公開鍵が無効または無限遠点
* 署名検証に失敗

### ガススケジュール

`P256VERIFY`のガスコストは**6900ガス**です。
これは既存の`ECRECOVER`プリコンパイル（3000ガス）より高く設定されています。
理由は、ベンチマークによりR1検証がより計算コストの高い処理であることが確認されたためです。

### エラー時のガス消費

エラーが発生した場合でも、プリコンパイルはリバートせず空の出力を返します。
また、成功時と同じガスを消費します。
これにより、ガスの扱いが一貫し、予測可能な挙動となります。

## 補足

### セキュリティ修正

**ERC7951**は、過去の提案である**RIP7212**に存在した2つの重大な脆弱性を解消しています。

#### 無限遠点（Point-at-infinity）の確認

**RIP7212**では、署名検証の過程で導出される点R’が無限遠点であるかどうかを確認していませんでした。
無限遠点は楕円曲線暗号において特別な扱いを受ける点で、適切に扱わなければ実装依存の挙動や不一致を招く可能性があります。
具体的には、ある実装では検証成功と判定され、別の実装では失敗と判定されるといった非決定的な動作が起き、最悪の場合はネットワーク全体の合意（コンセンサス）崩壊につながります。
**ERC7951**では、R’が無限遠点であれば必ず失敗として扱うよう明示され、問題を防止しています。

#### モジュラ比較の修正

**ERC7951**では、比較が `r' == r` と書かれていました。
しかし、数学的に正しいのは `r' ≡ r (mod n)` です。
なぜなら、R’のx座標は曲線の位数nを超えることがあり、その場合は `mod n` で剰余を取る必要があるからです。
この修正により、ECDSA標準に則った正しい検証が行われ、不正な署名が通過してしまうリスクを防ぎます。

### 検証と復元の違い

**ERC7951**では、`ECRECOVER`のような公開鍵復元方式ではなく、署名検証（Verification）を採用しています。
その理由は以下です。

* **既存実装との整合性**
    secp256r1を扱うほとんどのハードウェアやソフトウェアは、公開鍵の復元ではなく署名検証を直接行う設計になっています。
* **標準規格に準拠**
    NISTのFIPS 186-5規格でも署名検証のみが定義されており、復元方式は含まれていません。
    よって、標準準拠の観点からも検証方式が正しいといえます。
* **効率性**
    secp256r1曲線では、署名検証の方が計算的に効率的です。
    公開鍵復元は追加の計算が必要となり、無駄が多くなります。
* **ハードウェアサポート**
    Apple Secure EnclaveやFIDO2デバイスなど、現実に広く使われているハードウェアは「**署名検証**」を提供しており、復元機能は提供していません。
    したがって、実際の利用環境に即した形でEthereumでも検証方式を採用することが自然です。

### ガスコストの妥当性

今回のプリコンパイル`P256VERIFY`のガスコストは**6900ガス**に設定されています。

これは既存の`ECRECOVER`（3000ガス）とは互換性がなく、またLayer2との完全一致を保つものではありません。
しかし、ベンチマークの結果、実際のsecp256r1署名検証の計算コストはECRECOVERよりも大幅に高いことがわかっています。

したがって、6900ガスという値は理論値ではなく、実際の実装やハードウェアでの処理速度を反映した現実的なコストとして採用されました。
この調整により、Ethereum上での署名検証が現実的なリソース消費に基づいた安全な運用となります。

## 互換性

**ERC7951**は、Layer2上ですでに展開されている**RIP7212**実装とインターフェース互換を完全に維持します。
ここでいうインターフェース互換とは、呼び出し先アドレス、入力と出力のバイト配列の形、戻り値の意味が同一であるため、既存のコントラクトバイトコードを変更せずにそのまま動かせるという意味です。
今回のセキュリティ修正は、もともと失敗すべき境界ケースだけに影響するため、正しく実装された呼び出し側の通常ユースケースは壊れません。

#### インターフェース互換性

互換性の要点を表に整理します。
ガスコスト以外は同一です。
ガスコストは実測に合わせて見直されているため、ロジック互換は維持しつつ、経済面（ガス見積もり）だけが異なると理解してください。

| 項目 | **ERC7951** | **RIP7212** | 互換性の評価 |
| ---- | ---------- | ------------ | ---------- |
| プリコンパイルアドレス | `0x100` | `0x100` | 同一 |
| 入力フォーマット | 160バイト（`h‖r‖s‖qx‖qy`） | 160バイト | 同一 |
| 出力フォーマット | 32バイト | 32バイト | 同一 |
| 戻り値の意味 | 成功時`0x…01`／失敗時空 | 同一 | 同一 |
| ガスコスト | **6900 gas** | **3450 gas** | 異なる（実装ベンチマークに整合） |

## セキュリティ

#### 暗号学的安全性

**ERC7951**が対象とする**secp256r1**は、**128ビット**の安全性を提供します。
これは、Ethereumで広く用いられている**secp256k1**と同等クラスの安全強度です。
曲線パラメータは**NIST SP 800-186**（文書中の表記に従います）で標準化され、広く暗号コミュニティによる解析を受けています。
さらに、この曲線は**RIP7212**の形で複数のLayer2にも既に展開されており、実運用での知見が蓄積されています。

#### 可鍛性

可鍛性とは、署名の一部を変えても検証が通ってしまう可能性がある性質を指します。
secp256k1では、`non-malleable`（不可鍛）とするために`S`の範囲制約（いわゆる「low-S」）を実装ポリシーとして採用するのが一般的です。
一方、**secp256r1**のECDSA署名はFIPS 186-5の規格上、非可鍛性を必須要件としていません。
そのため、非可鍛性を求めるアプリケーションは、アプリケーション層で追加チェック（例：`S ≤ n/2`の強制）を実装にする必要があります。
具体的には、`s`をサブグループ位数`n`の半分以下に制限する等のポリシーを、コントラクトや上位の認証レイヤーで適用します。
**ERC7951**で提案されているプリコンパイルは、標準に準拠した検証を提供しますが、不可鍛性の保証はアプリケーション設計の範囲で行うという整理です。

#### サイドチャネル耐性

**サイドチャネル攻撃**とは、処理時間や消費電力など、本来の出力以外の「**副次的な情報**」から秘密情報を推測する攻撃です。
これを防ぐ方法の一つとして、入力の値にかかわらず常に同じ時間で処理が終わるように設計された定数時間（constant-time）アルゴリズムを使う手法があります。

**ERC7951**では、すべての演算を定数時間で実装することは必須要件としていません。
つまり「**必ず定数時間でなければならない**」とは規定していない、ということです。

この前提は、プリコンパイルの目的を機能そのものの仕様に絞り込み、具体的な最適化方法やサイドチャネル耐性の強化については実装者の判断に委ねる立場を明確にしています。
もし利用者がより強いサイドチャネル耐性を求めるのであれば、リスク評価に応じて実装の選定や運用上の追加対策（例：専用ハードウェアでの隔離、レート制御の導入など）を検討するのが現実的です。

## 引用

Carl Beekhuizen (@carlbeek), Ulaş Erdoğan (@ulerdogan), Doğan Alpaslan (@doganalpaslan), "EIP-7951: Precompile for secp256r1 Curve Support [DRAFT]," Ethereum Improvement Proposals, no. 7951, May 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7951.

## 最後に

今回は「Ethereumにsecp256r1（P-256）署名検証のプリコンパイルを追加し、iPhone等のハードウェア鍵やWebAuthnの署名を安全・低コストに検証できる仕組みを提案している**ERC7951**」についてまとめてきました！
いかがだったでしょうか？

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