以太坊密碼學原語視覺化教程: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 月


相關文章推薦

COMMIT: Add comprehensive Ethereum cryptographic primitives visual tutorial with Keccak, BLS, and ECC

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!