返回 Expert 笔记
Expert Day 233

ZK 应用 — 游戏(Dark Forest)

Dark Forest 架构、ZK fog-of-war、move 电路、MiMC hash 用法

2026-12-20
Phase 4 - ZK电路开发实战 (Day 223-243)
ZKDark-ForestZK-gamefog-of-warautonomous-worlds

日期: 2026-12-20 方向: ZK工程 / 电路开发 阶段: Phase 4 - ZK电路开发实战 (Day 223-243) 标签: #ZK #Dark-Forest #ZK-game #fog-of-war #autonomous-worlds


今日目标

类型内容
学习Dark Forest 架构、ZK fog-of-war、move 电路、MiMC hash 用法
实操阅读 Dark Forest move/init/biome 电路源码
产出game_zk.md(电路分析 + 游戏模式归纳 + ZK 游戏未来)

背景与定位

Dark Forest 是什么?/ What is Dark Forest?

由 0xPARC(Brian Gu, Vivek Bhupatiraju 等)2020 年开发,第一个完全链上的 ZK 战略游戏

  • 玩家在一个无限的 ZK MMO 宇宙中探索、占领星球、攻击敌人。
  • 游戏地图是 procedurally generated(用 MiMC hash),但只有玩家自己挖出来的部分可见("fog of war")。
  • 玩家的星球坐标是私有的(ZK),其他人无法 doxx 你的位置。
  • "Dark Forest" 名字来自刘慈欣《三体》的「黑暗森林」隐喻——你不知道敌人在哪,先暴露的死。

为什么是 ZK 游戏的圣杯?/ Why is it the holy grail?

  • 传统链上游戏:所有状态公开 → 信息不对称游戏不可玩
  • Dark Forest:用 ZK 让 隐藏信息也能验证,开启了「全链上不完全信息游戏」赛道
  • 衍生:Lattice/MUD, 0xPARC autonomous worlds, Primodium, Sky Strife

核心架构

1. 地图生成 / Map Generation

For each (x, y) in infinite grid:
    h = MiMCSponge(x, y)             // deterministic hash
    if h % SCALE < THRESHOLD:
        planet exists at (x, y)
        planet_level = f(h)
        planet_type  = g(h)
        biome        = biomeHash(x, y)

地图是 deterministic 的——同样 (x, y) 永远 hash 出同样结果。但游戏只让玩家用 ZK 证明自己的星球存在 + 有效而不暴露坐标。

2. 三大核心电路

电路功能输入输出
init初始化星球(x, y) privateh = MiMC(x, y), level, type
move从 A 移动到 B(xA, yA, xB, yB) privatehA, hB, distance
biomebase揭示 biome(x, y) privatebiomeBase = perlin-like

每个电路保证「我知道一对坐标,hash 等于公开的 hash,并满足游戏规则」。


完整 init 电路源码(简化)

pragma circom 2.1.0;

include "circomlib/circuits/mimcsponge.circom";
include "circomlib/circuits/comparators.circom";

template Init(PLANETHASH_KEY, SPACETYPE_KEY, SCALE) {
    signal input x;          // private
    signal input y;          // private

    signal output pub[3];    // [planetHash, perlin, distFromOrigin]

    // 1. compute planetHash = MiMC(x, y, key)
    component mimc = MiMCSponge(2, 220, 1);
    mimc.ins[0] <== x;
    mimc.ins[1] <== y;
    mimc.k <== PLANETHASH_KEY;
    pub[0] <== mimc.outs[0];

    // 2. compute perlin (biome / spacetype)
    //    real version uses a multi-step deterministic perlin-like hash
    component spaceMimc = MiMCSponge(2, 220, 1);
    spaceMimc.ins[0] <== x;
    spaceMimc.ins[1] <== y;
    spaceMimc.k <== SPACETYPE_KEY;
    pub[1] <== spaceMimc.outs[0];

    // 3. distance from origin = x^2 + y^2  (no sqrt in ZK)
    pub[2] <== x*x + y*y;

    // 4. range check: |x|, |y| < 2^31 to prevent overflow
    component xCheck = Num2Bits(32);   // signed 32-bit
    xCheck.in <== x + (1 << 31);
    component yCheck = Num2Bits(32);
    yCheck.in <== y + (1 << 31);
}

component main {public [pub]} = Init(/*HASH_KEY*/420, /*SPACE_KEY*/666, 4096);

move 电路(核心,简化)

template Move(PLANETHASH_KEY, MAX_DISTANCE) {
    signal input x1, y1;     // private from
    signal input x2, y2;     // private to

    signal output pub[3];    // [hashFrom, hashTo, distSquared]

    // 1. hashes
    component h1 = MiMCSponge(2, 220, 1);
    h1.ins[0] <== x1;  h1.ins[1] <== y1;
    h1.k <== PLANETHASH_KEY;
    pub[0] <== h1.outs[0];

    component h2 = MiMCSponge(2, 220, 1);
    h2.ins[0] <== x2;  h2.ins[1] <== y2;
    h2.k <== PLANETHASH_KEY;
    pub[1] <== h2.outs[0];

    // 2. distance squared = (x2-x1)^2 + (y2-y1)^2
    signal dx;  dx <== x2 - x1;
    signal dy;  dy <== y2 - y1;
    signal distSq;
    distSq <== dx*dx + dy*dy;
    pub[2] <== distSq;

    // 3. distSq <= MAX_DISTANCE^2  (range proof)
    component lt = LessEqThan(64);
    lt.in[0] <== distSq;
    lt.in[1] <== MAX_DISTANCE * MAX_DISTANCE;
    lt.out === 1;
}

链上合约接收 (hashFrom, hashTo, distSq),验证 proof 后做:

  • check hashFrom is owned by msg.sender
  • transfer 一定量 silver/energy 从 hashFrom 到 hashTo
  • 如果 hashTo 已有 owner,触发战斗结算(按 attack power vs defense)

真实游戏数据 / Real Game Data

Dark Forest 历届 round

Round时间玩家数移动次数总 gas
v0.52020-08~500~50kETH mainnet (有点疯)
v0.62021-04~1k~200kxDai (gas 低 + 速度快)
v0.6.42021-06~3k~500kxDai
v0.6.52022-01~5k~1MxDai

后期 round 因 xDai gas 增加移动到 zkSync Lite / Optimism。

性能

操作Prove (浏览器)Verify gas
init~3 sec~250k
move~5 sec~280k
biomebase~3 sec~250k

约束数:

  • init: ~5,000 (主要是 MiMCSponge × 2)
  • move: ~10,000 (MiMCSponge × 2 + range check)

ZK 游戏的设计模式 / ZK Game Design Patterns

Pattern 1: Hidden state with revealable proof

「玩家知道 X,链上只有 Hash(X);玩家可以 ZK proof 关于 X 的属性」

  • Dark Forest: 坐标
  • Mafia/Werewolf: 角色
  • Card game: 手牌

Pattern 2: Commit-reveal with ZK validation

「玩家先 commit Hash(action),后 reveal 时用 ZK 证明 action 满足规则」

  • ZK Battleship: 攻击坐标
  • ZK Poker: 出牌

Pattern 3: Procedural generation with private discovery

「世界是 deterministic 函数,玩家用 ZK 证明发现的内容是合法生成的」

  • Dark Forest 地图
  • Lattice's Sky Strife (部分)

Pattern 4: Anti-cheat via ZK

「玩家声称『我连续走了合法路径到这里』,用 ZK proof 证明」

  • 移动验证 (Dark Forest move)
  • DeFi-style 无信任结算

ZK 游戏的工程挑战 / Engineering Challenges

挑战 1:浏览器 prove 太慢

5 秒生成 move proof,对快节奏游戏不够。优化:

  • WASM-based prover(snarkjs)
  • Native compile via circom --c
  • 后端代理 prover(牺牲信任)
  • Plonky2 / 更快 backend

挑战 2:链上 verify gas 高

每个 move 280k gas,xDai 还能接受,主网会爆。Dark Forest 用 L2(zkSync Lite, Optimism)。新趋势:用 application-specific rollup。

挑战 3:地图同步

玩家本地需要扫描 (x, y) grid 找星球(perlin noise → 需要计算大量 hash)。Dark Forest 用 web worker + miner 后台扫描,但还是慢。

挑战 4:协作攻击

两玩家串通可以共享坐标信息。这不是 ZK 能解决的,是 game theory 问题。


衍生项目 / Successors

项目创新点状态
MUD (Lattice)ZK 游戏框架 + ECS主流框架
Sky StrifeRTS on MUD上线
Primodium太空 4X上线
0xPARC zkREPL浏览器 ZK 编程工具
Conquest.ethDF 改进版试运行
TarochiRPG实验

0xPARC 的 "Autonomous Worlds" 哲学

0xPARC 提出「Autonomous Worlds」概念:

  • 游戏规则完全在链上(不是「链下游戏 + 链上结算」)
  • 任何人可以扩展(部署新合约 = 在世界中加新规则)
  • ZK 让「不完全信息」成为可能 → 真正的策略游戏

参考 Ludens 文章:Autonomous Worlds (Part 1)


关键速查

Dark Forest 三大电路:
  init        — 创建星球
  move        — 移动 + 战斗
  biomebase   — 揭示 biome

Hash: MiMCSponge (220 rounds, 2 inputs)
约束: ~5k - 10k per circuit
Prove: 3-5 sec (browser, snarkjs)
Verify: ~250-280k gas (Groth16)

面试题

  1. Q: 为什么 Dark Forest 用 MiMC 而不是 Poseidon? A: 历史原因——Dark Forest 2020 年开发时 Poseidon 在 Circom 还不流行,MiMC 是当时主流 ZK hash。MiMC 约束 ~220/hash 略多于 Poseidon-2 的 215,但单输入快(用于 biome perlin 计算)。新项目都用 Poseidon。

  2. Q: ZK 游戏的「fog of war」是怎么实现的? A: 玩家 client 本地知道完整 (x, y);链上只存 hash。玩家提交 proof 时只暴露公开属性(distance, level)。其他玩家从链上事件看不到坐标,从而实现「迷雾」。

  3. Q: 既然 ZK 让 hidden state 可能,为什么链上游戏发展慢? A: 三大瓶颈:(1) ZK prove 慢(5s/move 不适合快节奏);(2) gas 贵(即使 L2 也比 web2 慢且贵);(3) 工具链复杂。MUD 框架 + 更快 prover (Plonky3, RISC0) 在改善这些。

  4. Q: Dark Forest 如何防止玩家提交假坐标? A: hash 在电路里强制 MiMC(x, y) === pub[0];玩家不能伪造 (x, y) 让 hash 等于别人的星球(hash 抗碰撞)。如果玩家提交「自己的 hash」但坐标其实是无效的(如出地图),距离/range 约束会失败。


明日预告

Day 234 — zk-Rollup 架构对比:Linea / zkSync Era / Scroll / Polygon zkEVM 横向对比,附真实合约地址、TVL、技术栈。