橢圓曲線密碼學直覺式圖解說明:從基礎原理到以太坊應用

本文以直覺式圖解說明讓讀者無需深厚數學背景也能理解橢圓曲線密碼學的核心概念。涵蓋橢圓曲線加法的幾何意義、離散對數問題的安全性基礎、以太坊地址生成的完整流程、ECDSA 簽名演算法、Vitalik 恢復機制,以及零知識電路和 Layer 2 中的橢圓曲線應用。

橢圓曲線密碼學與 Keccak256 雜湊函數直覺解釋:以太坊加密原語的工程視角

概述

理解以太坊的底層密碼學原語是成為進階開發者的必經之路。橢圓曲線密碼學(Elliptic Curve Cryptography, ECC)是以太坊地址生成、簽名驗證和共識機制的核心;而 Keccak256 雜湊函數則在以太坊地址生成、以太坊請求(EthRequest)、事件主題(Event Topics)和智能合約程式碼哈希等場景中扮演不可或缺的角色。

本文從工程師視角出發,提供橢圓曲線和 Keccak256 的直覺化解釋,輔以完整的程式碼範例,幫助讀者建立對這些密碼學原語的深刻理解。我們不僅解釋「是什麼」,更深入探討「為什麼這樣設計」和「如何實際運用」。


第一部分:橢圓曲線密碼學直覺解釋

1.1 從橢圓說起:什麼是橢圓曲線?

橢圓曲線並非橢圓形,而是一種滿足特定方程式的平面曲線。在密碼學中,我們使用的是以下形式:

y² = x³ + ax + b (模 p)

其中 a 和 b 是常數,p 是一個大質數。這個方程式定義的曲線具有以下關鍵特性:

封閉性:曲線上的任意兩點相加,結果仍在曲線上

結合律:三點相加與順序無關

單位元存在:存在一個「無窮遠點」O,使得 P + O = P

逆元存在:對於任意點 P,存在 -P 使得 P + (-P) = O

這些特性使得橢圓曲線上的點形成一個阿貝爾群(Abelian Group),而這正是密碼學應用的數學基礎。

1.2 為什麼選擇橢圓曲線?

在橢圓曲線密碼學出現之前,RSA 是最廣泛使用的公鑰密碼系統。讓我們比較兩者的核心差異:

密鑰長度比較(安全等級相當):

┌─────────────────┬──────────────┬──────────────┐
│ 安全等級        │ RSA 密鑰長度 │ ECC 密鑰長度 │
├─────────────────┼──────────────┼──────────────┤
│ 80-bit 安全     │ 1024 bits    │ 160 bits     │
│ 128-bit 安全    │ 3072 bits    │ 256 bits     │
│ 256-bit 安全    │ 15360 bits   │ 512 bits     │
└─────────────────┴──────────────┴──────────────┘

以 256-bit 安全為例:
- RSA 需要 15360 bits 的密鑰
- ECC 只需要 256 bits 的密鑰
- 密鑰大小減少約 60 倍!

這種巨大的效率差異源於離散對數問題在橢圓曲線上的特殊結構。ECC 的安全性基於「橢圓曲線離散對數問題」(ECDLP):已知點 G 和 kG,計算 k 在計算上是不可行的。

1.3 secp256k1:以太坊的心臟

以太坊使用的橢圓曲線是 secp256k1,其參數定義如下:

secp256k1 參數:

┌────────────────────┬────────────────────────────────────────────┐
│ 參數               │ 值                                          │
├────────────────────┼────────────────────────────────────────────┤
│ 質數 p             │ 2²⁵⁶ - 2³² - 2⁹ - 2⁸ - 2⁷ - 2⁶ - 2⁴ - 1    │
│                    │ = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF     │
│                    │   FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F       │
├────────────────────┼────────────────────────────────────────────┤
│ 係數 a             │ 0                                           │
├────────────────────┼────────────────────────────────────────────┤
│ 係數 b             │ 7                                           │
├────────────────────┼────────────────────────────────────────────┤
│ 基點 G             │ (0x79BE667E F9DCBBAC 55A06295 CE870B07      │
│                    │   029BFCDB 2DCE28D9 59F2815B 16F81798,      │
│                    │  0x483ADA77 26A3C465 5DA4FBFC 0E1108A8FD   │
│                    │   17B448A6 855174D7 2287E99B 619F26C)       │
├────────────────────┼────────────────────────────────────────────┤
│ 基點階數 n         │ 0xFFFFFFFF FFFFFFFF FFFFFFFF 5D576E73     │
│                    │   3A57D793 6F431EE2 28FB7A49FB4A0E3         │
├────────────────────┼────────────────────────────────────────────┤
│ 協因子 h           │ 1                                           │
└────────────────────┴────────────────────────────────────────────┘

為什麼以太坊選擇 secp256k1 而不是更常見的 secp256r1(又稱 P-256)?主要有以下原因:

可驗證隨機性:secp256k1 的參數是透過可驗證隨機程序生成的,任何人都可以確認這些參數不是刻意選擇的後門。相比之下,secp256r1 的參數由 NIST 選擇,存在疑似 NSA 後門的爭議。

計算效率:secp256k1 的 a=0 簡化了曲線方程,使得點加法和倍乘運算更快速。

密碼學 strength:在相同密鑰長度下,secp256k1 提供略高於 P-256 的安全邊際。

1.4 點加法:曲線上的數學運算

橢圓曲線密碼學的核心運算是「點加法」。给定曲线上的两点 P 和 Q,可以计算出它们的「和」R = P + Q。這個運算的幾何意義如下:

點加法幾何解釋:

1. 對稱點
   如果 Q = -P(即 Q 是 P 的 x 軸對稱點),則 P + Q = O(無窮遠點)

2. 一般加法 P + Q = R
   步驟:
   a) 畫直線穿過 P 和 Q
   b) 這條直線會與曲線交於第三點 R'
   c) R 是 R' 關於 x 軸的對稱點

3. 倍乘法 P + P = 2P(切線法)
   a) 畫曲線在 P 點的切線
   b) 切線與曲線交於第二點
   c) 對稱得到結果

讓我們用 Python 實現這個點加法運算:

"""
橢圓曲線密碼學實現:以太坊 secp256k1 曲線點運算
"""

# secp256k1 曲線參數
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
A = 0
B = 7
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
G_X = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
G_Y = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8

class Point:
    """橢圓曲線上的點"""
    def __init__(self, x, y, infinity=False):
        self.x = x
        self.y = y
        self.infinity = infinity
    
    def __repr__(self):
        if self.infinity:
            return "O (Infinity)"
        return f"({hex(self.x)}, {hex(self.y)})"

def mod_inverse(a, m):
    """模逆元:找 x 使得 a*x ≡ 1 (mod m)"""
    if a < 0:
        a = (a % m + m) % m
    g, x, _ = extended_gcd(a, m)
    if g != 1:
        raise ValueError("逆元不存在")
    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):
    """
    橢圓曲線點加法
    公式推導:
    若 P ≠ Q:λ = (y2 - y1) / (x2 - x1)
    若 P = Q:λ = (3x1² + a) / (2y1)
    Rx = λ² - x1 - x2
    Ry = λ(x1 - Rx) - y1
    """
    if p1.infinity:
        return p2
    if p2.infinity:
        return p1
    
    # 檢查是否是對稱點
    if p1.x == p2.x and p1.y == (-p2.y % P):
        return Point(None, None, infinity=True)
    
    # 計算斜率 lambda
    if p1.x == p2.x and p1.y == p2.y:
        # 倍點:P + P = 2P
        numerator = (3 * p1.x * p1.x + A) % P
        denominator = (2 * p1.y) % P
    else:
        # 普通加法
        numerator = (p2.y - p1.y) % P
        denominator = (p2.x - p1.x) % P
    
    lam = (numerator * mod_inverse(denominator, P)) % P
    
    # 計算結果點
    x_r = (lam * lam - p1.x - p2.x) % P
    y_r = (lam * (p1.x - x_r) - p1.y) % P
    
    return Point(x_r, y_r)

def scalar_multiply(k, point):
    """
    標量乘法:k * P = P + P + ... + P (k次)
    使用二元法(Binary Method)優化:
    將 k 視為二進制,逐步倍增
    """
    result = Point(None, None, infinity=True)
    addend = point
    
    while k:
        if k & 1:
            result = point_add(result, addend)
        addend = point_add(addend, addend)  # 倍增
        k >>= 1
    
    return result

# 測試:驗證 G 生成的循環群
G = Point(G_X, G_Y)
print(f"基點 G: {G}")

# 驗證 N * G = O(無窮遠點)
N_times_G = scalar_multiply(N, G)
print(f"N * G = {N_times_G}")  # 應該是無窮遠點

# 驗證 2 * G
two_G = scalar_multiply(2, G)
print(f"2 * G = {two_G}")

1.5 橢圓曲線離散對數問題

ECDLP 的安全性正是基於以下問題:

給定:
- 橢圓曲線上的公共基點 G
- 公共點 P = k * G

求:
- 私密密鑰 k

難點:
- 已知 k 計算 P 很容易:O(log k) 次點加法
- 已知 P 和 G 求 k 非常困難:目前沒有已知的多項式時間算法
- 對於 256-bit 曲線,最佳攻擊需要約 2^128 次操作

這就是「单向函数」的經典例子:正向計算容易,逆向計算幾乎不可能。


第二部分:Keccak256 雜湊函數直覺解釋

2.1 什麼是 Keccak256?

Keccak256(發音為「ketchak」)是一個密碼學雜湊函數,是 SHA-3 標準的原始版本。以太坊選擇 Keccak256 而非 NIST 標準化的 SHA-3,是因為以太坊在 SHA-3 標準最終確定之前就已經部署了 Keccak256。

直覺類比:將 Keccak256 想像成一台超級碎紙機:

輸入示例:
- "hello" → Keccak256("hello") = 0x1c8aff950685c51ed1e2...(64 字符)
- "hello world" → 完全不同於 "hello" 的輸出

輸出特性:
- 固定長度:256 bits(32 bytes)
- 確定性:相同輸入總是產生相同輸出
- 不可逆:無法從輸出推導輸入
- 抗碰撞:極難找到兩個不同輸入產生相同輸出

2.2 為什麼以太坊使用 Keccak256?

以太坊在多個關鍵場景中使用 Keccak256:

┌─────────────────────────────────────────────────────────────────────┐
│              Keccak256 在以太坊中的應用                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  1. 地址生成                                                        │
│     地址 = last 20 bytes of Keccak256(公鑰)                         │
│     目的:從公鑰衍生出不可預測的地址                                 │
│                                                                       │
│  2. 事件主題                                                        │
│     Event Topic = Keccak256(事件簽名)                               │
│     例如:Keccak256("Transfer(address,address,uint256)")          │
│           = 0xddf252ad...                                          │
│     目的:高效索引和過濾事件                                         │
│                                                                       │
│  3. 函數選擇器                                                       │
│     Function Selector = first 4 bytes of Keccak256(函數簽名)         │
│     例如:Keccak256("transfer(address,uint256)")                   │
│           = 0xa9059cbb...                                          │
│     目的:識別智能合約要調用的函數                                   │
│                                                                       │
│  4. 狀態根                                                          │
│     State Root = Keccak256(所有帳戶狀態的 Merkle Root)              │
│     目的:高效驗證整個區塊鏈狀態                                     │
│                                                                       │
│  5. 交易哈希                                                        │
│     Transaction Hash = Keccak256(交易編碼)                           │
│     目的:唯一標識交易,提供不可篡改的引用                           │
│                                                                       │
└─────────────────────────────────────────────────────────────────────┘

2.3 Keccak vs SHA-3:為什麼不是同一個東西?

這是一個常見的困惑點:

┌─────────────────────────────────────────────────────────────────────┐
│              Keccak256 vs SHA3-256                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  Keccak256                                                         │
│  - 以太坊使用的原始版本                                              │
│  - SHA-3 競賽的獲勝者                                               │
│  - 設計者:Giovanni et al.                                         │
│                                                                       │
│  SHA3-256                                                          │
│  - NIST 標準化的版本                                                │
│  - 與 Keccak 有微小的參數差異(padding 方式)                        │
│  - 2015 年標準化                                                     │
│                                                                       │
│  輸出示例對比:                                                     │
│                                                                       │
│  輸入:"abc"                                                        │
│  Keccak256: 0x4e03657aea15a29e...                                  │
│  SHA3-256:  0x3c98d45b04eab...                                     │
│                                                                       │
│  ⚠️ 以太坊使用 Keccak256,不是 SHA3-256!                           │
│                                                                       │
└─────────────────────────────────────────────────────────────────────┘

2.4 Keccak256 的抗碰撞性:直覺解釋

Keccak256 的安全性核心是其「抗碰撞性」(Collision Resistance)。

什麼是碰撞?

碰撞是指兩個不同的輸入產生相同的輸出。例如:

找到 x ≠ y,使得 Keccak256(x) = Keccak256(y)

為什麼抗碰撞很重要?

想像一個場景:攻擊者創造了一個「合法」智能合約和一個「惡意」智能合約,但兩者有相同的地址。攻擊者說服用戶發送 ETH 到這個地址,聲稱這是「合法合約」。實際上,用戶的資金進入「惡意合約」。

抗碰撞性的直覺解釋

比喻:撲克牌洗牌

1. 輸入:撲克牌的初始順序
2. 洗牌過程:完全隨機的洗牌操作
3. 輸出:洗牌後的順序

問題:找到兩種不同的初始順序,
     使得洗牌後的結果完全相同?

答案:幾乎不可能!
     52! ≈ 8×10^67 種可能,
     而我們只需要 2^256 種可能輸出。

數學證明:Keccak256 的抗碰撞性基於以下假設:

假設:Keccak-f[1600] 置換函數沒有捷徑

推論:
- 輸入空間:2^512 種可能(Keccak 使用 64-byte 輸入)
- 輸出空間:2^256 種可能(256-bit 輸出)
- 碰撞概率:根據生日悖論,攻擊者需要約 2^128 次嘗試
- 安全性:128-bit 安全等級(與 256-bit ECC 密鑰相當)

2.5 Keccak256 的 Python 實現

"""
Keccak256 實現:以太坊密碼學原語
"""

import hashlib

def keccak256(data: bytes) -> bytes:
    """
    Keccak-256 雜湊函數實現
    
    以太坊使用的 Keccak256 是 SHA-3 的前身,
    與標準 SHA3-256 有微小的差異。
    """
    # Python 的 hashlib 沒有直接的 keccak256,
    # 但可以使用 pysha3 或 pycryptodome
    try:
        # 方法 1:使用 pysha3 庫
        import sha3
        return sha3.keccak_256(data).digest()
    except ImportError:
        # 方法 2:使用 pycryptodome
        from Crypto.Hash import keccak
        k = keccak.new(digest_bits=256)
        k.update(data)
        return k.digest()

def keccak256_hex(data: str) -> str:
    """返回十六進制字串格式"""
    if isinstance(data, str):
        data = data.encode('utf-8')
    return keccak256(data).hex()

# 測試
print("Keccak256 測試:")
print(f"keccak256('hello') = {keccak256_hex('hello')}")
print(f"keccak256('Hello') = {keccak256_hex('Hello')}")
print(f"keccak256('hello world') = {keccak256_hex('hello world')}")

# 驗證:以太坊地址生成
def private_key_to_address(private_key_hex: str) -> str:
    """
    將私鑰轉換為以太坊地址
    
    流程:
    1. 私鑰 → 公鑰(橢圓曲線點乘法)
    2. 公鑰 → Keccak-256 哈希
    3. 哈希結果的最後 20 bytes 即為地址
    """
    private_key = bytes.fromhex(private_key_hex.replace('0x', ''))
    
    # 這裡假設你有一個 ECDSA 實現
    # 使用 secp256k1 曲線計算公鑰
    # public_key = ecdsa_scalar_multiply(private_key, G)
    
    # 假設這是計算後的公鑰(未壓縮格式:04 + x + y)
    # uncompressed_public_key = b'\x04' + x_bytes + y_bytes
    
    # 使用 Keccak-256 哈希公鑰
    # keccak_hash = keccak256(uncompressed_public_key)
    
    # 取最後 20 bytes 作為地址
    # address = '0x' + keccak_hash[-20:].hex()
    
    # 由於篇幅限制,這裡提供概念性代碼
    # 完整實現需要 ECC 庫(如 fastecdsa)
    return "0x" + "?" * 40  # 佔位符

# Keccak256 在事件主題中的應用
def get_event_topic(event_signature: str) -> str:
    """
    計算事件主題(Event Topic)
    
    Solidity 事件:
    event Transfer(address indexed from, address indexed to, uint256 value);
    
    在 EVM 中:
    - topics[0] = Keccak256("Transfer(address,address,uint256)")
    - topics[1] = indexed 参数 1 的哈希(地址)
    - topics[2] = indexed 参数 2 的哈希(地址)
    """
    return keccak256_hex(event_signature)

print("\n事件主題計算:")
transfer_topic = get_event_topic("Transfer(address,address,uint256)")
print(f"Transfer(address,address,uint256) = {transfer_topic}")

# Keccak256 在函數選擇器中的應用
def get_function_selector(function_signature: str) -> str:
    """
    計算函數選擇器(Function Selector)
    
    函數選擇器 = Keccak256(函數簽名) 的前 4 bytes
    
    Solidity:
    function transfer(address to, uint256 amount) public {...}
    
    在交易中:
    - data[:4] = Keccak256("transfer(address,uint256)")[:4]
    - data[4:36] = 地址參數
    - data[36:] = 數量參數
    """
    full_hash = keccak256_hex(function_signature)
    return "0x" + full_hash[:8]  # 前 4 bytes = 8 個十六進制字符

print("\n函數選擇器計算:")
transfer_selector = get_function_selector("transfer(address,uint256)")
print(f"transfer(address,uint256) = {transfer_selector}")
print(f"transfer(address,uint256) = 0xa9059cbb (這是標準 ERC-20 transfer)")

2.6 Keccak256 的海綿結構:直覺解釋

Keccak 的創新之處在於其「海綿結構」(Sponge Construction)。

┌─────────────────────────────────────────────────────────────────────┐
│                    Keccak 海綿結構                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  ┌─────────┐     ┌──────────────────┐     ┌─────────┐             │
│  │  輸入    │ ──▶ │                  │ ──▶ │  輸出    │             │
│  │  Padding │     │   Keccak-f 置換   │     │  Hash    │             │
│  │  &       │     │   (1600-bit)      │     │  Result   │             │
│  │  分割    │     │                  │     │  (256-bit)│             │
│  └─────────┘     └──────────────────┘     └─────────┘             │
│       │                  ▲                      │                   │
│       │                  │                      │                   │
│       ▼                  │                      ▼                   │
│  ┌─────────┐     ┌──────────────────┐     ┌─────────┐             │
│  │  Rate   │ ←─▶ │                  │ ←─▶ │ Capacity│             │
│  │  (576)  │     │   迭代 N 輪       │     │ (1024)  │             │
│  └─────────┘     └──────────────────┘     └─────────┘             │
│                                                                       │
│  吸收階段(Absorbing):                                             │
│  - 輸入被分割成 rate 大小的塊                                        │
│  - 每個塊與狀態進行 XOR                                              │
│  - 然後應用 Keccak-f 置換                                           │
│                                                                       │
│  擠出階段(Squeezing):                                            │
│  - 從狀態中讀取 rate 大小的塊                                       │
│  - 直到獲得足夠長度的輸出                                            │
│                                                                       │
└─────────────────────────────────────────────────────────────────────┘

直覺類比:海綿吸水

1. 吸收階段:
   - 把數據(一滴一滴的水)擠入海綿
   - 每滴水和海綿內部充分混合

2. 擠出階段:
   - 把海綿裡的水擠出來
   - 擠出的水(輸出)與原始數據無明顯關聯

3. 安全性來源:
   - 每滴水(輸入塊)與海綿(狀態)充分混合
   - 逆向操作(從擠出的水推斷原始數據)極其困難

2.7 Keccak256 與以太坊地址生成

讓我們完整追蹤以太坊地址的生成過程:

"""
以太坊地址生成完整流程
"""

def generate_ethereum_address(private_key_hex: str) -> str:
    """
    完整的以太坊地址生成流程
    
    步驟:
    1. 私鑰(32 bytes)→ 公鑰(64 bytes)
    2. 公鑰(未壓縮)→ Keccak-256 哈希(32 bytes)
    3. 取哈希的最後 20 bytes → 以太坊地址(20 bytes)
    """
    # 這需要完整的 ECC 實現
    # 以下是概念性代碼
    
    # Step 1: 私鑰 → 公鑰
    # private_key_int = int(private_key_hex, 16)
    # public_key_point = scalar_multiply(private_key_int, G)
    # uncompressed_pubkey = b'\x04' + 
    #     public_key_point.x.to_bytes(32, 'big') + 
    #     public_key_point.y.to_bytes(32, 'big')
    
    # Step 2: 公鑰 → Keccak-256
    # keccak_hash = keccak256(uncompressed_pubkey)
    
    # Step 3: 取最後 20 bytes
    # address = '0x' + keccak_hash[-20:].hex()
    
    # 由於篇幅限制,以下提供驗證示例
    # Vitalik Buterin 的公開地址
    vitalik_address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    print(f"Vitalik Buterin 的地址:{vitalik_address}")
    
    # 從 Etherscan 驗證
    # https://etherscan.io/address/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
    
    return vitalik_address

# 驗證:以太坊地址格式
def is_valid_ethereum_address(address: str) -> bool:
    """
    驗證以太坊地址格式
    
    規則:
    - 42 個字符(前缀 0x + 40 個十六進制字符)
    - 或 40 個字符(無前缀)
    """
    if address.startswith('0x'):
        address = address[2:]
    
    if len(address) != 40:
        return False
    
    # 檢查是否只包含有效的十六進制字符
    try:
        int(address, 16)
        return True
    except ValueError:
        return False

print("\n以太坊地址驗證:")
print(f"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 是否有效: {is_valid_ethereum_address('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')}")

第三部分:密碼學原語的實際應用

3.1 ECDSA 簽名:以太坊交易的核心

以太坊使用 ECDSA(橢圓曲線數字簽名算法)來驗證交易真實性:

"""
ECDSA 簽名與驗證
"""

import secrets

def sign_message(message_hash, private_key):
    """
    ECDSA 簽名
    
    參數:
    - message_hash: 消息的 Keccak-256 哈希(32 bytes)
    - private_key: 簽名者的私鑰
    
    返回:
    - (r, s): 簽名值
    """
    # 臨時私鑰 k(必須隨機且一次性使用)
    while True:
        k = secrets.randbelow(N - 1) + 1
        if k == 0:
            continue
        
        # R = k * G
        R_point = scalar_multiply(k, G)
        r = R_point.x % N
        
        if r == 0:
            continue
        
        # s = k^(-1) * (z + r * private_key) mod N
        z = int.from_bytes(message_hash[:32], 'big')
        k_inverse = mod_inverse(k, N)
        s = (k_inverse * (z + r * private_key)) % N
        
        if s == 0:
            continue
        
        # 使用低 s 值(BIP-62 可彎曲性修復)
        if s > N / 2:
            s = N - s
        
        return (r, s)

def verify_signature(message_hash, signature, public_key):
    """
    驗證 ECDSA 簽名
    
    驗證方程:
    u1 * G + u2 * public_key = (x, y)
    驗證:x ≡ r (mod N)
    
    其中:
    - u1 = z * s^(-1) mod N
    - u2 = r * s^(-1) mod N
    """
    r, s = signature
    z = int.from_bytes(message_hash[:32], 'big')
    
    # 檢查 s 在有效範圍內
    if s < 1 or s >= N:
        return False
    
    # 計算 u1 和 u2
    s_inverse = mod_inverse(s, N)
    u1 = (z * s_inverse) % N
    u2 = (r * s_inverse) % N
    
    # P = u1 * G + u2 * public_key
    P1 = scalar_multiply(u1, G)
    P2 = scalar_multiply(u2, public_key)
    P = point_add(P1, P2)
    
    if P.infinity:
        return False
    
    # 驗證:P.x mod N == r
    return (P.x % N) == r

3.2 後量子密碼學威脅

橢圓曲線密碼學面臨的最大長期威脅是量子計算。Shor's algorithm 可以在多項式時間內解決離散對數問題,使得 ECC 在量子計算機面前完全脆弱。

後量子 ECC 替代方案:

┌─────────────────┬──────────────┬──────────────────────────────┐
│ 方案            │ 原理         │ 特點                          │
├─────────────────┼──────────────┼──────────────────────────────┤
│ 格基密碼學      │ 格子中的     │ 已在 NIST PQC 標準化中       │
│ (Lattice-based) │ 最短向量問題 │ - CRYSTALS-Dilithium         │
│                 │              │ - CRYSTALS-Kyber             │
├─────────────────┼──────────────┼──────────────────────────────┤
│ 基於哈希的簽名  │ 安全性基於  │ 只需哈希函數,假設最少         │
│ (Hash-based)    │ 哈希函數安全 │ - SPHINCS+                   │
├─────────────────┼──────────────┼──────────────────────────────┤
│ 同源加密        │ 利用曲線間的 │ 與現有 ECC 兼容性較好        │
│ (Isogeny-based) │ 同源關係     │ - SIKE(已被攻擊)           │
└─────────────────┴──────────────┴──────────────────────────────┘

結論

本文深入分析了以太坊兩大密碼學原語——橢圓曲線密碼學和 Keccak256 雜湊函數——的數學原理、工程實現和實際應用。

橢圓曲線密碼學的核心價值:

Keccak256的核心價值:

理解這些密碼學原語對於深入理解以太坊的工作原理、安全模型和未來演進方向至關重要。


參考文獻

密碼學基礎

Keccak/SHA-3

以太坊密碼學

工具與實作


本網站內容僅供教育與資訊目的,不構成任何投資建議或推薦。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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