以太坊密碼學Primer:從零理解區塊鏈的安全基石

本文以口語化、易懂的方式介紹以太坊密碼學的核心概念,包括 Hash、Keccak-256、公私鑰、ECDSA 簽名、Merkle Tree 以及前編譯合約等基礎元件。文章使用大量生活化的比喻和實際程式碼範例,幫助讀者建立對密碼學的直觀理解,並為學習進階密碼學內容奠定基礎。

以太坊密碼學Primer:從零理解區塊鏈的安全基石

概述

嗨,如果你剛開始接觸以太坊開發,一定聽過「ECDSA」、「Keccak-256」、「橢圓曲線」這些名詞,但看了半天文件還是霧煞煞——恭喜你,進對地方了。這篇文章就是要用最白話的方式,把以太坊密碼學的核心概念全部拆解給你。

我當初學這块的時候,也是被一堆數學符號嚇到差點放棄。後來才發現,密碼學最重要的不是會算積分,而是搞懂「為什麼這樣設計」以及「這些機制怎麼保護你的資產」。只要把幾個關鍵概念串起來,整個系統就會突然變得清晰。

以太坊密碼學就像是一把精密的鎖——你知道它能保護你的寶藏,但你想搞懂鎖裡面到底藏了什麼玄機,對吧?那我們開始吧。


什麼是密碼學?區塊鏈為什麼需要它?

說白了,密碼學就是「讓訊息只有特定的人能看懂」的技術。你可以把訊息加密之後,就算被別人攔截也沒用——反正他們看不懂。

區塊鏈場景下的密碼學更嚴苛,因為它要解決三個核心問題:

  1. 身份驗證:這筆交易真的是「你」發的嗎?而不是別人假冒你?
  2. 完整性:這筆交易在傳輸過程中有沒有被篡改過?
  3. 不可否認性:你簽名承認的交易,之後不能說「那不是我做的」

以太坊用密碼學工具優雅地解決了這三個問題,而這一切的核心,就是接下來要介紹的幾個基礎元件。


第一課:Hash(雜湊函數)—— 數據的指紋

Hash 是什麼?

Hash 的中文翻譯是「雜湊」或「哈希」,但我更喜歡叫它「數據指紋」。就像每個人的指紋都是獨一無二的,Hash 也是每段數據的唯一標識。

以太坊使用的 Hash 函數叫 Keccak-256,它是 SHA-3 標準的祖先。給任意長度的輸入,它都會輸出固定 256 位元(32 bytes)的「指紋」。

實際操作看看

別緊張,我們不需要真的去算數學,用瀏覽器 console 就能體驗:

// 在瀏覽器 console 或 Node.js 環境執行
// 使用 Web3.js 或 ethers.js

const { keccak256 } = require('ethers').utils;

// 試試不同輸入
console.log(keccak256("hello"));
// 輸出: 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8

console.log(keccak256("hello "));  // 注意後面多了個空格
// 輸出: 0xa08dcfa70ebca8766a7b83c3a6494196c40893c621b0c50a9c39f52cb4f1823d

console.log(keccak256("Hello"));  // 大小寫不同
// 輸出: 0xd0927f45a073c12c4cf8b4e470369f5a1a9e0ce1646eb534c6c9c30cba6b4d8a

看,即使只差一個空格,輸出就完全不一樣了!這就是 Hash 的「雪崩效應」——輸入的小改變會導致輸出的大改變。

Hash 的三大特性

1. 確定性:同樣的輸入,永遠得到同樣的輸出

2. 單向性:可以從輸出反推輸入嗎?不行!Hash 是單向函數

3. 碰撞阻力:找不到兩筆不同的輸入會產生相同的輸出

這三個特性讓 Hash 成為區塊鏈的「數據指紋機」。任何區塊的內容改變了,Hash 就會跟著變,別人一眼就能發現數據被篡改過。

以太坊中的 Hash 應用

在以太坊區塊鏈上,Hash 無處不在:

區塊結構:
┌─────────────────────────────────────┐
│  Block Header                       │
│  ├─ parentHash   : 上個區塊的 Hash   │
│  ├─ stateRoot   : 狀態樹的 Hash     │
│  ├─ transactionsRoot : 交易樹 Hash  │
│  ├─ receiptsRoot : 收據樹 Hash      │
│  └─ ...                            │
└─────────────────────────────────────┘

每一個區塊都包含上一個區塊的 Hash,形成一條「區塊鏈」。如果要篡改某個歷史區塊的數據,你必須重新計算那個區塊之後所有區塊的 Hash——這幾乎是不可能的任務。


第二課:公私鑰——你的數位身份

從比喻開始

想像你有兩個神奇的盒子:

在以太坊的世界裡,你的公鑰就像是你的「銀行帳戶號碼」——別人可以匯錢給你,但無法從你的帳戶取錢。而私鑰就像是你的「ATM 密碼」加上「身份證」——千萬不能讓別人知道!

橢圓曲線密碼學(ECDSA)

以太坊使用的公私鑰系統基於 secp256k1 橢圓曲線。不用被這個名字嚇到,概念很簡單:

核心思想:利用橢圓曲線上的數學問題(ECDLP),讓你很容易從私鑰計算出公鑰,但幾乎不可能從公鑰反推私鑰。

私鑰 →(單向計算)→ 公鑰
公鑰 ─→(無法反推)──✗ 私鑰

這就像是你可以把雞蛋煮成熟蛋,但你沒辦法把熟蛋還原成生蛋。

生成你的第一個以太坊帳戶

const { Wallet } = require('ethers');

// 隨機生成一個錢包
const wallet = Wallet.createRandom();

console.log('私鑰(千萬別分享!):', wallet.privateKey);
// 輸出: 0x...
// 格式: 64個十六進制字元 = 256 bits

console.log('公鑰:', wallet.publicKey);
// 輸出: 0x...
// 格式: 128個十六進制字元 = 512 bits(壓縮後是256 bits)

console.log('以太坊地址:', wallet.address);
// 輸出: 0x...
// 格式: 40個十六進制字元 = 160 bits

公鑰經過 Keccak-256 Hash,取最後 20 bytes,就是你的以太坊地址。這就是為什麼別人可以把 ETH 發到你的地址,但他們無法從你的地址轉出——因為轉帳需要私鑰簽名。

地址的由來——完整過程

1. 生成隨機私鑰 (256 bits)
         ↓
2. 用私鑰推導公鑰 (橢圓曲線乘法)
         ↓
3. Keccak-256(公鑰)
         ↓
4. 取 Hash 的最後 20 bytes
         ↓
5. 加上 "0x" 前綴 = 以太坊地址
私鑰: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
公鑰: 0x4d5e5f8a4c2b1c3d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d
地址: 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

第三課:數位簽名——證明「這是我做的」

簽名是怎麼回事?

你可能會問:我用私鑰簽名,別人怎麼驗證是我簽的?他們又沒有我的私鑰。

好問題!這就是密碼學巧妙的地方。讓我用人類世界的比喻來解釋:

現實世界:你在一份文件上簽名,銀行會把你留下的「簽名樣本」拿出來比對。如果形狀差不多,就認為是你簽的。

數位世界:完全不一樣!你不是「比對形狀」,而是利用數學證明:

「我有私鑰,所以只有我能產生這個簽名。」

「我用私鑰對訊息的 Hash 做了某種計算,產生了簽名。」

「你用公鑰可以驗證這個計算是正確的。」

ECDSA 簽名過程

以太坊使用的簽名算法是 ECDSA(橢圓曲線數位簽名算法)。整個過程分為兩步:

步驟 1:創建簽名

const { Wallet, hashMessage } = require('ethers');

// 假設這是你的錢包
const wallet = new Wallet('0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80');

// 要簽名的訊息
const message = "I approve 1 ETH to 0x123...";

// 簽名
const signature = wallet.signMessage(message);
console.log(signature);
// 輸出: 0x...
// 格式: 65 bytes = r(32) + s(32) + v(1)

步驟 2:驗證簽名

const { verifyMessage } = require('ethers');

// 從簽名反推出簽署者的地址
const recoveredAddress = verifyMessage(message, signature);
console.log(recoveredAddress);
// 輸出: 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

// 比對是否一致
console.log(recoveredAddress === wallet.address);
// 輸出: true

簽名格式:r, s, v

一個 ECDSA 簽名由三個部分組成:

┌─────────────────────────────────────────────┐
│           ECDSA 簽名結構                     │
├─────────────────────────────────────────────┤
│  r (32 bytes): 0x79025d5d86b0f2a8e6f0e...  │
│  s (32 bytes): 0x5a8c9d8e7f6b5a4c3d2e1f...  │
│  v (1 byte)  : 0x1c                        │
└─────────────────────────────────────────────┘

重要提醒:千萬不要用同一個私鑰對相同的訊息簽名兩次!攻擊者可以從兩個簽名中數學推導出你的私鑰。這也是為什麼錢包每次交易都會使用 nonce(一個遞增的計數器)來確保訊息不會重複。


第四課:Merkle Tree——高效驗證大量數據

為什麼需要 Merkle Tree?

區塊鏈每秒鐘處理成千上萬筆交易,如果要驗證某一筆交易確實存在於某個區塊中,最笨的方法是下載整個區塊的所有交易數據,然後從頭到尾搜一遍。

Merkle Tree 解決了這個問題:它讓你只需要下載少量的「證明」,就能高效驗證任意交易是否存在。

Merkle Tree 的結構

想像你有 8 筆交易 Tx1 到 Tx8:

                    Root (根Hash)
                    /          \
           Hash(1-4)            Hash(5-8)
           /      \              /      \
     Hash(1-2)  Hash(3-4)  Hash(5-6)  Hash(7-8)
      /    \     /    \     /    \     /    \
    Tx1   Tx2  Tx3   Tx4  Tx5   Tx6  Tx7   Tx8

每個區塊的 Header 都包含 transactionsRoot,這就是 Merkle Tree 的根節點。

驗證某筆交易——Merkle Proof

假設你想驗證 Tx3 確實在這個區塊中。你不需要下載所有交易,只需要提供:

┌─────────────────────────────────────────────┐
│  Tx3 的 Merkle Proof                        │
├─────────────────────────────────────────────┤
│  1. Tx3 的 Hash                             │
│  2. Hash(Tx4)         → 計算 Hash(3-4)       │
│  3. Hash(Tx1-2)       → 計算 Hash(1-4)       │
│  4. Hash(Tx5-8)       → 計算 Root            │
│  5. 比對計算出的 Root 與區塊 Header 中的值 │
└─────────────────────────────────────────────┘

如果比對成功,就證明 Tx3 確實在這個區塊中!驗證成本從 O(n) 降到 O(log n)。

以太坊中的 Merkle 變種

以太坊其實用了兩種 Merkle 結構:

  1. Merkle Patricia Trie (MPT):用於存儲帳戶狀態(餘額、合約代碼等)
  2. Merkle Sum Trie:用於存儲交易和收據

MPT 比普通 Merkle Tree 更複雜,它能高效處理「前綴壓縮」和「更新」操作——因為區塊鏈的狀態是時刻變化的。


第五課:前編譯合約——以太坊內建的密碼學加速器

什麼是 Precompile?

以太坊虛擬機(EVM)原生並不擅長複雜的密碼學運算。如果你用 Solidity 純軟體實現橢圓曲線乘法,一筆交易可能要燃燒掉好幾個 ETH 的 Gas。

為了解決這個問題,以太坊在協議層面內建了 8 個「前編譯合約」——它們本質上是已編譯好的機器碼,執行效率比 EVM 解釋執行高出幾個數量級。

以太坊的前編譯合約

地址名稱功能
0x01ecrecover從簽名恢復簽署者地址
0x02sha256計算 SHA-256 Hash
0x03ripemd160計算 RIPEMD-160 Hash
0x04identity複製記憶體(資料驗證用)
0x05modExp模指數運算
0x06bn128AddBN128 曲線點加法
0x07bn128MulBN128 曲線標量乘法
0x08bn128PairingBN128 配對運算

使用前編譯合約——實例

ecrecover:這個超級重要!它讓你從簽名反推出地址,是智慧合約「驗證簽名」的基礎:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SignatureVerifier {
    /**
     * @notice 驗證簽名(使用 ecrecover 前編譯合約)
     * @param message 原始訊息
     * @param signature 簽名 (r, s, v)
     * @return 簽署者地址
     */
    function recoverSigner(
        bytes32 message,
        bytes32 r,
        bytes32 s,
        uint8 v
    ) public pure returns (address) {
        // ecrecover 返回與給定簽名對應的地址
        // 如果簽名無效,返回 0 地址
        return ecrecover(message, v, r, s);
    }
    
    /**
     * @notice 驗證訊息是否由特定地址簽署
     */
    function verify(
        address signer,
        bytes32 messageHash,
        bytes32 r,
        bytes32 s,
        uint8 v
    ) public pure returns (bool) {
        return recoverSigner(messageHash, r, s, v) == signer;
    }
}

Gas 消耗方面,ecrecover 只要 3000 Gas,而你自己用 Solidity 實現同樣功能可能需要數十萬 Gas!


實際應用場景

場景 1:錢包轉帳

當你用手機錢包轉帳 1 ETH 給朋友時,背後發生了什麼?

1. 錢包應用:
   - 你的私鑰存在手機的安全晶片中
   - 構造交易:from=你的地址, to=朋友地址, value=1 ETH
   - 計算交易的 Hash
   
2. 簽名過程:
   - 用私鑰對交易 Hash 進行 ECDSA 簽名
   - 產生的 (r, s, v) 附加到交易上
   
3. 廣播網路:
   - 節點收到交易,用公鑰驗證簽名
   - 如果驗證通過,交易進入內存池(mempool)
   
4. 區塊打包:
   - 礦工/驗證者將交易打包進區塊
   - 執行交易:扣減你的餘額,增加朋友的餘額

整個過程中,你的私鑰從頭到尾都沒有離開你的手機——這就是「非託管」的核心含義。

場景 2:智慧合約授權

當你在 Uniswap 上用 ETH 換 USDT 時:

1. 授權步驟:
   - 你簽署一筆「授權交易」,允許 Uniswap 合約
     最多動用你的 1000 ETH
   - 這個授權記錄在區塊鏈上,任何人都能查看
   
2. 兌換步驟:
   - 你調用 Uniswap 的 swap 函數
   - Uniswap 合約檢查你的授權額度
   - 如果額度足夠,合約自動轉走你的 ETH 並轉入 USDT

你不需要每次交易都簽名——授權一次,之後合約就能幫你執行。這大大提升了使用者體驗,但同時也帶來了安全風險:萬一合約有漏洞,你的資金可能被盜走。


常見誤解澄清

誤解 1:「區塊鏈是匿名的」

不完全對。區塊鏈是「假名」的——你的地址是一串隨機字元,看不出是誰。但如果有人能把你的地址和真實身份連結起來(例如你在某網站提供了地址),區塊鏈上的所有交易記錄都會暴露。

誤解 2:「私鑰丢了,區塊鏈公司可以幫你恢復」

錯!去中心化的意義就在於:沒有人能幫你恢復私鑰。如果你丢了私鑰,對應的資產就永遠無法訪問了。這就是為什麼「助記詞備份」如此重要。

誤解 3:「量子電腦出來,區塊鏈就完了」

這過度恐慌了。確實,Shor's algorithm 理論上可以在多項式時間內破解 ECDSA——但這需要數百萬個邏輯量子位元的通用量子電腦,而目前最先進的系統只有幾百個。而且,以太坊社群正在積極研究後量子密碼學遷移方案(如 CRYSTALS-Dilithium)。


繼續學習的路徑

恭喜你完成了密碼學入門!接下來你可以探索:


總結

今天我們學了:

  1. Hash:數據的唯一指紋,用於完整性驗證
  2. 公私鑰:你的數位身份,基於橢圓曲線數學
  3. 數位簽名:用私鑰「簽字」,用公鑰驗證
  4. Merkle Tree:高效驗證大量數據的樹狀結構
  5. 前編譯合約:以太坊內建的密碼學加速器

這些概念看起來抽象,但它們正是保護你資產安全的基石。搞懂了這些,你再看以太坊的各種操作——轉帳、簽名、部署合約——都會有「原來是這麼回事」的頓悟感。

下一篇文章,我們會深入探討密碼學在以太坊共識機制中的應用——特別是 POS 時代的 BLS 簽名和最終性保證。敬請期待!


延伸閱讀與參考

主題資源說明
密碼學基礎"Understanding Ethereum" by Andreas Antonopoulos經典教材,密碼學章節寫得很生動
ECDSA 原理CoinDesk 文章「Elliptic Curve Cryptography Explained」圖文並茂的科普文章
Merkle Tree以太坊官方文檔 - Trees官方對 Merkle Patricia Trie 的說明
Precompileethereum/execution-specs GitHub各前編譯合約的詳細規格

本指南旨在教育目的,不構成任何投資建議。密碼學是複雜的領域,建議在實際應用前充分測試。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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