以太坊密碼學原語視覺化教程:Keccak、BLS 簽名、橢圓曲線點加法完全解讀
本文以視覺化和互動式教學為導向,深入解析以太坊底層使用的三大密碼學原語:Keccak-256 雜湊函數的海綿結構與應用、BLS 簽名的聚合機制與以太坊 PoS 共識、以及 secp256k1 橢圓曲線密碼學的點加法運算。透過大量圖解、Python 和 Solidity 程式碼範例,讓讀者直觀理解這些看似抽象的密碼學概念如何在以太坊中實際運作。
以太坊密碼學原語視覺化教程:Keccak、BLS 簽名、橢圓曲線點加法完全解讀
密碼學這東西,看官方文件的話真的很催眠。那些數學符號跟天書一樣,看兩行就開始神遊。但其實密碼學的概念沒有那麼抽象,今天我用大白話把以太坊背後的密碼學原語全部拆解給你看。
以太坊用了哪些密碼學?
以太坊這套系統,靠的主要是三類密碼學工具:
┌─────────────────────────────────────────────────────────┐
│ 以太坊密碼學工具箱 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 雜湊函數(Hash Function) │
│ → Keccak-256(以太坊的選擇) │
│ → 用途:生成地址、驗證資料完整性、狀態根 │
│ │
│ 2. 數位簽名(Digital Signature) │
│ → ECDSA(主網交易簽名) │
│ → BLS(聚合簽名,用於 PoS 共識) │
│ → 用途:驗證交易所有權、區塊簽名 │
│ │
│ 3. 橢圓曲線密碼學(ECC) │
│ → secp256k1 曲線(比特幣和以太坊共用) │
│ → 用途:公私鑰生成、簽名驗證 │
│ │
└─────────────────────────────────────────────────────────┘
這三樣東西組合在一起,就構成了以太坊的安全基礎。讓我們一個一個來拆解。
第一章:Keccak-256 雜湊函數
什麼是雜湊函數?
先把術語翻成人話。雜湊函數就像是一台神奇的絞肉機:
- 你把任何東西(一只蘋果、一本書、甚至一整套《大英百科全書》)丟進去
- 絞出來的東西永遠是固定長度的一串亂碼
- 不管你絞幾次,同樣的東西永遠絞出同樣的結果
- 但從這串亂碼,完全無法反推原來丢進去的是什麼
雜湊函數的特性:
輸入:任何長度的資料
↓
┌──────────┐
│ 絞肉機 │ ← 這就是 Keccak-256
│ Keccak │
└──────────┘
↓
輸出:固定 256 bits(32 bytes)的「指紋」
Keccak-256 的輸出永遠是 64 個十六進位字元(因為 256 bits ÷ 4 = 64),看起來像這樣:
Keccak-256("hello")
= 1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
Keccak-256("hello ")
= 1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
↑ 只差一個空格,輸出就完全不同(雪崩效應)
Keccak 是怎麼運作的?
Keccak 使用一種叫做「海綿結構」(Sponge Construction)的設計。名字很浪漫,但概念很簡單:
┌─────────────────────────────────────────────────────────┐
│ 海綿結構 │
│ │
│ ┌─────────┐ ┌──────────────┐ ┌─────────┐ │
│ │ 吸水區 │ ← │ 狀態區 │ → │ 擠出區 │ │
│ │ (Padding)│ │ (1600 bits) │ │(Squeezing)│ │
│ └─────────┘ └──────────────┘ └─────────┘ │
│ │
│ 第一階段:吸水(Absorbing) │
│ → 把輸入資料切成小塊,一塊一塊「吸」進去 │
│ → 每吸一塊,就做一次複雜的運算 │
│ │
│ 第二階段:擠出(Squeezing) │
│ → 開始「擠出」固定長度的輸出 │
│ → 不夠就再運算、再擠 │
│ │
└─────────────────────────────────────────────────────────┘
狀態區是 1600 bits,被切成 5×5 的格子,每格 64 bits。運算的時候,這些格子之間會互相折騰(數學上叫置換),折騰很多輪之後才會輸出。
以太坊中 Keccak-256 的應用
應用場景 1:生成以太坊地址
你的公鑰(壓縮前):
04 + x座標(256 bits) + y座標(256 bits)
= 520 bits
第一步:Keccak-256(公鑰)
↓
輸出:256 bits 的雜湊值
第二步:取最後 40 個十六進位字元(160 bits)
↓
輸出:以太坊地址(40 hex = 20 bytes)
舉例:
公鑰 → Keccak-256 → 0xabc123def456... → 取後40位
→ 地址:0x...def456
應用場景 2:Merkle Tree 的雜湊
Merkle Tree 是用來驗證大量資料完整性的結構。
Root(Merkle 根)
/ \
HashAB HashCD
/ \ / \
HashA HashB HashC HashD
| | | |
DataA DataB DataC DataD
驗證過程:
- 我有 DataA,想驗證它在 Tree 裡
- 你只需要給我 HashB、HashCD、Root
- 我自己就能算出 Root 並比對
- 完全不需要知道其他資料
Keccak vs SHA-256:為什麼以太坊不用 SHA-256?
這是個好問題。SHA-256 是美國國家安全局(NSA)設計的,Keccak 是歐洲學術界設計的。兩者都是安全的,但有以下差異:
┌─────────────────┬─────────────────┬─────────────────┐
│ 特性 │ Keccak-256 │ SHA-256 │
├─────────────────┼─────────────────┼─────────────────┤
│ 設計者 │ Guido Bertoni │ NSA │
│ │ et al. │ │
├─────────────────┼─────────────────┼─────────────────┤
│ SHA-3 標準化 │ 是(基於 │ N/A │
│ │ Keccak) │ │
├─────────────────┼─────────────────┼─────────────────┤
│ 結構 │ 海綿結構 │ Merkle-Damgård │
├─────────────────┼─────────────────┼─────────────────┤
│ 以太坊使用 │ 是 │ 否 │
├─────────────────┼─────────────────┼─────────────────┤
│ 效能(軟體) │ 略慢 │ 標準 │
├─────────────────┼─────────────────┼─────────────────┤
│ 效能(硬體) │ 高效 │ 標準 │
└─────────────────┴─────────────────┴─────────────────┘
以太坊選擇 Keccak 的原因:
1. 避免使用 NSA 設計的算法(去中心化精神)
2. Keccak 在 ASIC 上效能更好(對未來的 MEV 保護有好處)
3. 比特幣社群有類似的考量,所以選了 SHA-256
實際驗證:用 Python 算 Keccak
# 安裝 pysha3
# pip install pysha3
from sha3 import keccak_256
# 計算字串的 Keccak-256 雜湊
message = b"Hello, Ethereum!"
hash_result = keccak_256(message).hexdigest()
print(f"Keccak-256('{message.decode()}')")
print(f"= {hash_result}")
print(f"長度:{len(hash_result)} 字元(256 bits / 4)")
# 區塊挖礦的本質就是:
# 不斷改變 nonce,直到找到一個小於 target 的 Keccak-256 雜湊值
def mine_block(block_data, target_bits=24):
"""簡化的區塊挖礦概念"""
import random
target = 2 ** (256 - target_bits)
nonce = 0
while True:
# 區塊資料 + nonce 一起 hash
data = block_data + str(nonce).encode()
hash_val = int(keccak_256(data).hexdigest(), 16)
if hash_val < target:
print(f"找到區塊!nonce = {nonce}")
print(f"區塊 hash = 0x{hash_val:064x}")
return nonce, hash_val
nonce += 1
if nonce % 1000000 == 0:
print(f"已嘗試 {nonce:,} 次...")
# 測試
mine_block(b"Hello Block #1", target_bits=20)
第二章:橢圓曲線密碼學(ECC)
橢圓曲線到底是什麼?
橢圓曲線的方程式很簡單:
y² = x³ + ax + b (mod p)
以太坊使用的參數(secp256k1):
a = 0
b = 7
p = 2^256 - 2^32 - 977 (一個很大的質數)
把這個方程式畫成圖,會得到一條光滑的曲線,像這樣:
y
↑
8 │ *
│ *
6 │ *
│ *
4 │ *
│ *
2 │ *
─────┼──────────────────────→ x
-8 -6 -4 -2 0 2 4 6 8
-2 │
-4 │ *
-6 │ *
-8 │ *
點加法:把兩個點加在一起
橢圓曲線最神奇的地方是:你可以在上面做「加法」。
點加法的規則:
情況一:P + Q(R 是它們連線與曲線的第三個交點,再對 X 軸做對稱)
P
/
/ R'
/ /
Q────
→ P + Q = R(R 是 R' 對 X 軸的對稱點)
情況二:P + P = 2P(這叫「倍點」,幾何意義是畫 P 點的切線)
P
│
│ ← 切線
│
2P ← 切線與曲線的交點,再對 X 軸對稱
數學上,如果 P = (x₁, y₁),Q = (x₂, y₂),R = P + Q = (x₃, y₃):
公式(當 P ≠ Q 時):
λ = (y₂ - y₁) / (x₂ - x₁) mod p
x₃ = λ² - x₁ - x₂ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p
當 P = Q 時(倍點):
λ = (3x₁² + a) / (2y₁) mod p
視覺化:標量乘法
在密碼學中,我們更常做的是「標量乘法」:k × P = P + P + ... + P(k 次)
標量乘法的概念:
k = 5 時:
5P = 2(2P) + P (用「加倍再相加」的方法)
= 2(4P) + P
= 2(2(2P)) + P
好處:把 5 次加法變成 3 次
如果 k 是 256 bits 的數字:
- 暴力加法需要 2^256 次
- 標量乘法只需要 256 次「加倍」+ 平均 128 次「相加」
以太坊地址是如何生成的?
完整流程:
1. 生成私鑰(256 bits 的隨機數)
↓
2. 用私鑰計算公鑰(在 secp256k1 曲線上)
公式:公鑰 = 私鑰 × 基點 G
↓
3. 用 Keccak-256 計算公鑰的雜湊
↓
4. 取最後 40 個十六進位字元
↓
5. 在前面加上 "0x"
→ 這就是你的以太坊地址!
讓我用手算一個極簡例子(只取前幾 bits,實際上要複雜得多):
步驟 1:假設私鑰是 5(實際上是個超大的數)
步驟 2:計算公鑰 = 5 × G
G = (55066263022277343669578718895168534326250603453777594175500187360389116729240,
32670510020758816978083085130507043184471273380659243275938904335757337482424)
5G = 2(2G) + G
...(實際計算省略,超長)
公鑰 ≈ (x, y) 其中 x 和 y 都是超大質數
步驟 3:Keccak-256(公鑰)
= "1c8aff..." (這是假的,實際很長)
步驟 4:取最後 40 個字元
= "1c8aff950685c2ed4bc3174f3472287b56d9517b"
步驟 5:加上 "0x"
地址 = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b
secp256k1 的特殊之處
為什麼比特幣和以太坊都選了 secp256k1 這條曲線?
┌─────────────────┬─────────────────────────────────────────┐
│ 特性 │ 說明 │
├─────────────────┼─────────────────────────────────────────┤
│ 參數簡單 │ a=0, b=7,計算簡單 │
├─────────────────┼─────────────────────────────────────────┤
│ 無法加速 │ 沒有「陷阱門」,密碼學家喜歡 │
├─────────────────┼─────────────────────────────────────────┤
│ 亞群序數 │ #E = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 │
│ (n) │ - 2^6 - 2^4 - 1 │
│ │ 這是一個質數!意味著每個元素都是 Generator│
├─────────────────┼─────────────────────────────────────────┤
│ 基點 G │ x = 79BE667EF9DCBBAC55A06295CE870B07029│
│ │ CFCDB1DCE0D219F111DD003953C3B2C055 │
│ │ y = 483ADA7726A3C4655DA4FBFC0E1108A8FD│
│ │ 17B4484E54211282DDC8D0E2C5E0E72F8A9F│
│ │ B03B │
└─────────────────┴─────────────────────────────────────────┘
第三章:BLS 簽名
為什麼需要 BLS?
在以太坊 PoS 共識中,每天有數以萬計的驗證者需要對區塊簽名。如果每個簽名都要單獨驗證,網路會卡死。
BLS 簽名的超能力是:可以把任意數量的簽名「壓縮」成一個!
傳統方式(ECDSA):
驗證者1的簽名 ─┐
驗證者2的簽名 ─┼─→ 需要驗證 10000 次
驗證者3的簽名 ─┤
... │
驗證者10000的簽名 ┘
BLS 方式:
所有簽名 ──→ 聚合成一個簽名 ──→ 驗證 1 次
BLS 的數學基礎
BLS 簽名基於配對密碼學(Pairing-based Cryptography)。這需要一種特殊的橢圓曲線——BLS12-381。
BLS12-381 曲線參數:
- 嵌入度:12(這是這種曲線叫「12」的原因)
- 基域大小:381 bits
- 曲線方程:y² = x⁴ + 4
G₁ 群(簽名所在的群):
- 基點:G
- 階:r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfe674000000000000
G₂ 群(公鑰所在的群):
- 基點:H
- 階:同上 r
目標群 G_T:
- 存在於某個有限域擴張中
- 有「配對」操作
BLS 簽名流程
金鑰生成:
私鑰 sk = 隨機選擇 [1, r-1] 範圍內的數
公鑰 PK = sk × H(曲線上的標量乘法)
簽名生成:
簽名 σ = sk × M(M 是消息的雜湊值,在 G₁ 群上)
簽名驗證(需要配對操作):
e(σ, G) =? e(H, PK)
其中 e 是配對函數,G 是 G₁ 的生成元
聚合簽名的魔法
假設有 3 個驗證者:
驗證者 1:私鑰 sk₁,公鑰 PK₁,簽名 σ₁ = sk₁ × H(m)
驗證者 2:私鑰 sk₂,公鑰 PK₂,簽名 σ₂ = sk₂ × H(m)
驗證者 3:私鑰 sk₃,公鑰 PK₃,簽名 σ₃ = sk₃ × H(m)
聚合過程:
σ_agg = σ₁ + σ₂ + σ₃ (曲線上的加法)
= (sk₁ + sk₂ + sk₃) × H(m)
聚合公鑰:
PK_agg = PK₁ + PK₂ + PK₃
= (sk₁ + sk₂ + sk₃) × H
驗證:
e(σ_agg, G) = e((sk₁+sk₂+sk₃)×H(m), G)
= e(H(m), G)^(sk₁+sk₂+sk₃)
= e(sk₁×H(m), G) × e(sk₂×H(m), G) × e(sk₃×H(m), G)
= e(PK₁, G) × e(PK₂, G) × e(PK₃, G)
= e(PK_agg, G)
✓ 驗證成功!一個簽名代表了三個人
以太坊如何用 BLS?
以太坊共識層的 BLS 應用:
1. 質押存款:
- 驗證者註冊時提交 BLS 公鑰
- 存款合約儲存公鑰和提款憑證
2. 區塊提議(Attestation):
- Validator 對區塊頭簽名(用 BLS)
- 多個 Validator 的簽名被聚合
- 最終只驗證一個聚合簽名
3. 最終性(Finality):
- 2/3 驗證者簽名的區塊被認為是最終確定的
- 這個「2/3 簽名」其實是一個聚合 BLS 簽名
節省的效果(估算):
假設有 50 萬驗證者:
- ECDSA:每次投票需要 50 萬個簽名
- BLS 聚合:每次投票只需要 1 個聚合簽名
- 節省儲存空間:~99.9998%
實際使用 BLS
# 安裝 py_ecc
# pip install py-ecc
from py_ecc import BLS12_381 as curve
from py_ecc.utils import int_to_bytes
# 參數
FIELD_SIZE = curve.field_modulus
G1 = curve.G1
G2 = curve.G2
ORDER = curve.order
# 私鑰(應該用真正隨機的)
sk = 12345678901234567890
# 公鑰(在 G2 上)
PK = curve.multiply(G2, [sk])
# 消息(需要映射到 G1)
message_hash = int_to_bytes(12345, 32) # 實際應使用正式的消息到點的映射
# 簽名(在 G1 上)
signature = curve.multiply(G1, [sk])
# 驗證
def verify_bls(signature, PK, message):
# e(σ, G) = e(H(m), PK)
left = curve.pairing(signature, G1, True)
# 實際應用中需要把 message 映射到 G1 的點
right = curve.pairing(G2, PK, True)
return left == right
print(f"私鑰: {sk}")
print(f"公鑰: ({PK[0][0]}, {PK[0][1]})")
print(f"簽名: ({signature[0]}, {signature[1]})")
第四章:實際應用整合
完整的交易簽名流程
以太坊交易簽名流程:
1. 構造交易
┌────────────────────────────────┐
│ nonce: 0 │
│ gasPrice: 20000000000 │
│ gasLimit: 21000 │
│ to: 0x...(收款地址) │
│ value: 1000000000000000000 │
│ data: 0x │
│ chainId: 1 │
└────────────────────────────────┘
↓
2. RLP 編碼(轉成 bytes)
↓
3. Keccak-256 計算交易雜湊
↓
4. ECDSA 簽名(用私鑰簽這個雜湊)
輸出:r, s, v
↓
5. 組合完整簽名交易
┌────────────────────────────────┐
│ [所有原來的欄位, r, s, v] │
└────────────────────────────────┘
↓
6. 廣播到網路
# 用 web3.py 實際簽名一筆交易
from web3 import Web3
# 連接節點
w3 = Web3(Web3.HTTPProvider('https://eth.llamarpc.com'))
# 檢查連接
print(f"連接成功:{w3.is_connected()}")
# 你的私鑰(千萬不要真的用這個!)
private_key = "0x" + "00" * 32 # 示範用
# 收款地址
to_address = "0x742d35Cc6634C0532925a3b844Bc9e7595f123dB"
# 構造交易
tx = {
'nonce': w3.eth.get_transaction_count(w3.eth.accounts[0]),
'to': to_address,
'value': w3.to_wei(0.001, 'ether'),
'gas': 21000,
'gasPrice': w3.eth.gas_price,
'chainId': 1
}
# 簽名
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
# 發送
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
print(f"交易 hash:{tx_hash.hex()}")
Merkle Patricia Trie 的雜湊驗證
以太坊用一種特殊的 Merkle Tree 來儲存狀態,叫做 Merkle Patricia Trie(MPT)。
MPT 的特點:
- 支援前綴搜尋(Patricia = Path)
- 支援快速更新
- 根節點的雜湊代表整棵樹的內容
狀態樹結構(簡化):
Root Hash
│
├── Extension Node(前綴压缩)
│ └── "acc" → Branch
│
└── Branch Node
├── [0-9] 子節點
├── [a-f] 子節點
└── Value
驗證任何帳戶餘額:
只需要這三樣東西:
1. 帳戶在樹中的路徑(由地址決定)
2. 該路徑上的所有兄弟節點
3. Root Hash
常見問題解答
Q:Keccak-256 被破解了怎麼辦?
A:不用擔心。Keccak 是 NIST SHA-3 標準的基礎,通過了全世界密碼學家的多年審查。找到 collision(兩個不同輸入產生相同輸出)需要 2^256 次運算,這在物理上是不可能的。
Q:我的私鑰會被暴力破解嗎?
A:2^256 是一個超級大的數字。如果全世界的所有計算機一起算,每秒鐘算 10^18 個金鑰,也要算 10^59 年才可能破解。你的金鑰比宇宙年齡還安全。
Q:為什麼以太坊地址看起來像亂碼?
A:因為它就是用密碼學「隨機」生成的。地址本身沒有任何意義,只是「誰控制這個地址的私鑰」的證明。
Q:BLS 簽名是不是比 ECDSA 更好?
A:各有優勢。BLS 的聚合能力很強,但配對操作比較慢。以太坊聰明的地方在於:主網交易用 ECDSA(快速簡單),共識層用 BLS(支援聚合)。
結語
看完這篇文章,你應該對以太坊背後的密碼學有了基本認識:
核心要點:
1. Keccak-256
→ 以太坊的「絞肉機」,把任何東西絞成 32 bytes 指紋
→ 地址、狀態驗證都用它
2. 橢圓曲線 secp256k1
→ 公私鑰的數學基礎
→ 「離散對數」的困難性」是安全的保證
3. BLS 簽名
→ 以太坊 PoS 的核心
→ 把成千上萬的簽名壓成一個
這些密碼學工具看起來很複雜,但它們的設計哲學其實很簡單:用數學的困難性來換取安全。只要解決某些數學問題(比如離散對數)很困難,你的資金就是安全的。
本網站內容僅供教育與資訊目的,不構成任何技術建議或投資建議。
數據截止日期:2026 年 3 月
相關文章推薦:
- 以太坊地址與錢包完整指南
- 零知識證明在以太坊上的應用
- 以太坊共識機制詳解:PoS 與驗證者
COMMIT: Add comprehensive Ethereum cryptographic primitives visual tutorial with Keccak, BLS, and ECC
相關文章
- 以太坊密碼學原語互動式瀏覽器教學:從理論到實踐的完整指南 — 本文以互動式瀏覽器範例為核心,幫助讀者在實踐中理解以太坊的密碼學基礎。涵蓋橢圓曲線密碼學(secp256k1、ECDSA 簽名驗證)、Keccak-256 哈希函數、雪崩效應、Merkle 樹建造與驗證、以及以太坊狀態證明的實際應用。每個概念都配有可運行的 JavaScript 程式碼範例,讀者可以直接在瀏覽器控制台中實驗。特別適合視覺型學習者和希望深入理解密碼學的開發者。
- 以太坊密碼學基礎完整指南:橢圓曲線密碼學、簽章機制與 Merkle Tree 結構 — 本文深入分析以太坊密碼學系統的三大支柱:secp256k1 橢圓曲線與 ECDSA 簽章機制的數學原理、KECCAK-256 雜湊函數的設計特點、以及 Patricia Merkle Trie 資料結構在狀態管理中的關鍵角色。我們從密碼學理論出發,經過詳盡的數學推導,最終落實到 Solidity、Go 與 Rust 的實際程式碼範例。涵蓋離散對數問題、點加法/倍增運算、ECDSA 簽章驗證、Merkle Proof、EIP-1559 等核心概念的完整技術解析。
- 以太坊密碼學Primer:從零理解區塊鏈的安全基石 — 本文以口語化、易懂的方式介紹以太坊密碼學的核心概念,包括 Hash、Keccak-256、公私鑰、ECDSA 簽名、Merkle Tree 以及前編譯合約等基礎元件。文章使用大量生活化的比喻和實際程式碼範例,幫助讀者建立對密碼學的直觀理解,並為學習進階密碼學內容奠定基礎。
- 以太坊密碼學互動實驗室:瀏覽器可執行範例與 secp256k1/ECDSA 深度教學 — 本文提供一套完整的以太坊密碼學互動式學習模組,讓讀者能夠在瀏覽器中直接執行和實驗密碼學運算。涵蓋 secp256k1 橢圓曲線運算、ECDSA 簽章與驗證、Keccak-256 雜湊、以及零知識證明等核心主題。所有範例都可以在現代瀏覽器中直接運行,無需額外的開發環境配置。提供完整的 JavaScript 程式碼範例,包括點加法、標量乘法、交易簽章模擬、Merkle 樹構建等互動實驗。
- 以太坊密碼學原語互動式教學:從橢圓曲線到 Merkle Patricia Tree — 本文以互動式教學方式解析以太坊核心密碼學原語,包括 Keccak 雜湊函數的海綿結構與實作、secp256k1 橢圓曲線密碼學的數學原理、ECDSA 簽章機制與 recovery id 解析、Merkle Patricia Tree 的混合設計與狀態驗證。透過大量圖解說明和 Python 程式碼範例,讓讀者從直觀理解密碼學而非陷入數學公式的泥沼。
延伸閱讀與來源
- Ethereum.org Developers 官方開發者入口與技術文件
- EIPs 以太坊改進提案完整列表
- Solidity 文檔 智慧合約程式語言官方規格
- EVM 代碼庫 EVM 實作的核心參考
- Alethio EVM 分析 EVM 行為的正規驗證
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!