Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第五十一章 区块链与加密货币

去中心化的信任机器:从密码学原语到分布式共识

区块链(Blockchain)是近年来最具影响力的密码学应用之一。它巧妙地组合了哈希函数、数字签名、默克尔树等密码学原语,配合共识机制,构建了一个无需中心化机构即可实现信任传递的分布式系统。本章将从密码学视角剖析区块链的核心原理,并用 Rust 实现一个简化但完整的区块链。

51.1 区块链基本原理

什么是区块链

区块链本质上是一个分布式的、不可篡改的、按时间顺序链接的账本。其核心特征包括:

  • 去中心化:没有单一控制方,网络中的节点共同维护账本
  • 不可篡改:一旦数据被写入,几乎不可能被修改
  • 透明性:所有交易对网络参与者可见(或按权限可见)
  • 可追溯:每笔交易都有完整的历史链条

区块结构

每个区块通常包含以下部分:

+----------------------------------+
|  区块头(Block Header)           |
|  - 前一区块哈希(Previous Hash)  |
|  - 时间戳(Timestamp)            |
|  - 默克尔根(Merkle Root)        |
|  - 随机数(Nonce)                |
|  - 难度目标(Difficulty Target)  |
+----------------------------------+
|  区块体(Block Body)             |
|  - 交易列表(Transactions)       |
+----------------------------------+

前一区块哈希将区块链接成链:修改任何一个区块的数据,其哈希会改变,导致后续所有区块的链接断裂。

链式结构

创世区块(Genesis Block)
    Hash: 0000a3f2...
    Previous: 00000000...
         |
         v
区块 1
    Hash: 0000b8e1...
    Previous: 0000a3f2...  ← 指向创世区块的哈希
         |
         v
区块 2
    Hash: 00001c4d...
    Previous: 0000b8e1...  ← 指向区块 1 的哈希
         |
         v
区块 3
    Hash: 0000f92a...
    Previous: 00001c4d...  ← 指向区块 2 的哈希

这种链式结构使得篡改成本极高:攻击者不仅要修改目标区块,还要重新计算该区块之后所有区块的工作量证明。

51.2 哈希链与默克尔树

哈希指针

区块链使用哈希指针(Hash Pointer)替代普通指针。哈希指针不仅指向数据的位置,还包含该数据的哈希值,从而可以验证数据是否被篡改。

#![allow(unused)]
fn main() {
struct HashPointer<T> {
    data: T,
    hash: [u8; 32],  // 数据的 SHA-256 哈希
}

fn verify_integrity<T: AsRef<[u8]>>(pointer: &HashPointer<T>) -> bool {
    let computed_hash = sha256(pointer.data.as_ref());
    computed_hash == pointer.hash
}
}

默克尔树(Merkle Tree)

默克尔树是一种二叉树结构,用于高效验证大量数据的完整性。

                    Root Hash
                   /         \
              Hash(A+B)    Hash(C+D)
              /      \      /      \
            Hash(A) Hash(B) Hash(C) Hash(D)
              |        |      |        |
             Tx A    Tx B   Tx C    Tx D

默克尔树的优势

  • 高效验证:要验证交易 C 是否包含在区块中,只需提供 Hash(D) 和 Hash(A+B),共 O(log n) 个哈希
  • 轻节点友好:SPV(简单支付验证)节点只需存储区块头(80 字节),无需下载完整交易数据

默克尔证明

#![allow(unused)]
fn main() {
// 验证交易是否包含在区块中
fn verify_merkle_proof(
    tx_hash: &[u8; 32],
    merkle_root: &[u8; 32],
    proof: &[(bool, [u8; 32])],  // (is_right_sibling, sibling_hash)
) -> bool {
    let mut current_hash = *tx_hash;

    for &(is_right, sibling) in proof {
        current_hash = if is_right {
            sha256_concat(&current_hash, &sibling)
        } else {
            sha256_concat(&sibling, &current_hash)
        };
    }

    current_hash == *merkle_root
}
}

51.3 共识机制

共识机制解决分布式系统中的拜占庭将军问题:如何在可能存在恶意节点的网络中达成一致?

工作量证明(Proof of Work, PoW)

PoW 是比特币采用的共识机制。节点(矿工)通过计算难题来竞争记账权。

工作原理

  1. 矿工收集待确认交易,构建候选区块
  2. 不断改变随机数(Nonce),计算区块头的哈希
  3. 当哈希值小于难度目标(即哈希前面有足够多的 0)时,找到有效区块
  4. 将区块广播到网络,其他节点验证后接受
目标:找到 nonce,使得 SHA256(SHA256(block_header)) < target

难度目标示例:
  00000000 00000000 00000000 00000000 00000000 00000000 0000ffff 00000000
  
有效哈希示例:
  00000000 00000000 00000000 00000000 00000000 00000000 0000a3f2 8b1c4d5e

难度调整:比特币每 2016 个区块(约 2 周)调整一次难度,使平均出块时间保持在 10 分钟左右。

PoW 的优缺点

优点缺点
安全性高,攻击成本巨大能源消耗巨大
去中心化程度高交易确认慢(比特币约 10 分钟/区块)
无需准入许可存在算力集中风险

权益证明(Proof of Stake, PoS)

PoS 是以太坊 2.0 等新型区块链采用的共识机制。验证者通过质押代币来获得记账权。

工作原理

  1. 验证者质押一定数量的代币作为“保证金“
  2. 系统根据质押金额、质押时长等因素随机选择出块者
  3. 验证者提议区块,其他验证者投票确认
  4. 作恶者的质押金会被罚没(Slashing)

PoS 的优缺点

优点缺点
能耗极低(比 PoW 低 99% 以上)可能加剧财富集中
交易确认快安全性理论不如 PoW 成熟
可扩展性更好存在“无利害关系“问题

其他共识机制

机制代表项目核心思想
DPoSEOS代币持有者投票选举代表节点
PBFTHyperledger Fabric多轮投票达成拜占庭容错共识
AvalancheAvalanche随机抽样投票,快速最终确认
PoHSolana历史证明,创建可验证的时间序列

51.4 智能合约简介

什么是智能合约

智能合约(Smart Contract)是运行在区块链上的自动执行的程序代码。它类似于传统合约,但执行不依赖任何第三方,代码即法律(Code is Law)。

智能合约的特征

  • 自动执行:满足条件时自动触发,无需人工干预
  • 不可篡改:部署后代码不可修改
  • 透明公开:代码和执行结果对所有人可见
  • 确定性:给定相同输入,所有节点执行结果一致

智能合约示例(概念)

// 简单的以太坊智能合约:众筹
pragma solidity ^0.8.0;

contract Crowdfunding {
    address public beneficiary;
    uint public goal;
    uint public deadline;
    mapping(address => uint) public contributions;

    constructor(address _beneficiary, uint _goal, uint _duration) {
        beneficiary = _beneficiary;
        goal = _goal;
        deadline = block.timestamp + _duration;
    }

    function contribute() public payable {
        require(block.timestamp < deadline, "众筹已结束");
        contributions[msg.sender] += msg.value;
    }

    function withdraw() public {
        require(block.timestamp >= deadline, "众筹未结束");
        require(address(this).balance >= goal, "未达到目标金额");
        payable(beneficiary).transfer(address(this).balance);
    }
}

Rust 与智能合约

Rust 正成为区块链智能合约开发的重要语言:

  • Solana:使用 Rust 编写智能合约(Program)
  • Polkadot/Substrate:使用 Rust 构建区块链和智能合约
  • Near Protocol:支持 Rust 编写智能合约
  • Cosmos:Rust 是主要开发语言之一
#![allow(unused)]
fn main() {
// Solana 智能合约示例(简化概念)
use solana_program::{
    account_info::AccountInfo,
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey,
    msg,
};

entrypoint!(process_instruction);

fn process_instruction(
    _program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    msg!("Hello, Solana!");
    msg!("账户数量: {}", accounts.len());
    Ok(())
}
}

51.5 Rust 实现:简单区块链

区块定义

#![allow(unused)]
fn main() {
use sha2::{Sha256, Digest};
use chrono::Utc;
use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
    pub index: u64,
    pub timestamp: i64,
    pub data: String,
    pub previous_hash: String,
    pub hash: String,
    pub nonce: u64,
}

impl Block {
    pub fn new(index: u64, data: String, previous_hash: String) -> Self {
        let timestamp = Utc::now().timestamp();
        let mut block = Block {
            index,
            timestamp,
            data,
            previous_hash,
            hash: String::new(),
            nonce: 0,
        };
        block.hash = block.calculate_hash();
        block
    }

    pub fn calculate_hash(&self) -> String {
        let input = format!(
            "{}{}{}{}{}",
            self.index, self.timestamp, self.data, self.previous_hash, self.nonce
        );
        let mut hasher = Sha256::new();
        hasher.update(input);
        format!("{:x}", hasher.finalize())
    }
}
}

工作量证明挖矿

#![allow(unused)]
fn main() {
impl Block {
    pub fn mine(&mut self, difficulty: usize) {
        let target = "0".repeat(difficulty);
        
        while !self.hash.starts_with(&target) {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
        
        println!(
            "区块 {} 挖矿成功! nonce: {}, hash: {}",
            self.index, self.nonce, self.hash
        );
    }
}
}

区块链结构

#![allow(unused)]
fn main() {
#[derive(Debug, Serialize, Deserialize)]
pub struct Blockchain {
    pub chain: Vec<Block>,
    pub difficulty: usize,
    pub pending_transactions: Vec<Transaction>,
    pub mining_reward: f64,
}

impl Blockchain {
    pub fn new(difficulty: usize) -> Self {
        let genesis_block = Block::new(
            0,
            "创世区块".to_string(),
            "0".repeat(64),
        );

        Blockchain {
            chain: vec![genesis_block],
            difficulty,
            pending_transactions: Vec::new(),
            mining_reward: 100.0,
        }
    }

    pub fn get_latest_block(&self) -> &Block {
        self.chain.last().expect("链不应为空")
    }

    pub fn add_block(&mut self, mut new_block: Block) {
        new_block.previous_hash = self.get_latest_block().hash.clone();
        new_block.mine(self.difficulty);
        self.chain.push(new_block);
    }

    pub fn is_chain_valid(&self) -> bool {
        for i in 1..self.chain.len() {
            let current = &self.chain[i];
            let previous = &self.chain[i - 1];

            // 验证当前区块哈希
            if current.hash != current.calculate_hash() {
                println!("区块 {} 的哈希无效", i);
                return false;
            }

            // 验证链的连续性
            if current.previous_hash != previous.hash {
                println!("区块 {} 的前一哈希链接断裂", i);
                return false;
            }

            // 验证工作量证明
            let target = "0".repeat(self.difficulty);
            if !current.hash.starts_with(&target) {
                println!("区块 {} 的工作量证明无效", i);
                return false;
            }
        }
        true
    }
}
}

交易与默克尔树

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
    pub from: String,
    pub to: String,
    pub amount: f64,
    pub timestamp: i64,
}

impl Transaction {
    pub fn new(from: String, to: String, amount: f64) -> Self {
        Transaction {
            from,
            to,
            amount,
            timestamp: Utc::now().timestamp(),
        }
    }

    pub fn hash(&self) -> String {
        let input = format!("{}{}{}{}", self.from, self.to, self.amount, self.timestamp);
        let mut hasher = Sha256::new();
        hasher.update(input);
        format!("{:x}", hasher.finalize())
    }
}

// 计算默克尔根
pub fn calculate_merkle_root(transactions: &[Transaction]) -> String {
    if transactions.is_empty() {
        return "0".repeat(64);
    }

    let mut hashes: Vec<String> = transactions.iter()
        .map(|tx| tx.hash())
        .collect();

    while hashes.len() > 1 {
        if hashes.len() % 2 != 0 {
            hashes.push(hashes.last().unwrap().clone());
        }

        let mut next_level = Vec::new();
        for i in (0..hashes.len()).step_by(2) {
            let combined = format!("{}{}", hashes[i], hashes[i + 1]);
            let mut hasher = Sha256::new();
            hasher.update(combined);
            next_level.push(format!("{:x}", hasher.finalize()));
        }
        hashes = next_level;
    }

    hashes[0].clone()
}
}

完整的区块链演示

use sha2::{Sha256, Digest};
use chrono::Utc;
use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Transaction {
    from: String,
    to: String,
    amount: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Block {
    index: u64,
    timestamp: i64,
    transactions: Vec<Transaction>,
    previous_hash: String,
    merkle_root: String,
    hash: String,
    nonce: u64,
}

impl Block {
    fn new(index: u64, transactions: Vec<Transaction>, previous_hash: String) -> Self {
        let timestamp = Utc::now().timestamp();
        let merkle_root = calculate_merkle_root(&transactions);
        let mut block = Block {
            index,
            timestamp,
            transactions,
            previous_hash,
            merkle_root,
            hash: String::new(),
            nonce: 0,
        };
        block.hash = block.calculate_hash();
        block
    }

    fn calculate_hash(&self) -> String {
        let input = format!(
            "{}{}{}{}{}{}",
            self.index, self.timestamp, self.merkle_root,
            self.previous_hash, self.nonce,
            serde_json::to_string(&self.transactions).unwrap_or_default()
        );
        let mut hasher = Sha256::new();
        hasher.update(input);
        format!("{:x}", hasher.finalize())
    }

    fn mine(&mut self, difficulty: usize) {
        let target = "0".repeat(difficulty);
        while !self.hash.starts_with(&target) {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
    }
}

fn calculate_merkle_root(transactions: &[Transaction]) -> String {
    if transactions.is_empty() {
        return "0".repeat(64);
    }
    let mut hashes: Vec<String> = transactions.iter().map(|tx| {
        let input = format!("{}{}{}", tx.from, tx.to, tx.amount);
        let mut hasher = Sha256::new();
        hasher.update(input);
        format!("{:x}", hasher.finalize())
    }).collect();

    while hashes.len() > 1 {
        if hashes.len() % 2 != 0 {
            hashes.push(hashes.last().unwrap().clone());
        }
        let mut next_level = Vec::new();
        for i in (0..hashes.len()).step_by(2) {
            let combined = format!("{}{}", hashes[i], hashes[i + 1]);
            let mut hasher = Sha256::new();
            hasher.update(combined);
            next_level.push(format!("{:x}", hasher.finalize()));
        }
        hashes = next_level;
    }
    hashes[0].clone()
}

struct Blockchain {
    chain: Vec<Block>,
    difficulty: usize,
    pending_transactions: Vec<Transaction>,
}

impl Blockchain {
    fn new() -> Self {
        let genesis = Block::new(0, vec![], "0".repeat(64));
        Blockchain {
            chain: vec![genesis],
            difficulty: 4,
            pending_transactions: Vec::new(),
        }
    }

    fn add_transaction(&mut self, tx: Transaction) {
        self.pending_transactions.push(tx);
    }

    fn mine_pending_transactions(&mut self, miner_address: String) {
        // 奖励交易
        let reward_tx = Transaction {
            from: "network".to_string(),
            to: miner_address,
            amount: 50.0,
        };
        self.pending_transactions.push(reward_tx);

        let mut block = Block::new(
            self.chain.len() as u64,
            self.pending_transactions.clone(),
            self.chain.last().unwrap().hash.clone(),
        );
        block.mine(self.difficulty);
        self.chain.push(block);
        self.pending_transactions.clear();
    }

    fn is_valid(&self) -> bool {
        for i in 1..self.chain.len() {
            let current = &self.chain[i];
            let previous = &self.chain[i - 1];

            if current.hash != current.calculate_hash() {
                return false;
            }
            if current.previous_hash != previous.hash {
                return false;
            }
            if !current.hash.starts_with(&"0".repeat(self.difficulty)) {
                return false;
            }
        }
        true
    }

    fn get_balance(&self, address: &str) -> f64 {
        let mut balance = 0.0;
        for block in &self.chain {
            for tx in &block.transactions {
                if tx.from == address {
                    balance -= tx.amount;
                }
                if tx.to == address {
                    balance += tx.amount;
                }
            }
        }
        balance
    }
}

fn main() {
    let mut blockchain = Blockchain::new();

    println!("=== 开始挖矿 ===");
    blockchain.add_transaction(Transaction {
        from: "alice".to_string(),
        to: "bob".to_string(),
        amount: 10.0,
    });
    blockchain.mine_pending_transactions("miner1".to_string());

    blockchain.add_transaction(Transaction {
        from: "bob".to_string(),
        to: "charlie".to_string(),
        amount: 5.0,
    });
    blockchain.mine_pending_transactions("miner1".to_string());

    println!("\n=== 区块链状态 ===");
    for block in &blockchain.chain {
        println!("区块 {}: {}", block.index, block.hash);
    }

    println!("\n=== 余额查询 ===");
    println!("miner1: {}", blockchain.get_balance("miner1"));
    println!("alice: {}", blockchain.get_balance("alice"));
    println!("bob: {}", blockchain.get_balance("bob"));
    println!("charlie: {}", blockchain.get_balance("charlie"));

    println!("\n=== 验证区块链 ===");
    println!("有效: {}", blockchain.is_valid());

    // 尝试篡改
    println!("\n=== 篡改测试 ===");
    if blockchain.chain.len() > 1 {
        blockchain.chain[1].transactions[0].amount = 1000.0;
        println!("篡改后有效: {}", blockchain.is_valid());
    }
}

Cargo.toml 依赖

[dependencies]
sha2 = "0.10"
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

51.6 本章总结

概念说明Rust 应用
哈希链用前一区块哈希链接区块,保证不可篡改sha2 crate
默克尔树高效验证交易完整性的二叉树结构自定义实现或 rs_merkle
PoW通过计算难题竞争记账权CPU/GPU 挖矿程序
PoS通过质押代币获得记账权验证者节点实现
智能合约区块链上自动执行的代码Solana/Substrate 合约
数字签名交易所有权验证ed25519-dalek, secp256k1

练习建议

  1. 基础练习:运行上述区块链示例,调整 difficulty 参数观察挖矿时间变化。

  2. 中级练习:为区块链添加数字签名验证:每笔交易必须由发送方签名,节点验证签名后才接受交易。

  3. 高级练习:实现一个简单的 P2P 网络同步:多个节点可以互相广播区块,维护一致的区块链副本。

  4. 实践项目:使用 substrate 框架搭建一条自定义区块链,或编写一个 Solana 智能合约实现简单的代币转账。


密码学箴言:区块链不是魔法,而是密码学原语的精妙组合。理解哈希、签名和共识,就理解了区块链的本质。