以太坊密碼學基礎完整指南:橢圓曲線與數位簽章
深入探討以太坊的密碼學基礎,包括 secp256k1 橢圓曲線、ECDSA 簽章演算法、Keccak-256 雜湊函數,以及它們如何在以太坊中協同工作,提供完整的數學原理與程式碼範例。
以太坊密碼學基礎完整指南:橢圓曲線與數位簽章
概述
密碼學是以太坊安全性的基石。從帳戶地址生成到交易簽章驗證,從智慧合約狀態雜湊到共識機制,密碼學無處不在。理解這些底層技術不僅對於區塊鏈開發者至關重要,也是評估系統安全性的必要知識。
本文深入探討以太坊使用的密碼學技術,特別是 secp256k1 橢圓曲線、ECDSA 簽章演算法、Keccak-256 雜湊函數,以及它們如何在以太坊生態中協同工作。我們將從數學原理出發,結合實際程式碼範例,幫助讀者建立完整的密碼學知識體系。
一、橢圓曲線密碼學基礎
1.1 橢圓曲線數學原理
橢圓曲線密碼學(Elliptic Curve Cryptography, ECC)是一種基於橢圓曲線代數結構的公鑰密碼學系統。與傳統的 RSA 相比,ECC 以更短的密鑰長度提供同等的安全性,這使其特別適合資源受限的區塊鏈環境。
橢圓曲線的數學定義如下:
y² = x³ + ax + b (mod p)
其中 a 和 b 是曲線參數,p 是大質數。以太坊使用的 secp256k1 曲線參數為:
- a = 0
- b = 7
- p = 2^256 - 2^32 - 977
這個曲線在有限域 Fp 上定義,意味著所有運算都對質數 p 取模。曲線上的點 (x, y) 滿足上述方程,且存在一個特殊的無窮遠點 O(稱為零點或 identity element)。
1.2 橢圓曲線上的運算
點加法:給定曲線上兩個不同點 P 和 Q,存在唯一第三點 R = P + Q,其計算方式為:
λ = (y₂ - y₁) / (x₂ - x₁) (mod p)
x₃ = λ² - x₁ - x₂ (mod p)
y₃ = λ(x₁ - x₃) - y₁ (mod p)
倍點運算:給定曲線上一点 P,計算 nP(即 P 添加自身 n 次)稱為倍點運算。這是 ECC 安全性的核心——已知點 P 和 nP 計算 n 在計算上是不可行的(離散對數問題)。
λ = (3x₁² + a) / (2y₁) (mod p)
x₃ = λ² - 2x₁ (mod p)
y₃ = λ(x₁ - x₃) - y₁ (mod p)
1.3 橢圓曲線的安全性
橢圓曲線密碼學的安全性基於以下計算困難問題:
- 橢圓曲線離散對數問題(ECDLP):給定曲線上點 P 和 Q = nP,在計算上無法有效地確定 n。
- 橢圓曲線 Diffie-Hellman(ECDH):允許雙方在不安全通道上建立共享密鑰。
- 橢圓曲線數位簽章演算法(ECDSA):用於數位簽章和身份驗證。
這些問題的計算困難性使得 ECC 能夠以較短的密鑰提供與 RSA 相當的安全性。根據 NIST 建議,256 位 ECC 密鑰大致相當於 3072 位 RSA 密鑰的安全性。
二、secp256k1 曲線詳解
2.1 曲線參數
secp256k1 是以太坊採用的橢圓曲線,其標準化參數定義如下:
曲線方程:y² = x³ + 7
質數 p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
= 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
基點 G 的座標:
Gx = 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
Gy = 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8
基點階 n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
輔助因子 h = 1
選擇 secp256k1 的原因包括:
- 效率:曲線參數經過優化,點運算速度快
- 安全性:曲線結構已知是安全的,沒有已知弱點
- 簡潔:參數選擇簡單,易於實現
- 比特幣先例:比特幣已採用此曲線,有豐富的實作經驗
2.2 基點與生成元
基點 G 是曲線上的一個特殊點,所有其他點都可以通過重複倍點運算生成。基點的選擇必須確保其階 n 是質數,且 n 乘以任何小整數都不會得到零點。
在 secp256k1 中,基點 G 的選擇經過精心設計,確保:
- n 是質數(便於生成循環群)
- n 不是 p 的因數(確保每個點都有唯一的倍點序列)
- n 的二進製表示不是全 0 或全 1(便於實現)
2.3 點壓縮與表示
橢圓曲線點可以使用多種表示方式:
未壓縮表示:04 [X座標][Y座標],共 65 位元組
壓縮表示:
- 如果 Y 是偶數:02 [X座標]
- 如果 Y 是奇數:03 [X座標]
共 33 位元組
以太坊地址生成中使用未壓壓縮表示,而交易簽章中則使用壓縮表示以節省空間。
三、ECDSA 數位簽章演算法
3.1 簽章生成過程
ECDSA(Elliptic Curve Digital Signature Algorithm)是以太坊使用的數位簽章標準。簽章過程如下:
輸入:私鑰 d、消息 m
輸出:簽章 (r, s)
1. 計算消息雜湊:e = SHA256(m) 或使用 Keccak-256
2. 生成隨機臨時密鑰 k(重要:必須隨機且每次不同)
3. 計算臨時公鑰:
R = k * G
r = Rx mod n(取 x 座標對 n 取模)
4. 計算 s:
s = k⁻¹ * (e + r * d) mod n
其中 k⁻¹ 是 k 在模 n 下的乘法逆元
5. 如果 r = 0 或 s = 0,重新選擇 k
返回值:(r, s)
3.2 簽章驗證過程
輸入:公鑰 Q、消息 m、簽章 (r, s)
輸出:有效/無效
1. 驗證 r, s 在有效範圍內:
1 ≤ r < n
1 ≤ s < n
2. 計算消息雜湊:e = SHA256(m) 或 Keccak-256
3. 計算 s 的逆元:s⁻¹ mod n
4. 計算:
u₁ = e * s⁻¹ mod n
u₂ = r * s⁻¹ mod n
5. 計算驗證點:
P = u₁ * G + u₂ * Q
6. 驗證:
如果 P 是無窮遠點,返回無效
計算 v = Px mod n
如果 v = r,返回有效
否則返回無效
3.3 臨時密鑰 k 的重要性
臨時密鑰 k 的選擇對 ECDSA 安全性至關重要:
重用 k 的災難:
如果相同的 k 用於簽章兩條不同消息,可以從兩個簽章中直接計算出私鑰:
假設使用相同 k 簽署消息 m1 和 m2:
s1 = k⁻¹ * (e1 + r * d) mod n
s2 = k⁻¹ * (e2 + r * d) mod n
通過代數運算:
d = (s1 * e1 - s2 * e2) * (s2 * r - s1 * r)⁻¹ mod n
比特幣和以太坊歷史上都發生過因 k 重用導致私鑰洩露的事件。2010 年比特幣客戶端曾因隨機數生成器問題導致私鑰洩露。
確定性簽章(RFC 6979):
為避免隨機數生成問題,RFC 6979 定義了確定性 ECDSA:
- 使用消息雜湊和私鑰通過確定性過程生成 k
- 每次簽章相同消息會得到相同簽章
- 消除了對真正隨機數的需求
以太坊客戶端通常實現確定性簽章,確保安全性。
3.4 簽章類型:Replay Protection
以太坊使用交易的 RLP 編碼內容作為簽章消息,這自動提供了 replay protection:
- 每筆交易有唯一的 nonce
- 每筆交易綁定到特定鏈(chainId)
- 簽章不能在其他鏈上重放
四、以太坊地址生成
4.1 從私鑰到地址
以太坊地址生成過程如下:
1. 生成隨機私鑰:256 位隨機數 d(1 到 n-1 之間)
2. 生成公鑰:Q = d * G
- 使用橢圓曲線倍點運算
- 公鑰是曲線上的一個點 (x, y)
3. Keccak-256 雜湊公鑰:
h = Keccak256(0x04 || Qx || Qy)
注意:使用 0x04 前綴表示未壓縮公鑰
4. 取雜湊最後 20 位元組作為地址:
address = "0x" || last20Bytes(h)
5. 通常轉換為 checksum 格式:
EIP-55:對地址字母大小寫進行編碼
4.2 地址空間
以太坊地址是 20 位元組(160 位):
- 總地址數:2^160 ≈ 1.46 × 10^48
- 這是一個極大的空間,實際上不可能發生地址碰撞
4.3 EOA 與合約帳戶
以太坊有兩種帳戶類型:
外部擁有帳戶(EOA):
- 由私鑰控制
- 地址由公鑰雜湊生成
- 可以發起交易
- 沒有關聯的程式碼
合約帳戶:
- 由部署的程式碼控制
- 地址由 CREATE 操作碼生成
- 不能主動發起交易
- 可以回應呼叫
兩種帳戶類型共享相同的地址空間,但控制方式完全不同。
五、Keccak-256 雜湊函數
5.1 Keccak 演算法
Keccak 是 SHA-3 標準的基礎演算法,採用海綿結構(Sponge Construction):
┌────────────────────────────────────────────┐
│ │
│ Message Input ──▶│ f │──▶ Hash Output │
│ │ │ │
│ (padding) │ │ (optional) │
│ └──────┘ │
│ Rate (r) Capacity (c) │
└────────────────────────────────────────────┘
Keccak-256 的參數:
- 輸出長度:256 位元
- 速率 r = 1088 位元(1600 - 512)
- 容量 c = 512 位元
- 輸出安全性:256 位元
5.2 以太坊中的 Keccak
以太坊使用 Keccak-256(而非標準化的 SHA-3-256)用於:
- 地址生成
- 狀態雜湊
- 交易雜湊
- Merkle Patricia Trie
為什麼選擇 Keccak:
- SHA-3 標準化時以太坊已經使用 Keccak
- Keccak 已經過充分審計
- 避免與 NIST SHA-3 標準可能的關聯
5.3 Keccak vs SHA-3
雖然 Keccak 是 SHA-3 的基礎,但兩者不完全相同:
- SHA-3 使用不同的 padding
- SHA-3 有更多的配置參數
- 輸出結果不同,不能互換使用
在以太坊生態中,引用 "sha3" 通常指的是 Keccak-256。
5.4 雜湊函數的安全性要求
密碼學雜湊函數必須滿足:
- 原像阻力:給定雜湊值 h,找到滿足 SHA256(m) = h 的 m 在計算上不可行
- 第二原像阻力:給定 m1,找到滿足 SHA256(m1) = SHA256(m2) 的 m2 ≠ m1 在計算上不可行
- 碰撞阻力:找到任意滿足 SHA256(m1) = SHA256(m2) 的 m1 ≠ m2 在計算上不可行
- 雪崩效應:輸入變化一位,輸出平均變化約 50%
Keccak-256 被認為具備所有這些安全特性。
六、簽章與交易驗證
6.1 交易類型
以太坊有不同類型的交易:
Legacy 交易(Type 0):
RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])
EIP-2930 交易(Type 1):
RLP([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, v, r, s])
EIP-1559 交易(Type 2):
RLP([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, accessList, v, r, s])
6.2 簽章訊息
不同交易類型使用不同的簽章訊息:
Legacy 交易:
msg = SHA3(RLP([nonce, gasPrice, gasLimit, to, value, data]))
EIP-1559 交易:
msg = SHA3(0x02 || RLP([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, accessList]))
6.3 驗證流程
節點收到交易後的驗證流程:
1. 格式驗證:
- RLP 解碼成功
- 所有欄位類型正確
- 無效字段為空
2. 範圍驗證:
- nonce 是非負整數
- gasLimit > 0
- value >= 0
- 簽章 (r, s) 在有效範圍內
3. 鏈 ID 驗證(EIP-155):
- 從 v 值提取 chainId
- 必須匹配當前鏈
4. 簽章驗證:
- 恢復公鑰
- 驗證簽章有效性
5. 帳戶狀態驗證:
- nonce 正確
- 餘額足夠支付 gas
6. Gas 估算:
- 估算執行成本
- 確保 gasLimit 足夠
6.4 ECRECOVER 與公鑰恢復
以太坊提供 ECRECOVER 操作碼用於從簽章恢復地址:
function ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
工作原理:
- 使用 v, r, s 計算可能的公鑰點
- 從公鑰計算地址
- 返回地址
注意:ECRECOVER 在以下情況會返回零地址:
- 簽章無效
- k 值不在有效範圍
這是許多簽章相關漏洞的根源,開發者應注意處理這種情況。
七、常見漏洞與防護
7.1 簽章重放攻擊
問題:未經授權的第三方可以重放有效的交易。
以太坊防護:
- 每筆交易包含唯一的 nonce
- 每筆交易綁定到特定 chainId
- EIP-155 防止跨鏈重放
7.2 密鑰管理漏洞
問題:私鑰洩露導致資金被盜。
防護建議:
- 使用硬體錢包
- 實施多重簽章
- 使用 MPC 方案
- 實施角色分離
7.3 隨機數生成漏洞
問題:弱隨機數導致私鑰或簽章可預測。
防護:
- 使用確定性簽章(RFC 6979)
- 使用硬體隨機數生成器
- 避免使用區塊變數作為隨機源
7.4 橢圓曲線攻擊
問題:針對特定曲線參數的攻擊。
防護:
- 使用經過驗證的曲線(如 secp256k1)
- 驗證所有曲線點
- 實施適當的錯誤處理
八、程式碼範例
8.1 Python 實現橢圓曲線運算
import hashlib
# secp256k1 曲線參數
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
A = 0
B = 7
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return f"({hex(self.x)}, {hex(self.y)})"
# 零點(無窮遠點)
ZERO = Point(None, None)
def mod_inverse(a, m):
"""計算模逆元"""
if a < 0:
a = (a % m + m) % m
g, x, _ = extended_gcd(a, m)
if g != 1:
raise Exception('Modular inverse does not exist')
return x % m
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
def point_add(p1, p2):
"""橢圓曲線點加法"""
if p1 == ZERO:
return p2
if p2 == ZERO:
return p1
if p1.x == p2.x:
if p1.y == p2.y:
return point_double(p1)
return ZERO
# 計算斜率
slope = ((p2.y - p1.y) * mod_inverse(p2.x - p1.x, P)) % P
# 計算新點
x3 = (slope * slope - p1.x - p2.x) % P
y3 = (slope * (p1.x - x3) - p1.y) % P
return Point(x3, y3)
def point_double(p):
"""橢圓曲線倍點"""
if p == ZERO:
return p
# 計算斜率
slope = ((3 * p.x * p.x + A) * mod_inverse(2 * p.y, P)) % P
# 計算新點
x3 = (slope * slope - 2 * p.x) % P
y3 = (slope * (p.x - x3) - p.y) % P
return Point(x3, y3)
def scalar_mult(k, p):
"""標量乘法(二進制法)"""
result = ZERO
while k:
if k & 1:
result = point_add(result, p)
p = point_double(p)
k >>= 1
return result
8.2 地址生成範例
def keccak256(data):
"""Keccak-256 雜湊"""
import sha3
k = sha3.keccak_256()
k.update(data)
return k.digest()
def pubkey_to_address(pubkey_bytes):
"""從公鑰字節生成以太坊地址"""
# Keccak-256 雜湊公鑰
h = keccak256(pubkey_bytes)
# 取最後 20 位元組
return "0x" + h[-20:].hex()
def generate_address_from_private_key(private_key_hex):
"""從私鑰生成以太坊地址"""
# 將私鑰轉換為整數
d = int(private_key_hex, 16)
# 生成公鑰
G = Point(Gx, Gy)
Q = scalar_mult(d, G)
# 轉換為未壓縮格式(0x04 前綴)
pubkey_bytes = b'\x04' + Q.x.to_bytes(32, 'big') + Q.y.to_bytes(32, 'big')
# 生成地址
return pubkey_to_address(pubkey_bytes)
# 測試
test_privkey = "0x" + "01" * 32 # 測試私鑰
address = generate_address_from_private_key(test_privkey)
print(f"測試地址: {address}")
8.3 ECDSA 簽章範例
def hash_message(message):
"""對消息進行 Keccak-256 雜湊"""
if isinstance(message, str):
message = message.encode('utf-8')
return int.from_bytes(keccak256(message), 'big')
def sign_message(message, private_key):
"""ECDSA 簽章(確定性 RFC 6979)"""
e = hash_message(message)
d = private_key
# RFC 6979 確定性 k 生成
v = b'\x01' * 32
k = b'\x00' * 32
# 這裡省略 RFC 6979 完整實現
# 實際實現需要複雜的確定性隨機數生成
# 計算 r, s
G = Point(Gx, Gy)
R = scalar_mult(k, G)
r = R.x % N
s = (mod_inverse(k, N) * (e + r * d)) % N
return (r, s)
def verify_signature(message, signature, public_key):
"""驗證 ECDSA 簽章"""
r, s = signature
# 驗證 r, s 範圍
if not (1 <= r < N and 1 <= s < N):
return False
e = hash_message(message)
s_inv = mod_inverse(s, N)
u1 = (e * s_inv) % N
u2 = (r * s_inv) % N
G = Point(Gx, Gy)
P = point_add(scalar_mult(u1, G), scalar_mult(u2, public_key))
if P == ZERO:
return False
return (P.x % N) == r
九、未來發展:後量子密碼學
9.1 量子計算威脅
量子計算機的發展對現有密碼學構成潛在威脅:
Shor 演算法:可在多項式時間內分解大整數和計算離散對數
- 威脅 RSA、ECDSA、ECDSA
- 需要大約 4000 邏輯量子位元
Grover 演算法:可加速雜湊函數暴力搜索
- 雜湊函數安全性減半
- 需要 256 位元以上輸出以維持安全性
9.2 後量子密碼學候選
基於格(Lattice-based):
- Kyber(密鑰封裝)
- Dilithium(數位簽章)
基於雜湊(Hash-based):
- SPHINCS+(數位簽章)
- XMSS(數位簽章)
基於碼(Code-based):
- McEliece(密鑰封裝)
9.3 以太坊的應對
以太坊社區正在評估後量子遷移策略:
- 短期:關注量子計算發展態勢
- 中期:準備遷移路徑
- 長期:可能需要硬分叉升級
預計在量子計算機實際威脅到 secp256k1 之前,以太坊有充足時間進行準備。
總結
以太坊的密碼學基礎建立在經過驗證的橢圓曲線密碼學之上。secp256k1 曲線、ECDSA 簽章和 Keccak-256 雜湊函數共同構成了以太坊安全性的基石。
理解這些底層技術對於:
- 開發安全的智慧合約
- 設計錢包和簽章方案
- 審計密碼學實現
- 評估系統安全性
至關重要。雖然這些技術對大多數用戶是透明的,但任何安全相關的決策都應該基於對這些基礎原理的理解。
隨著後量子密碼學的發展,以太坊密碼學棧也將持續演進。開發者和安全專業人員應持續關注這些領域的最新發展,確保系統的安全性能夠應對未來的挑戰。
相關文章
- 後量子密碼學與以太坊遷移策略完整指南:從威脅評估到長期規劃 — 深入分析量子計算對以太坊的威脅、CRYSTALS-Kyber、Dilithium 等 NIST 後量子密碼學標準,以及以太坊的遷移時間軸與機構準備策略,提供完整的技術實施細節與風險評估框架。
- EIP-1559 深度解析:以太坊費用市場的範式轉移 — 深入解析 EIP-1559 的費用結構、ETH 燃燒機制、經濟學意涵,以及對用戶、驗證者和生態系統的影響。
- EIP-7702 帳戶抽象完整指南 — 深入介紹 EIP-7702 讓 EOA 臨時獲得合約功能的技术原理,涵蓋社交恢復錢包、自動化交易、權限委托等應用場景。
- 智能合約部署實戰:從環境搭建到主網上線 — 涵蓋從開發環境準備、本地測試、測試網部署、正式環境部署的完整流程,深入探討 Gas 優化、安全審計、合約升級等進階主題,提供開發者從新手到專業的實戰指南。
- Proto-Danksharding 與以太坊分片路線圖完整指南 — 深入解析 EIP-4844 的技術原理、KZG 承諾機制、Blob 費用市場,以及完整分片路線圖的長期發展願景。
延伸閱讀與來源
- Ethereum.org Developers 官方開發者入口與技術文件
- EIPs 以太坊改進提案
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!